/*
** nester - NES emulator
** Copyright (C) 2000  Darren Ranalli
**
** This program is free software; you can redistribute it and/or modify
** it under the terms of the GNU General Public License as published by
** the Free Software Foundation; either version 2 of the License, or
** (at your option) any later version.
**
** This program is distributed in the hope that it will be useful, 
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU 
** Library General Public License for more details.  To obtain a 
** copy of the GNU Library General Public License, write to the Free 
** Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
**
** Any permitted reproduction of these routines, in whole or in part,
** must bear this legend.
*/

/* 
** NesterDC by Ken Friece
** This routine was so different than the original, that I included 
** diff output at the bottom of the routine. The orginal is also called
** nes_rom.cpp.original
*/

#include "libc.h" 
#include "stdlib.h" 
//#include <stdio.h>
//#include <string.h>
//#include <malloc.h>
#include "NES_ROM.h"
#include "NES.h"
#include "dream.h"
#include "debug.h"

NES_ROM::NES_ROM(const char* fn)
{
  //FILE* fp;
  int fp;

  trainer    = (uint8 *)NULL;
  ROM_banks  = (uint8 *)NULL;
  VROM_banks = (uint8 *)NULL;

  rom_name = (char *)NULL;
  rom_path = (char *)NULL;

  try 
  {
    // store filename and path
    rom_name = (char*)malloc(strlen(fn)+1);
    rom_path = (char*)malloc(strlen(fn)+1);
    if(!rom_name || !rom_path) {
	  dc_print ("Error loading ROM: out of memory");
      throw "Error loading ROM: out of memory";
	}

	uint32 i = 0; 
	uint32 j = 0;
	while (fn[i] != '/') {
		i++;
	}
	i++;
	while (fn[i + j] != '\0') {
		rom_name[j] = fn[i + j];
		j++;
	}
	rom_name[j] = '\0';
	//dc_print (rom_name);

//	dc_print ("opening the rom");
	fp = cd_open (fn, O_RDONLY);
    //fp = fopen(fn, "rb");
    if(fp < 0) {
	  dc_print ("Error opening ROM file");
      throw "Error opening ROM file";
	}

//	dc_print ("reading the header");
	if(cd_read(fp, (void*)&header, sizeof(struct NES_header)) != sizeof(struct NES_header)) {
    //if(fread((void*)&header, /*sizeof(struct NES_header)*/16, 1, fp) != 1) {
	  dc_print ("Error reading from NES ROM");
      throw "Error reading from NES ROM";
	}

    if(strncmp((const char*)header.id, "NES", 3) || (header.ctrl_z != 0x1A)) {
	  dc_print ("Invalid NES file");
      throw "Invalid NES file";
	}

	//space_buffer = (uint8*)malloc(1024*16);

//	dc_print ("allocating ROM banks");
    // allocate memory
    ROM_banks = (uint8*)malloc(header.num_16k_rom_banks * (16*1024));
    if(!ROM_banks) { 
		dc_print ("Out of memory ROM_banks");	
		throw "Out of memory";
	}

//	dc_print ("allocating VROM banks");
    VROM_banks = (uint8*)malloc(header.num_8k_vrom_banks * (8*1024));
    if(!VROM_banks) {
		dc_print ("Out of memory VROM banks");	
		throw "Out of memory";
	}

    // load trainer if present
    if(has_trainer())
    {
//	  dc_print ("allocating trainer memory");
      trainer = (uint8*)malloc(TRAINER_LEN);
      if(!trainer) {
		  dc_print ("Out of memory");
		  throw "Out of memory";
	  }

//	  dc_print ("reading trainer");
	  if(cd_read (fp, trainer, TRAINER_LEN) < 1) {
      //if(fread(trainer, TRAINER_LEN, 1, fp) != 1) {
		dc_print ("Error reading trainer from NES ROM");
        throw "Error reading trainer from NES ROM";
	  }
    }

//	dc_print ("reading ROM banks from NES ROM");
	if(cd_read(fp, ROM_banks,(16*1024*header.num_16k_rom_banks)) != (16*1024*header.num_16k_rom_banks)) {
    //if(fread(ROM_banks,(16*1024),header.num_16k_rom_banks,fp) != header.num_16k_rom_banks) {
	  dc_print ("Error reading ROM banks from NES ROM");
      //throw "Error reading ROM banks from NES ROM";
	}

//	dc_print ("reading VROM banks from NES ROM");
	if(cd_read(fp, VROM_banks,(8*1024*header.num_8k_vrom_banks)) != (8*1024*header.num_8k_vrom_banks)) {
    //if(fread(VROM_banks,(8*1024),header.num_8k_vrom_banks,fp) != header.num_8k_vrom_banks) {
	  dc_print ("Error reading VROM banks from NES ROM");
      //throw "Error reading VROM banks from NES ROM";
	}

	//dc_print ("done opening rom");
	cd_close (fp);
    //fclose(fp);

  } catch(...) {
    if(fp)          cd_close(fp);

    if(VROM_banks)  free(VROM_banks);
    if(ROM_banks)   free(ROM_banks);
    if(trainer)     free(trainer);

    if(rom_name)    free(rom_name);
    if(rom_path)    free(rom_path);
    throw;
  }

  //dc_print ("doing mapper stuff");
  // figure out mapper number
  mapper = (header.flags_1 >> 4);

  // if there is anything in the reserved bytes,
  // don't trust the high nybble of the mapper number
  for(uint32 i = 0; i < sizeof(header.reserved); i++)
  {
    if(header.reserved[i] != 0x00) return;
  }
  mapper |= (header.flags_2 & 0xF0);

 // dc_print ("done opening rom!!!");
}

NES_ROM::~NES_ROM()
{
	//dc_print ("before VROM banks");
  if(VROM_banks)  free(VROM_banks);
  if(ROM_banks)   free(ROM_banks);
  if(trainer)     free(trainer);
  if(rom_name)    free(rom_name);
  if(rom_path)    free(rom_path);
  //dc_print ("done");
}

void NES_ROM::GetPathInfo(const char* fn)
{
  // find index of first letter of actual ROM file name (after path)
  uint32 i = strlen(fn); // start at end of string

  // copy rom name
  {
    uint32 j = i;
    uint32 a = 0;

    // copy up to period
    while(1)
    {
      if(!fn[j]) break;
      if(fn[j] == '.') break;

      rom_name[a] = fn[j];

      a++;
      j++;
    }

    // terminate rom name string
    rom_name[a] = '\0';
  }

}


/* Begin diff output

key:
< nester public beta 3 code 
> NesterDC code

21,23c21,32
< #include <stdio.h>
< #include <string.h>
< #include <malloc.h>
---
> 
> #include "libc.h" 
> #include "stdlib.h" 
> //#include <stdio.h>
> //#include <string.h>
> //#include <malloc.h>
25c34,35
< 
---
> #include "NES.h"
> #include "dream.h"
30,32c40,41
<   FILE* fp;
< 
<   fp         = NULL;
---
>   //FILE* fp;
>   int fp;
34,36c43,45
<   trainer    = NULL;
<   ROM_banks  = NULL;
<   VROM_banks = NULL;
---
>   trainer    = (uint8 *)NULL;
>   ROM_banks  = (uint8 *)NULL;
>   VROM_banks = (uint8 *)NULL;
38,39c47,48
<   rom_name = NULL;
<   rom_path = NULL;
---
>   rom_name = (char *)NULL;
>   rom_path = (char *)NULL;
46c55,56
<     if(!rom_name || !rom_path)
---
>     if(!rom_name || !rom_path) {
> 	  dc_print ("Error loading ROM: out of memory");
47a58
> 	}
49c60,71
<     GetPathInfo(fn);
---
> 	uint32 i = 0; 
> 	uint32 j = 0;
> 	while (fn[i] != '/') {
> 		i++;
> 	}
> 	i++;
> 	while (fn[i + j] != '\0') {
> 		rom_name[j] = fn[i + j];
> 		j++;
> 	}
> 	rom_name[j] = '\0';
> 	//dc_print (rom_name);
51,52c73,77
<     fp = fopen(fn, "rb");
<     if(fp == NULL)
---
> //	dc_print ("opening the rom");
> 	fp = cd_open (fn, O_RDONLY);
>     //fp = fopen(fn, "rb");
>     if(fp < 0) {
> 	  dc_print ("Error opening ROM file");
53a79
> 	}
55c81,84
<     if(fread((void*)&header, sizeof(struct NES_header), 1, fp) != 1)
---
> //	dc_print ("reading the header");
> 	if(cd_read(fp, (void*)&header, sizeof(struct NES_header)) != sizeof(struct NES_header)) {
>     //if(fread((void*)&header, sizeof(struct NES_header)16, 1, fp) != 1) {
> 	  dc_print ("Error reading from NES ROM");
56a86
> 	}
58c88,89
<     if(strncmp((const char*)header.id, "NES", 3) || (header.ctrl_z != 0x1A))
---
>     if(strncmp((const char*)header.id, "NES", 3) || (header.ctrl_z != 0x1A)) {
> 	  dc_print ("Invalid NES file");
59a91
> 	}
60a93,95
> 	//space_buffer = (uint8*)malloc(1024*16);
> 
> //	dc_print ("allocating ROM banks");
63c98,101
<     if(!ROM_banks) throw "Out of memory";
---
>     if(!ROM_banks) { 
> 		dc_print ("Out of memory ROM_banks");	
> 		throw "Out of memory";
> 	}
64a103
> //	dc_print ("allocating VROM banks");
66c105,108
<     if(!VROM_banks) throw "Out of memory";
---
>     if(!VROM_banks) {
> 		dc_print ("Out of memory VROM banks");	
> 		throw "Out of memory";
> 	}
70a113
> //	  dc_print ("allocating trainer memory");
72c115,118
<       if(!trainer) throw "Out of memory";
---
>       if(!trainer) {
> 		  dc_print ("Out of memory");
> 		  throw "Out of memory";
> 	  }
74c120,123
<       if(fread(trainer, TRAINER_LEN, 1, fp) != 1)
---
> //	  dc_print ("reading trainer");
> 	  if(cd_read (fp, trainer, TRAINER_LEN) < 1) {
>       //if(fread(trainer, TRAINER_LEN, 1, fp) != 1) {
> 		dc_print ("Error reading trainer from NES ROM");
76a126
>     }
78,84c128,144
<     if(fread(ROM_banks,(16*1024),header.num_16k_rom_banks,fp) != header.num_16k_rom_banks) 
<       throw "Error reading ROM banks from NES ROM";
< 
<     if(fread(VROM_banks,(8*1024),header.num_8k_vrom_banks,fp) != header.num_8k_vrom_banks) 
<       throw "Error reading VROM banks from NES ROM";
< 
<     fclose(fp);
---
> //	dc_print ("reading ROM banks from NES ROM");
> 	if(cd_read(fp, ROM_banks,(16*1024*header.num_16k_rom_banks)) != (16*1024*header.num_16k_rom_banks)) {
>     //if(fread(ROM_banks,(16*1024),header.num_16k_rom_banks,fp) != header.num_16k_rom_banks) {
> 	  dc_print ("Error reading ROM banks from NES ROM");
>       //throw "Error reading ROM banks from NES ROM";
> 	}
> 
> //	dc_print ("reading VROM banks from NES ROM");
> 	if(cd_read(fp, VROM_banks,(8*1024*header.num_8k_vrom_banks)) != (8*1024*header.num_8k_vrom_banks)) {
>     //if(fread(VROM_banks,(8*1024),header.num_8k_vrom_banks,fp) != header.num_8k_vrom_banks) {
> 	  dc_print ("Error reading VROM banks from NES ROM");
>       //throw "Error reading VROM banks from NES ROM";
> 	}
> 
> 	//dc_print ("done opening rom");
> 	cd_close (fp);
>     //fclose(fp);
87c147
<     if(fp)          fclose(fp);
---
>     if(fp)          cd_close(fp);
97a158
>   //dc_print ("doing mapper stuff");
108a170
>  // dc_print ("done opening rom!!!");
112a175
> 	//dc_print ("before VROM banks");
117a181
>   //dc_print ("done");
125,137d188
<   while(1)
<   {
<     // look for directory delimiter
<     if((fn[i] == '\\') || (fn[i] == '/'))
<     {
<       i++;
<       break;
<     }
< 
<     i--;
<     if(!i) break;
<   }
< 
159,173d209
<   // copy rom path
<   {
<     uint32 j = 0;
< 
<     // copy up to rom file name
<     while(j < i)
<     {
<       rom_path[j] = fn[j];
<       j++;
<     }
< 
<     // terminate rom path string
<     rom_path[i] = '\0';
<   }
< 

*/
