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

#ifdef IDA55UP
 #define getSize get_item_size
#endif

//--------------------------------------------------------------------------
//Get mapped nms file.
//
// set - NM32 creationNumber (look into nm32.h)
//
// returns - pointer or FAILED_ (for size look to NM32_HEADER)
//
unsigned long* SetSoftIce::GetNMSFile(unsigned long set)
{
	segment_t*		segment;
		
	int				nSegments;
	unsigned long	physSize;

	char			fileName[16];
	char			number[4];
	char			segmClass[0xC];
	char*			segmClassNew;

	unsigned long*	nm32;
//small "header" sections
	FPOD_HEADER		fpod;
	SRCP_HEADER		srcp;
	GTYP_HEADER		gtyp;


//set segments data
	nSegments=get_segm_qty();
	for (unsigned long i=0; i<nSegments; i++)
	{
		segment=getnseg(i);

		if ( SEG_NORM==(segment->type) )
		{
			strcpy(segmClass, get_segm_class(segment) );
			segmClass[4]='\x0';
			set_segm_class(segment,segmClass);  // set segment class
			//test if segment class was fixed
			if ( SEG_NORM==(segment->type) )
			{
				segmClassNew=askstr(HIST_IDENT,segmClass,"Unknown segment type (%s).\n\nPlease fix segment class (to something like CODE,DATA,STACK,BSS,...):",get_segm_name(segment));
				if ( 0!=segmClassNew )
				{
					strcpy(segmClass, segmClassNew );
					set_segm_class(segment,segmClass);  // set segment class
					if ( SEG_NORM==(segment->type) ) warning("Segment class was not fixed.");
				}
			}
		}

		if ( SEG_CODE==(segment->type) )
		{
		//start
			auto unsigned long	currentAddress;
			auto func_t*		procedure;
			auto unsigned long	segmentEnd;
			auto flags_t		flags;

			segmentEnd=segment->endEA;
			physSize=segmentEnd-(segment->startEA);

			//set new SEGMENT_DATA
			if ( FAILED_==InitializeMemory_SYMD() ) return(FAILED_);
			symd.segmentCurrent->nSeg=i+1;
			symd.segmentCurrent->iNameSegment=SetStringTable(get_segm_name(segment));

		//set data
			//set new segment
			minEA=segment->startEA;	//set start of segment

			//set functions
				//all functions are in one area so we want to find those that are in current segment

				//Find first function in current segment.

			currentAddress=segment->startEA;
			while ( currentAddress<segmentEnd )
			{
				if ( 0!=wasBreak() )
				{
					plugInFlags|=USERCANCELLED;
					return(FAILED_);
				}

				flags=getFlags(currentAddress);

				//function
				if ( isFunc(flags) )
				{
					procedure=get_func(currentAddress);
					if ( FAILED_==SYMD_SetProcedure(procedure) ) return(FAILED_);
					currentAddress=procedure->endEA;	//it points to start of the next item
					continue;
				}

				//variable or a label
				if ( has_any_name(flags) )
				{
					auto unsigned long		type;	
					auto unsigned long*		VLPOffset;
					auto SEGDATA_VLPTABLE*	segVLP;
			#ifdef IDA55UP
					auto char				addressName[MAXSTR];
			#endif

				//Test if we have enough memory
					if ( (symd.segmentCurrent->freeVLP) <= (sizeof(SEGDATA_VLPTABLE)+1) )
						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) == 0 )
						if ( FAILED_== InitializeMemory(ALLOCATESMALL, symd.segmentCurrent->hVLPOffsets, (void**)&(symd.segmentCurrent->VLPOffsets), (void**)&(symd.segmentCurrent->VLPOffsetsCurrent), &(symd.segmentCurrent->freeVLPOffsets), &(symd.segmentCurrent->sizeVLPOffsets)) ) return(FAILED_);

				//set VLP TABLE
					segVLP=symd.segmentCurrent->VLPCurrent;

					segVLP->ten=0x10;
					segVLP->offVLP=currentAddress-minEA;
					if ( isCode(flags) )	//is it a label
					{
						segVLP->tableType=TT_LABEL;
						segVLP->type=0x1000;
					}
					else	//variable
					{
						segVLP->tableType=TT_VARIABLE;
						if ( FAILED_==(type=GetType_ea(currentAddress)) )
						{
							jumpto(currentAddress,-1);
							if ( FF_ALIGN==((getFlags(currentAddress))&DT_TYPE) )
							{
								warning("Align directive (ea:%x) isn't alowed to have a name.", currentAddress);
							}
							else
							{
								warning("Failed to get type (ea:%x).", currentAddress);
							}
							return(FAILED_);
						}
						segVLP->type=type;
					}
			#ifdef IDA55UP
					segVLP->iNameVLP=SetStringTable( get_name(BADADDR, currentAddress, addressName, MAXSTR) );
			#else
					segVLP->iNameVLP=SetStringTable( get_name(BADADDR, currentAddress) );
			#endif

				//Update
					++(symd.segmentCurrent->VLPCurrent);//to next struct
					VLPOffset=symd.segmentCurrent->VLPOffsetsCurrent;
					*(VLPOffset + 1)=*(VLPOffset)+sizeof(SEGDATA_VLPTABLE);
					++symd.segmentCurrent->VLPOffsetsCurrent;
					symd.segmentCurrent->freeVLP-=sizeof(SEGDATA_VLPTABLE);
					--symd.segmentCurrent->freeVLPOffsets;

					//Increase number of VLPs
					++symd.segmentCurrent->cVLP;
				}
				currentAddress+=getSize(currentAddress);
			}

			//physSize
			symd.segmentCurrent->physSize=physSize;

			//we'll have only one source file per segment
			auto SEGDATA_SOURCESECTION*	segSourceSection;
			auto SEGDATA_SOURCEFILE*	segSourceFile;
			segSourceSection=&(symd.segmentCurrent->sourceSection);
			segSourceFile=&(symd.segmentCurrent->sourceFile);

			segSourceSection->offStartSourceSection=0;
			segSourceSection->offEndSourceSection=physSize;
			segSourceSection->offSourceLine=0;
			segSourceSection->cLineTables=symd.segmentCurrent->cSourceLines;
			segSourceSection->offInSFDef=offInSFDefCurrent;
			offInSFDefCurrent+=sizeof(SEGDATA_SOURCESECTION);

			strcpy(fileName, "code_");
			strncat(fileName, ultoa(i,number,10), 4);
			++cSourceFiles;
			segSourceFile->iNameSource=SetStringTable(fileName);
			segSourceFile->offSource=cSourceFiles;
			segSourceFile->sourceLength=0x500000;	//until now sorce file is 500k long
			//end
		}
		else if ( SEG_DATA==(segment->type) )
		{
			physSize=(segment->endEA)-(segment->startEA);

			//set new SEGMENT_DATA
			if ( FAILED_==InitializeMemory_SYMD() ) return(FAILED_);
			symd.segmentCurrent->nSeg=i+1;
			symd.segmentCurrent->iNameSegment=SetStringTable(get_segm_name(segment));
			
			//set data
			minEA=segment->startEA;	//set start of segment
				//set new segment
			if ( FAILED_==SYMD_SetDataVariables(segment) ) return(FAILED_);

			//physSize
			symd.segmentCurrent->physSize=physSize;
		}
	}


if ( 0==symd.segments )
{
	warning("Couldn't define the segments.");
	return(FAILED_);
}

//set all sections
	sections.sttb=SetSection_STTB();
	sections.nmtp=SetSection_NMTP();
	sections.tytb=SetSection_TYTB();
	sections.hsht=SetSection_HSHT();
	sections.symd=SetSection_SYMD();

//	sections.fpod=SetSection_FPOD();
	sections.fpod=(unsigned long*)&fpod;
	fpod.FPOD=FPODs;
	fpod.sectionLength=sizeof(FPOD_HEADER);
	fpod.N1=0;
	fpod.N2=0;
	fpod.N3=0;
	fpod.N4=0;
	fpod.N5=0;
	fpod.N6=0;
	fpod.N7=0;
	fpod.N8=0;
	fpod.N9=0;
	fpod.NA=0;
//	sections.srcp=SetSection_SRCP();
	sections.srcp=(unsigned long*)&srcp;	//offset will be defined in SetSection_NM32
	srcp.SRCP=SRCPs;
	srcp.sectionLength=sizeof(SRCP_HEADER);
	srcp.offSourceFiles=0;					//source is not in file
	srcp.N1=0;
	srcp.N2=0;
//	sections.gtyp=SetSection_GTYP();
	sections.gtyp=(unsigned long*)&gtyp;	//offsets will be defined in SetSection_NM32
	gtyp.GTYP=GTYPs;
	gtyp.sectionLength=sizeof(GTYP_HEADER);
	gtyp.offTYTB=0;
	gtyp.offHSHT=0;
	gtyp.N1=0;
	gtyp.N2=0;


//Set NM32_Header
	nm32=SetSection_NM32(set);	//create whole file
	sections.nm32=nm32;

//return
	return(nm32);

}
//--------------------------------------------------------------------------
//Load mapped nms file to Softice.
//
// nmsMapped - Pointer to mapped nms file in memory.
//
// return - error (FAILED_, SUCCESS_)
//
int SetSoftIce::LoadNMSFile(unsigned long* nmsMapped)
{
	HANDLE			hVXDFile;
	MODULEINFO		moduleInfo;
	unsigned long	bytesReturned;
	char			fileName[MAX_PATH];
	char*			radix;


//get handle
	hVXDFile=CreateFile( "\\\\.\\SICE", GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE,
	                    NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
	if ( hVXDFile==INVALID_HANDLE_VALUE )
	{
		hVXDFile = CreateFile( "\\\\.\\NTICE", GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE,
		                     NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
		
	}

	if ( hVXDFile!=INVALID_HANDLE_VALUE )
	{
		//get the name of the file
		strcpy( fileName, get_root_filename() );	//only file name
		radix=strstr(fileName, ".");
		radix[0]='\x0';								//we want only name

		moduleInfo.pModuleName=fileName;
		moduleInfo.pMappedFile=nmsMapped;
		moduleInfo.fileSize=*(nmsMapped+7);
		moduleInfo.pSourceCode=NULL;
		moduleInfo.sourceLength=NULL;
		
		if ( 0!=DeviceIoControl( hVXDFile, 0x9C406004, &moduleInfo, sizeof(MODULEINFO), NULL, NULL, &bytesReturned, NULL) ) return(SUCCESS_);
	}
	return(FAILED_);
}

