shithub: rgbds

ref: 3ce06cd42417862d69f1df3b914aba5a09eddd72
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 "link/mylink.h"
#include "link/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);

	*ppSections = malloc(sizeof **ppSections);
	if (!*ppSections) {
		fatalerror("Out of memory!");
		return NULL;
	}

	(*ppSections)->tSymbols = tSymbols;
	(*ppSections)->pNext = NULL;
	(*ppSections)->pPatches = NULL;
	(*ppSections)->oAssigned = 0;
	return *ppSections;
}

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

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

	pSym = malloc(sizeof *pSym);
	if (!pSym)
		fatalerror("Out of memory!");

	readasciiz(s, f);
	pSym->pzName = malloc(strlen(s) + 1);
	if (!pSym->pzName)
		fatalerror("Out of memory!");

	strcpy(pSym->pzName, s);
	if ((pSym->Type = (enum eSymbolType)fgetc(f)) != SYM_IMPORT) {
		pSym->nSectionID = readlong(f);
		pSym->nOffset = readlong(f);
	}

	return pSym;
}

/*
 * 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) {
			pSection->pData = malloc(pSection->nByteSize);
			if (!pSection->pData)
				fatalerror("Out of memory!");

			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--) {
				pPatch = malloc(sizeof *pPatch);
				if (!pPatch)
					fatalerror("Out of memory!");

				*ppPatch = pPatch;
				readasciiz(s, f);

				pPatch->pzFilename = malloc(strlen(s) + 1);
				if (!pPatch->pzFilename)
					fatalerror("Out of memory!");

				strcpy(pPatch->pzFilename, s);

				pPatch->nLineNo =
					readlong(f);
				pPatch->nOffset =
					readlong(f);
				pPatch->Type =
					(enum ePatchType)
					fgetc(f);

				if ((pPatch->nRPNSize = readlong(f)) > 0) {
					pPatch->pRPN = malloc(pPatch->nRPNSize);
					if (!pPatch->pRPN)
						fatalerror("Out of memory!");

					fread(pPatch->pRPN, sizeof(UBYTE),
						pPatch->nRPNSize, f);
				} else
					pPatch->pRPN = NULL;

				pPatch->pNext = NULL;
				ppPatch = &(pPatch->pNext);
			}
		} else {
			/* Skip number of patches */
			readlong(f);
			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) {
		tSymbols = malloc(nNumberOfSymbols * sizeof(struct sSymbol *));
		if (!tSymbols)
			fatalerror("Out of memory!");

		for (i = 0; i < nNumberOfSymbols; i += 1)
			tSymbols[i] = obj_ReadSymbol(pObjfile);
	} 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) {
			pSection->pData = malloc(pSection->nByteSize);
			if (!pSection->pData)
				fatalerror("Out of memory!");

			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--) {
				pPatch = malloc(sizeof *pPatch);
				if (!pPatch)
					fatalerror("Out of memory!");

				*ppPatch = pPatch;
				readasciiz(s, f);
				pPatch->pzFilename = malloc(strlen(s) + 1);
				if (!pPatch->pzFilename)
					fatalerror("Out of memory!");

				strcpy(pPatch->pzFilename, s);
				pPatch->nLineNo = readlong(f);
				pPatch->nOffset = readlong(f);
				pPatch->Type = (enum ePatchType) fgetc(f);
				if ((pPatch->nRPNSize = readlong(f)) > 0) {
					pPatch->pRPN = malloc(pPatch->nRPNSize);
					if (!pPatch->pRPN)
						fatalerror ("Out of memory!");

					fread(pPatch->pRPN, sizeof(UBYTE),
						pPatch->nRPNSize, f);
				} else
					pPatch->pRPN = NULL;

				pPatch->pNext = NULL;
				ppPatch = &(pPatch->pNext);
			}
		} else {
			/* Skip number of patches */
			readlong(f);
			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) {
		tSymbols = malloc(nNumberOfSymbols * sizeof *tSymbols);
		if (!tSymbols)
			fatalerror("Out of memory!");

		for (i = 0; i < nNumberOfSymbols; i += 1)
			tSymbols[i] = obj_ReadSymbol(pObjfile);
	} 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;

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

	obj_ReadOpenFile(pObjfile, tzObjectfile);
	fclose(pObjfile);

	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;

	pObjfile = fopen(tzLibfile, "rb");
	if (!pObjfile) {
		sprintf(temptext, "Unable to open '%s'\n", tzLibfile);
		fatalerror(temptext);
	}

	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);
}