/*
 *	vrfytool.c
 *
 *	tool that does read a data-stream from stdin and does compare
 *	it with a file on the hard disk.
 *	23.09.99 tn
 *
 *
 *  Copyright (C) 1995, 1996, 1997 Free Software Foundation, Inc.
 *
 *  This file is part of xcdroast.
 *
 *  This program is free software; you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation; either version 2 of the License, or
 *  (at your option) any later version.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with this program; if not, write to the Free Software
 *  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 */

#ifdef HAVE_CONFIG_H
# include <config.h>
#endif

#include "largefile.h"

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <errno.h>
#include <glib.h>
#include "xcdroast.h"

#define WAVHEADER 44

void usage() {
	g_print("Usage: vrfytool [-d|-a] <file1> <file2> (Version: %s)\n", XCDROAST_VERSION);
	g_print("\twhen file2 is a dash (-) then compare from stdin\n");
	g_print("\t -d: compare data-files (blocksize: 2048)\n");
	g_print("\t -b: compare data-files (blocksize: 512)\n");
	g_print("\t -a: compare audio-files (blocksize: 2352)\n");
}

gint main(gint argc, gchar **argv) {
gchar file1[MAXLINE];
gchar file2[MAXLINE];
guchar *buf1;
guchar *buf2;
struct stat buf;
off_t size;
gint fd1, fd2;
gint nread1, nread2;
off_t bytesread;
gint percent, oldpercent;
gint bs;

	if (argc != 4) {
		usage();
		exit(1);
	}
	bs = 0;

	if (strcmp(argv[1],"-a") == 0) {
		bs = CDDAFRAME;
	}
	if (strcmp(argv[1],"-d") == 0) {
                bs = DATASECTORSIZE;
	}
	if (strcmp(argv[1],"-b") == 0) {
                bs = SUNDATASECTORSIZE;
	}

	if (bs == 0) {
		usage();
		exit(1);
	}

	strncpy(file1,argv[2],MAXLINE);
	strncpy(file2,argv[3],MAXLINE);

	/* get filesize */
	if (stat(file1,&buf) != 0) {
		g_print("Error stating %s: %s\n",file1,strerror(errno));
		exit(1);
	}

	/* calculate how many bytes to handle */
	size = buf.st_size;

	buf1 = (guchar *)g_new(guchar, bs);
	buf2 = (guchar *)g_new(guchar, bs);

	/* open first file */
	fd1 = open(file1, O_RDONLY, 0);
	if (fd1 < 0) {
		g_print("Error opening %s: %s\n",file1,strerror(errno));
		exit(1);
	}

	/* open second file..or do read from stdin */
	if (strcmp(file2, "-") == 0) {
		fd2 = STDIN_FILENO;
	} else {
		fd2 = open(file2, O_RDONLY, 0);
		if (fd2 < 0) {
			g_print("Error opening %s: %s\n",file2,strerror(errno));
			exit(1);
		}
	}

	bytesread = 0;
	oldpercent = 0;

	g_print("Verifying %s (%"LL_FORMAT" bytes)\n",file1,(gint64) size);
	fflush(stdout);

	/* start comparing */
	while (1) {

		/* first sector for audio-files is only the wavheader */
		/* so read first 44 bytes and then always 2352 bytes */
		if (bs == WAVHEADER) {
			bs = CDDAFRAME;
		}
		if (bs == CDDAFRAME && bytesread == 0) {
			bs = WAVHEADER;
		}

		nread1 = read(fd1, buf1, bs);
		if (nread1 < 0) {
			g_print("Error reading %s: %s\n",file1,strerror(errno));
			exit(1);
		}

		/* EOF */
		if (nread1 == 0) 
			break;

		/* read exactly as many bytes from stdin as from file */
		nread2 = read(fd2, buf2, nread1);
		if (nread2 < 0) {
			g_print("Error reading %s: %s\n",file2,strerror(errno));
			exit(1);
		}

		if (nread1 != nread2 || nread1 < bs || nread2 < bs) {
			g_print("Warning: Short read on position %"LL_FORMAT"\n", (gint64) bytesread);
			exit(1);
		}

		if (memcmp(buf1,buf2,bs) != 0) {
			g_print("Warning: Files differ on position %"LL_FORMAT"\n", (gint64) bytesread);
			exit(1);
		}

		bytesread+=(off_t) nread1;

		/* output percent meter */
		percent = ((gint)((off_t)bytesread >> 10) * 100) / 
			(gint)((off_t)size >> 10);
		if (percent != oldpercent) {
			g_print(" %d%%\n", percent);
			fflush(stdout);
			oldpercent = percent;
		}
	}

	if (bytesread != size) {
		g_print("Warning: different file sizes.\n");
		exit(1);
	}

	/* continue comparing the rest of stdin with optional padding zeros */
	while (1) {

		nread2 = read(fd2, buf2, bs);
		if (nread2 < 0) {
			g_print("Error reading %s: %s\n",file2,strerror(errno));
			exit(1);
		}

		/* EOF */
		if (nread2 == 0) 
			break;

		if (nread2 < bs) {
			g_print("Warning: Short read on position %"LL_FORMAT"\n", (gint64) bytesread);
			exit(1);
		}

		memset (buf1, 0, bs);

		if (memcmp(buf1,buf2,bs) != 0) {
			g_print("Warning: Files differ on position %"LL_FORMAT"\n", (gint64) bytesread);
			exit(1);
		}
	}

	g_free(buf1);
	g_free(buf2);
	
	close(fd1);
	close(fd2);

	/* padding is usually 15 sectors by cdrecord */
	if (bytesread < size || bytesread > size+15*bs) {
		g_print("Warning: different file sizes.\n");
		exit(1);
	}

	/* all ok - compare perfect */
	g_print("Compare of %s successful.\n",file1);
	fflush(stdout);

	return 0;
}	
