///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//
// Source code for "Creating Efficient Triangle Strips"
// (C) 2000, <NAME> (<EMAIL>)
//
// Version is 2.0.
//
// This is a versatile and customized import/export array class I use for a long time.
//
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Precompiled Header
#include "Stdafx.h"

///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Constructor
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
CustomArray::CustomArray(unsigned long startsize, void* inputbuffer) : mNbPushedAddies(0), mNbAllocatedAddies(0), mBitCount(0), mBitMask(0), mAddresses(null), mCollapsed(null)
{
	// Initialize first export block
	NewBlock(null, startsize);

	// Keep track of this first cell
	mInitCell = mCurrentCell;

	// Fill first block with provided buffer, if needed
	if(inputbuffer)	memcpy(mCurrentCell->Item.Addy, inputbuffer, startsize);

	// Initialize mLastAddress so that it won't crash if the first thing you ever do is a PushAddress/PopAddressAndStore!!
	mLastAddress = mCurrentCell->Item.Addy;
}

///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Constructor
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
CustomArray::CustomArray(const char* filename) : mNbPushedAddies(0), mNbAllocatedAddies(0), mBitCount(0), mBitMask(0), mAddresses(null), mCollapsed(null)
{
	// Catch the file's size to initialize first block
	unsigned long StartSize = FileSize(filename);
	if(!StartSize)	StartSize=CUSTOMARRAY_BLOCKSIZE;

	// Initialize first export block
	NewBlock(null, StartSize);

	// Keep track of this first cell
	mInitCell = mCurrentCell;

	// Fill first block with file data
	FILE* fp = fopen(filename, "rb");
	if(fp)
	{
		fread(mCurrentCell->Item.Addy, StartSize, 1, fp);
		fclose(fp);
	}

	// Initialize mLastAddress so that it won't crash if the first thing you ever do is a PushAddress/PopAddressAndStore!!
	mLastAddress = mCurrentCell->Item.Addy;
}

///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Destructor
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
CustomArray::~CustomArray()
{
	// Free possible collapsed array
	RELEASEARRAY(mCollapsed);

	// Free possible adress list
	RELEASEARRAY(mAddresses);

	// Free linked list
	CustomCell* CurCell = mInitCell;
	while(CurCell)
	{
		CustomCell* Cell = CurCell;
		CurCell = CurCell->NextCustomCell;
		RELEASE(Cell);
	}
}



///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//
// MANAGEMENT METHODS
//
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////



///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// A method to create and link a new block to previous ones.
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Input	:	previouscell	= the previous cell, or null if this is the first
//				size			= #bytes to allocate for the first cell
// Output	:	-
// Return	:	self-reference
// Exception:	-
// Remark	:	'size' is only used if previouscell is null (i.e. for the first cell)
CustomArray& CustomArray::NewBlock(CustomCell* previouscell, unsigned long size)
{
	// Create a new cell
	CustomCell* Cell = new CustomCell;

	// If a previous cell exists, doubles the needed ram, else get default size
	Cell->Item.Max = previouscell ? previouscell->Item.Max*2 : size;

	// Get some bytes for this cell
	Cell->Item.Addy = (void*)new ubyte[Cell->Item.Max];
	Cell->Item.Size = 0;

	mCurrentCell = Cell;

	// Update linked list
	if(previouscell) previouscell->NextCustomCell = mCurrentCell;

	return *this;
}

///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// A method to check whether there's enough room in current block for expected datas, or not.
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Input	:	bytesneeded		= #expected bytes
// Output	:	-
// Return	:	self-reference
// Exception:	-
// Remark	:	a new block is created if there's no more space left in current block.
CustomArray& CustomArray::CheckArray(unsigned long bytesneeded)
{
	unsigned long ExpectedSize = mCurrentCell->Item.Size + bytesneeded;
	if(ExpectedSize > mCurrentCell->Item.Max)	NewBlock(mCurrentCell);
	// I assume there IS enough room in the new block for expected data. It should always be the case since 'bytesneeded' is not supposed to be larger than 8
	// (i.e. sizeof(double))
	return *this;
}

///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// A method to export an array to disk.
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Input	:	filename	= the destination file's name.
// Output	:	-
// Return	:	true if success
// Exception:	-
// Remark	:	-
bool CustomArray::ExportToDisk(const char* filename)
{
	FILE* fp = fopen(filename, "wb");
	if(!fp) return false;
	ExportToDisk(fp);
	fclose(fp);
	return true;
}

///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// A method to export an array to disk.
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Input	:	fp		= the file pointer.
// Output	:	-
// Return	:	true if success
// Exception:	-
// Remark	:	-
bool CustomArray::ExportToDisk(FILE* fp)
{
	// Fill possible remaining bits with 0
	EndBits();

	CustomCell* p = mInitCell;

	while(p->NextCustomCell)
	{
		// Save current cell
		if(!SaveCell(p, fp)) return false;
		// Go to next cell
		p = p->NextCustomCell;
	}
	// Save last cell
	if(!SaveCell(p, fp)) return false;

	return true;
}

///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// A method to write a single cell to disk.
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Input	:	p		= current cell.
//				fp		= file pointer.
// Output	:	-
// Return	:	true if success
// Exception:	-
// Remark	:	-
bool CustomArray::SaveCell(CustomCell* p, FILE* fp)
{
	unsigned long BytesToWrite = p->Item.Size;
	if(!BytesToWrite) return true;
	if(fwrite(p->Item.Addy, 1, BytesToWrite, fp)!=BytesToWrite) return false;
	return true;
}

///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// A method to get current #bytes stored.
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Input	:	-
// Output	:	-
// Return	:	unsigned long	= #bytes stored
// Exception:	-
// Remark	:	-
unsigned long CustomArray::GetOffset()
{
	unsigned long Offset = 0;
	CustomCell* p = mInitCell;

	while(p->NextCustomCell)
	{
		// Add offset from current cell
		Offset+=p->Item.Size;
		// Go to next cell
		p = p->NextCustomCell;
	}
	// Add offset from last cell
	Offset+=p->Item.Size;

	return(Offset);
}

///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// A method to padd offset on a 8 bytes boundary.
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Input	:	-
// Output	:	-
// Return	:	self-reference
// Exception:	-
// Remark	:	-
CustomArray& CustomArray::Padd()
{
	// Fill possible remaining bits with 0
	EndBits();

	unsigned long Offset = GetOffset();
	unsigned long NbPadd = Offset - (Offset & 7);
	for(unsigned long i=0;i<NbPadd;i++) Store((char)0);
	return *this;
}

///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// A method to link 2 arrays.
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Input	:	array	= the array to link
// Output	:	-
// Return	:	self-reference
// Exception:	-
// Remark	:	OBSOLETE CODE
CustomArray& CustomArray::LinkTo(CustomArray* array)
{
	// ### THIS METHOD NEEDS RECODING & TESTING
/*
	CustomCell* p = mInitCell;
	char* Addy;
	unsigned long i;

	while(p->NextCustomCell)
	{
		// Link current cell
		Addy = (char*)p->Item.Addy;
		for(i=0;i<p->Item.Size;i++) Store(*Addy++);

		// Go to next cell
		p = p->NextCustomCell;
	}
	// Link last cell
	Addy = (char*)p->Item.Addy;
	for(i=0;i<p->Item.Size;i++) Store(*Addy++);
*/
	return *this;
}

///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// A method to collapse a CustomArray into a single continuous buffer. This invalidates all pushed addies.
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Input	:	userbuffer	= destination buffer (provided or not)
// Output	:	-
// Return	:	void*		= destination buffer
// Exception:	-
// Remark	:	if you provide your destination buffer original bytes are copied into it, then it's safe using them.
//				if you don't, returned address is valid until the array's destructor is called. Beware of memory corruption...
void* CustomArray::Collapse(void* userbuffer)
{
	// Fill possible remaining bits with 0
	EndBits();

	char* Addy;
	CustomCell* p = mInitCell;

	if(!userbuffer)
	{
		RELEASEARRAY(mCollapsed);						// Free possibly already collapsed array
		unsigned long CurrentSize = GetOffset();
		mCollapsed = CurrentSize ? new ubyte[CurrentSize] : null;
		Addy = (char*)mCollapsed;
	}
	else
	{
		Addy = (char*)userbuffer;
	}

	char* AddyCopy = Addy;
	if(Addy)
	{
		while(p->NextCustomCell)
		{
			// Collapse current cell
			memcpy(Addy, p->Item.Addy, p->Item.Size);
			Addy+=p->Item.Size;

			// Go to next cell
			p = p->NextCustomCell;
		}
		// Collapse last cell
		memcpy(Addy, p->Item.Addy, p->Item.Size);
		Addy+=p->Item.Size;
		mNbPushedAddies=0;
	}
	return AddyCopy;
}



///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//
// STORE METHODS
//
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////



///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// A method to store a BOOL.
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Input	:	Bo		= BOOL to store
// Output	:	-
// Return	:	self-reference
// Exception:	-
// Remark	:	Warning! BOOL actually is an int. Converted to long.
CustomArray& CustomArray::Store(BOOL Bo)
{
	// Fill possible remaining bits with 0
	EndBits();

	long b = (long)Bo;

	CheckArray(sizeof(long));

	char* CurrentAddy = (char*)mCurrentCell->Item.Addy;
	CurrentAddy+=mCurrentCell->Item.Size;

	long* Current = (long*)CurrentAddy;
	*Current=b;
	mLastAddress = (void*)Current;
	mCurrentCell->Item.Size+=sizeof(long);
	return *this;
}

///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// A method to store a bool.
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Input	:	Bo		= bool to store.
// Output	:	-
// Return	:	self-reference
// Exception:	-
// Remark	:	Converted to char.
CustomArray& CustomArray::Store(bool Bo)
{
	// Fill possible remaining bits with 0
	EndBits();

	char b = Bo ? 1 : 0;

	CheckArray(sizeof(char));

	char* CurrentAddy = (char*)mCurrentCell->Item.Addy;
	CurrentAddy+=mCurrentCell->Item.Size;

	char* Current = (char*)CurrentAddy;
	*Current=b;
	mLastAddress = (void*)Current;
	mCurrentCell->Item.Size+=sizeof(char);
	return *this;
}

///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// A method to store a char.
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Input	:	b		= char to store.
// Output	:	-
// Return	:	self-reference
// Exception:	-
// Remark	:	-
CustomArray& CustomArray::Store(char b)
{
	// Fill possible remaining bits with 0
	EndBits();

	CheckArray(sizeof(char));

	char* CurrentAddy = (char*)mCurrentCell->Item.Addy;
	CurrentAddy+=mCurrentCell->Item.Size;

	char* Current = (char*)CurrentAddy;
	*Current=b;
	mLastAddress = (void*)Current;
	mCurrentCell->Item.Size+=sizeof(char);
	return *this;
}

///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// A method to store an unsigned char.
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Input	:	b		= unsigned char to store.
// Output	:	-
// Return	:	self-reference
// Exception:	-
// Remark	:	-
CustomArray& CustomArray::Store(unsigned char b)
{
	// Fill possible remaining bits with 0
	EndBits();

	CheckArray(sizeof(unsigned char));

	char* CurrentAddy = (char*)mCurrentCell->Item.Addy;
	CurrentAddy+=mCurrentCell->Item.Size;

	unsigned char* Current = (unsigned char*)CurrentAddy;
	*Current=b;
	mLastAddress = (void*)Current;
	mCurrentCell->Item.Size+=sizeof(unsigned char);
	return *this;
}

///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// A method to store a short.
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Input	:	w		= short to store.
// Output	:	-
// Return	:	self-reference
// Exception:	-
// Remark	:	-
CustomArray& CustomArray::Store(short w)
{
	// Fill possible remaining bits with 0
	EndBits();

	CheckArray(sizeof(short));

	char* CurrentAddy = (char*)mCurrentCell->Item.Addy;
	CurrentAddy+=mCurrentCell->Item.Size;

	short* Current = (short*)CurrentAddy;
	*Current=w;
	mLastAddress = (void*)Current;
	mCurrentCell->Item.Size+=sizeof(short);
	return *this;
}

///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// A method to store an unsigned short.
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Input	:	w		= unsigned short to store.
// Output	:	-
// Return	:	self-reference
// Exception:	-
// Remark	:	-
CustomArray& CustomArray::Store(unsigned short w)
{
	// Fill possible remaining bits with 0
	EndBits();

	CheckArray(sizeof(unsigned short));

	char* CurrentAddy = (char*)mCurrentCell->Item.Addy;
	CurrentAddy+=mCurrentCell->Item.Size;

	unsigned short* Current = (unsigned short*)CurrentAddy;
	*Current=w;
	mLastAddress = (void*)Current;
	mCurrentCell->Item.Size+=sizeof(unsigned short);
	return *this;
}

///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// A method to store a long.
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Input	:	d		= long to store.
// Output	:	-
// Return	:	self-reference
// Exception:	-
// Remark	:	-
CustomArray& CustomArray::Store(long d)
{
	// Fill possible remaining bits with 0
	EndBits();

	CheckArray(sizeof(long));

	char* CurrentAddy = (char*)mCurrentCell->Item.Addy;
	CurrentAddy+=mCurrentCell->Item.Size;

	long* Current = (long*)CurrentAddy;
	*Current=d;
	mLastAddress = (void*)Current;
	mCurrentCell->Item.Size+=sizeof(long);
	return *this;
}

///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// A method to store an unsigned long.
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Input	:	d		= unsigned long to store.
// Output	:	-
// Return	:	self-reference
// Exception:	-
// Remark	:	-
CustomArray& CustomArray::Store(unsigned long d)
{
	// Fill possible remaining bits with 0
	EndBits();

	CheckArray(sizeof(unsigned long));

	char* CurrentAddy = (char*)mCurrentCell->Item.Addy;
	CurrentAddy+=mCurrentCell->Item.Size;

	unsigned long* Current = (unsigned long*)CurrentAddy;
	*Current=d;
	mLastAddress = (void*)Current;
	mCurrentCell->Item.Size+=sizeof(unsigned long);
	return *this;
}
/*
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// A method to store an int.
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Input	:	d		= int to store.
// Output	:	-
// Return	:	self-reference
// Exception:	-
// Remark	:	-
CustomArray& CustomArray::Store(int d)
{
	// Fill possible remaining bits with 0
	EndBits();

	CheckArray(sizeof(int));

	char* CurrentAddy = (char*)mCurrentCell->Item.Addy;
	CurrentAddy+=mCurrentCell->Item.Size;

	int* Current = (int*)CurrentAddy;
	*Current=d;
	mLastAddress = (void*)Current;
	mCurrentCell->Item.Size+=sizeof(int);
	return *this;
}
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// A method to store an unsigned int.
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Input	:	d		= unsigned int to store.
// Output	:	-
// Return	:	self-reference
// Exception:	-
// Remark	:	-
CustomArray& CustomArray::Store(unsigned int d)
{
	// Fill possible remaining bits with 0
	EndBits();

	CheckArray(sizeof(unsigned int));

	char* CurrentAddy = (char*)mCurrentCell->Item.Addy;
	CurrentAddy+=mCurrentCell->Item.Size;

	unsigned int* Current = (unsigned int*)CurrentAddy;
	*Current=d;
	mLastAddress = (void*)Current;
	mCurrentCell->Item.Size+=sizeof(unsigned int);
	return *this;
}

///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// A method to store a float.
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Input	:	f		= float to store.
// Output	:	-
// Return	:	self-reference
// Exception:	-
// Remark	:	-
CustomArray& CustomArray::Store(float f)
{
	// Fill possible remaining bits with 0
	EndBits();

	CheckArray(sizeof(float));

	char* CurrentAddy = (char*)mCurrentCell->Item.Addy;
	CurrentAddy+=mCurrentCell->Item.Size;

	float* Current = (float*)CurrentAddy;
	*Current=f;
	mLastAddress = (void*)Current;
	mCurrentCell->Item.Size+=sizeof(float);
	return *this;
}

///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// A method to store a double.
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Input	:	f		= double to store.
// Output	:	-
// Return	:	self-reference
// Exception:	-
// Remark	:	-
CustomArray& CustomArray::Store(double f)
{
	// Fill possible remaining bits with 0
	EndBits();

	CheckArray(sizeof(double));

	char* CurrentAddy = (char*)mCurrentCell->Item.Addy;
	CurrentAddy+=mCurrentCell->Item.Size;

	double* Current = (double*)CurrentAddy;
	*Current=f;
	mLastAddress = (void*)Current;
	mCurrentCell->Item.Size+=sizeof(double);
	return *this;
}

///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// A method to store a string.
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Input	:	String		= the string to store.
// Output	:	-
// Return	:	self-reference
// Exception:	-
// Remark	:	-
CustomArray& CustomArray::Store(const char *String)
{
	// Fill possible remaining bits with 0
	EndBits();

	for(unsigned long i=0;i<strlen(String);i++)
	{
		Store((char)String[i]);
	}
	return *this;
}



///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//
// STOREASCII METHODS
//
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////



///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// A method to store an ASCII code.
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Input	:	Code		= input byte
// Output	:	-
// Return	:	self-reference
// Exception:	-
// Remark	:	-
CustomArray& CustomArray::StoreASCIICode(char Code)
{
	// Fill possible remaining bits with 0
	EndBits();

	CheckArray(sizeof(char));

	char* CurrentAddy = (char*)mCurrentCell->Item.Addy;
	CurrentAddy+=mCurrentCell->Item.Size;

	char* Current = (char*)CurrentAddy;
	*Current=Code;
	mCurrentCell->Item.Size+=sizeof(char);
	return *this;
}

///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// A method to store a BOOL in ASCII.
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Input	:	Bo		= the BOOL to store.
// Output	:	-
// Return	:	self-reference
// Exception:	-
// Remark	:	-
CustomArray& CustomArray::StoreASCII(BOOL Bo)
{
	char Text[256];
	sprintf(Text, "%d", (long)Bo);
	StoreASCII((const char*)Text);
	return *this;
}

///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// A method to store a bool in ASCII.
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Input	:	Bo		= the bool to store.
// Output	:	-
// Return	:	self-reference
// Exception:	-
// Remark	:	-
CustomArray& CustomArray::StoreASCII(bool Bo)
{
	if(Bo)	StoreASCII((const char*)"true");
	else	StoreASCII((const char*)"false");
	return *this;
}

///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// A method to store a char in ASCII.
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Input	:	b		= the char to store.
// Output	:	-
// Return	:	self-reference
// Exception:	-
// Remark	:	-
CustomArray& CustomArray::StoreASCII(char b)
{
	char Text[256];
	sprintf(Text, "%d", b);
	StoreASCII((const char*)Text);
	return *this;
}

///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// A method to store an unsigned char in ASCII.
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Input	:	b		= the unsigned char to store.
// Output	:	-
// Return	:	self-reference
// Exception:	-
// Remark	:	-
CustomArray& CustomArray::StoreASCII(unsigned char b)
{
	char Text[256];
	sprintf(Text, "%u", b);
	StoreASCII((const char*)Text);
	return *this;
}

///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// A method to store a short in ASCII.
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Input	:	w		= the short to store.
// Output	:	-
// Return	:	self-reference
// Exception:	-
// Remark	:	-
CustomArray& CustomArray::StoreASCII(short w)
{
	char Text[256];
	sprintf(Text, "%d", w);
	StoreASCII((const char*)Text);
	return *this;
}

///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// A method to store an unsigned short in ASCII.
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Input	:	w		= the unsigned short to store.
// Output	:	-
// Return	:	self-reference
// Exception:	-
// Remark	:	-
CustomArray& CustomArray::StoreASCII(unsigned short w)
{
	char Text[256];
	sprintf(Text, "%u", w);
	StoreASCII((const char*)Text);
	return *this;
}

///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// A method to store a long in ASCII.
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Input	:	d		= the long to store.
// Output	:	-
// Return	:	self-reference
// Exception:	-
// Remark	:	-
CustomArray& CustomArray::StoreASCII(long d)
{
	char Text[256];
	sprintf(Text, "%d", d);
	StoreASCII((const char*)Text);
	return *this;
}

///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// A method to store an unsigned long in ASCII.
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Input	:	d		= the unsigned long to store.
// Output	:	-
// Return	:	self-reference
// Exception:	-
// Remark	:	-
CustomArray& CustomArray::StoreASCII(unsigned long d)
{
	char Text[256];
	sprintf(Text, "%u", d);
	StoreASCII((const char*)Text);
	return *this;
}
/*
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// A method to store an int in ASCII.
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Input	:	d		= the int to store.
// Output	:	-
// Return	:	self-reference
// Exception:	-
// Remark	:	-
CustomArray& CustomArray::StoreASCII(int d)
{
	char Text[256];
	sprintf(Text, "%d", d);
	StoreASCII((const char*)Text);
	return *this;
}
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// A method to store an unsigned int in ASCII.
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Input	:	d		= the unsigned int to store.
// Output	:	-
// Return	:	self-reference
// Exception:	-
// Remark	:	-
CustomArray& CustomArray::StoreASCII(unsigned int d)
{
	char Text[256];
	sprintf(Text, "%u", d);
	StoreASCII((const char*)Text);
	return *this;
}

///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// A method to store a float in ASCII.
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Input	:	f		= the float to store.
// Output	:	-
// Return	:	self-reference
// Exception:	-
// Remark	:	-
CustomArray& CustomArray::StoreASCII(float f)
{
	char Text[256];
	sprintf(Text, "%f", f);
	StoreASCII((const char*)Text);
	return *this;
}

///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// A method to store a double in ASCII.
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Input	:	f		= the double to store.
// Output	:	-
// Return	:	self-reference
// Exception:	-
// Remark	:	-
CustomArray& CustomArray::StoreASCII(double f)
{
	char Text[256];
	sprintf(Text, "%f", f);
	StoreASCII((const char*)Text);
	return *this;
}

///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// A method to store a string in ASCII.
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Input	:	String		= the string to store.
// Output	:	-
// Return	:	self-reference
// Exception:	-
// Remark	:	-
CustomArray& CustomArray::StoreASCII(const char *String)
{
	// Fill possible remaining bits with 0
	EndBits();

	for(unsigned long i=0;i<strlen(String);i++)
	{
		if(String[i]=='\n')
		{
			StoreASCIICode((char)0x0d);
			StoreASCIICode((char)0x0a);
		}
		else 
			StoreASCIICode((char)String[i]);
	}
	return *this;
}



///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//
// PUSH/POP ADDRESS METHODS
//
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////



///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// A method to push current address into the address-stack for later processing.
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Input	:	-
// Output	:	-
// Return	:	true if success, else false
// Exception:	-
// Remark	:	-
bool CustomArray::PushAddress()
{
	// Check available space and resize if needed.
	if((mNbPushedAddies+1)>mNbAllocatedAddies)
	{
		// Here we must resize. We get twice as much bytes as already allocated in order to minimize total #resizes.
		udword NewSize = mNbAllocatedAddies ? mNbAllocatedAddies * 2 : 1;

		// Create new buffer...
		void** Addresses = new void*[NewSize];
		if(!Addresses)	return false;

		// ...copy & release old one to new one if old one exists...
		if(mNbAllocatedAddies)
		{
			memcpy(Addresses, mAddresses, mNbAllocatedAddies * sizeof(void*));
			RELEASEARRAY(mAddresses);
		}

		// ...and set new members.
		mAddresses			= Addresses;
		mNbAllocatedAddies	= NewSize;
	}

	// Save last address
	mAddresses[mNbPushedAddies++] = mLastAddress;
	return true;
}

///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// A method to pop an address and store a BOOL where the poped address tells.
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Input	:	Bo		= the BOOL to store
// Output	:	-
// Return	:	self-reference
// Exception:	-
// Remark	:	-
CustomArray& CustomArray::PopAddressAndStore(BOOL Bo)
{
	if(mNbPushedAddies)
	{
		BOOL* Addy = (BOOL*)mAddresses[--mNbPushedAddies];
		*Addy=Bo;
	}
	return *this;
}

///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// A method to pop an address and store a bool where the poped address tells.
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Input	:	Bo		= the bool to store
// Output	:	-
// Return	:	self-reference
// Exception:	-
// Remark	:	-
CustomArray& CustomArray::PopAddressAndStore(bool Bo)
{
	if(mNbPushedAddies)
	{
		char* Addy = (char*)mAddresses[--mNbPushedAddies];
		*Addy=(char)Bo;
	}
	return *this;
}

///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// A method to pop an address and store a char where the poped address tells.
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Input	:	b		= the char to store
// Output	:	-
// Return	:	self-reference
// Exception:	-
// Remark	:	-
CustomArray& CustomArray::PopAddressAndStore(char b)
{
	if(mNbPushedAddies)
	{
		char* Addy = (char*)mAddresses[--mNbPushedAddies];
		*Addy=b;
	}
	return *this;
}

///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// A method to pop an address and store an unsigned char where the poped address tells.
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Input	:	b		= the unsigned char to store
// Output	:	-
// Return	:	self-reference
// Exception:	-
// Remark	:	-
CustomArray& CustomArray::PopAddressAndStore(unsigned char b)
{
	if(mNbPushedAddies)
	{
		unsigned char* Addy = (unsigned char*)mAddresses[--mNbPushedAddies];
		*Addy=b;
	}
	return *this;
}

///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// A method to pop an address and store a short where the poped address tells.
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Input	:	w		= the short to store
// Output	:	-
// Return	:	self-reference
// Exception:	-
// Remark	:	-
CustomArray& CustomArray::PopAddressAndStore(short w)
{
	if(mNbPushedAddies)
	{
		short* Addy = (short*)mAddresses[--mNbPushedAddies];
		*Addy=w;
	}
	return *this;
}

///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// A method to pop an address and store an unsigned short where the poped address tells.
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Input	:	w		= the unsigned short to store
// Output	:	-
// Return	:	self-reference
// Exception:	-
// Remark	:	-
CustomArray& CustomArray::PopAddressAndStore(unsigned short w)
{
	if(mNbPushedAddies)
	{
		unsigned short* Addy = (unsigned short*)mAddresses[--mNbPushedAddies];
		*Addy=w;
	}
	return *this;
}

///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// A method to pop an address and store a long where the poped address tells.
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Input	:	d		= the long to store
// Output	:	-
// Return	:	self-reference
// Exception:	-
// Remark	:	-
CustomArray& CustomArray::PopAddressAndStore(long d)
{
	if(mNbPushedAddies)
	{
		long* Addy = (long*)mAddresses[--mNbPushedAddies];
		*Addy=d;
	}
	return *this;
}

///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// A method to pop an address and store an unsigned long where the poped address tells.
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Input	:	d		= the unsigned long to store
// Output	:	-
// Return	:	self-reference
// Exception:	-
// Remark	:	-
CustomArray& CustomArray::PopAddressAndStore(unsigned long d)
{
	if(mNbPushedAddies)
	{
		unsigned long* Addy = (unsigned long*)mAddresses[--mNbPushedAddies];
		*Addy=d;
	}
	return *this;
}
/*
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// A method to pop an address and store an int where the poped address tells.
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Input	:	d		= the int to store
// Output	:	-
// Return	:	self-reference
// Exception:	-
// Remark	:	-
CustomArray& CustomArray::PopAddressAndStore(int d)
{
	if(mNbPushedAddies)
	{
		int* Addy = (int*)mAddresses[--mNbPushedAddies];
		*Addy=d;
	}
	return *this;
}
*/
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// A method to pop an address and store an unsigned int where the poped address tells.
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Input	:	d		= the unsigned int to store
// Output	:	-
// Return	:	self-reference
// Exception:	-
// Remark	:	-
CustomArray& CustomArray::PopAddressAndStore(unsigned int d)
{
	if(mNbPushedAddies)
	{
		unsigned int* Addy = (unsigned int*)mAddresses[--mNbPushedAddies];
		*Addy=d;
	}
	return *this;
}

///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// A method to pop an address and store a float where the poped address tells.
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Input	:	f		= the float to store
// Output	:	-
// Return	:	self-reference
// Exception:	-
// Remark	:	-
CustomArray& CustomArray::PopAddressAndStore(float f)
{
	if(mNbPushedAddies)
	{
		float* Addy = (float*)mAddresses[--mNbPushedAddies];
		*Addy=f;
	}
	return *this;
}

///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// A method to pop an address and store a double where the poped address tells.
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Input	:	f		= the double to store
// Output	:	-
// Return	:	self-reference
// Exception:	-
// Remark	:	-
CustomArray& CustomArray::PopAddressAndStore(double f)
{
	if(mNbPushedAddies)
	{
		double* Addy = (double*)mAddresses[--mNbPushedAddies];
		*Addy=f;
	}
	return *this;
}



///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//
// BIT STORAGE METHODS
//
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////



///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// A method to store a bit.
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Input	:	bool		= the bit to store
// Output	:	-
// Return	:	self-reference
// Exception:	-
// Remark	:	-
CustomArray& CustomArray::StoreBit(bool bit)
{
	mBitMask<<=1;
	if(bit)	mBitMask |= 1;
	mBitCount++;
	if(mBitCount==8)
	{
		mBitCount = 0;
		Store(mBitMask);
		mBitMask = 0;
	}
	return *this;
}

///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// A method to padd bits on a byte.
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Input	:	-
// Output	:	-
// Return	:	self-reference
// Exception:	-
// Remark	:	-
CustomArray& CustomArray::EndBits()
{
	while(mBitCount)	StoreBit(false);
	return *this;
}



///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//
// READ METHODS
//
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

char CustomArray::GetByte()
{
	char* CurrentAddy = (char*)mCurrentCell->Item.Addy;
	CurrentAddy+=mCurrentCell->Item.Size;

	char* Current = (char*)CurrentAddy;
	char result = *Current;
	mLastAddress = (void*)Current;
	mCurrentCell->Item.Size+=sizeof(char);
	return result;
}

short CustomArray::GetWord()
{
	char* CurrentAddy = (char*)mCurrentCell->Item.Addy;
	CurrentAddy+=mCurrentCell->Item.Size;

	short* Current = (short*)CurrentAddy;
	short result = *Current;
	mLastAddress = (void*)Current;
	mCurrentCell->Item.Size+=sizeof(short);
	return result;
}

long CustomArray::GetDword()
{
	char* CurrentAddy = (char*)mCurrentCell->Item.Addy;
	CurrentAddy+=mCurrentCell->Item.Size;

	long* Current = (long*)CurrentAddy;
	long result = *Current;
	mLastAddress = (void*)Current;
	mCurrentCell->Item.Size+=sizeof(long);
	return result;
}

float CustomArray::GetFloat()
{
	char* CurrentAddy = (char*)mCurrentCell->Item.Addy;
	CurrentAddy+=mCurrentCell->Item.Size;

	float* Current = (float*)CurrentAddy;
	float result = *Current;
	mLastAddress = (void*)Current;
	mCurrentCell->Item.Size+=sizeof(float);
	return result;
}


///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//
// HELP METHODS
//
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// A method to get a file length.
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Input	:	name	= file name
// Output	:	-
// Return	:	udword	= size in bytes, or 0 if file doesn't exist
// Exception:	-
// Remark	:	-
#ifndef SEEK_END
#define SEEK_END 2
#endif
udword CustomArray::FileSize(const char* name)
{
	FILE* File = fopen(name, "rb");
	if (!File) return 0;
	fseek(File, 0, SEEK_END);
	udword eof_ftell = ftell(File);
	fclose(File);
	return eof_ftell;
}

