/* This sample source code shows how to retrieve the checksum in a GP2
 * track file and how to calculate the checksum based on the file contents.
 * Checksum is either printed using the long value (4 bytes) and the two
 * short values (2bytes).
 */

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

int main(int argc, char** argv)
{
	FILE* fp;

	unsigned long checksum;
	unsigned short check1, check2;

	long size;
	unsigned char c = 0;

	fp = fopen(argv[1], "rb");
	if (fp == NULL) {
		fprintf(stderr, "Unable to open file %s\n", argv[1]);
		return 1;
	}

	/* Get the length of the file */

	fseek(fp, 0L, SEEK_END);
	size = ftell(fp);

	/* Fetch Checksum from the file */

	fseek(fp, -4L, SEEK_CUR);
	fread(&checksum, 4, 1, fp);

	fseek(fp, -4L, SEEK_CUR);
	fread(&check1, 2, 1, fp);
	fread(&check2, 2, 1, fp);

	printf("File Checksum is 0x%.8x 0x%.4x 0x%.4x\n", checksum, check1, check2);

	/* Computing Checksum */

	checksum= 0;
	check2 = 0;
	check1 = 0;

	fseek(fp, 0L, SEEK_SET);

	/* The checksum1 is the sum of all bytes, up to (size - 4).
	 * The checksum2 is rotated on the left by three before being added
	 * to the current byte.
	 */

	while (ftell(fp) < (size - 4)) {
		check1 += c;
		check2 += c;
		c = fgetc(fp);
		check2 = (check2 << 3) + (check2 >> 13);
	}
	
	checksum = (check2 << 16) + check1;

	printf("Computed Checksum is 0x%.8x 0x%.4x 0x%.4x\n", checksum, check1, check2);

	fclose(fp);
	return 0;
}

