#include <iostream>
#include <io.h>
#include <fstream>
#include <direct.h>
#include <Windows.h>
using std::cout;
using std::ifstream;
using std::ofstream;
using std::ios;

struct TEXsample
{
	unsigned short x;
	unsigned short y;
}*TEX;

void writefile(char * memblockwrite,int sizewrite,char * namewrite)
{
	ofstream onfile;
	onfile.open(namewrite,ios::binary);
	onfile.write(memblockwrite,sizewrite);
	onfile.close();
}
void ConvertSFD(char * memblock, int size, char * name)
{
	//
	//uncompression
	if(memblock[1] == 1)
	{
		//cout << "its compressed\n";
		unsigned short numframescmp = (unsigned short)((BYTE)memblock[6]);
		//cout << "num frames " << numframescmp << "\n";
		//raven: now what to do is unknown =)
		//this file is whole archive, and file is compressed
		//we need count uncompressed size of file to alloc memory.
		int newsize = 0;
		BYTE compressionsign  = ((BYTE)memblock[7])-2;//raven: ? //-2
		//cout << (unsigned short)compressionsign << "cmp sign\n";
		unsigned short cmprange = 30;
		for(int i = 6; i < size; i++)
		{
			//if((int)((BYTE)memblock[i]) > (int)((BYTE)memblock[i]))
			//(int)((BYTE)memblock[i])
			if((int)((BYTE)memblock[i])>=compressionsign-1 &&(int)((BYTE)memblock[i])<compressionsign) 
			{
				//i++;
				//currentbyte = ((BYTE)memblock[i]);
				//continue;
			}
			if((int)((BYTE)memblock[i]) >= (int)(compressionsign)&&(int)((BYTE)memblock[i]) <= (int)(compressionsign)+cmprange)
			{
				//cout << ((int)((BYTE)memblock[i]) - (int)(compressionsign)) << " cmp sign " << i << " pos";
				//system("pause");
				for(int j = 0; j <= ((unsigned short)((BYTE)memblock[i]) - (unsigned short)compressionsign); j++)
				{
					newsize++;
				}
				i++;
			}
			else
			{
				newsize++;
			}
	
		}
		//cout << newsize << " uncompressed size\n";
		//try writefile
		char * memblockwrite = new char[newsize];

		int i = strlen(name);
		char * newname = new char[i+2+5];
		//strcpy(newname,name);
		sprintf(newname,"%s%s.sfd",name,"un");

		//int i = strlen(name);
		//name[i-3] = 'S';
		//name[i-2] = 'F';
		//name[i-1] = 'D';
		//
		int k = 0;
		for(int i = 6; i < size; i++)
		{
			if((int)((BYTE)memblock[i])>=compressionsign-1 &&(int)((BYTE)memblock[i])<compressionsign) 
			{
				//i++;
			}
			if((int)((BYTE)memblock[i]) >= (int)(compressionsign)&&(int)((BYTE)memblock[i]) <= (int)(compressionsign)+cmprange)
			{
				for(int j = 0; j <= ((unsigned short)((BYTE)memblock[i]) - (unsigned short)compressionsign); j++)
				{
					if((((unsigned short)((BYTE)memblock[i]) - (unsigned short)compressionsign) == 30)&&i >1464)
					{
						//cout << (int)(BYTE)memblock[i-1];
						//system("pause");
					}
					memblockwrite[k] = memblock[i+1];
					k++;
				}
				i++;
			}
			else
			{
				memblockwrite[k] = memblock[i];
				k++;
			}
		}
		//
		//writefile(memblockwrite,newsize,newname);
		ConvertSFD(memblockwrite,newsize,name);
		delete memblockwrite;	
	}
	else
	{
	//
	unsigned int numframes = *(unsigned int*)&memblock[0];
	//cout << numframes << "\n";
	bool dumptozero = true;
	for(int j = 1; j <= numframes;j++)
	{
		unsigned int offset = *(unsigned int*)&memblock[j*4];
		if(offset>size)
		{
			cout << "out of range, compressed? frame " << j << " in file " << name << "\n";
			dumptozero = false;
			break;
		}
		TEX = (TEXsample*)&memblock[offset];
		if(offset+8+TEX->x*TEX->y > size) 
		{
			cout << "out of range, compressed? frame " << j << " in file " << name << "\n";
			dumptozero = false;
			break;
		}
		//cout << "x = " << TEX->x << "\n";
		//cout << "y = " << TEX->y << "\n";
		char * memblockwrite = new char[1706+TEX->x*TEX->y+1];

		ifstream infile2;
		infile2.open("HEADER.TIF",ios::in|ios::binary|ios::ate);
		ifstream::pos_type size2;
		size2 = infile2.tellg();
		infile2.seekg(0,ios::beg);
		infile2.read(memblockwrite,size2);
		//
		memcpy(&memblockwrite[1706],&memblock[offset+8],TEX->x*TEX->y);
		memcpy(&memblockwrite[30], &TEX->x,2);
		memcpy(&memblockwrite[42], &TEX->y,2);
		int i = strlen(name);
		char * newname = new char[i+2+5];
		//strcpy(newname,name);
		sprintf(newname,"%s%i.tif",name,j);
		
		//newname[i+2-4] = '.';
		//newname[i+2-3] = 'T';
		//newname[i+2-2] = 'I';
		//newname[i+2-1] = 'F';
		writefile(memblockwrite,(1706+TEX->x*TEX->y+1),newname);
		//
		delete memblockwrite;	
		infile2.close();
	}
	if(dumptozero);
		//writefile(memblock,0,name);
	}
}

struct palette
{
	BYTE r;
	BYTE g;
	BYTE b;
}*PAL;

struct palette32
{
	BYTE r;
	BYTE g;
	BYTE b;
	BYTE a;
}*PAL32;
void ConvertM32(char * memblock, int size, char * name)
{
	int readx;
	int ready;
	int readp;
	switch((BYTE)memblock[0])
	{
	case 2:
		readx = 132;
		ready = 196;
		readp = 376;
		break;
	case 3:
		readx = 388;
		ready = 452;
		readp = 376;//?
		break;
	case 4:
		readx = 516;
		ready = 580;
		readp = 968;
		break;
	default:
		cout << "unsupported " << name << "\n";
		return;
	}
	unsigned short x = *(unsigned short *)&memblock[readx];
	unsigned short y = *(unsigned short *)&memblock[ready];
	char * memblockwrite = new char[18+x*4*y+1];

	ifstream infile2;
	infile2.open("HEADERTGA32",ios::in|ios::binary|ios::ate);
	ifstream::pos_type size2;
	size2 = infile2.tellg();
	infile2.seekg(0,ios::beg);
	infile2.read(memblockwrite,size2);
	//
	PAL32 = (palette32*)&memblock[readp];
	for(int k = 0; k<x*y; k++)
	{
		BYTE tmp = PAL32->r;
		PAL32->r = PAL32->b;
		PAL32->b = tmp     ;
		PAL32++            ;
	}
	memcpy(&memblockwrite[     18], &memblock[readp],x*4*y);
	memcpy(&memblockwrite[     12], &x,2);
	memcpy(&memblockwrite[     14], &y,2);

	int i = strlen(name);
	char * newname = new char[i+4];
	//strcpy(newname,name);
	sprintf(newname,"%s.tga",name);

	//name[i-3] = 'B';
	//name[i-2] = 'M';
	//name[i-1] = 'P';
	writefile(memblockwrite,(18+x*4*y),newname);
	//
	delete memblockwrite;	
	infile2.close();
}
void ConvertM8(char * memblock, int size, char * name)
{
	unsigned short x = *(unsigned short *)&memblock[ 36];
	unsigned short y = *(unsigned short *)&memblock[100];
	PAL = (palette*)&memblock[260];
	palette32 pal[256];
	for(int i = 0; i<256;i++)
	{
		pal[i].r = PAL->b;
		pal[i].g = PAL->g;
		pal[i].b = PAL->r;
		pal[i].a = 0     ;
		PAL++;
	}
	
	char * memblockwrite = new char[54+1024+x*y+1];

	ifstream infile2;
	infile2.open("HEADERBMP",ios::in|ios::binary|ios::ate);
	ifstream::pos_type size2;
	size2 = infile2.tellg();
	infile2.seekg(0,ios::beg);
	infile2.read(memblockwrite,size2);
	//
	memcpy(&memblockwrite[     54], &pal,1024);
	for(int j=0;j<y;j++)
	{
		memcpy(&memblockwrite[54+1024+x*(y-j-1)], &memblock[1040+x*j],x);
	}
	//memcpy(&memblockwrite[54+1024], &memblock[1040],x*y);
	memcpy(&memblockwrite[     18], &x,2);
	memcpy(&memblockwrite[     22], &y,2);

	int i = strlen(name);
	char * newname = new char[i+4];
	//strcpy(newname,name);
	sprintf(newname,"%s.bmp",name);

	//name[i-3] = 'B';
	//name[i-2] = 'M';
	//name[i-1] = 'P';
	writefile(memblockwrite,(54+1024+x*y+1),newname);
	//
	delete memblockwrite;	
	infile2.close();
}

void ConvertTEX(char * memblock, char * memblockd, int size, char * name)
{
	TEX = (TEXsample*)&memblock[0];
	//cout << "x = " << TEX->x << "\n";
	//cout << "y = " << TEX->y << "\n";
	if(size >= TEX->x*TEX->y)
	{
		char * memblockwrite = new char[1706+TEX->x*TEX->y+1];

		ifstream infile2;
		infile2.open("HEADER.TIF",ios::in|ios::binary|ios::ate);
		ifstream::pos_type size2;
		size2 = infile2.tellg();
		infile2.seekg(0,ios::beg);
		infile2.read(memblockwrite,size2);
		//
		memcpy(&memblockwrite[1706],&memblock[20],TEX->x*TEX->y);
		memcpy(&memblockwrite[30], &TEX->x,2);
		memcpy(&memblockwrite[42], &TEX->y,2);
		int i = strlen(name);
		name[i-3] = 'T';
		name[i-2] = 'I';
		name[i-1] = 'F';
		
		//writefile(memblockwrite,(1706+TEX->x*TEX->y+1),name);
		//
		delete memblockwrite;	
		infile2.close();
	}
	else
	{
		//
		//assume its rle compressed
		//reread size 
		TEX = (TEXsample*)&memblock[6];
		//lets be sure its really compressed
		if(!(int)memblock[4]&&!(int)memblock[5])
		{
			//cout << "we here\n";
			char * memblockwrite = new char[1706+TEX->x*TEX->y+1];

			ifstream infile2;
			infile2.open("HEADER.TIF",ios::in|ios::binary|ios::ate);
			ifstream::pos_type size2;
			size2 = infile2.tellg();
			infile2.seekg(0,ios::beg);
			infile2.read(memblockwrite,size2);
			//
			int k = -2;
			BYTE readposition     = 23;//23 on some cases 25 right
			BYTE compressionrange = 29;//((BYTE)memblock[ 3])  ; //29 is right
			BYTE compressionsign  = ((BYTE)memblock[15]);//raven: ?
			BYTE currentbyte;
			BYTE difference ;

			bool inspect = false;
			if(inspect) 
			{
				cout << (int)compressionsign << " compression sign " << name << "\n";
				system("pause");
			}
			//cout << compressionsign << "\n";
			//
			cout << name << "\n";
			//system("pause");
			//if(TEX->x>512&&TEX->y>512) return;
			for(int i = (int)readposition; i < size/*TEX->x*TEX->y*/; i++)
			{
				currentbyte = ((BYTE)memblock[i]);
				if(inspect)
				{
					cout << (int)currentbyte << " currentbyte " << name << "\n";
					system("pause");
				}
				if((int)currentbyte>=compressionsign-1 &&(int)currentbyte<compressionsign) 
				{
					i++;
					//currentbyte = ((BYTE)memblock[i]);
					//continue;
				}
				if((int)currentbyte>=(int)compressionsign && (int)currentbyte<=(int)compressionsign+(int)compressionrange)
				//if(memblock[i]>compressionsign) //start working for other textures weird!
				{
					//if(((BYTE)memblock[i])-compressionsign+1 <= 0) cout << "bug!/n";
					difference = ((int)currentbyte-(int)compressionsign+1);

					if(inspect)
					{
						cout << (int)difference << " difference " << name << "\n";
						system("pause");
					}

					if((int)difference == 17 && false)
					{
						difference = 1;
						cout << "cmp bug! " << (int)((BYTE)memblock[i]) << " pos " << i << " " ;
						system("pause");
					}
					for(int j = 0; j <= difference;++j)
					{
						//if(j < 0) cout << "bug!/n";
						
						//cout << (int)memblock[i] << "\n";
						if(1706+k == 1706+TEX->x*TEX->y) break;
						//
						//if(((BYTE)memblock[i+1]) != ((BYTE)memblockd[i+j-5]))
						//{
						//	cout << "bug! \npos unc " << i+j-5 << " \npos cmp " << i << " \nunc value " << (int)((BYTE)memblockd[i-5]) << " \ncmp value " << (int)((BYTE)memblock[i+1]) << " \ncmp sign " << (int)compressionsign << "\ncur sign " << (int)((BYTE)memblock[i]) <<"\n";
						//	system("pause");
						//}
						//else
						//{
						//	cout << "ok! \npos unc " << i+j-5 << " \npos cmp " << i << " \nunc value " << (int)((BYTE)memblockd[i-5]) << " \ncmp value " << (int)((BYTE)memblock[i+1]) << " \ncmp sign " << (int)compressionsign << "\ncur sign " << (int)((BYTE)memblock[i]) <<"\n";
						//}
						//
						if(k >= 0)
						memcpy(&memblockwrite[1706+k],&memblock[i+1],1);
						if(inspect)
						if(memblockwrite[1706+k] != memblockd[1706+k])
						{
							cout << "bug!\n pos cmp" << i+1  << "\n pos unc " << 1706+k << "\n got " << (int)((BYTE)memblockwrite[1706+k]) << "\n req " << (int)((BYTE)memblockd[1706+k]) << "\ncmp sign " << (int)((BYTE)memblock[i]) << "\n";
							system("pause");
						}
						k++;
					}
					i++;
				}
				else 
				{
					//if(((BYTE)memblock[i]) != ((BYTE)memblockd[i-5]))
					//{
					//	cout << "bug! \npos unc " << i-5 << " \npos cmp " << i << " \nunc value " << (int)((BYTE)memblockd[i-5]) << " \ncmp value " << (int)((BYTE)memblock[i]) << "\n";
					//	system("pause");
					//}
					//else
					//{
					//	cout << "ok! \npos unc " << i-5 << " \npos cmp " << i << " \nunc value " << (int)((BYTE)memblockd[i-5]) << " \ncmp value " << (int)((BYTE)memblock[i]) << "\n";
					//}
					if(1706+k == 1706+TEX->x*TEX->y) break;
					memcpy(&memblockwrite[1706+k],&memblock[i],1);
					k++;
				}
			}
			//		cout << "we here\n";
			//memcpy(&memblockwrite[1706],&memblock[20],TEX->x*TEX->y);
			memcpy(&memblockwrite[30], &TEX->x,2);
			memcpy(&memblockwrite[42], &TEX->y,2);
			
			int i = strlen(name);
			name[i-3] = 'T';
			name[i-2] = 'I';
			name[i-1] = 'F';
			if(TEX->x<512&&TEX->y<512)
			writefile(memblockwrite,(1706+TEX->x*TEX->y+1),name);
			//
			delete memblockwrite;	
			infile2.close();
		}
		//
	}
}

void OpenFileM32(char *name)
{
	ifstream infile;
	infile.open(name,ios::in|ios::binary|ios::ate);
	ifstream::pos_type size;
	size = infile.tellg();
	char * memblock;
	memblock = new char[size];
	infile.seekg(0,ios::beg);
	infile.read(memblock,size);
	ConvertM32(memblock,size,name);
	delete memblock;
	infile.close();
}

void OpenFileM8(char *name)
{
	ifstream infile;
	infile.open(name,ios::in|ios::binary|ios::ate);
	ifstream::pos_type size;
	size = infile.tellg();
	char * memblock;
	memblock = new char[size];
	infile.seekg(0,ios::beg);
	infile.read(memblock,size);
	ConvertM8(memblock,size,name);
	delete memblock;
	infile.close();
}

void OpenFile(char *name, bool sfd)
{
	ifstream infile;
	infile.open(name,ios::in|ios::binary|ios::ate);
	ifstream::pos_type size;
	size = infile.tellg();
	char * memblock;
	memblock = new char[size];
	infile.seekg(0,ios::beg);
	infile.read(memblock,size);
	//debug
	ifstream infiled;
	char * named = new char[strlen(name)+3];
	//sprintf(named,"d\\%s",name);
	sprintf(named,"%s",name);
	infiled.open(named,ios::in|ios::binary|ios::ate);
	ifstream::pos_type sized;
	sized = infiled.tellg();
	char * memblockd;
	memblockd = new char[sized];
	infiled.seekg(0,ios::beg);
	infiled.read(memblockd,sized);
	//debug

	if(sfd)
		ConvertSFD(memblock,size,name);
	else
		ConvertTEX(memblock,memblockd, size, name);
	delete memblock;
	infile.close();
	//debug
	delete named;
	delete memblockd;
	infiled.close();
	//debug
}

void FindSFD()
{
	char *path="*.sfd";
	_finddata_t *mas=new _finddata_t;
	long done=_findfirst(path,mas);
	int MayWeWork = done;	
	while (MayWeWork!=-1)
	{	
		OpenFile(mas->name,true);
		MayWeWork = _findnext(done, mas);        
	}
	delete mas;
	_findclose(done);
}

void FindM32()
{
	char *path="*.m32";
	_finddata_t *mas=new _finddata_t;
	long done=_findfirst(path,mas);
	int MayWeWork = done;	
	while (MayWeWork!=-1)
	{	
		OpenFileM32(mas->name);
		MayWeWork = _findnext(done, mas);        
	}
	delete mas;
	_findclose(done);
}

void FindM8()
{
	char *path="*.m8";
	_finddata_t *mas=new _finddata_t;
	long done=_findfirst(path,mas);
	int MayWeWork = done;	
	while (MayWeWork!=-1)
	{	
		OpenFileM8(mas->name);
		MayWeWork = _findnext(done, mas);        
	}
	delete mas;
	_findclose(done);
}

void FindTEX()
{
	char *path="*.tex";
	_finddata_t *mas=new _finddata_t;
	long done=_findfirst(path,mas);
	int MayWeWork = done;	
	while (MayWeWork!=-1)
	{	
		OpenFile(mas->name,false);
		MayWeWork = _findnext(done, mas);        
	}
	delete mas;
	_findclose(done);
}

void main()
{
	//FindM8();
	//FindM32();
	FindSFD();
	//FindTEX();
	system("pause");
}

