//
//  PlugIn name: IDA to SoftIce converter (only for 32bit programs)
//
//  Version: 0.01 prerelease
//
//
//  This file contains memory function.
//
//
#include "i2s.h"

//--------------------------------------------------------------------------
//Allocates memory for the program.
//
// return - error (FAILED_ / SUCCESS_)
//
int InitializeMemory(void)		//no parameters => initialization of the memory
{
	HLOCAL		hTemp;

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Set memory for strings.
	if ( 0==(hTemp=LocalAlloc(LHND, ALLOCATEBIG)) )
	{
		return(FAILED_);
	}
	else
	{
		if ( 0==(sttb.strings=(char*)LocalLock(hTemp)) )
		{
			LocalFree(hTemp);
			return(FAILED_);
		}
		else
		{
			sttb.hStrings=hTemp;
		}
	}
	if ( 0==(hTemp=LocalAlloc(LHND, ALLOCATESMALL*4)) )
	{
		return(FAILED_);
	}
	else
	{
		if ( 0==(sttb.offsets=(unsigned long*)LocalLock(hTemp)) )
		{
			LocalFree(hTemp);
			return(FAILED_);
		}
		else
		{
			sttb.hOffsets=hTemp;
		}
	}
	sttb.stringsCurrent=sttb.strings+1;					//first string is a zero string '\x0'
	sttb.offsetsCurrent=sttb.offsets+1;					//first offset is zero
	*sttb.offsetsCurrent=1;								//second offset is one (over null string)


//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Set memory for NM types.
	if ( 0==(hTemp=LocalAlloc(LHND, ALLOCATEBIG)) )
	{
		return(FAILED_);
	}
	else
	{
		if ( 0==(nmtp.typesData=(unsigned char*)LocalLock(hTemp)) )
		{
			LocalFree(hTemp);
			return(FAILED_);
		}
		else
		{
			nmtp.hTypesData=hTemp;
		}
	}
	nmtp.typesDataCurrent=nmtp.typesData;

	if ( 0==(hTemp=LocalAlloc(LHND, ALLOCATESMALL*4)) )
	{
		return(FAILED_);
	}
	else
	{
		if ( 0==(nmtp.typesOffsets=(unsigned long*)LocalLock(hTemp)) )
		{
			LocalFree(hTemp);
			return(FAILED_);
		}
		else
		{
			nmtp.hTypesOffsets=hTemp;
		}
	}
	nmtp.typesOffsetsCurrent=nmtp.typesOffsets;


//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Set memory for type tables.
	if ( 0==(hTemp=LocalAlloc(LHND, ALLOCATEBIG)) )
	{
		return(FAILED_);
	}
	else
	{
		if ( 0==(tytb.typeTables=(TYPETABLE*)LocalLock(hTemp)) )
		{
			LocalFree(hTemp);
			return(FAILED_);
		}
		else
		{
			tytb.hTypeTables=hTemp;
		}
	}
	tytb.typeTablesCurrent=tytb.typeTables;

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Set memory for hash tables
	if ( 0==(hTemp=LocalAlloc(LHND, ALLOCATEBIG)) )
	{
		return(FAILED_);
	}
	else
	{
		if ( 0==(hsht.hashTables=(HSHT_TYPETABLE*)LocalLock(hTemp)) )
		{
			LocalFree(hTemp);
			return(FAILED_);
		}
		else
		{
			hsht.hHashTables=hTemp;
		}
	}
	hsht.hashTablesCurrent=hsht.hashTables;

//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Set memory for symbols
//THIS LINE SHOULD BE USED WHEN YOU WANT A NEW SEGMENT! (check createLoad.cpp)
//	if ( FAILED_==InitializeMemory_SYMD() ) return(FAILED_);

// End
	return(SUCCESS_);
}

//ReAllocates memory for the program.
// choice - ALLOCATEBIG (64k), ALLOCATESMALL (4k)
// HLOCAL - Local memory handle. This one is always the same in MOVEABLE memory so we don't need to update it.
// buffer - Pointer to pointer of the buffer.
// ....
//
// return - error (FAILED_ / SUCCESS_)
//
int InitializeMemory(int choice, HLOCAL handle, void** buffer, void** bufferCurrent, unsigned long* freeBuffer, unsigned long* sizeBuffer)
{
	unsigned long	offset;
	unsigned long*	oldPointer;


	oldPointer=*(unsigned long**)buffer;		//get the old pointer to memory
	offset=*(unsigned long*)bufferCurrent-*(unsigned long*)buffer;	//get the offset in memory to 1st free ?
	
	if (choice==ALLOCATEBIG)
	{
//		LocalUnlock(handle);
		if (0==(handle=LocalReAlloc(handle, *sizeBuffer+ALLOCATEBIG, LMEM_ZEROINIT|LMEM_MOVEABLE)) )
		{
			*(unsigned long**)buffer=oldPointer;
			return(FAILED_);
		}
		*freeBuffer+=ALLOCATEBIG;
		*sizeBuffer+=ALLOCATEBIG;
		*buffer=LocalLock(handle);	//increase the lock
		LocalUnlock(handle);	//so that the lock will always be 1
	}
	else	//(choice==ALLOCATESMALL)
	{
		if (0==(handle=LocalReAlloc(handle, (*sizeBuffer+ALLOCATESMALL)*4, LMEM_ZEROINIT|LMEM_MOVEABLE)) )
		{
			*(unsigned long**)buffer=oldPointer;
			return(FAILED_);
		}
		*freeBuffer+=ALLOCATESMALL;
		*sizeBuffer+=ALLOCATESMALL;
		*buffer=LocalLock(handle);
		LocalUnlock(handle);	//so that the lock will always be 1
	}

	*(char**)bufferCurrent=*(char**)buffer+offset;

//End
	return(SUCCESS_);
}

//Allocate memory for symd segment (SEGMENT_DATA)
//
// return - Pointer to SEGMENT_DATA or FAILED_.
//
SEGMENT_DATA* InitializeMemory_SYMD_S(void)
{
	SEGMENT_DATA*	segmentStruct;
	HLOCAL			hTemp;

//Set memory for SEGMENT_DATA
	if ( 0==(segmentStruct=(SEGMENT_DATA*)LocalAlloc(LPTR, sizeof(SEGMENT_DATA))) ) return(FAILED_);

//Set memory for everithing in SEGMENT_DATA
	if ( 0==(hTemp=LocalAlloc(LHND, ALLOCATEBIG)) )
	{
		return(FAILED_);
	}
	else
	{
		if ( 0==(segmentStruct->procDefinitions=(SEGDATA_PROCEDURE*)LocalLock(hTemp)) )
		{
			LocalFree(hTemp);
			return(FAILED_);
		}
		else
		{
			segmentStruct->hProcDefinitions=hTemp;
		}
	}
	segmentStruct->procDefinitionsCurrent=segmentStruct->procDefinitions;
	segmentStruct->freeProcDefinitions=ALLOCATEBIG-1;
	segmentStruct->sizeProcDefinitions=ALLOCATEBIG;

	if ( 0==(hTemp=LocalAlloc(LHND, ALLOCATEBIG)) )
	{
		return(FAILED_);
	}
	else
	{
		if ( 0==(segmentStruct->localVariables=(SEGDATA_VLPTABLE*)LocalLock(hTemp)) )
		{
			LocalFree(hTemp);
			return(FAILED_);
		}
		else
		{
			segmentStruct->hLocalVariables=hTemp;
		}
	}
	segmentStruct->localVariablesCurrent=segmentStruct->localVariables;
	segmentStruct->freeLocalVariables=ALLOCATEBIG-1;
	segmentStruct->sizeLocalVariables=ALLOCATEBIG;

	if ( 0==(hTemp=LocalAlloc(LHND, ALLOCATEBIG)) )
	{
		return(FAILED_);
	}
	else
	{
		if ( 0==(segmentStruct->sourceLines=(SEGDATA_SOURCELINES*)LocalLock(hTemp)) )
		{
			LocalFree(hTemp);
			return(FAILED_);
		}
		else
		{
			segmentStruct->hSourceLines=hTemp;
		}
	}
	segmentStruct->sourceLinesCurrent=segmentStruct->sourceLines;
	segmentStruct->freeSourceLines=ALLOCATEBIG-1;
	segmentStruct->sizeSourceLines=ALLOCATEBIG;

	if ( 0==(hTemp=LocalAlloc(LHND, ALLOCATEBIG)) )
	{
		return(FAILED_);
	}
	else
	{
		if ( 0==(segmentStruct->VLP=(SEGDATA_VLPTABLE*)LocalLock(hTemp)) )
		{
			LocalFree(hTemp);
			return(FAILED_);
		}
		else
		{
			segmentStruct->hVLP=hTemp;
		}
	}
	segmentStruct->VLPCurrent=segmentStruct->VLP;
	segmentStruct->freeVLP=ALLOCATEBIG-1;
	segmentStruct->sizeVLP=ALLOCATEBIG;

	if ( 0==(hTemp=LocalAlloc(LHND, ALLOCATEBIG)) )
	{
		return(FAILED_);
	}
	else
	{
		if ( 0==(segmentStruct->VLPOffsets=(unsigned long*)LocalLock(hTemp)) )
		{
			LocalFree(hTemp);
			return(FAILED_);
		}
		else
		{
			segmentStruct->hVLPOffsets=hTemp;
		}
	}
	segmentStruct->VLPOffsetsCurrent=segmentStruct->VLPOffsets;
	segmentStruct->freeVLPOffsets=ALLOCATESMALL-1;
	segmentStruct->sizeVLPOffsets=ALLOCATESMALL;

//Return pointer to defined segment
	return(segmentStruct);
}

//Check for old SEGMENT_DATA-s and sets new one.
//This procedure should be called when you want to set a new segment.
//
// return - error (FAILED_, SUCCESS_)
//
int InitializeMemory_SYMD(void)
{
	SEGMENT_DATA*		segmentCurrent;
	
	if ( 0==symd.cSegments )	//1st one
	{
		if ( 0==(symd.segments=InitializeMemory_SYMD_S()) ) return(FAILED_);
		symd.segmentCurrent=symd.segments;
	}
	else //n-th one
	{
		segmentCurrent=symd.segmentCurrent;
		if ( 0==(symd.segmentCurrent=InitializeMemory_SYMD_S()) ) return(FAILED_);
		segmentCurrent->pNext=symd.segmentCurrent;
	}
	++symd.cSegments;
	return(SUCCESS_);
}


//--------------------------------------------------------------------------
//Frees all the memory that was allocated in the program.
//
// return - error (FAILED_ / SUCCESS_)
//
int	FreeMemory(void)
{
//FreeLocal frees locked memory too
	SEGMENT_DATA*	pNext;
//sections
	if ( 0!=sections.nm32 ) LocalFree(sections.nm32 );	//all fixed
	if ( 0!=sections.sttb ) LocalFree(sections.sttb );
	if ( 0!=sections.nmtp ) LocalFree(sections.nmtp );
	if ( 0!=sections.tytb ) LocalFree(sections.tytb );
	if ( 0!=sections.hsht ) LocalFree(sections.hsht );
	if ( 0!=sections.symd ) LocalFree(sections.symd );
//	if ( 0!=sections.fpod ) LocalFree(sections.fpod );	//on stack
//	if ( 0!=sections.srcp ) LocalFree(sections.srcp );	//on stack
//	if ( 0!=sections.gtyp ) LocalFree(sections.gtyp );	//on stack

//symbols
	for (auto int i=0;i<symd.cSegments; i++ )
	{
		if ( 0!= symd.segments->procDefinitions ) LocalFree( symd.segments->hProcDefinitions );
		if ( 0!= symd.segments->localVariables ) LocalFree( symd.segments->hLocalVariables );
		if ( 0!= symd.segments->sourceLines ) LocalFree( symd.segments->hSourceLines );
		if ( 0!= symd.segments->VLP ) LocalFree( symd.segments->hVLP );
		if ( 0!= symd.segments->VLPOffsets ) LocalFree( symd.segments->hVLPOffsets );

		pNext=symd.segments->pNext;
		LocalFree( symd.segments );	//fixed memory
		symd.segments=pNext;
	}

//hash tables
	if ( 0!=hsht.hashTables ) LocalFree(hsht.hHashTables);

//type tables
	if ( 0!=tytb.typeTables ) LocalFree(tytb.hTypeTables);

//NM types.
	if ( 0!=nmtp.typesData ) LocalFree(nmtp.hTypesData);
	if ( 0!=nmtp.typesOffsets ) LocalFree(nmtp.hTypesOffsets);

//strings.
	if ( 0!=sttb.strings ) LocalFree(sttb.hStrings);
	if ( 0!=sttb.offsets ) LocalFree(sttb.hOffsets);


//End
	return(SUCCESS_);
}

//--------------------------------------------------------------------------
//NOTICE!
//This function is just for SYMD VLP structure. Next one is for all others.
//
//Checks if specificied buffer has enought space left.
//
// lenght - Wanted space in bytes.
// type - MEMORY_xxxx (look into i2s.h)
// count - Number of structures. (Only needed in SYMD_SetProcedure.)
//
// return - error (FAILED_, SUCCESS_)
//

int SetSoftIce::CheckMemory(unsigned long lenght, unsigned long type, unsigned long	count)
{
	if ( type==MEMORY_SYMD_VLP )
	{
		if ( (symd.segmentCurrent->freeVLP) <= lenght )
			if ( FAILED_== InitializeMemory(ALLOCATEBIG, symd.segmentCurrent->hVLP, (void**)&(symd.segmentCurrent->VLP), (void**)&(symd.segmentCurrent->VLPCurrent), &(symd.segmentCurrent->freeVLP), &(symd.segmentCurrent->sizeVLP)) ) return(FAILED_);
		if ( (symd.segmentCurrent->freeVLPOffsets) <= count )
			if ( FAILED_== InitializeMemory(ALLOCATESMALL, symd.segmentCurrent->hVLPOffsets, (void**)&(symd.segmentCurrent->VLPOffsets), (void**)&(symd.segmentCurrent->VLPOffsetsCurrent), &(symd.segmentCurrent->freeVLPOffsets), &(symd.segmentCurrent->sizeVLPOffsets)) ) return(FAILED_);
		return(SUCCESS_);
	}
	return(FAILED_);
}

//Same as upper.
int SetSoftIce::CheckMemory(unsigned long lenght, unsigned long type)
{
	switch ( type )
	{
//		case MEMORY_SYMD_SOURCEFILES :
		case MEMORY_SYMD_SOURCELINES :
							if ( symd.segmentCurrent->freeSourceLines <= lenght )
								if ( FAILED_== InitializeMemory(ALLOCATEBIG, symd.segmentCurrent->hSourceLines, (void**)&(symd.segmentCurrent->sourceLines), (void**)&(symd.segmentCurrent->sourceLinesCurrent), &(symd.segmentCurrent->freeSourceLines), &(symd.segmentCurrent->sizeSourceLines)) ) return(FAILED_);
							break;
//		case MEMORY_SYMD_VLP :	//in separate function
		case MEMORY_SYMD_LOCAL :
							if ( symd.segmentCurrent->freeLocalVariables <= lenght )
								if ( FAILED_== InitializeMemory(ALLOCATEBIG, symd.segmentCurrent->hLocalVariables, (void**)&(symd.segmentCurrent->localVariables), (void**)&(symd.segmentCurrent->localVariablesCurrent), &(symd.segmentCurrent->freeLocalVariables), &(symd.segmentCurrent->sizeLocalVariables)) ) return(FAILED_);
							break;
		case MEMORY_SYMD_PROCEDURE :
							if ( symd.segmentCurrent->freeProcDefinitions <= lenght )
								if ( FAILED_== InitializeMemory(ALLOCATEBIG, symd.segmentCurrent->hProcDefinitions, (void**)&(symd.segmentCurrent->procDefinitions), (void**)&(symd.segmentCurrent->procDefinitionsCurrent), &(symd.segmentCurrent->freeProcDefinitions), &(symd.segmentCurrent->sizeProcDefinitions)) ) return(FAILED_);
							break;
		case MEMORY_HSHT :
							if ( hsht.freeHashTables <= lenght )
								if ( FAILED_== InitializeMemory(ALLOCATEBIG, hsht.hHashTables, (void**)&(hsht.hashTables), (void**)&(hsht.hashTablesCurrent), &(hsht.freeHashTables), &(hsht.sizeHashTables)) ) return(FAILED_);
							break;
		case MEMORY_TYTB :
							if ( tytb.freeTypeTables <= lenght )
								if ( FAILED_== InitializeMemory(ALLOCATEBIG, tytb.hTypeTables, (void**)&(tytb.typeTables), (void**)&(tytb.typeTablesCurrent), &(tytb.freeTypeTables), &(tytb.sizeTypeTables)) ) return(FAILED_);
							break;
		case MEMORY_NMTP :
							if ( nmtp.freeTypesData <= lenght )
								if ( FAILED_== InitializeMemory(ALLOCATEBIG, nmtp. hTypesData, (void**)&(nmtp.typesData), (void**)&(nmtp.typesDataCurrent), &nmtp.freeTypesData, &nmtp.sizeTypesData) ) return(FAILED_);

							if ( nmtp.freeTypesOffsets == 0 )	//because I encountered offset error in sttb.freeOffsets I changed 0 to 1 here too
								if ( FAILED_== InitializeMemory(ALLOCATESMALL, nmtp.hTypesOffsets, (void**)&(nmtp.typesOffsets), (void**)&(nmtp.typesOffsetsCurrent), &nmtp.freeTypesOffsets, &nmtp.sizeTypesOffsets) ) return(FAILED_);
							break;
		case MEMORY_STTB :
							if ( sttb.freeStrings <= (lenght+4) ) //+4 because of the problem in SetSection_STTB
								if ( FAILED_== InitializeMemory(ALLOCATEBIG, sttb.hStrings, (void**)&(sttb.strings), (void**)&(sttb.stringsCurrent), &sttb.freeStrings, &sttb.sizeStrings) ) return(FAILED_);

							if ( sttb.freeOffsets == 0 )	//I don't know where the error is so I fixed it here (it should be 0)
								if ( FAILED_== InitializeMemory(ALLOCATESMALL, sttb.hOffsets, (void**)&(sttb.offsets), (void**)&(sttb.offsetsCurrent), &sttb.freeOffsets, &sttb.sizeOffsets) ) return(FAILED_);
							break;
		default :
							return(FAILED_);
	}
	return(SUCCESS_);
}


//--------------------------------------------------------------------------
//Reset global variables
//
void ResetGlobalVariables(void)
{
//sttb = {0,0,0,0,0,0,ALLOCATEBIG-1,ALLOCATESMALL-1,ALLOCATEBIG,ALLOCATESMALL,1};
	sttb.hStrings=0;
	sttb.hOffsets=0;
	sttb.strings=0;
	sttb.offsets=0;
	sttb.stringsCurrent=0;		//I wouldn't need to do that but ...
	sttb.offsetsCurrent=0;		//Pointer to 1st free dword in offsets buffer.
	sttb.freeStrings=ALLOCATEBIG-2;
	sttb.freeOffsets=ALLOCATESMALL-2;
	sttb.sizeStrings=ALLOCATEBIG;
	sttb.sizeOffsets=ALLOCATESMALL;
	sttb.cStrings=1;

//nmtp = {0,0,0,0,0,0,ALLOCATEBIG-9*4,ALLOCATESMALL-3,ALLOCATEBIG,ALLOCATESMALL,3};
	nmtp.hTypesData=0;
	nmtp.hTypesOffsets=0;
	nmtp.typesData=0;
	nmtp.typesOffsets=0;
	nmtp.typesDataCurrent=0;
	nmtp.typesOffsetsCurrent=0;
	nmtp.freeTypesData=ALLOCATEBIG-9*4-1;
	nmtp.freeTypesOffsets=ALLOCATESMALL-4;
	nmtp.sizeTypesData=ALLOCATEBIG;
	nmtp.sizeTypesOffsets=ALLOCATESMALL;
	nmtp.cTypesData=3;

//tytb = {0,0,0,ALLOCATEBIG,ALLOCATEBIG,0};
	tytb.hTypeTables=0;
	tytb.typeTables=0;
	tytb.typeTablesCurrent=0;
	tytb.freeTypeTables=ALLOCATEBIG-1;
	tytb.sizeTypeTables=ALLOCATEBIG;
	tytb.cTypeTables=0;

//hsht = {0,0,0,ALLOCATEBIG,ALLOCATEBIG,0, 0, 0...0};
	hsht.hHashTables=0;
	hsht.hashTables=0;
	hsht.hashTablesCurrent=0;
	hsht.freeHashTables=ALLOCATEBIG-1;
	hsht.sizeHashTables=ALLOCATEBIG;
	hsht.cHashTables=0;
		//hashOffsets
	for (int i=0; i<0x25 ;i++ )
		hsht.hashOffsets[i]=0;

//symd = {0,0,0};
	symd.cSegments=0;
	symd.segments=0;
	symd.segmentCurrent=0;

//sections = {0,0,0,0,0,0,0,0,0};
	sections.nm32=0;
	sections.sttb=0;
	sections.nmtp=0;
	sections.tytb=0;
	sections.hsht=0;
	sections.symd=0;
	sections.fpod=0;
	sections.srcp=0;
	sections.gtyp=0;

//lineNumber (just a temp variables)
	lineNumberCurrent=0;
	offInSFDefCurrent=0;
	cSourceFiles=0;
}


//--------------------------------------------------------------------------
//Copy DWORD memory.
//
// bufferTo - Where to copy.
// bufferFrom - From where.
// size - Number of DWORDs to copy.
//
// return - number of DWORDs copied.
//
unsigned long CopyDWORDMemory(unsigned long* bufferTo, unsigned long* bufferFrom, unsigned long size)
{
	unsigned long	i;

	for (i=0; i<size; i++)
		bufferTo[i]=bufferFrom[i];
	
	return(size);	//quite useless but I need it in sections.cpp
}
