/*
 * sfv checker by Andreas Henriksson <andreas@fatal.se>
 *
 * TODO: 
 * Check how filenames which includes spaces are encoded in SFV files.
 */

#include <stdio.h>
#include <stdlib.h> /* exit */
#include <string.h> /* strlen */

#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>

#include "zlib.h"

static int verbose = 0;

void usage(char *name)
{
	fprintf(stderr, "%s <file.sfv>\n", name);
}

int read_buffer (int fd, char buffer[], size_t *length)
{
	*length = 1024;
	*length = read(fd, buffer, *length);
	if (*length == 0)
		return EOF;

	return *length;
}

int validate_crc(char *file, char *sfvcrc)
{
	int fd;
	char buffer[1024];
	size_t length;
	unsigned long crc = crc32 (0UL, NULL, 0);

	fd = open(file, O_RDONLY); 
	if (fd < 0) {
		fprintf(stderr, "ERROR opening file %s\n", file);
		return -2;
	}

	while (read_buffer (fd, buffer, &length) != EOF) {
		crc = crc32 (crc, buffer, length);
	}

	close(fd);

	//printf("DEBUG: name=%s, sfvcrc=%s, crc=%08X\n",
	//		file, sfvcrc, crc);

	sprintf(buffer, "%08X", crc);
	return (strcasecmp(buffer, sfvcrc) == 0);
}

int parse_sfv(char *sfvfile)
{
	FILE* fp;
	int ret = 0;
	char buf[1024];

	fp = fopen(sfvfile, "r");
	if (!fp) {
		fprintf(stderr, "Failed to open %s\n", sfvfile);
		return -1;
	}

	while (fgets(buf, sizeof(buf), fp)) {
		int buflen = strlen(buf);
		char *sfv_crcstart;

		/* skip comment lines */
		if (buf[0] == ';')
			continue;

		/* find name/crc beginning/end */
		sfv_crcstart = strrchr(buf, ' ');
		if (!sfv_crcstart) {
			fprintf(stderr, "ERROR parsing '%s'\n", buf);
			continue;
		}
		*(sfv_crcstart++) = '\0';

		/* crc has 8 characters,
		 * strip of trailing newlines and whatever.
		 */
		buflen = sfv_crcstart + 8 - buf;
		*(sfv_crcstart+8) = '\0';


		/* convert paths to unix style */
		for (int i = 0; i < sfv_crcstart-buf; i++) {
			/* replace dos dir separator character */
			if (buf[i] == '\\')
				buf[i]='/';

			/* break at first space == name/crc separator */
			/* FIXME: is the first space the separator?
			 * Maybe it's the last? How does files with space
			 * get encoded.
			 */
			if (buf[i] == ' ')
				break;
		}

		//printf("DEBUG: name=%s, crc=%s\n", buf, sfv_crcstart);

		if (!validate_crc(buf, sfv_crcstart)) {
			fprintf(stderr, "CRC for %s does not match %s!\n",
					buf, sfv_crcstart);
			continue;
		} else if (verbose) {
			printf("CRC %s match for %s\n", sfv_crcstart, buf);
		}
	}
	

out:
	fclose(fp);
	return ret;
}


int main (int argc, char **argv)
{
	char *sfvfile;

	if (argc < 2) {
		usage(argv[0]);
		exit(-1);
	}

	sfvfile = argv[1];

	if ((argc > 2) && (*argv[1] == '-')) {
		int i = 1;

		sfvfile = argv[2];

		while (argv[1][i++] == 'v')
			verbose++;
	}

	if (parse_sfv(sfvfile) != 0) {
		fprintf(stderr, "CRC errors found!\n");
		exit(-2);
	} else if (verbose) {
		printf("All OK!\n");
	}

	return 0;
}


