/*
 * Convert .bit bitstream to .bit.bin file for streaming into ICAP.
 *
 * Compile using: gcc -O3 -o bit2bin bit2bin.c
 *
 */

#include <stdio.h>
#include <stdint.h>

#define MAX_HEADER_SIZE		1024

/**
 * Taken from my bachelor thesis, based on example code from UG744.
 */
int GetHeaderLength(unsigned char *buffer)
{
	int pos = 0, i;
	uint32_t c, bitstreamLength;

	uint32_t magicLength = buffer[pos++];
	magicLength = (magicLength << 8) | buffer[pos++];

	// read magic
	for(i=0; i<magicLength-1; i++)
	{
		c = buffer[pos++];

		if(((i%2)==0 && c != 0x0f)
				|| ((i%2)==1 && c != 0xf0))
		{
			printf("ERROR: GetHeaderLength(): Invalid header magic\r\n");
			return(-1);
		}
	}
	pos++;

	// 0x01
	c = buffer[pos++];
	c = (c << 8) | buffer[pos++];
	if(c != 0x01)
	{
		printf("ERROR: GetHeaderLength(): Invalid header data (0x01)\r\n");
		return(-1);
	}

	// a
	if(buffer[pos++] != 'a')
	{
		printf("ERROR: GetHeaderLength(): Invalid header data (a)\r\n");
		return(-1);
	}

	// design name length
	c = buffer[pos++];
	c = (c << 8) | buffer[pos++];
	pos += c;

	// b
	if(buffer[pos++] != 'b')
	{
		printf("ERROR: GetHeaderLength(): Invalid header data (b)\r\n");
		return(-1);
	}

	// laenge des part-namens
	c = buffer[pos++];
	c = (c << 8) | buffer[pos++];
	pos += c;

	// c
	if(buffer[pos++] != 'c')
	{
		printf("ERROR: GetHeaderLength(): Invalid header data (c)\r\n");
		return(-1);
	}

	// date string length
	c = buffer[pos++];
	c = (c << 8) | buffer[pos++];
	pos += c;

	// d
	if(buffer[pos++] != 'd')
	{
		printf("ERROR: GetHeaderLength(): Invalid header data (d)\r\n");
		return(-1);
	}

	// time string length
	c = buffer[pos++];
	c = (c << 8) | buffer[pos++];
	pos += c;

	// e
	if(buffer[pos++] != 'e')
	{
		printf("ERROR: GetHeaderLength(): Invalid header data (e)\r\n");
		return(-1);
	}

	bitstreamLength = buffer[pos++];
	bitstreamLength = (bitstreamLength << 8) | buffer[pos++];
	bitstreamLength = (bitstreamLength << 8) | buffer[pos++];
	bitstreamLength = (bitstreamLength << 8) | buffer[pos++];

	return(pos);
}

int main(int argc, char *argv[])
{
	// check args
	if(argc != 3)
	{
		printf("Usage: %s [input-file] [output-file]\n", argv[0]);
		return(1);
	}
	
	// read input file
	const char *inFile = argv[1];
	FILE *fpIn = fopen(inFile, "rb");
	if(fpIn == NULL)
	{
		printf("ERROR: Cannot open input file: %s\n", inFile);
		return(1);
	}
	
	// read output file
	const char *outFile = argv[2];
	FILE *fpOut = fopen(outFile, "wb");
	if(fpOut == NULL)
	{
		printf("ERROR: Cannot open output file: %s\n", outFile);
		fclose(fpIn);
		return(1);
	}
	
	// read header
	unsigned char buffer[MAX_HEADER_SIZE];
	fread(buffer, 1, sizeof(buffer), fpIn);
	int headerLength = GetHeaderLength(buffer);
	if(headerLength == -1)
	{
		fclose(fpIn);
		fclose(fpOut);
		return(1);
	}
	
	// skip header
	fseek(fpIn, headerLength, SEEK_SET);
	
	// read data and swap byte order
	while(!feof(fpIn))
	{
		uint8_t word[4] = { 0 };
		size_t readBytes = fread(&word, sizeof(uint8_t), 4, fpIn);
		
		if(readBytes == 0)
			break;
		if(readBytes != 4)
			printf("WARNING: Bitstream size not divisible by 4!\n");
		
		uint8_t flippedWord[4] = { word[3], word[2], word[1], word[0] };
		fwrite(flippedWord, sizeof(uint8_t), 4, fpOut);
	}
	
	// close files
	fclose(fpIn);
	fclose(fpOut);
	
	return(0);
}
