/*
	Combat Team II Data Decomp routines 0.31
	Data DeComp & Comp routines are made by Ismo Horppu on 1996 - 1997
*/

#include <stdio.h>
#include <mem.h>
#include "dchead.h"

/*
	Calculates how rawsize of the packed data
	(DataPointer must be valid)
*/
int DeCompressedSize (void)
{
	DWORD Counter;
	RawSize = 0;

	// prevent from general protection error
	if (init != 1) return -1;

	for (Counter = 0; Counter < PackedSize; Counter++){
		// packed id ?
		if (DataPointer[Counter] == ID){
			Counter += 2;
			RawSize += DataPointer[Counter];
		}

		// normal data
		else RawSize++;
	}

	return 0;
}

/*
	Decompresses from memory to specified file
	(DataPointer must be valid)
*/
int DeCompressFile (char *fn2)
{
	FILE *f2;
	BYTE value;
	BYTE same = 0;
	register BYTE c;
	DWORD mem_offset = 0;

	Data_CRC32 = 0;

	// file open error ?
	if ((f2 = fopen (fn2, "wb")) == NULL){
		return -2;
	}

	while (1){
		// fgetc
		value = DataPointer[mem_offset];
		mem_offset++;

		// all bytes done ?
		if (mem_offset >= PackedSize){
			break;
		}

		if (value == ID){
			value = DataPointer[mem_offset];
			mem_offset++;
			same = DataPointer[mem_offset];
			mem_offset++;

			for (c = 0; c < same; c++){
				fputc (value, f2);
				Data_CRC32 += (DWORD) value;
			}
		}

		else{
			fputc (value, f2);
			Data_CRC32 += (DWORD) value;
		}
	}

	fclose (f2);
	return 0;
}

/*
	Decompresses from memory to specified memory area
	(TargetPointer & DataPointer must be valid)
*/
int DeCompressMemory (void)
{
	BYTE value;
	BYTE same = 0;
	register BYTE c;
	DWORD mem_offset = 0;
	DWORD target_offset = 0;

	Data_CRC32 = 0;

	while (1){
		value = DataPointer[mem_offset];
		mem_offset++;

		// all bytes done ?
		if (mem_offset >= PackedSize){
			break;
		}

		// packed id ?
		if (value == ID){
			value = DataPointer[mem_offset];
			mem_offset++;
			same = DataPointer[mem_offset];
			mem_offset++;

			for (c = 0; c < same; c++){
				TargetPointer[target_offset] = value;
				target_offset++;
				Data_CRC32 += (DWORD) value;
			}
		}

		// normal data
		else{
			TargetPointer[target_offset] = value;
			target_offset++;
			Data_CRC32 += (DWORD) value;
		}
	}

	return 0;
}

/*
	Reads data file in blocks & allocates pointer
	(DataPointer must be valid)
*/
int ReadDataFile (char *fname)
{
	WORD Blocks;
	WORD Last_Block_Size, xc;
	FILE *f;
	WORD c;
	fpos_t fpos;
	DWORD Source, Dest = 0;

	// file not found ?
	if ((f = fopen (fname, "rb")) == NULL){
		return -1;
	}

	// free previous data pointer area
	if (init != -1){
		free (DataPointer);
		init = -1;
	}

	fseek (f, 0L, SEEK_END);
	fgetpos (f, &fpos);
	PackedSize = (DWORD) fpos;
	fseek (f, 0L, SEEK_SET);

	// out of memory ?
	if ((DataPointer = (BYTE *) malloc (PackedSize)) == NULL){
		return -2;
	}

	Blocks = (WORD) (PackedSize / DATA_BUFFER_LENGTH);
	Last_Block_Size = (WORD) (PackedSize % DATA_BUFFER_LENGTH);

	for (c = 0; c < Blocks; c++){
		fread (&data_transfer_buffer[0], 1, DATA_BUFFER_LENGTH, f);

		for (Source = 0; Source < DATA_BUFFER_LENGTH; Source++){
			DataPointer[Dest] = data_transfer_buffer[Source];
			Dest++;
		}
	}

	if (Last_Block_Size != 0){
		fread (&data_transfer_buffer[0], 1, Last_Block_Size, f);

		for (Source = 0; Source < Last_Block_Size; Source++){
			DataPointer[Dest] = data_transfer_buffer[Source];
			Dest++;
		}
	}

	fclose (f);
	init = 1;
	return 0;
}

/*
	writes data file in blocks & allocates pointer
	(DataPointer must be valid)
*/
int WriteDataFile (char *fname)
{
	WORD Blocks;
	WORD Last_Block_Size, Source = 0, Dest;
	FILE *f;
	WORD Counter;
	fpos_t fpos;

	// file not found ?
	if ((f = fopen (fname, "wb")) == NULL){
		return -1;
	}

	Blocks = (WORD) (RawSize / DATA_BUFFER_LENGTH);
	Last_Block_Size = (WORD) (RawSize % DATA_BUFFER_LENGTH);

	for (Counter = 0; Counter < Blocks; Counter++){
		for (Dest = 0; Dest < DATA_BUFFER_LENGTH; Dest++){
			data_transfer_buffer[Dest] = TargetPointer[Source];
			Source++;
		}

		fwrite (&data_transfer_buffer, 1, DATA_BUFFER_LENGTH, f);
	}

	if (Last_Block_Size != 0){
		for (Dest = 0; Dest < Last_Block_Size; Dest++){
			data_transfer_buffer[Dest] = TargetPointer[Source];
			Source++;
		}

		fwrite (&data_transfer_buffer, 1, Last_Block_Size, f);
	}

	fclose (f);
	return 0;
}