/*
 * tool to check and gain some basic information about videodum-files
 */

/* enable files > 2GB on 32 bit systems */
#define _LARGEFILE64_SOURCE 1
#define _FILE_OFFSET_BITS 64

#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#ifdef BUILD_WINDOWS
#else
#include <arpa/inet.h>
#endif

#include <string>

std::string convert_from_pixelformat (uint32_t fmt) {
	char txt[5];

	snprintf (txt, 5, "%c%c%c%c", ((char*)&fmt)[0], ((char*)&fmt)[1], ((char*)&fmt)[2], ((char*)&fmt)[3]);
	return txt;
};



int fixfile(char *src, char *dest) {
	int fd, fd2;
	int cnt = 0;
	char *inbuf = NULL;
	int inbufsize = 0;
	int frmcnt = 0;

	uint32_t i;
	uint32_t size, size2;

	printf ("fix file:'%s'   output file:'%s'\n", src, dest);

	if ((fd = open (src, O_RDONLY)) < 0) {
		printf ("could not open input file: %s\n", strerror(errno));
		return -1;
	}

	if ((fd2 = open (dest, O_WRONLY | O_CREAT | O_TRUNC), S_IRUSR | S_IWUSR) < 0) {
		printf ("could not open output file: %s\n", strerror(errno));
		close (fd);
		return -1;
	}

	//
	// read header w, h, pixfmt
	if (read (fd, &i, 4) != 4) {
		printf ("could not read all bytes.\n");
		close (fd);
		return -1;
	}
	if (write (fd2, &i, 4) != 4) {
		printf ("could not write all bytes.\n");
		close (fd2);
		close (fd);
		return -1;
	}
	printf ("      Width: %d\n", ntohl(i));

	if (read (fd, &i, 4) != 4) {
		printf ("could not read all bytes.\n");
		close (fd);
		return -1;
	}
	if (write (fd2, &i, 4) != 4) {
		printf ("could not write all bytes.\n");
		close (fd2);
		close (fd);
		return -1;
	}
	printf ("      Height: %d\n", ntohl(i));

	if (read (fd, &i, 4) != 4) {
		printf ("could not read all bytes.\n");
		close (fd);
		return -1;
	}
	if (write (fd2, &i, 4) != 4) {
		printf ("could not write all bytes.\n");
		close (fd2);
		close (fd);
		return -1;
	}
	printf("      Pixfmt: %s\n", convert_from_pixelformat(ntohl(i)).c_str());


	//
	// read frame
	while (read (fd, &size, 4) == 4) {
		size = ntohl(size);
		size2 = htonl(size / 2);
		if (write (fd2, &size2, 4) != 4) {
			printf ("could not write framesize of frame %d.\n", frmcnt);
			close (fd2);
			close (fd);
			return -1;
		}

		if (read (fd, &i, 4) != 4) {
			printf ("could not read all bytes.\n");
			close (fd);
			return -1;
		}
		if (write (fd2, &i, 4) != 4) {
			printf ("could not write timestamp of frame %d.\n", frmcnt);
			close (fd2);
			close (fd);
			return -1;
		}
		i = ntohl(i);

		if (inbuf == NULL){
			inbuf = (char*) malloc (size);
			inbufsize = size;
		}
		else if (inbufsize < size) {
			inbuf = (char*)realloc(inbuf, size);
			inbufsize = size;
		}

		if (inbuf == NULL) {
			printf ("Error could not allocate enough memory\n");
			close (fd);
			return -1;
		}
		if (read (fd, inbuf, size) != size) {
			printf ("could not read to next frame.\n");
			close (fd);
			return -1;
		}
		if (write (fd2, inbuf, size/2) != size/2) {
			printf ("could not write frame %d.\n", frmcnt);
			close (fd2);
			close (fd);
			return -1;
		}

		printf ("Frame: %-9d     Timestamp:%-9d    Size:%d\n", cnt++, i, size);
	}

	close (fd);
	close (fd2);
	return 0;
}


int checkfile(char *src) {
	uint32_t i;
	uint32_t size;
	int fd;
	int cnt = 0;
	char *inbuf = NULL;
	int inbufsize = 0;

	printf ("reading file :'%s'\n", src);

	if ((fd = open (src, O_RDONLY)) < 0) {
		printf ("could not open file: %s\n", strerror(errno));
	}

	//
	// read header w, h, pixfmt
	if (read (fd, &i, 4) != 4) {
		printf ("could not read all bytes.\n");
		close (fd);
		return -1;
	}
	printf ("      Width: %d\n", ntohl(i));

	if (read (fd, &i, 4) != 4) {
		printf ("could not read all bytes.\n");
		close (fd);
		return -1;
	}
	printf ("      Height: %d\n", ntohl(i));

	if (read (fd, &i, 4) != 4) {
		printf ("could not read all bytes.\n");
		close (fd);
		return -1;
	}
	printf("      Pixfmt: %s\n", convert_from_pixelformat(ntohl(i)).c_str());


	//
	// read frame
	while (read (fd, &size, 4) == 4) {
		size = ntohl(size);
		if (read (fd, &i, 4) != 4) {
			printf ("could not read all bytes.\n");
			close (fd);
			return -1;
		}
		i = ntohl(i);

		if (inbuf == NULL){
			inbuf = (char*) malloc (size);
			inbufsize = size;
		}
		else if (inbufsize < size) {
			inbuf = (char*)realloc(inbuf, size);
			inbufsize = size;
		}

		if (inbuf == NULL) {
			printf ("Error could not allocate enough memory\n");
			close (fd);
			return -1;
		}
		if (read (fd, inbuf, size) != size) {
			printf ("could not read to next frame.\n");
			close (fd);
			return -1;
		}

		printf ("Frame: %-9d     Timestamp:%-9d    Size:%d\n", cnt++, i, size);
	}

	printf ("\nFile seems to be fine.\n");

	close (fd);
	return 0;
};


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

	if (argc == 2) {
		checkfile(argv[1]);
	}
	else if (argc == 3) {
		fixfile(argv[1], argv[2]);
	}
	else {
		 printf ("please give a file name as parameter.\n");
		 printf ("checkdumpfile FILE				to check file\n");
		 printf ("checkdumpfile SRCFILE DESTFILE	to fix file\n");
		 printf ("\n");
	}
	return 0;
}
