💾 Archived View for uscoffings.net › retro-computing › systems › TI994a › x99tape › x99tape_src › ti… captured on 2023-03-20 at 21:54:16.

View Raw

More Information

⬅️ Previous capture (2022-06-04)

-=-=-=-=-=-=-

/*
	Portable TI99 tape encoder/decoder

	tifiles.c: Code to read and write TI99 data files.

	Currently supports TIFILE format, though I intend to support V9T9 FIAD,
	and native (header-less) binary and text files.

	Raphael Nabet 2002


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

#include "common.h"

#include "tifiles.h"


/* 0: raw binary format, 1: TIFILE */
#define FORMAT 1


error_t open_tifile_in(FILE *handle, tifile_in_t *tifile, ftype_t default_type, unsigned int default_reclen)
{
#if FORMAT == 0
	/* raw binary format */
	int file_len;

	tifile->handle = handle;
	tifile->type = default_type;

	/* raw binary format */
	if (default_type == ftype_program)
		tifile->reclen = 64;
	else
	{
		if ((default_reclen < 0) || (default_reclen > 192))
			return invalid_parameters;

		if (default_reclen == 0)
			return cant_auto_record_len;

		tifile->reclen = default_reclen;
	}

	/* compute file len */
	{
		int increment;
		char buf[16384];

		file_len = 0;
		do
		{
			increment = fread(buf, 1, sizeof(buf), handle);
			file_len += increment;
		}
		while (increment == sizeof(buf));

		if (ferror(handle))
			return read_error;

		rewind(handle);
	}

	if (file_len % /*tifile->reclen*/ ((tifile->reclen + 63) & ~63))
		return invalid_record_len;

	//file_len_in_records = file_len / /*record_len*/ ((record_len + 63) & ~63);

	return no_error;
#else
	/* tifile format */
	tifile_header header;
	int recspersec;


	(void) default_type;
	(void) default_reclen;

	tifile->handle = handle;

	if (! fread(&header, sizeof(header), 1, handle))
		return read_error;

	if (memcmp(header.tifiles, "\7TIFILES", 8))
		return invalid_tifile_format;

	tifile->secsused = (header.secsused_MSB << 8) | header.secsused_LSB;
	tifile->eof = header.eof;

	if (header.flags & fdr99_f_program)
	{
		tifile->type = ftype_program;
		tifile->reclen = 64;		/* no record, but, in order to write the tape, we read data in chunks of 64 bytes */

		if (tifile->eof)
			tifile->fixrecs = (tifile->secsused-1)*4 + (tifile->eof+63)/64;
		else
			tifile->fixrecs	= tifile->secsused*4;
	}
	else
	{
		tifile->type = ftype_data;

		/* check that the file does not have variable lenght records */
	 	if (header.flags & fdr99_f_var)
			return unsupported_tifile_format;

		tifile->reclen = header.reclen;
		/* check record size */
		if (tifile->reclen == 0)
			return invalid_tifile_format;
		if (tifile->reclen > 192)
			return unsupported_tifile_format;

		recspersec = 256 / tifile->reclen;
		if (recspersec != header.recspersec)
			return invalid_tifile_format;

		if (tifile->eof % tifile->reclen)
			return invalid_tifile_format;

		tifile->fixrecs = (header.fixrecs_MSB << 8) | header.fixrecs_LSB;
		if (tifile->fixrecs != (tifile->eof ? ((tifile->secsused-1)*recspersec + tifile->eof/tifile->reclen)
												: (tifile->secsused*recspersec)))
			return invalid_tifile_format;
	}

	tifile->cursec = 0;
	tifile->curpos = 0;

	return no_error;
#endif
}

error_t tifile_read(unsigned char *dest, tifile_in_t *tifile)
{
#if FORMAT == 0
	/* raw binary format */
	if (! fread(dest, /*tifile->reclen*/ ((tifile->reclen + 63) & ~63), 1, tifile->handle))
		return read_error;	/* read error, or unexpected eof */

	return no_error;
#else
	int i;


	/* tifile format */
	if (tifile->curpos+tifile->reclen > 256)
	{
		if (fseek(tifile->handle, 256-tifile->curpos, SEEK_CUR))
			return read_error;
		tifile->curpos = 0;
		tifile->cursec++;
	}

	if (tifile->cursec >= tifile->secsused)
		return eof_error;

	if (tifile->type == ftype_program)
	{
		if ((tifile->eof) ? ((tifile->cursec == (tifile->secsused-1))
								&& (tifile->curpos >= tifile->eof))
							: (tifile->cursec == tifile->secsused))
			/* eof */
			return eof_error;
		else if ((tifile->eof) && (tifile->cursec == (tifile->secsused-1))
				&& (tifile->curpos+64 > tifile->eof))
		{	/* there is less than 64 bytes of data left */
			if (! fread(dest, tifile->eof-tifile->curpos, 1, tifile->handle))
				return read_error;	/* read error, or unexpected eof */

			for (i=tifile->eof-tifile->curpos; i<64; i++)
				dest[i] = 0;

			tifile->curpos = tifile->eof;
		}
		else
		{	/* read one 64-byte chunk */
			if (! fread(dest, 64, 1, tifile->handle))
				return read_error;	/* read error, or unexpected eof */

			tifile->curpos += tifile->reclen;
		}
	}
	else
	{
		/* check for eof */
		if ((tifile->cursec == (tifile->secsused-1))
				&& (tifile->curpos+tifile->reclen > tifile->eof))
			return eof_error;

		if (! fread(dest, tifile->reclen, 1, tifile->handle))
			return read_error;	/* read error, or unexpected eof */

		tifile->curpos += tifile->reclen;
	}

	return no_error;
#endif
}

error_t open_tifile_out(FILE *handle, tifile_out_t *tifile, ftype_t type, unsigned int reclen)
{
	/* tifile format */
	int i;


	tifile->handle = handle;

	tifile->type = type;

	switch (type)
	{
	case ftype_program:
		tifile->reclen = 64;		/* no record, but, in order to write the tape, we read data in chunks of 64 bytes */

		break;

	case ftype_data:
		tifile->reclen = reclen;
		/* check record size */
		/*if (tifile->reclen == 0)
			return invalid_parameters;*/
		if (tifile->reclen > 192)
			return invalid_parameters;

		break;
	}

	for (i=0; i<128; i++)
		if (putc(0, tifile->handle) == EOF)
			return write_error;

	tifile->fixrecs = 0;
	tifile->cursec = 0;
	tifile->curpos = 0;

	return no_error;
}

error_t tifile_write(const unsigned char *src, tifile_out_t *tifile)
{
#if FORMAT == 0
	/* raw binary format */
	if (! fwrite(src, /*tifile->reclen*/ ((tifile->reclen + 63) & ~63), 1, tifile->handle))
		return write_error;

	return no_error;
#else
	int i;


	/* tifile format */
	if (tifile->curpos+tifile->reclen > 256)
	{
		for (i=0; i<256-tifile->curpos; i++)
			if (putc(0, tifile->handle) == EOF)
				return write_error;

		tifile->curpos = 0;
		tifile->cursec++;
	}

	if (tifile->type == ftype_program)
	{
		/* write one 64-byte chunk */
		if (! fwrite(src, 64, 1, tifile->handle))
			return write_error;

		tifile->curpos += tifile->reclen;
	}
	else
	{
		/* write one record */
		if (! fwrite(src, tifile->reclen, 1, tifile->handle))
			return write_error;

		tifile->curpos += tifile->reclen;
		tifile->fixrecs++;
	}

	return no_error;
#endif
}

error_t close_tifile_out(tifile_out_t *tifile)
{
#if FORMAT == 0
	/* raw binary format */
	(void) tifile;

	/*fclose(tifile->handle);*/

	return no_error;
#else
	tifile_header header;
	int secsused;
	error_t error = no_error;
	int i;


	if (tifile->curpos == 256)
	{
		tifile->curpos = 0;
		tifile->cursec++;
	}
	if (tifile->curpos)
		for (i=0; i<256-tifile->curpos; i++)
			if (putc(0, tifile->handle) == EOF)
				return write_error;

	rewind(tifile->handle);

	memset(&header, 0, sizeof(header));

	memcpy(header.tifiles, "\7TIFILES", 8);

	secsused = (tifile->curpos) ? tifile->cursec+1 : tifile->cursec;

	header.secsused_MSB = secsused >> 8;
	header.secsused_LSB = secsused & 0xff;

	header.flags = (tifile->type == ftype_program) ? fdr99_f_program : 0;

	header.recspersec = (tifile->type == ftype_program) ? 0 : (256 / tifile->reclen);

	header.eof = tifile->curpos;
	header.reclen = (tifile->type == ftype_program) ? 0 : tifile->reclen;

	header.fixrecs_MSB = tifile->fixrecs >> 8;
	header.fixrecs_LSB = tifile->fixrecs & 0xff;

	if (! fwrite(&header, sizeof(header), 1, tifile->handle))
		error = write_error;

	/*fclose(tifile->handle);*/

	return error;
#endif
}