

/*****************************************************************************

   This file is part of x2600, the Atari 2600 Emulator
   ===================================================
   
   Copyright 1996 Alex Hornby. For contributions see the file CREDITS.

   This software is distributed under the terms of the GNU General Public
   License. This is free software with ABSOLUTELY NO WARRANTY.
   
   See the file COPYING for details.
   
   $Id: files.c,v 1.17 1996/11/24 16:55:40 ahornby Exp $

   Tweaked by Matthew Stroup for Amiga v2600, January 27, 1997.

******************************************************************************/

/*
   Used to load cartridge images into memory.
 */

#include "config.h"
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include "options.h"
#include "types.h"
#include "vmachine.h"
#include "c26def.h"

/* Return the size of the file pointed to by fp */
/* Avoids need for UNIX type stat, leaves file */
/* pointer untouched. */
long
filesize (FILE * fp)
{
  long curpos, length;

  curpos = ftell (fp);
  fseek (fp, 0L, SEEK_END);
  length = ftell (fp);
  fseek (fp, curpos, SEEK_SET);
  return length;
}

/* Load from the common 2600 format */
/* Uses the tag structure from c26def.h */
int
loadc26 (FILE * fp, long flen)
{
  char databuf[65535];
  struct c26_tag tag;

  while (fread (&tag, sizeof (struct c26_tag), 1, fp))
    {
      /* If positive then it has a data block */
      if (tag.type >= 0)
	{
	  if (fread (databuf, sizeof (UBYTE), tag.len, fp))
	    {
	      perror ("x2600 loadc26:");
	      fprintf (stderr, "Error reading data.\n");
	    }
	}

      switch (tag.type)
	{

	case VERSION:
	  if (Verbose)
	    printf ("File version %d\n", tag.len);
	  break;

	case WRITER:
	  if (Verbose)
	    printf ("Written by: %s\n", databuf);
	  break;

	case TVTYPE:
	  base_opts.tvtype = tag.len;
	  break;

	case CONTROLLERS:
	  /* Higher byte */
	  base_opts.lcon = (tag.len & 0xff00)>>8;
	  /* Low byte */
	  base_opts.rcon = (tag.len) & 0xff;

	case BANKING:
	  base_opts.bank = tag.len;
	  break;

	case DATA:
	  if (tag.len <= 16384)
	    memcpy (&theCart[0], databuf, tag.len);
	  else
	    {
	      fprintf (stderr, "Data larger that 16k!\n");
	      exit (-1);
	    }
	  rom_size = tag.len;
	  if (tag.len == 2048)
	    {
	      memcpy (&theCart[0], databuf, tag.len);
	      memcpy (&theCart[2048], databuf, tag.len);
	    }
	  break;

	default:
	  fprintf (stderr, "Unknown tag %d\n. Ignoring.", tag.type);
	  break;
	}
    }
    return 1;
}

/* Load a raw binary image  */
/* fp: file stream to load */
/* stat_data: unix stat structure for file pointed to by fp */
/* returns: size of file loaded */
int
loadRaw (FILE * fp, long flen)
{
  int size = flen;
  if (Verbose)
    printf ("Raw loading %d bytes\n", size);

  if (size > 16384)
    size = 16384;
  fread (theCart, sizeof (UBYTE), size, fp);

  rom_size = size;
  if (size == 2048)
    {
      memcpy (&theCart[2048], &theCart[0], 2048);
      rom_size = 4096;
    }
  else if (size < 2048)
    {
      theCart[0x0ffc] = 0x00;
      theCart[0x0ffd] = 0xf0;
      rom_size = 4096;
    }
  
  return size;
}

/* Load a commodore format .prg file  */
/* fp: file stream to load */
/* stat_data: unix stat structure for file pointed to by fp */
/* returns: size of file loaded */
int
loadPrg (FILE * fp, long flen)
{
  int start;
  int rompos;
  int size;
  UBYTE buf1, buf2;

  /* Get the load address */
  fread (&buf1, sizeof (UBYTE), 1, fp);
  fread (&buf2, sizeof (UBYTE), 1, fp);
  start = buf2 * 256 + buf1;

  /* Translate the load address to a ROM address */
  rompos = start & 0xfff;

  /* Get length of data part */
  size = flen - 2;

  if (Verbose)
    printf ("Loading .prg at %x\n", start);

  /* Load the data */
  fread (&theCart[rompos], sizeof (UBYTE), size, fp);

  /* Put the load address into the reset vector */
  theCart[0x0ffc] = buf1;
  theCart[0x0ffd] = buf2;
  return size;
}

/* Load a cartridge image */
/* name: filename to load */
/* returns: -1 on error 0 otherwise  */
int
loadCart (void)
{
  FILE *fp;
  char *ext;
  int flen;
  char *name = base_opts.filename;

  if (name == NULL)
    {
      fprintf (stderr, "filename is NULL!\n");
      return -1;
    }

  fp = fopen (name, "rb");
  if (!fp)
    {
      fprintf (stderr, "Can't find %s\n", name);
      return -1;
    }

  if (Verbose)
    printf ("Loading cart: %s\n", name);
  flen = filesize (fp);

  ext = strrchr (name, '.');
  if (strcmp (".pal", ext) == 0 || strcmp (".vcs", ext) == 0 ||
      strcmp (".raw", ext) == 0 || strcmp (".bin", ext) == 0 ||
      strcmp (".BIN", ext) == 0)
    {
      loadRaw (fp, flen);
    }
  else if (strcmp (".prg", ext) == 0)
    {
      loadPrg (fp, flen);
    }
  else if (strcmp (".c26", ext) == 0)
    {
      loadc26 (fp, flen);
    }
  else
    {
      fprintf (stderr, "Unknown file format %s\n", ext);
      return -1;
    }
  fclose (fp);
  return 0;
}
