shithub: rgbds

ref: b53e17078150a42cc74e78e3f4327457c66854e0
dir: /src/link/object.c/

View raw version
/*
 * Here we have the routines that read an objectfile
 *
 */

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include "mylink.h"
#include "main.h"

struct	sSymbol		**tSymbols;
struct	sSection	*pSections=NULL;
struct	sSection	*pLibSections=NULL;
UBYTE	dummymem;
BBOOL	oReadLib=0;


/*
 * The usual byte order stuff
 *
 */

SLONG	readlong( FILE *f )
{
	SLONG	r;

	r =fgetc(f);
	r|=fgetc(f)<<8;
	r|=fgetc(f)<<16;
	r|=fgetc(f)<<24;

	return( r );
}

UWORD	readword( FILE *f )
{
	UWORD	r;

	r =fgetc(f);
	r|=fgetc(f)<<8;

	return( r );
}

/*
 * Read a NULL terminated string from a file
 *
 */

SLONG	readasciiz( char *s, FILE *f )
{
	SLONG	r=0;

	while( ((*s++)=fgetc(f))!=0 )
		r+=1;

	return( r+1 );
}


/*
 * Allocate a new section and link it into the list
 *
 */

struct	sSection	*AllocSection( void )
{
	struct	sSection	**ppSections;

	if( oReadLib==1 )
		ppSections=&pLibSections;
	else
		ppSections=&pSections;

	while( *ppSections )
		ppSections=&((*ppSections)->pNext);

	if( (*ppSections)=(struct sSection *)malloc(sizeof(struct sSection)) )
	{
		(*ppSections)->tSymbols=tSymbols;
		(*ppSections)->pNext=NULL;
		(*ppSections)->pPatches=NULL;
		(*ppSections)->oAssigned=0;
		return( *ppSections );
	}
	else
	{
		fatalerror( "Out of memory!" );
		return( NULL );
	}
}

/*
 * Read a symbol from a file
 *
 */

struct sSymbol *obj_ReadSymbol( FILE *f )
{
	char	s[256];
	struct	sSymbol	*pSym;

	if( pSym=(struct sSymbol *)malloc(sizeof(struct sSymbol)) )
	{
		readasciiz( s, f );
		if( pSym->pzName=(char *)malloc(strlen(s)+1) )
		{
			strcpy( pSym->pzName, s );
			if( (pSym->Type=(enum eSymbolType)fgetc(f))!=SYM_IMPORT )
			{
				pSym->nSectionID=readlong(f);
				pSym->nOffset=readlong(f);
			}
			return( pSym );
		}
		else
			fatalerror( "Out of memory!" );
	}
	else
		fatalerror( "Out of memory!" );

	return( NULL );
}

/*
 * RGB0 object reader routines
 *
 */

struct	sSection	*obj_ReadRGB0Section( FILE *f )
{
	struct	sSection	*pSection;

	pSection=AllocSection();

	pSection->nByteSize=readlong( f );
	pSection->Type=(enum eSectionType)fgetc( f );
	pSection->nOrg=-1;
	pSection->nBank=-1;

	/* does the user want the -s mode? */

	if( (options&OPT_SMALL) && (pSection->Type==SECT_CODE) )
	{
		pSection->Type=SECT_HOME;
	}

	if( (pSection->Type==SECT_CODE) || (pSection->Type==SECT_HOME) )
	{
		/*
		 * These sectiontypes contain data...
		 *
		 */
		if( pSection->nByteSize )
		{
			if( pSection->pData=(UBYTE *)malloc(pSection->nByteSize) )
			{
				SLONG	nNumberOfPatches;
				struct	sPatch	**ppPatch, *pPatch;
				char	s[256];

				fread( pSection->pData, sizeof(UBYTE), pSection->nByteSize, f );
				nNumberOfPatches=readlong(f);
				ppPatch=&pSection->pPatches;

				/*
				 * And patches...
				 *
				 */
				while( nNumberOfPatches-- )
				{
					if( pPatch=(struct sPatch *)malloc(sizeof(struct sPatch)) )
					{
						*ppPatch=pPatch;
						readasciiz( s, f );
						if( pPatch->pzFilename=(char *)malloc(strlen(s)+1) )
						{
							strcpy( pPatch->pzFilename, s );
							pPatch->nLineNo=readlong( f );
							pPatch->nOffset=readlong( f );
							pPatch->Type=(enum ePatchType)fgetc( f );
							if( (pPatch->nRPNSize=readlong(f))>0 )
							{
								if( pPatch->pRPN=(UBYTE *)malloc(pPatch->nRPNSize) )
									fread( pPatch->pRPN, sizeof(UBYTE), pPatch->nRPNSize, f );
								else
									fatalerror( "Out of memory!" );
							}
							else
								pPatch->pRPN=NULL;
							pPatch->pNext=NULL;
							ppPatch=&(pPatch->pNext);
						}
						else
							fatalerror( "Out of memory!" );
					}
					else
						fatalerror( "Out of memory!" );
				}
			}
			else
				fatalerror( "Out of memory!" );
		}
		else
		{
			readlong(f);	//	Skip number of patches
			pSection->pData=&dummymem;
		}
	}

	return( pSection );
}

void	obj_ReadRGB0( FILE *pObjfile )
{
	struct	sSection	*pFirstSection;
	SLONG	nNumberOfSymbols, nNumberOfSections, i;

	nNumberOfSymbols=readlong( pObjfile );
	nNumberOfSections=readlong( pObjfile );

	/* First comes the symbols */

	if( nNumberOfSymbols )
	{
		if( tSymbols=(struct sSymbol **)malloc(nNumberOfSymbols*sizeof(struct sSymbol *)) )
		{
			for( i=0; i<nNumberOfSymbols; i+=1 )
				tSymbols[i]=obj_ReadSymbol( pObjfile );
		}
		else
			fatalerror( "Out of memory!" );
	}
	else
		tSymbols=(struct sSymbol **)&dummymem;

	/* Next we have the sections */

	pFirstSection=NULL;
	while( nNumberOfSections-- )
	{
		struct sSection *pNewSection;

		pNewSection=obj_ReadRGB0Section( pObjfile );
		pNewSection->nNumberOfSymbols=nNumberOfSymbols;
		if( pFirstSection==NULL )
			pFirstSection=pNewSection;
	}

	/*
	 * Fill in the pSection entry in the symbolstructure.
	 * This REALLY needs some cleaning up... but, hey, it works
	 *
	 */

	for( i=0; i<nNumberOfSymbols; i+=1 )
	{
		struct	sSection	*pConvSect=pFirstSection;

		if( tSymbols[i]->Type!=SYM_IMPORT && tSymbols[i]->nSectionID!=-1 )
		{
			SLONG	j=0;
			while( j != tSymbols[i]->nSectionID )
			{
				j+=1;
				pConvSect=pConvSect->pNext;
			}
			tSymbols[i]->pSection=pConvSect;
		}
		else
			tSymbols[i]->pSection=NULL;
	}
}

/*
 * RGB1 object reader routines
 *
 */

struct	sSection	*obj_ReadRGB1Section( FILE *f )
{
	struct	sSection	*pSection;

	pSection=AllocSection();

	pSection->nByteSize=readlong( f );
	pSection->Type=(enum eSectionType)fgetc( f );
	/*
	 * And because of THIS new feature I'll have to rewrite loads and
	 * loads of stuff... oh well it needed to be done anyway
	 *
	 */
	pSection->nOrg=readlong( f );
	pSection->nBank=readlong( f );

	/* does the user want the -s mode? */

	if( (options&OPT_SMALL) && (pSection->Type==SECT_CODE) )
	{
		pSection->Type=SECT_HOME;
	}

	if( (pSection->Type==SECT_CODE) || (pSection->Type==SECT_HOME) )
	{
		/*
		 * These sectiontypes contain data...
		 *
		 */
		if( pSection->nByteSize )
		{
			if( pSection->pData=(UBYTE *)malloc(pSection->nByteSize) )
			{
				SLONG	nNumberOfPatches;
				struct	sPatch	**ppPatch, *pPatch;
				char	s[256];

				fread( pSection->pData, sizeof(UBYTE), pSection->nByteSize, f );
				nNumberOfPatches=readlong(f);
				ppPatch=&pSection->pPatches;

				/*
				 * And patches...
				 *
				 */
				while( nNumberOfPatches-- )
				{
					if( pPatch=(struct sPatch *)malloc(sizeof(struct sPatch)) )
					{
						*ppPatch=pPatch;
						readasciiz( s, f );
						if( pPatch->pzFilename=(char *)malloc(strlen(s)+1) )
						{
							strcpy( pPatch->pzFilename, s );
							pPatch->nLineNo=readlong( f );
							pPatch->nOffset=readlong( f );
							pPatch->Type=(enum ePatchType)fgetc( f );
							if( (pPatch->nRPNSize=readlong(f))>0 )
							{
								if( pPatch->pRPN=(UBYTE *)malloc(pPatch->nRPNSize) )
									fread( pPatch->pRPN, sizeof(UBYTE), pPatch->nRPNSize, f );
								else
									fatalerror( "Out of memory!" );
							}
							else
								pPatch->pRPN=NULL;
							pPatch->pNext=NULL;
							ppPatch=&(pPatch->pNext);
						}
						else
							fatalerror( "Out of memory!" );
					}
					else
						fatalerror( "Out of memory!" );
				}
			}
			else
				fatalerror( "Out of memory!" );
		}
		else
		{
			readlong(f);	//	Skip number of patches
			pSection->pData=&dummymem;
		}
	}

	return( pSection );
}

void	obj_ReadRGB1( FILE *pObjfile )
{
	struct	sSection	*pFirstSection;
	SLONG	nNumberOfSymbols, nNumberOfSections, i;

	nNumberOfSymbols=readlong( pObjfile );
	nNumberOfSections=readlong( pObjfile );

	/* First comes the symbols */

	if( nNumberOfSymbols )
	{
		if( tSymbols=(struct sSymbol **)malloc(nNumberOfSymbols*sizeof(struct sSymbol *)) )
		{
			for( i=0; i<nNumberOfSymbols; i+=1 )
				tSymbols[i]=obj_ReadSymbol( pObjfile );
		}
		else
			fatalerror( "Out of memory!" );
	}
	else
		tSymbols=(struct sSymbol **)&dummymem;

	/* Next we have the sections */

	pFirstSection=NULL;
	while( nNumberOfSections-- )
	{
		struct	sSection	*pNewSection;

		pNewSection=obj_ReadRGB1Section( pObjfile );
		pNewSection->nNumberOfSymbols=nNumberOfSymbols;
		if( pFirstSection==NULL )
			pFirstSection=pNewSection;
	}

	/*
	 * Fill in the pSection entry in the symbolstructure.
	 * This REALLY needs some cleaning up... but, hey, it works
	 *
	 */

	for( i=0; i<nNumberOfSymbols; i+=1 )
	{
		struct	sSection	*pConvSect=pFirstSection;

		if( tSymbols[i]->Type!=SYM_IMPORT && tSymbols[i]->nSectionID!=-1 )
		{
			SLONG	j=0;
			while( j != tSymbols[i]->nSectionID )
			{
				j+=1;
				pConvSect=pConvSect->pNext;
			}
			tSymbols[i]->pSection=pConvSect;
		}
		else
			tSymbols[i]->pSection=NULL;
	}
}

/*
 * The main objectfileloadroutine (phew)
 *
 */

void	obj_ReadOpenFile( FILE *pObjfile, char *tzObjectfile )
{
	char	tzHeader[8];

	fread( tzHeader, sizeof(char), 4, pObjfile );
	tzHeader[4]=0;
	if( strncmp(tzHeader,"RGB", 3)==0 )
	{
		switch( tzHeader[3] )
		{
			case	'0':
				obj_ReadRGB0( pObjfile );
				break;
			case	'1':
			case	'2':	//	V2 is really the same but the are new patch types
				obj_ReadRGB1( pObjfile );
				break;
			default:
				sprintf( temptext, "'%s' is an unsupported version\n", tzObjectfile );
				fatalerror( temptext );
				break;
		}
	}
	else
	{
		sprintf( temptext, "'%s' is not a valid object\n", tzObjectfile );
		fatalerror( temptext );
	}
}

void	obj_Readfile( char *tzObjectfile )
{
	FILE	*pObjfile;

	if( options&OPT_SMART_C_LINK )
		oReadLib=1;
	else
		oReadLib=0;

	if( pObjfile=fopen(tzObjectfile,"rb") )
	{
		obj_ReadOpenFile( pObjfile, tzObjectfile );
		fclose( pObjfile );
	}
	else
	{
		sprintf( temptext, "Unable to open '%s'\n", tzObjectfile );
		fatalerror( temptext );
	}

	oReadLib=0;
}

SLONG	file_Length( FILE *f )
{
	ULONG	r,
			p;

	p=ftell( f );
	fseek( f, 0, SEEK_END );
	r=ftell( f );
	fseek( f, p, SEEK_SET );

	return( r );
}

void	lib_ReadXLB0( FILE *f )
{
	SLONG	size;

	size=file_Length( f )-4;
	while( size )
	{
		char	name[256];

		size-=readasciiz( name, f );
		readword( f ); size-=2;
		readword( f ); size-=2;
		size-=readlong( f ); size-=4;
		obj_ReadOpenFile( f, name );
	}
}

void	lib_Readfile( char *tzLibfile )
{
	FILE	*pObjfile;

	oReadLib=1;

	if( pObjfile=fopen(tzLibfile,"rb") )
	{
		char	tzHeader[5];

		fread( tzHeader, sizeof(char), 4, pObjfile );
		tzHeader[4]=0;
		if( strcmp(tzHeader,"XLB0")==0 )
			lib_ReadXLB0( pObjfile );
		else
		{
			sprintf( temptext, "'%s' is an invalid library\n", tzLibfile );
			fatalerror( temptext );
		}
		fclose( pObjfile );
	}
	else
	{
		sprintf( temptext, "Unable to open '%s'\n", tzLibfile );
		fatalerror( temptext );
	}
}