/*--------------------------------------------------------------------------
 * File: xstdio.c
 * Written by: Alexander Boczar, 1997-04-16
 * Description: Extended stdio, uses virtual filesystem...
 *
 * Updates:
 * -- Date -- | ----- Name ----- |-- Did what....
 * 1997-xx-xx | Alexander Boczar | Implementation
 * 1997-05-07 | Fredrik Kling    | xfile_load, xfile_save, xfile_size
 *
 * Todo:
 *
 -------------------------------------------------------------------------------*/

#include "system/xstdlib.h"
#include "system/xstdio.h"
#include "system/xstddef.h"
#include "system/xstring.h"
#include "misc/dbfs.h"


static int findfile( char *dbfsname, char *filename, char *name)
{
	char path[256];
	char *pathptr = &path[0];
	DBFS *dbfs;
	DBFILE *dbfile;
	FILE *file;

	while( TRUE)
	{
		while( (*name != '\0') && (*name != '\\') && (*name != '/'))
			*(pathptr++) = *(name++);
		*(pathptr) = '\0';
		if( *(name++) == '\0')
			break;

		sprintf( dbfsname, "%s.dbf", path);
		strcpy( filename, name);

		if( (dbfs = dbfsopen( dbfsname)) != NULL)
		{
			if( (dbfile = dbfilefind( dbfs, filename)) != NULL)
			{
				dbfsclose( dbfs);
				return( TRUE);
			}
			dbfsclose( dbfs);
		}
		*(pathptr++) = '/';
	}
	if( (file = fopen( path, "rb")) != NULL)
	{
		*dbfsname = '\0';
		strcpy( filename, path);
		fclose( file);
		return( TRUE);
	}

	return( FALSE);
}

/************************************************************************
 *
 * Func: xfopen
 *
 ************************************************************************/

XFILE *xfopen( char *filename, char *mode)
{
	XFILE *xf;
	DBFS *dbfs;
	char dbfsname[256];
	DBFILE *dbfile;
	char dbfilename[256];

	if( stricmp( mode, "rb") != 0)
		return( NULL);

	if( !findfile( &dbfsname[0], &dbfilename[0], filename))
		return( NULL);

	if( (xf = xmalloc( sizeof( XFILE))) == NULL)
		return( NULL);

	if( strlen( dbfsname) < 1)
	{
		if( (xf->buff = fload( filename, &xf->length)) == NULL)
		{
			xfree( xf);
			return( NULL);
		}
		xf->position = 0;
		return( xf);
	}
	else
	{
		dbfs = dbfsopen( dbfsname);
		dbfile = dbfilefind( dbfs, dbfilename);

		if( (xf->buff = xmalloc( dbfile->length)) == NULL)
		{
			dbfsclose( dbfs);
			xfree( xf);
			return( NULL);
		}

		xf->length = dbfile->length;

		if( !dbfileread( dbfile, xf->buff))
		{
			xfree( xf->buff);
			dbfsclose( dbfs);
			xfree( xf);
			return( NULL);
		}

		dbfsclose( dbfs);
		xf->position = 0;
		return( xf);
	}
}

/************************************************************************
 *
 * Func: xfclose
 *
 ************************************************************************/

int xfclose( XFILE *xf)
{
	xfree( xf->buff);
	xfree( xf);
	return( 0);
}

/************************************************************************
 *
 * Func: xfseek
 *
 ************************************************************************/

int xfseek( XFILE *xf, int pos, int mode)
{
	switch( mode)
	{
		case SEEK_SET: xf->position = pos; break;
		case SEEK_CUR: xf->position += pos; break;
		case SEEK_END: xf->position = xf->length + pos; break;
	}
	return( 0);
}

/************************************************************************
 *
 * Func: xftell
 *
 ************************************************************************/

int xftell( XFILE *xf)
{
	return( xf->position);
}

/************************************************************************
 *
 * Func: xfeof
 *
 ************************************************************************/

int xfeof( XFILE *xf)
{
  return( (xf->position >= xf->length)?TRUE:FALSE);
}

/************************************************************************
 *
 * Func: xfread
 *
 ************************************************************************/

int xfread( void *buff, int elsize, int length, XFILE *xf)
{
  if( xf->position >= xf->length)
    return( 0);
  if( (xf->position + length * elsize) > xf->length)
    length = (xf->length - xf->position) / elsize;
	if( length < 1)
		length = 0;
  else
    memcpy( buff, xf->buff + xf->position, length * elsize);
  xf->position += length * elsize;
	return( length);
}

static void convert32( void *data)
{
	BYTE a;
	BYTE *c = (BYTE *)data;
	a = c[3],	c[3] = c[0], c[0] = a;
	a = c[2],	c[2] = c[1], c[1] = a;
}
static void convert16( void *data)
{
	BYTE a;
	BYTE *c = (BYTE *)data;
	a = c[1],	c[1] = c[0], c[0] = a;
}

/* For extended files */

#if defined(__X86__) /* big endian machines */

BYTE xfr_byte( XFILE *f)
{
	BYTE data;
	xfread( &data, sizeof(BYTE), 1, f);
	return( data);
}

WORD xfrbe_word( XFILE *f)
{
	WORD data;
	xfread( &data, sizeof(WORD), 1, f);
	return( data);
}
DWORD xfrbe_dword( XFILE *f)
{
	DWORD data;
	xfread( &data, sizeof(DWORD), 1, f);
	return( data);
}
float xfrbe_float( XFILE *f)
{
	float data;
	xfread( &data, sizeof(float), 1, f);
	return( data);
}

WORD xfrle_word( XFILE *f)
{
	WORD data;
	xfread( &data, sizeof(WORD), 1, f);
	convert16( &data);
	return( data);
}
DWORD xfrle_dword( XFILE *f)
{
	DWORD data;
	xfread( &data, sizeof(DWORD), 1, f);
	convert32( &data);
	return( data);
}
float xfrle_float( XFILE *f)
{
	float data;
	xfread( &data, sizeof(DWORD), 1, f);
	convert32( &data);
	return( data);
}
/*
void xfw_byte( XFILE *f, BYTE data)
{
	xfwrite( &data, sizeof(BYTE), 1, f);
}

void xfwbe_word( XFILE *f, WORD data)
{
	xfwrite( &data, sizeof(WORD), 1, f);
}
void xfwbe_dword( XFILE *f, DWORD data)
{
	xfwrite( &data, sizeof(DWORD), 1, f);
}
void xfwbe_float( XFILE *f, float data)
{
	xfwrite( &data, sizeof(float), 1, f);
}

void xfwle_word( XFILE *f, WORD data)
{
	convert16( &data);
	xfwrite( &data, sizeof(WORD), 1, f);
}
void xfwle_dword( XFILE *f, DWORD data)
{
	convert32( &data);
	xfwrite( &data, sizeof(DWORD), 1, f);
}
void xfwle_float( XFILE *f, float data)
{
	convert32( &data);
	xfwrite( &data, sizeof(float), 1, f);
}
*/
#else /* Low endian machines */

BYTE xfr_byte( XFILE *f)
{
	BYTE data;
	xfread( &data, sizeof(BYTE), 1, f);
	return( data);
}

WORD xfrbe_word( XFILE *f)
{
	WORD data;
	xfread( &data, sizeof(WORD), 1, f);
	convert16( &data);
	return( data);
}
DWORD xfrbe_dword( XFILE *f)
{
	DWORD data;
	xfread( &data, sizeof(DWORD), 1, f);
	convert32( &data);
	return( data);
}
float xfrbe_float( XFILE *f)
{
	float data;
	xfread( &data, sizeof(float), 1, f);
	convert32( &data);
	return( data);
}

WORD xfrle_word( XFILE *f)
{
	WORD data;
	xfread( &data, sizeof(WORD), 1, f);
	return( data);
}
DWORD xfrle_dword( XFILE *f)
{
	DWORD data;
	xfread( &data, sizeof(DWORD), 1, f);
	return( data);
}
float xfrle_float( XFILE *f)
{
	float data;
	xfread( &data, sizeof(DWORD), 1, f);
	return( data);
}
/*
void xfw_byte( FILE *f, BYTE data)
{
	xfwrite( &data, sizeof(BYTE), 1, f);
}

void xfwbe_word( FILE *f, WORD data)
{
	convert16( &data);
	xfwrite( &data, sizeof(WORD), 1, f);
}
void xfwbe_dword( FILE *f, DWORD data)
{
	convert32( &data);
	xfwrite( &data, sizeof(DWORD), 1, f);
}
void xfwbe_float( FILE *f, float data)
{
	convert32( &data);
	xfwrite( &data, sizeof(float), 1, f);
}

void xfwle_word( FILE *f, WORD data)
{
	xfwrite( &data, sizeof(WORD), 1, f);
}
void xfwle_dword( FILE *f, DWORD data)
{
	xfwrite( &data, sizeof(DWORD), 1, f);
}
void xfwle_float( FILE *f, float data)
{
	xfwrite( &data, sizeof(float), 1, f);
}
*/
#endif


/* For normal files */


#if defined(__X86__) /* big endian machines */

BYTE fr_byte( FILE *f)
{
	BYTE data;
	fread( &data, sizeof(BYTE), 1, f);
	return( data);
}

WORD frbe_word( FILE *f)
{
	WORD data;
	fread( &data, sizeof(WORD), 1, f);
	return( data);
}
DWORD frbe_dword( FILE *f)
{
	DWORD data;
	fread( &data, sizeof(DWORD), 1, f);
	return( data);
}
float frbe_float( FILE *f)
{
	float data;
	fread( &data, sizeof(float), 1, f);
	return( data);
}

WORD frle_word( FILE *f)
{
	WORD data;
	fread( &data, sizeof(WORD), 1, f);
	convert16( &data);
	return( data);
}
DWORD frle_dword( FILE *f)
{
	DWORD data;
	fread( &data, sizeof(DWORD), 1, f);
	convert32( &data);
	return( data);
}
float frle_float( FILE *f)
{
	float data;
	fread( &data, sizeof(DWORD), 1, f);
	convert32( &data);
	return( data);
}

void fw_byte( FILE *f, BYTE data)
{
	fwrite( &data, sizeof(BYTE), 1, f);
}

void fwbe_word( FILE *f, WORD data)
{
	fwrite( &data, sizeof(WORD), 1, f);
}
void fwbe_dword( FILE *f, DWORD data)
{
	fwrite( &data, sizeof(DWORD), 1, f);
}
void fwbe_float( FILE *f, float data)
{
	fwrite( &data, sizeof(float), 1, f);
}

void fwle_word( FILE *f, WORD data)
{
	convert16( &data);
	fwrite( &data, sizeof(WORD), 1, f);
}
void fwle_dword( FILE *f, DWORD data)
{
	convert32( &data);
	fwrite( &data, sizeof(DWORD), 1, f);
}
void fwle_float( FILE *f, float data)
{
	convert32( &data);
	fwrite( &data, sizeof(float), 1, f);
}

#else /* Low endian machines */

BYTE fr_byte( FILE *f)
{
	BYTE data;
	fread( &data, sizeof(BYTE), 1, f);
	return( data);
}

WORD frbe_word( FILE *f)
{
	WORD data;
	fread( &data, sizeof(WORD), 1, f);
	convert16( &data);
	return( data);
}
DWORD frbe_dword( FILE *f)
{
	DWORD data;
	fread( &data, sizeof(DWORD), 1, f);
	convert32( &data);
	return( data);
}
float frbe_float( FILE *f)
{
	float data;
	fread( &data, sizeof(float), 1, f);
	convert32( &data);
	return( data);
}

WORD frle_word( FILE *f)
{
	WORD data;
	fread( &data, sizeof(WORD), 1, f);
	return( data);
}
DWORD frle_dword( FILE *f)
{
	DWORD data;
	fread( &data, sizeof(DWORD), 1, f);
	return( data);
}
float frle_float( FILE *f)
{
	float data;
	fread( &data, sizeof(DWORD), 1, f);
	return( data);
}

void fw_byte( FILE *f, BYTE data)
{
	fwrite( &data, sizeof(BYTE), 1, f);
}

void fwbe_word( FILE *f, WORD data)
{
	convert16( &data);
	fwrite( &data, sizeof(WORD), 1, f);
}
void fwbe_dword( FILE *f, DWORD data)
{
	convert32( &data);
	fwrite( &data, sizeof(DWORD), 1, f);
}
void fwbe_float( FILE *f, float data)
{
	convert32( &data);
	fwrite( &data, sizeof(float), 1, f);
}

void fwle_word( FILE *f, WORD data)
{
	fwrite( &data, sizeof(WORD), 1, f);
}
void fwle_dword( FILE *f, DWORD data)
{
	fwrite( &data, sizeof(DWORD), 1, f);
}
void fwle_float( FILE *f, float data)
{
	fwrite( &data, sizeof(float), 1, f);
}

#endif

/************************************************************************
 *
 * Func: flength
 * Auth: Alexander Boczar
 * Date: 1997-06-15 - Implementation
 *
 * Desc: File size
 *
 ************************************************************************/
DWORD flength( FILE *f)
{
  DWORD pos,len;

  pos = ftell( f);
  fseek (f, 0, SEEK_END);
  len = ftell( f);
  fseek (f, pos, SEEK_SET);
  return( len);
}

/************************************************************************
 *
 * Func: fload
 * Auth: Alexander Boczar
 * Date: 1997-06-15 - Implementation
 *
 * Desc: Loads file contents into a allocated buffer
 *
 *
 ************************************************************************/

BYTE *fload( char *filename, DWORD *length)
{
  FILE *f;
	BYTE *data;
	DWORD len;

  if( (f = fopen( filename, "rb")) == NULL)
		return( NULL);

  len = flength( f);
  data = (BYTE *)xmalloc( len);
	if( data == NULL)
	{
		fclose( f);
		return( NULL);
	}
  if( fread( data, sizeof( BYTE), len, f) != len)
	{
		fclose( f);
		xfree( data);
		return( NULL);
	}
  fclose( f);
	if( length != NULL)
		*length = len;
  return( data);
}

/************************************************************************
 *
 * Func: fsave
 * Auth: Alexander Boczar
 * Date: 1997-06-15 - Implementation
 *
 * Desc: Saves buffer contents into a a file
 *
 *
 ************************************************************************/

int fsave( char *filename, BYTE *data, DWORD length)
{
  FILE *f;

  f = fopen( filename, "wb");
  if( fwrite( data, sizeof( BYTE), length, f) != length)
	{
		fclose( f);
		return( FALSE);
	}
  fclose( f);
  return( TRUE);
}

/************************************************************************
 *
 * Func: xfload
 * Auth: Alexander Boczar
 * Date: 1997-06-15 - Implementation
 *
 * Desc: Loads file contents into a allocated buffer
 *
 *
 ************************************************************************/

BYTE *xfload( char *filename, DWORD *length)
{
  XFILE *f;
	BYTE *data;
	DWORD len;

  if( (f = xfopen( filename, "rb")) == NULL)
		return( NULL);

	data = f->buff, f->buff = NULL;
	len = f->length;

	xfclose( f);

	if( length != NULL)
		*length = len;
  return( data);
}

