mupen64plus-oldsvn/main/rom.c
2008-03-19 06:39:57 +00:00

586 lines
14 KiB
C

/**
* Mupen64 - rom.c
* Copyright (C) 2002 Hacktarux
*
* Mupen64 homepage: http://mupen64.emulation64.com
* email address: hacktarux@yahoo.fr
*
* If you want to contribute to the project please contact
* me first (maybe someone is already making what you are
* planning to do).
*
*
* This program is free software; you can redistribute it and/
* or modify it under the terms of the GNU General Public Li-
* cence as published by the Free Software Foundation; either
* version 2 of the Licence, or any later version.
*
* This program is distributed in the hope that it will be use-
* ful, but WITHOUT ANY WARRANTY; without even the implied war-
* ranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
* See the GNU General Public Licence for more details.
*
* You should have received a copy of the GNU General Public
* Licence along with this program; if not, write to the Free
* Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139,
* USA.
*
**/
/* This is the functions that load a rom into memory, it loads a roms
* in multiple formats, gzipped or not. It searches the rom, in the roms
* subdirectory or in the path specified in the path.cfg file.
*/
#include <stdio.h>
#include <stdlib.h>
#include <zlib.h>
#include <string.h>
#include <ctype.h>
#include "rom.h"
#include "../memory/memory.h"
#include "unzip.h"
#include "guifuncs.h"
#include "md5.h"
#include "mupenIniApi.h"
#include "guifuncs.h"
#include "translate.h"
#include "main.h"
#include "util.h"
static FILE *rom_file;
static gzFile *z_rom_file;
static unzFile zip;
static unz_file_info pfile_info;
static int i, tmp, z;
int taille_rom;
unsigned char *rom;
rom_header *ROM_HEADER;
rom_settings ROM_SETTINGS;
static void findsize()
{
if (!z)
{
fseek(rom_file, 0L, SEEK_END);
taille_rom=ftell(rom_file);
printf ("rom size: %d bytes (or %d Mb or %d Megabits)\n",
taille_rom, taille_rom/1024/1024, taille_rom/1024/1024*8);
fseek(rom_file, 0L, SEEK_SET);
}
else if (z == 1)
{
taille_rom=0;
rom=malloc(100000);
for(;;)
{
i = gzread(z_rom_file, rom, 100000);
taille_rom += i;
printf ("rom size: %d bytes (or %d Mb or %d Megabits)\r",
taille_rom, taille_rom/1024/1024, taille_rom/1024/1024*8);
fflush(stdout);
if (!i) break;
}
free(rom);
rom = NULL;
printf("\n");
gzseek(z_rom_file, 0L, SEEK_SET);
}
}
static int find_file(char *argv)
{
z=0;
i=strlen(argv);
{
unsigned char buf[4];
char szFileName[255], extraField[255], szComment[255];
zip = unzOpen(argv);
if (zip != NULL)
{
unzGoToFirstFile(zip);
do
{
unzGetCurrentFileInfo(zip, &pfile_info, szFileName, 255,
extraField, 255, szComment, 255);
unzOpenCurrentFile(zip);
if (pfile_info.uncompressed_size >= 4)
{
unzReadCurrentFile(zip, buf, 4);
if ((*((unsigned int*)buf) != 0x40123780) &&
(*((unsigned int*)buf) != 0x12408037) &&
(*((unsigned int*)buf) != 0x80371240))
{
unzCloseCurrentFile(zip);
}
else
{
taille_rom = pfile_info.uncompressed_size;
unzCloseCurrentFile(zip);
z = 2;
return 0;
}
}
}
while (unzGoToNextFile(zip) != UNZ_END_OF_LIST_OF_FILE);
unzClose(zip);
return 1;
}
}
if((i>3) && (argv[i-3]=='.') &&
(tolower(argv[i-2])=='g') && (tolower(argv[i-1])=='z'))
argv[i-3]=0;
rom_file=NULL;
z_rom_file=NULL;
rom_file=fopen(argv, "rb");
if (rom_file == NULL)
{
z_rom_file=gzopen(strcat(argv, ".gz"), "rb");
if (z_rom_file == NULL)
{
argv[i-3]=0;
z_rom_file=gzopen(strcat(argv, ".GZ"), "rb");
if (z_rom_file == NULL) return 1;
}
z = 1;
}
return 0;
}
static int ask_bad(void)
{
if(g_Noask)
{
printf(tr("The rom you are trying to load is probably a bad dump!\n"
"Be warned that this will probably give unexpected results.\n"));
return 1;
}
return confirm_message(tr("The rom you are trying to load is probably a bad dump!\n"
"Be warned that this will probably give unexpected results.\n"
"Do you still want to run it?"));
}
static int ask_hack(void)
{
if(g_Noask)
{
printf(tr("The rom you are trying to load is probably a hack!\n"
"Be warned that this will probably give unexpected results.\n"));
return 1;
}
return confirm_message(tr("The rom you are trying to load is probably a hack!\n"
"Be warned that this will probably give unexpected results.\n"
"Do you still want to run it?"));
}
static void display_loading_progress(int p)
{
// this info can clutter up the console
if(gui_enabled())
info_message(tr("Loading Rom: %d%%"), p);
if(p == 100)
{
info_message(tr("Rom \"%s\" loaded."), ROM_HEADER->nom);
}
}
int rom_read(const char *argv)
{
md5_state_t state;
md5_byte_t digest[16];
mupenEntry *entry;
char buf[1024], arg[1024], *s;
strncpy(arg, argv, 1000);
if (find_file(arg))
{
strncpy(arg, "roms/", 1000);
if (find_file(strncat(arg, argv, 1000)))
{
rom_file=fopen("path.cfg", "rb");
if(rom_file) fscanf(rom_file, "%1000s", buf);
else buf[0]=0;
if(rom_file) fclose(rom_file);
strncpy(arg, argv, 1000);
if (find_file(strcat(buf, arg)))
{
printf ("file not found or wrong path\n");
return -1;
}
}
}
/*------------------------------------------------------------------------*/
findsize();
if (rom) free(rom);
rom = malloc(taille_rom);
tmp=0;
if (!z)
{
for (i=0; i<taille_rom;i+=fread(rom+i, 1, 1000, rom_file))
{
if (tmp!=(int)((i/(float)taille_rom)*100))
{
tmp=(int)(i/(float)(taille_rom)*100);
display_loading_progress(tmp);
}
}
}
else if (z == 1)
{
for (i=0; i<taille_rom;i+=gzread(z_rom_file, rom+i, 1000))
{
if (tmp!=(int)((i/(float)taille_rom)*100))
{
tmp=(int)(i/(float)(taille_rom)*100);
display_loading_progress(tmp);
}
}
}
else
{
unzOpenCurrentFile(zip);
for (i=0; i<taille_rom;i+=unzReadCurrentFile(zip, rom+i, 1000))
{
if (tmp!=(int)((i/(float)taille_rom)*100))
{
tmp=(int)(i/(float)(taille_rom)*100);
display_loading_progress(tmp);
}
}
unzCloseCurrentFile(zip);
}
if (!z) fclose(rom_file);
else if (z==1) gzclose(z_rom_file);
else unzClose(zip);
if (rom[0]==0x37)
{
printf ("byteswaping rom...\n");
for (i=0; i<(taille_rom/2); i++)
{
tmp=rom[i*2];
rom[i*2]=rom[i*2+1];
rom[i*2+1]=tmp;
}
printf ("rom byteswaped\n");
}
if (rom[0]==0x40)
{
for (i=0; i<(taille_rom/4); i++)
{
tmp=rom[i*4];
rom[i*4]=rom[i*4+3];
rom[i*4+3]=tmp;
tmp=rom[i*4+1];
rom[i*4+1]=rom[i*4+2];
rom[i*4+2]=tmp;
}
printf("rom byteswaped\n");
}
else if ((rom[0] != 0x80) || (rom[1] != 0x37) || (rom[2] != 0x12) || (rom[3] != 0x40))
{
printf("wrong file format !\n");
free(rom);
rom = NULL;
return -2;
}
printf("rom loaded successfully\n");
if (!ROM_HEADER) ROM_HEADER = malloc(sizeof(rom_header));
memcpy(ROM_HEADER, rom, sizeof(rom_header));
trim((char *)ROM_HEADER->nom); // remove trailing whitespace from Rom name
display_loading_progress(100);
printf ("%x %x %x %x\n", ROM_HEADER->init_PI_BSB_DOM1_LAT_REG,
ROM_HEADER->init_PI_BSB_DOM1_PGS_REG,
ROM_HEADER->init_PI_BSB_DOM1_PWD_REG,
ROM_HEADER->init_PI_BSB_DOM1_PGS_REG2);
printf("ClockRate=%x\n", sl((unsigned int)ROM_HEADER->ClockRate));
printf("Version:%x\n", sl((unsigned int)ROM_HEADER->Release));
printf("CRC: %x %x\n", sl((unsigned int)ROM_HEADER->CRC1), sl((unsigned int)ROM_HEADER->CRC2));
printf ("name: %s\n", ROM_HEADER->nom);
if (sl(ROM_HEADER->Manufacturer_ID) == 'N') printf ("Manufacturer: Nintendo\n");
else printf ("Manufacturer: %x\n", (unsigned int)(ROM_HEADER->Manufacturer_ID));
printf("Cartridge_ID: %x\n", ROM_HEADER->Cartridge_ID);
switch(ROM_HEADER->Country_code)
{
case 0x0044:
printf("Country : Germany\n");
break;
case 0x0045:
printf("Country : United States\n");
break;
case 0x004A:
printf("Country : Japan\n");
break;
case 0x0050:
printf("European cartridge\n");
break;
case 0x0055:
printf("Country : Australie\n");
default:
printf("Country Code : %x\n", ROM_HEADER->Country_code);
}
printf ("size: %d\n", (unsigned int)(sizeof(rom_header)));
printf ("PC= %x\n", sl((unsigned int)ROM_HEADER->PC));
// loading rom settings and checking if it's a good dump
md5_init(&state);
md5_append(&state, (const md5_byte_t *)rom, taille_rom);
md5_finish(&state, digest);
printf("md5 code:");
for (i=0; i<16; i++) printf("%02X", digest[i]);
printf("\n");
ini_openFile();
for (i=0; i<16; i++) sprintf(arg+i*2, "%02X", digest[i]);
arg[32] = 0;
strcpy(ROM_SETTINGS.MD5, arg);
if ((entry = ini_search_by_md5(arg)) == NULL)
{
char mycrc[1024];
printf("%lx\n", (long)entry);
sprintf(mycrc, "%08X-%08X-C%02X",
(int)sl(ROM_HEADER->CRC1), (int)sl(ROM_HEADER->CRC2),
ROM_HEADER->Country_code);
if ((entry = ini_search_by_CRC(mycrc)) == NULL)
{
strcpy(ROM_SETTINGS.goodname, (char *) ROM_HEADER->nom);
strcat(ROM_SETTINGS.goodname, " (unknown rom)");
printf("%s\n", ROM_SETTINGS.goodname);
ROM_SETTINGS.eeprom_16kb = 0;
ini_closeFile();
return 0;
}
else
{
if (!ask_bad())
{
free(rom);
rom = NULL;
free(ROM_HEADER);
ROM_HEADER = NULL;
ini_closeFile();
return -3;
}
strcpy(ROM_SETTINGS.goodname, entry->goodname);
strcat(ROM_SETTINGS.goodname, " (bad dump)");
if (strcmp(entry->refMD5, ""))
entry = ini_search_by_md5(entry->refMD5);
ROM_SETTINGS.eeprom_16kb = entry->eeprom16kb;
ini_closeFile();
return 0;
}
}
s=entry->goodname;
for (i=strlen(s); i > 0 && s[i-1] != '['; i--);
if (i != 0)
{
if (s[i] == 'T' || s[i] == 't' || s[i] == 'h' || s[i] == 'f' || s[i] == 'o')
{
if (!ask_hack())
{
free(rom);
rom = NULL;
free(ROM_HEADER);
ROM_HEADER = NULL;
ini_closeFile();
return -3;
}
}
if (s[i] == 'b')
{
if (!ask_bad())
{
free(rom);
rom = NULL;
free(ROM_HEADER);
ROM_HEADER = NULL;
ini_closeFile();
return -3;
}
}
}
strcpy(ROM_SETTINGS.goodname, entry->goodname);
if (strcmp(entry->refMD5, ""))
entry = ini_search_by_md5(entry->refMD5);
ROM_SETTINGS.eeprom_16kb = entry->eeprom16kb;
printf("eeprom type:%d\n", ROM_SETTINGS.eeprom_16kb);
ini_closeFile();
return 0;
}
int fill_header(const char *argv)
{
char arg[1024];
strncpy(arg, argv, 1000);
if (find_file(arg))
{
printf ("file not found or wrong path\n");
return 0;
}
/*------------------------------------------------------------------------*/
findsize();
if (rom) free(rom);
rom = malloc(0x40);
tmp=0;
if (!z)
fread(rom, 1, 0x40, rom_file);
else if (z == 1)
gzread(z_rom_file, rom, 0x40);
else
{
unzOpenCurrentFile(zip);
unzReadCurrentFile(zip, rom, 0x40);
unzCloseCurrentFile(zip);
}
if (!z) fclose(rom_file);
else if (z==1) gzclose(z_rom_file);
else unzClose(zip);
if (rom[0]==0x37)
{
for (i=0; i<(0x40/2); i++)
{
tmp=rom[i*2];
rom[i*2]=rom[i*2+1];
rom[i*2+1]=tmp;
}
}
if (rom[0]==0x40)
{
for (i=0; i<(0x40/4); i++)
{
tmp=rom[i*4];
rom[i*4]=rom[i*4+3];
rom[i*4+3]=tmp;
tmp=rom[i*4+1];
rom[i*4+1]=rom[i*4+2];
rom[i*4+2]=tmp;
}
}
else if ((rom[0] != 0x80) || (rom[1] != 0x37) || (rom[2] != 0x12) || (rom[3] != 0x40))
{
free(rom);
rom = NULL;
return 0;
}
if (ROM_HEADER == NULL) ROM_HEADER= malloc(sizeof(rom_header));
memcpy(ROM_HEADER, rom, 0x40);
free(rom);
rom = NULL;
return taille_rom;
}
static void display_MD5calculating_progress(int p)
{
info_message(tr("Calculating Rom MD5: %d%%"), p);
}
void calculateMD5(const char *argv, unsigned char digest[16])
{
md5_state_t state;
char arg[1024];
strncpy(arg, argv, 1000);
if (find_file(arg))
{
printf("file not found or wrong path\n");
return;
}
/*------------------------------------------------------------------------*/
findsize();
if (rom) free(rom);
rom = malloc(taille_rom);
tmp=0;
if (!z)
{
for (i=0; i<taille_rom;i+=fread(rom+i, 1, 1000, rom_file))
{
if (tmp!=(int)((i/(float)taille_rom)*100))
{
tmp=(int)(i/(float)(taille_rom)*100);
display_MD5calculating_progress(tmp);
}
}
}
else if (z == 1)
{
for (i=0; i<taille_rom;i+=gzread(z_rom_file, rom+i, 1000))
{
if (tmp!=(int)((i/(float)taille_rom)*100))
{
tmp=(int)(i/(float)(taille_rom)*100);
display_MD5calculating_progress(tmp);
}
}
}
else
{
unzOpenCurrentFile(zip);
for (i=0; i<taille_rom;i+=unzReadCurrentFile(zip, rom+i, 1000))
{
if (tmp!=(int)((i/(float)taille_rom)*100))
{
tmp=(int)(i/(float)(taille_rom)*100);
display_MD5calculating_progress(tmp);
}
}
unzCloseCurrentFile(zip);
}
if (!z) fclose(rom_file);
else if (z==1) gzclose(z_rom_file);
else unzClose(zip);
display_MD5calculating_progress(100);
if (rom[0]==0x37)
{
printf ("byteswaping rom...\n");
for (i=0; i<(taille_rom/2); i++)
{
tmp=rom[i*2];
rom[i*2]=rom[i*2+1];
rom[i*2+1]=tmp;
}
printf ("rom byteswaped\n");
}
if (rom[0]==0x40)
{
for (i=0; i<(taille_rom/4); i++)
{
tmp=rom[i*4];
rom[i*4]=rom[i*4+3];
rom[i*4+3]=tmp;
tmp=rom[i*4+1];
rom[i*4+1]=rom[i*4+2];
rom[i*4+2]=tmp;
}
printf("rom byteswaped\n");
}
else if ((rom[0] != 0x80) || (rom[1] != 0x37) || (rom[2] != 0x12) || (rom[3] != 0x40))
{
printf("wrong file format !\n");
free(rom);
rom = NULL;
return;
}
md5_init(&state);
md5_append(&state, (const md5_byte_t *)rom, taille_rom);
md5_finish(&state, digest);
display_MD5calculating_progress(-1);
free(rom);
rom = NULL;
}