/********************************************************************
 *																	*
 *	Resource manipulation module									*
 *																	*
 *	Copyright (c) Clever Bits and Bitgate Software 1993	- 1994		*
 *	All Rights Reserved.											*
 *																	*
 *	This modules deals with resources and objects, loading, and		*
 *	object fixation during the loading process.						*
 *																	*
 ********************************************************************
 *																	*
 *	Update log:														*
 *																	*
 *	[1.11.93] Karl A. 0ygard										*
 *							- changed some code layout				*
 *	[2.11.93] Karl A. 0ygard										*
 *		rsrc_search			- removed; it was no longer required	*
 *	[14.12.93 - 23.2.94] Ken Hollis and Oliver Groeger				*
 *							- added xrsrc source from InterFace 2.00*
 *		xrsrc_load			- added internal title loading stuff...	*
 *																	*
 *	Note: Resource files can be as large as 4294967295 bytes in		*
 *	""""" length if needed.  (4.294 GB)								*
 *																	*
 ********************************************************************/

#include <aes.h>
#include <tos.h>
#include <stdio.h>

#include "winlib.h"

#ifndef	__XRSRC__
#define	__XRSRC__
#endif

#ifdef __TURBOC__
#pragma warn -pia
#endif

static int		pglobal[15];
static int		*rs_global;
static RSXHDR 	*rs_hdr;
static RSXHDR	hdr_buf;
int				rsrc_objects, rsrc_trees;

LOCAL void rs_obfix (OBJECT *rs_otree, int rs_oobject);
LOCAL void rs_sglobal (int *base);
LOCAL int rs_free (int *base);
LOCAL int rs_gaddr (int *base, int re_gtype, int re_gindex, OBJECT **re_gaddr);
LOCAL int rs_sadd (int *base, int rs_stype, int rs_sindex, OBJECT *re_saddr);
LOCAL int rs_load (int *global, const signed char *fname);
LOCAL void *get_address (int type, int index);
LOCAL void *get_sub (int index, long offset, int size);
LOCAL int rs_read (int *global, const signed char *fname);
LOCAL void rs_fixindex (int *global);
LOCAL void do_rsfix (RSXHDR *hdr, unsigned long size);
LOCAL void fix_treeindex (void);
LOCAL void fix_ob (void);
LOCAL void fix_tedinfo();
LOCAL void fix_nptr (long index, int ob_type);
LOCAL int fix_ptr (int type, long index);
LOCAL int fix_long (long *lptr);
LOCAL void fix_chp (int *pcoord, int flag);

/*
 *	Free resource (unfix objects and free resource)
 *
 *	Returns: 0 on failure
 */
GLOBAL int Rsrc_Free(void)
{
	int i;
	OBJECT *tree;

	rsrc_gaddr(0, 0, &tree);

	for (i = 0; i < rsrc_objects; i++)
		unfix_object(tree + i);

	return rsrc_free();
}

GLOBAL int xrsrc_load(const char *re_lpfname)
{
	int ret = TRUE;	char *title;

	WGrafMouse(LOAD_MOUSE);

	sprintf(title, "Loading %s", re_lpfname);
	TChangeTitleText(title);

	if (ret = rsrc_load(re_lpfname)) {
		int rsrc_header[18], i = 0;
		OBJECT *tree;
		FILE *file;
		RSHDR *rsc;

		TChangeTitleText("Fixing objects...");

		WGrafMouse(INIT_MOUSE);

		file = fopen(re_lpfname, "rb");
		fread(&rsrc_header, sizeof(int), 18, file);
		fclose(file);

		rsc = (RSHDR *) rsrc_header;
		rsrc_objects = rsc->rsh_nobs;
		rsrc_trees = rsc->rsh_ntree;

		for (; i < rsc->rsh_ntree; i++) {
			rsrc_gaddr(R_TREE, i, &tree);
			if (!fix_object(tree, TRUE)) {
				Rsrc_Free();
				WGrafMouse(ARROW);
				return 0;
			}
		}

		TEndTitle();
	}

	WGrafMouse(ARROW);
	return ret;
}

/*
 *	Load resource file
 *
 *	re_lpfname	= Name of file to load
 */
/*GLOBAL int xrsrc_load (const signed char *re_lpfname)
{
	return (rs_load (pglobal, re_lpfname));
}

/*
 *	Free resource memory
 */
GLOBAL int xrsrc_free (void)
{
	return (rs_free (pglobal));
}

/*
 *	Get resource address
 *
 *	re_gtype	= index to type of object to get
 *	re_gindex	= index of object to get
 *	re_gaddr	= address (returned) of requested object
 */
GLOBAL int xrsrc_gaddr (int re_gtype, int re_gindex, void *re_gaddr)
{
	return (rs_gaddr (pglobal, re_gtype, re_gindex, re_gaddr));
}

/*
 *	Save resource address
 *
 *	re_stype	= Type of object to add
 *	re_sindex	= Number of object to add
 *	re_saddr	= Address of the object to add
 */
GLOBAL int xrsrc_saddr (int re_stype, int re_sindex, void *re_saddr)
{
	return (rs_sadd (pglobal, re_stype, re_sindex, re_saddr));
}

/*
 *	Fix resource coordinates
 *
 *	re_otree	= Object tree to fix
 *	re_oobject	= Object of unfixed coordinates
 */
GLOBAL int xrsrc_obfix (OBJECT *re_otree, int re_oobject)
{
	rs_obfix (re_otree, re_oobject);

	return (TRUE);
}

/*
 *	Fix object (actual routine)
 *
 *	rs_otree	= Object tree to fix
 *	rs_oobject	= Actual object to fix
 */
LOCAL void rs_obfix (OBJECT *rs_otree, int rs_oobject)
{
	int *coord;
	int tmp = FALSE;
	int count = 0;

	coord = &rs_otree[rs_oobject].ob_x;

	while (count++ < 4)
	{
		fix_chp (coord++, tmp);
		tmp = tmp ? FALSE : TRUE;
	}

	return;
}

/*
 *	Save global information
 *
 *	base	= base address of resource file
 */
LOCAL void rs_sglobal (int *base)
{
	rs_global = base;
	rs_hdr = (RSXHDR *)*(long *)&rs_global[7];

	return;
}

/*
 *	Free resource memory
 *
 *	base		= base address of resource file
 */
LOCAL int rs_free (int *base)
{
	rs_global = base;

	if (free ((RSXHDR *)*(long *)&rs_global[7]))
		return (FALSE);

	return (TRUE);
}

/*
 *	Get resource information
 *
 *	base		= base address of resource file
 *	re_gtype	= type of object to get info on
 *	re_gindex	= number of object to get info on
 *	re_gaddr	= actual address of object
 */
LOCAL int rs_gaddr (int *base, int re_gtype, int re_gindex, OBJECT **re_gaddr)
{
	rs_sglobal (base);

	*re_gaddr = get_address (re_gtype, re_gindex);

	if (*re_gaddr == (OBJECT *)NULL)
		return (FALSE);

	return (TRUE);
}

/*
 *	Save resource information
 *
 *	base		= base of resource file
 *	rs_stype	= type of object to save
 *	rs_sindex	= number of object to save
 *	re_saddr	= address of object to save
 */
LOCAL int rs_sadd (int *base, int rs_stype, int rs_sindex, OBJECT *re_saddr)
{
	OBJECT *old_addr;

	rs_sglobal (base);

	old_addr = get_address (rs_stype, rs_sindex);

	if (old_addr == (OBJECT *)NULL)
		return (FALSE);

	*old_addr = *re_saddr;

	return (TRUE);
}

/*
 *	Load resource file and fix coordinates
 *
 *	global		= global resource information
 *	fname		= name of resource to load
 */
LOCAL int rs_load (int *global, const signed char *fname)
{
	if (!rs_read (global, fname))
		return (FALSE);

	rs_fixindex (global);

	return (TRUE);
}

/*
 *	Return address of an object
 *
 *	type	= object type
 *	index	= object resource index
 */
LOCAL void *get_address (int type, int index)
{
	void *the_addr = (void *)NULL;
	union
	{
		void	*dummy;
		signed char	*string;
		OBJECT	**dpobject;
		OBJECT	*object;
		TEDINFO	*tedinfo;
		ICONBLK	*iconblk;
		BITBLK	*bitblk;
	} all_ptr;

	switch (type)
	{
		case R_TREE:
			all_ptr.dpobject = (OBJECT **)(*(long **)&rs_global[5]);
			the_addr = all_ptr.dpobject[index];
			break;

		case R_OBJECT:
			the_addr = get_sub (index, rs_hdr->rsh_object, sizeof(OBJECT));
			break;

		case R_TEDINFO:
		case R_TEPTEXT:
			the_addr = get_sub (index, rs_hdr->rsh_tedinfo, sizeof(TEDINFO));
			break;

		case R_ICONBLK:
		case R_IBPMASK:
			the_addr = get_sub (index, rs_hdr->rsh_iconblk, sizeof(ICONBLK));
			break;

		case R_BITBLK:
		case R_BIPDATA:
			the_addr = get_sub (index, rs_hdr->rsh_bitblk, sizeof(BITBLK));
			break;

		case R_OBSPEC:
			all_ptr.object = get_address(R_OBJECT, index);
			the_addr = &all_ptr.object->ob_spec;
			break;

		case R_TEPVALID:
		case R_TEPTMPLT:
			all_ptr.tedinfo = get_address(R_TEDINFO, index);
			if (type == R_TEPVALID)
				the_addr = &all_ptr.tedinfo->te_pvalid;
			else
				the_addr = &all_ptr.tedinfo->te_ptmplt;
			break;

		case R_IBPDATA:
		case R_IBPTEXT:
			all_ptr.iconblk = get_address(R_ICONBLK, index);
			if (type == R_IBPDATA)
				the_addr = &all_ptr.iconblk->ib_pdata;
			else
				the_addr = &all_ptr.iconblk->ib_ptext;
			break;

		case R_STRING:
			the_addr = get_sub (index, rs_hdr->rsh_frstr, sizeof (signed char *));
			the_addr = (void *)*(signed char *)the_addr;
			break;

		case R_IMAGEDATA:
			the_addr = get_sub (index, rs_hdr->rsh_imdata, sizeof (signed char *));
			the_addr = (void *)*(signed char *)the_addr;
			break;

		case R_FRIMG:
			the_addr = get_sub (index, rs_hdr->rsh_frimg, sizeof (signed char *));
			the_addr = (void *)*(signed char *)the_addr;
			break;

		case R_FRSTR:
			the_addr = get_sub (index, rs_hdr->rsh_frstr, sizeof (signed char *));
			break;
	}

	return (the_addr);
}

/*
 *	Get object address chunk
 *
 *	index	= index of the object to get
 *	offset	= size of move
 *	size	= size of chunk to return
 */
LOCAL void *get_sub (int index, long offset, int size)
{
	unsigned char *ptr = (unsigned char *)rs_hdr;

	ptr += offset;
	ptr += (index * size);

	return ((void *)ptr);
}

/*
 *	Actual routine to read resource file
 *
 *	global	= global resource file index
 *	fname	= name of file to load
 */
LOCAL int rs_read (int *global, const signed char *fname)
{
	int fh;
	signed char tmpnam[128];

	strcpy (tmpnam, fname);

	if (!shel_find (tmpnam))
		return (FALSE);

	rs_global = global;

	if ((fh = Fopen (tmpnam, 0)) < 0)
		return (FALSE);

	if (Fread (fh, sizeof(RSXHDR), &hdr_buf) != sizeof (RSXHDR))
	{
		Fclose (fh);
		return (FALSE);
	}

	if ((rs_hdr = (RSXHDR *)malloc (hdr_buf.rsh_rssize)) == NULL)
	{
		Fclose (fh);
		return (FALSE);
	}

	Fseek (0L, fh, 0);

	if (Fread (fh, hdr_buf.rsh_rssize, &rs_hdr) != hdr_buf.rsh_rssize)
	{
		Fclose (fh);
		return (FALSE);
	}

	do_rsfix (rs_hdr, hdr_buf.rsh_rssize);

	Fclose (fh);

	return (TRUE);
}

/*
 *	Fix object positions
 *
 *	global	= pointer to resource information
 */
LOCAL void rs_fixindex (int *global)
{
	rs_sglobal (global);

	fix_ob ();
}

/*
 *	Locate and fix objects
 *
 *	hdr		= header information of resource
 *	size	= size of resource file
 */
LOCAL void do_rsfix (RSXHDR *hdr, unsigned long size)
{
	rs_global[7] = ((long)hdr >> 16) & 0xFFFF;
	rs_global[8] = (long)hdr & 0xFFFF;
	rs_global[9] = size;

	fix_treeindex ();
	fix_tedinfo ();

	fix_nptr (hdr->rsh_nib - 1, R_IBPMASK);
	fix_nptr (hdr->rsh_nib - 1, R_IBPDATA);
	fix_nptr (hdr->rsh_nib - 1, R_IBPTEXT);

	fix_nptr (rs_hdr->rsh_nbb - 1, R_BIPDATA);
	fix_nptr (rs_hdr->rsh_nstring - 1, R_FRSTR);
	fix_nptr (rs_hdr->rsh_nimages - 1, R_FRIMG);
}

/*
 *	Fix indices of all trees
 */
LOCAL void fix_treeindex (void)
{
	OBJECT **adr;
	long   count;

	count = rs_hdr->rsh_ntree - 1L;

	adr = get_sub (0, rs_hdr->rsh_trindex, sizeof (OBJECT *));

	rs_global[5] = ((long)adr >> 16) & 0xFFFF;
	rs_global[6] = (long)adr & 0xFFFF;

	while (count >= 0)
	{
		fix_long ((long *)(count * sizeof (OBJECT *) + (long)adr));
		count--;
	}
}

/*
 *	Fix objects
 */
LOCAL void fix_ob (void)
{
	int 	 count;
	OBJECT *obj;

	count = rs_hdr->rsh_nobs - 1;

	while (count >= 0)
	{
		obj = get_address (R_OBJECT, count);
		rs_obfix (obj, 0);
		if ((obj->ob_type & 0xff) != G_BOX && (obj->ob_type & 0xff) != G_IBOX && (obj->ob_type & 0xff) != G_BOXCHAR)
			fix_long ((long *)&obj->ob_spec);

		count--;
	}
}

/*
 *	Fix Text Editing Dialog info
 */
LOCAL void fix_tedinfo()
{
	long		count;
	TEDINFO *tedinfo;

	count = rs_hdr->rsh_nted - 1;

	while (count >= 0)
	{
		tedinfo = get_address (R_TEDINFO, count);

		if (fix_ptr (R_TEPTEXT, count))
			tedinfo->te_txtlen = strlen (tedinfo->te_ptext) + 1;

		if (fix_ptr (R_TEPTMPLT, count))
			tedinfo->te_tmplen = strlen (tedinfo->te_ptmplt) + 1;

		fix_ptr (R_TEPVALID, count);

		count--;
	}

	return;
}

/*
 *	Fix pointer information
 *
 *	index	= index of object
 *	ob_type	= new object type
 */
LOCAL void fix_nptr (long index, int ob_type)
{
	while (index >= 0)
		fix_long (get_address(ob_type, index--));
}

/*
 *	Fix memory pointer
 *
 *	type	= type of object to fix
 *	index	= its index
 */
LOCAL int fix_ptr (int type, long index)
{
	return (fix_long (get_address (type, index)));
}

/*
 *	Fix pointer information
 *
 *	lptr	= pointer to information
 */
LOCAL int fix_long (long *lptr)
{
	long base;

	base = *lptr;
	if (base == 0L)
		return (FALSE);

	base += (long)rs_hdr;

	*lptr = base;

	return (TRUE);
}

/*
 *	Fix character position
 *
 *	pcoord	= coordinates of object
 *	flag	= flag of whether to fix or not
 */
LOCAL void fix_chp (int *pcoord, int flag)
{
	int ncoord;

	ncoord = *pcoord & 0xff;

	if (!flag && ncoord == 0x50)
		ncoord = desk.g_w;										/* desk.g_w = Breite des Bildschirms in Pixel */
	else
		ncoord *= (flag ? gr_bh : gr_bw);	/* gr_bw, gr_bh = Zeichenbreite, Zeichenh”he in Pixel */

	if (((*pcoord >> 8) & 0xff) > 0x80)
		ncoord += (((*pcoord >> 8) & 0xff) | 0xff00);
	else
		ncoord += ((*pcoord >> 8) & 0xff);

	*pcoord = ncoord;
} */

GLOBAL void RFix_ObjectPos(OBJECT *obj)
{
	int i;

	i = -1;
	do {
		i++;
		rsrc_obfix(obj, i);
	} while(!(obj[i].ob_flags & LASTOB));
}