2012-12-19 09:30:18 +00:00
|
|
|
/****************************************************************************
|
|
|
|
* *
|
2015-11-10 05:21:49 +00:00
|
|
|
* Project64 - A Nintendo 64 emulator. *
|
2012-12-19 09:30:18 +00:00
|
|
|
* http://www.pj64-emu.com/ *
|
|
|
|
* Copyright (C) 2012 Project64. All rights reserved. *
|
|
|
|
* *
|
|
|
|
* License: *
|
|
|
|
* GNU/GPLv2 http://www.gnu.org/licenses/gpl-2.0.html *
|
|
|
|
* *
|
|
|
|
****************************************************************************/
|
2010-05-23 10:05:41 +00:00
|
|
|
#include "stdafx.h"
|
2015-12-06 09:59:58 +00:00
|
|
|
#include "N64RomClass.h"
|
|
|
|
#include "SystemGlobals.h"
|
|
|
|
#include <Project64-core/3rdParty/zip.h>
|
|
|
|
#include <Project64-core/3rdParty/7zip.h>
|
|
|
|
#include <Common/md5.h>
|
|
|
|
#include <Windows.h>
|
2008-09-18 03:15:49 +00:00
|
|
|
|
2015-04-28 22:19:02 +00:00
|
|
|
CN64Rom::CN64Rom()
|
2008-09-18 03:15:49 +00:00
|
|
|
{
|
2015-11-15 09:56:34 +00:00
|
|
|
m_hRomFile = NULL;
|
|
|
|
m_hRomFileMapping = NULL;
|
|
|
|
m_ROMImage = NULL;
|
|
|
|
m_ErrorMsg = EMPTY_STRING;
|
|
|
|
m_RomName = "";
|
|
|
|
m_FileName = "";
|
|
|
|
m_MD5 = "";
|
|
|
|
m_Country = UnknownCountry;
|
|
|
|
m_CicChip = CIC_UNKNOWN;
|
2008-09-18 03:15:49 +00:00
|
|
|
}
|
|
|
|
|
2015-04-28 22:19:02 +00:00
|
|
|
CN64Rom::~CN64Rom()
|
|
|
|
{
|
2015-11-15 09:56:34 +00:00
|
|
|
UnallocateRomImage();
|
2008-09-18 03:15:49 +00:00
|
|
|
}
|
|
|
|
|
2015-11-15 20:05:55 +00:00
|
|
|
bool CN64Rom::AllocateAndLoadN64Image(const char * FileLoc, bool LoadBootCodeOnly)
|
|
|
|
{
|
2015-11-15 09:56:34 +00:00
|
|
|
//Try to open the target file
|
|
|
|
HANDLE hFile = CreateFile(FileLoc, GENERIC_READ, FILE_SHARE_READ, NULL,
|
|
|
|
OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_RANDOM_ACCESS,
|
|
|
|
NULL);
|
|
|
|
if (hFile == INVALID_HANDLE_VALUE) { return false; }
|
|
|
|
|
|
|
|
//Read the first 4 bytes and make sure it is a valid n64 image
|
2015-11-15 20:05:55 +00:00
|
|
|
DWORD dwRead; uint8_t Test[4];
|
2015-11-15 09:56:34 +00:00
|
|
|
|
|
|
|
SetFilePointer(hFile, 0, 0, FILE_BEGIN);
|
|
|
|
ReadFile(hFile, Test, 4, &dwRead, NULL);
|
2015-11-15 20:05:55 +00:00
|
|
|
if (!IsValidRomImage(Test))
|
|
|
|
{
|
2015-11-15 09:56:34 +00:00
|
|
|
CloseHandle(hFile);
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
//Get the size of the rom and try to allocate the memory needed.
|
|
|
|
DWORD RomFileSize = GetFileSize(hFile, NULL);
|
|
|
|
//if loading boot code then just load the first 0x1000 bytes
|
|
|
|
if (LoadBootCodeOnly) { RomFileSize = 0x1000; }
|
|
|
|
|
2015-11-15 20:05:55 +00:00
|
|
|
uint8_t * Image = (uint8_t *)VirtualAlloc(NULL, RomFileSize, MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE);
|
|
|
|
if (Image == NULL)
|
|
|
|
{
|
2015-11-15 09:56:34 +00:00
|
|
|
SetError(MSG_MEM_ALLOC_ERROR);
|
|
|
|
CloseHandle(hFile);
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
//Load the n64 rom to the allocated memory
|
|
|
|
g_Notify->DisplayMessage(5, MSG_LOADING);
|
|
|
|
SetFilePointer(hFile, 0, 0, FILE_BEGIN);
|
|
|
|
|
|
|
|
DWORD count, TotalRead = 0;
|
2015-11-15 20:05:55 +00:00
|
|
|
for (count = 0; count < (int)RomFileSize; count += ReadFromRomSection)
|
|
|
|
{
|
2015-11-15 09:56:34 +00:00
|
|
|
DWORD dwToRead = RomFileSize - count;
|
|
|
|
if (dwToRead > ReadFromRomSection) { dwToRead = ReadFromRomSection; }
|
|
|
|
|
2015-11-15 20:05:55 +00:00
|
|
|
if (!ReadFile(hFile, &Image[count], dwToRead, &dwRead, NULL))
|
|
|
|
{
|
2015-11-15 09:56:34 +00:00
|
|
|
VirtualFree(Image, 0, MEM_RELEASE);
|
|
|
|
CloseHandle(hFile);
|
|
|
|
SetError(MSG_FAIL_IMAGE);
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
TotalRead += dwRead;
|
|
|
|
|
|
|
|
//Show Message of how much % wise of the rom has been loaded
|
2015-12-23 20:04:36 +00:00
|
|
|
g_Notify->DisplayMessage(0, stdstr_f("%s: %.2f%c", GS(MSG_LOADED), ((float)TotalRead / (float)RomFileSize) * 100.0f, '%').c_str());
|
2015-11-15 09:56:34 +00:00
|
|
|
}
|
|
|
|
dwRead = TotalRead;
|
|
|
|
|
2015-11-15 20:05:55 +00:00
|
|
|
if (RomFileSize != dwRead)
|
|
|
|
{
|
2015-11-15 09:56:34 +00:00
|
|
|
VirtualFree(Image, 0, MEM_RELEASE);
|
|
|
|
CloseHandle(hFile);
|
|
|
|
SetError(MSG_FAIL_IMAGE);
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
//save information about the rom loaded
|
|
|
|
m_hRomFile = hFile;
|
|
|
|
m_ROMImage = Image;
|
|
|
|
m_RomFileSize = RomFileSize;
|
|
|
|
|
|
|
|
g_Notify->DisplayMessage(5, MSG_BYTESWAP);
|
|
|
|
ByteSwapRom();
|
|
|
|
|
|
|
|
//Protect the memory so that it can not be written to.
|
|
|
|
DWORD OldProtect;
|
|
|
|
VirtualProtect(m_ROMImage, m_RomFileSize, PAGE_READONLY, &OldProtect);
|
|
|
|
|
|
|
|
return true;
|
2008-09-18 03:15:49 +00:00
|
|
|
}
|
|
|
|
|
2015-11-15 20:05:55 +00:00
|
|
|
bool CN64Rom::AllocateAndLoadZipImage(const char * FileLoc, bool LoadBootCodeOnly)
|
|
|
|
{
|
2015-11-15 09:56:34 +00:00
|
|
|
unzFile file = unzOpen(FileLoc);
|
|
|
|
if (file == NULL)
|
2015-11-15 20:05:55 +00:00
|
|
|
{
|
2015-11-15 09:56:34 +00:00
|
|
|
return false;
|
2015-11-15 20:05:55 +00:00
|
|
|
}
|
2015-11-15 09:56:34 +00:00
|
|
|
|
|
|
|
int port = unzGoToFirstFile(file);
|
|
|
|
bool FoundRom = false;
|
|
|
|
|
|
|
|
//scan through all files in zip to a suitable file is found
|
2015-11-15 20:05:55 +00:00
|
|
|
while (port == UNZ_OK && !FoundRom)
|
|
|
|
{
|
2015-11-15 09:56:34 +00:00
|
|
|
unz_file_info info;
|
|
|
|
char zname[_MAX_PATH];
|
|
|
|
|
|
|
|
unzGetCurrentFileInfo(file, &info, zname, sizeof(zname), NULL, 0, NULL, 0);
|
2015-11-15 20:05:55 +00:00
|
|
|
if (unzLocateFile(file, zname, 1) != UNZ_OK)
|
|
|
|
{
|
2015-11-15 09:56:34 +00:00
|
|
|
SetError(MSG_FAIL_ZIP);
|
|
|
|
break;
|
|
|
|
}
|
2015-11-15 20:05:55 +00:00
|
|
|
if (unzOpenCurrentFile(file) != UNZ_OK)
|
|
|
|
{
|
2015-11-15 09:56:34 +00:00
|
|
|
SetError(MSG_FAIL_ZIP);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
//Read the first 4 bytes to check magic number
|
2015-11-15 20:05:55 +00:00
|
|
|
uint8_t Test[4];
|
2015-11-15 09:56:34 +00:00
|
|
|
unzReadCurrentFile(file, Test, sizeof(Test));
|
2015-11-15 20:05:55 +00:00
|
|
|
if (IsValidRomImage(Test))
|
|
|
|
{
|
2015-11-15 09:56:34 +00:00
|
|
|
//Get the size of the rom and try to allocate the memory needed.
|
|
|
|
DWORD RomFileSize = info.uncompressed_size;
|
2015-11-15 20:05:55 +00:00
|
|
|
if (LoadBootCodeOnly)
|
|
|
|
{
|
2015-11-15 09:56:34 +00:00
|
|
|
RomFileSize = 0x1000;
|
|
|
|
}
|
2015-11-15 20:05:55 +00:00
|
|
|
uint8_t * Image = (uint8_t *)VirtualAlloc(NULL, RomFileSize, MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE);
|
|
|
|
if (Image == NULL)
|
|
|
|
{
|
2015-11-15 09:56:34 +00:00
|
|
|
SetError(MSG_MEM_ALLOC_ERROR);
|
|
|
|
unzCloseCurrentFile(file);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
//Load the n64 rom to the allocated memory
|
|
|
|
g_Notify->DisplayMessage(5, MSG_LOADING);
|
|
|
|
memcpy(Image, Test, 4);
|
|
|
|
|
|
|
|
DWORD dwRead, count, TotalRead = 0;
|
2015-11-15 20:05:55 +00:00
|
|
|
for (count = 4; count < (int)RomFileSize; count += ReadFromRomSection)
|
|
|
|
{
|
2015-11-15 09:56:34 +00:00
|
|
|
DWORD dwToRead = RomFileSize - count;
|
|
|
|
if (dwToRead > ReadFromRomSection) { dwToRead = ReadFromRomSection; }
|
|
|
|
|
|
|
|
dwRead = unzReadCurrentFile(file, &Image[count], dwToRead);
|
2015-11-15 20:05:55 +00:00
|
|
|
if (dwRead == 0)
|
|
|
|
{
|
2015-11-15 09:56:34 +00:00
|
|
|
SetError(MSG_FAIL_ZIP);
|
|
|
|
VirtualFree(Image, 0, MEM_RELEASE);
|
|
|
|
unzCloseCurrentFile(file);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
TotalRead += dwRead;
|
|
|
|
|
|
|
|
//Show Message of how much % wise of the rom has been loaded
|
2015-12-23 20:04:36 +00:00
|
|
|
g_Notify->DisplayMessage(5, stdstr_f("%s: %.2f%c", GS(MSG_LOADED), ((float)TotalRead / (float)RomFileSize) * 100.0f, '%').c_str());
|
2015-11-15 09:56:34 +00:00
|
|
|
}
|
|
|
|
dwRead = TotalRead + 4;
|
|
|
|
|
2015-11-15 20:05:55 +00:00
|
|
|
if (RomFileSize != dwRead)
|
|
|
|
{
|
2015-11-15 09:56:34 +00:00
|
|
|
VirtualFree(Image, 0, MEM_RELEASE);
|
|
|
|
unzCloseCurrentFile(file);
|
|
|
|
SetError(MSG_FAIL_ZIP);
|
2015-12-23 20:04:36 +00:00
|
|
|
g_Notify->DisplayMessage(1, "");
|
2015-11-15 09:56:34 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
//save information about the rom loaded
|
|
|
|
m_hRomFile = NULL;
|
|
|
|
m_ROMImage = Image;
|
|
|
|
m_RomFileSize = RomFileSize;
|
|
|
|
FoundRom = true;
|
|
|
|
|
|
|
|
g_Notify->DisplayMessage(5, MSG_BYTESWAP);
|
|
|
|
ByteSwapRom();
|
|
|
|
|
|
|
|
//Protect the memory so that it can not be written to.
|
|
|
|
DWORD OldProtect;
|
|
|
|
VirtualProtect(m_ROMImage, m_RomFileSize, PAGE_READONLY, &OldProtect);
|
2015-12-23 20:04:36 +00:00
|
|
|
g_Notify->DisplayMessage(1, "");
|
2015-11-15 09:56:34 +00:00
|
|
|
}
|
|
|
|
unzCloseCurrentFile(file);
|
|
|
|
|
|
|
|
if (!FoundRom)
|
2015-11-15 20:05:55 +00:00
|
|
|
{
|
2015-11-15 09:56:34 +00:00
|
|
|
port = unzGoToNextFile(file);
|
2015-11-15 20:05:55 +00:00
|
|
|
}
|
2015-11-15 09:56:34 +00:00
|
|
|
}
|
|
|
|
unzClose(file);
|
|
|
|
|
|
|
|
return FoundRom;
|
2008-09-18 03:15:49 +00:00
|
|
|
}
|
|
|
|
|
2015-11-15 20:05:55 +00:00
|
|
|
void CN64Rom::ByteSwapRom()
|
|
|
|
{
|
2015-11-15 09:56:34 +00:00
|
|
|
DWORD count;
|
|
|
|
|
2015-11-15 20:05:55 +00:00
|
|
|
switch (*((DWORD *)&m_ROMImage[0]))
|
|
|
|
{
|
2015-11-15 09:56:34 +00:00
|
|
|
case 0x12408037:
|
2015-11-15 20:05:55 +00:00
|
|
|
for (count = 0; count < m_RomFileSize; count += 4)
|
|
|
|
{
|
2015-11-15 09:56:34 +00:00
|
|
|
m_ROMImage[count] ^= m_ROMImage[count + 2];
|
|
|
|
m_ROMImage[count + 2] ^= m_ROMImage[count];
|
|
|
|
m_ROMImage[count] ^= m_ROMImage[count + 2];
|
|
|
|
m_ROMImage[count + 1] ^= m_ROMImage[count + 3];
|
|
|
|
m_ROMImage[count + 3] ^= m_ROMImage[count + 1];
|
|
|
|
m_ROMImage[count + 1] ^= m_ROMImage[count + 3];
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case 0x40072780: //64DD IPL
|
|
|
|
case 0x40123780:
|
2015-11-15 20:05:55 +00:00
|
|
|
for (count = 0; count < m_RomFileSize; count += 4)
|
|
|
|
{
|
2015-11-15 09:56:34 +00:00
|
|
|
m_ROMImage[count] ^= m_ROMImage[count + 3];
|
|
|
|
m_ROMImage[count + 3] ^= m_ROMImage[count];
|
|
|
|
m_ROMImage[count] ^= m_ROMImage[count + 3];
|
|
|
|
m_ROMImage[count + 1] ^= m_ROMImage[count + 2];
|
|
|
|
m_ROMImage[count + 2] ^= m_ROMImage[count + 1];
|
|
|
|
m_ROMImage[count + 1] ^= m_ROMImage[count + 2];
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case 0x80371240: break;
|
|
|
|
default:
|
2015-12-23 20:04:36 +00:00
|
|
|
g_Notify->DisplayError(stdstr_f("ByteSwapRom: %X", m_ROMImage[0]).c_str());
|
2015-11-15 09:56:34 +00:00
|
|
|
}
|
2008-09-18 03:15:49 +00:00
|
|
|
}
|
|
|
|
|
2015-04-28 22:19:02 +00:00
|
|
|
void CN64Rom::CalculateCicChip()
|
2008-09-18 03:15:49 +00:00
|
|
|
{
|
2015-11-15 20:05:55 +00:00
|
|
|
int64_t CRC = 0;
|
2015-11-15 09:56:34 +00:00
|
|
|
|
|
|
|
if (m_ROMImage == NULL)
|
|
|
|
{
|
|
|
|
m_CicChip = CIC_UNKNOWN;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2015-11-15 20:05:55 +00:00
|
|
|
for (int count = 0x40; count < 0x1000; count += 4)
|
|
|
|
{
|
2015-11-15 09:56:34 +00:00
|
|
|
CRC += *(DWORD *)(m_ROMImage + count);
|
|
|
|
}
|
|
|
|
switch (CRC) {
|
|
|
|
case 0x000000D0027FDF31: m_CicChip = CIC_NUS_6101; break;
|
|
|
|
case 0x000000CFFB631223: m_CicChip = CIC_NUS_6101; break;
|
|
|
|
case 0x000000D057C85244: m_CicChip = CIC_NUS_6102; break;
|
|
|
|
case 0x000000D6497E414B: m_CicChip = CIC_NUS_6103; break;
|
|
|
|
case 0x0000011A49F60E96: m_CicChip = CIC_NUS_6105; break;
|
|
|
|
case 0x000000D6D5BE5580: m_CicChip = CIC_NUS_6106; break;
|
|
|
|
case 0x000001053BC19870: m_CicChip = CIC_NUS_5167; break; //64DD CONVERSION CIC
|
|
|
|
case 0x000000D2E53EF008: m_CicChip = CIC_NUS_8303; break; //64DD IPL
|
|
|
|
default:
|
|
|
|
if (bHaveDebugger())
|
|
|
|
{
|
2015-12-23 20:04:36 +00:00
|
|
|
g_Notify->DisplayError(stdstr_f("Unknown CIC checksum:\n%I64X.", CRC).c_str());
|
2015-11-15 09:56:34 +00:00
|
|
|
}
|
|
|
|
m_CicChip = CIC_UNKNOWN; break;
|
|
|
|
}
|
2008-09-18 03:15:49 +00:00
|
|
|
}
|
|
|
|
|
2015-06-15 13:08:07 +00:00
|
|
|
void CN64Rom::CalculateRomCrc()
|
|
|
|
{
|
2015-11-15 09:56:34 +00:00
|
|
|
DWORD t0, t2, t3, t4, t5;
|
|
|
|
DWORD a0, a1, a2, a3;
|
|
|
|
DWORD s0;
|
|
|
|
DWORD v0, v1;
|
|
|
|
|
|
|
|
// CIC_NUS_6101 at=0x5D588B65 , s6=0x3F
|
|
|
|
// CIC_NUS_6102 at=0x5D588B65 , s6=0x3F
|
|
|
|
// CIC_NUS_6103 at=0x6C078965 , s6=0x78
|
|
|
|
// CIC_NUS_6105 at=0x5d588b65 , s6=0x91
|
|
|
|
// CIC_NUS_6106 at=0x6C078965 , s6=0x85
|
|
|
|
|
|
|
|
// 64DD IPL at=0x02E90EDD , s6=0xdd
|
|
|
|
|
|
|
|
//v0 = 0xFFFFFFFF & (0x3F * at) + 1;
|
2015-11-15 20:05:55 +00:00
|
|
|
switch (m_CicChip)
|
|
|
|
{
|
2015-11-15 09:56:34 +00:00
|
|
|
case CIC_NUS_6101:
|
|
|
|
case CIC_NUS_6102: v0 = 0xF8CA4DDC; break;
|
|
|
|
case CIC_NUS_6103: v0 = 0xA3886759; break;
|
|
|
|
case CIC_NUS_6105: v0 = 0xDF26F436; break;
|
|
|
|
case CIC_NUS_6106: v0 = 0x1FEA617A; break;
|
|
|
|
default:
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
DWORD OldProtect;
|
|
|
|
VirtualProtect(m_ROMImage, m_RomFileSize, PAGE_READWRITE, &OldProtect);
|
|
|
|
|
|
|
|
v1 = 0;
|
|
|
|
t0 = 0;
|
|
|
|
t5 = 0x20;
|
|
|
|
|
|
|
|
a3 = v0;
|
|
|
|
t2 = v0;
|
|
|
|
t3 = v0;
|
|
|
|
s0 = v0;
|
|
|
|
a2 = v0;
|
|
|
|
t4 = v0;
|
|
|
|
|
2015-11-15 20:05:55 +00:00
|
|
|
for (t0 = 0; t0 < 0x00100000; t0 += 4)
|
|
|
|
{
|
2015-11-15 09:56:34 +00:00
|
|
|
v0 = *(DWORD *)(m_ROMImage + t0 + 0x1000);
|
|
|
|
|
|
|
|
v1 = a3 + v0;
|
|
|
|
a1 = v1;
|
|
|
|
|
|
|
|
if (v1 < a3) t2 += 0x1;
|
|
|
|
v1 = v0 & 0x001F;
|
|
|
|
|
|
|
|
a0 = (v0 << v1) | (v0 >> (t5 - v1));
|
|
|
|
|
|
|
|
a3 = a1;
|
|
|
|
t3 = t3 ^ v0;
|
|
|
|
|
|
|
|
s0 = s0 + a0;
|
|
|
|
if (a2 < v0) a2 = a3 ^ v0 ^ a2;
|
|
|
|
else a2 = a2 ^ a0;
|
|
|
|
|
2015-11-15 20:05:55 +00:00
|
|
|
if (m_CicChip == CIC_NUS_6105)
|
|
|
|
{
|
2015-11-15 09:56:34 +00:00
|
|
|
t4 = (v0 ^ (*(DWORD *)(m_ROMImage + (0xFF & t0) + 0x750))) + t4;
|
|
|
|
}
|
|
|
|
else t4 = (v0 ^ s0) + t4;
|
|
|
|
}
|
2015-11-15 20:05:55 +00:00
|
|
|
if (m_CicChip == CIC_NUS_6103)
|
|
|
|
{
|
2015-11-15 09:56:34 +00:00
|
|
|
a3 = (a3 ^ t2) + t3;
|
|
|
|
s0 = (s0 ^ a2) + t4;
|
|
|
|
}
|
2015-11-15 20:05:55 +00:00
|
|
|
else if (m_CicChip == CIC_NUS_6106)
|
|
|
|
{
|
2015-11-15 09:56:34 +00:00
|
|
|
a3 = 0xFFFFFFFF & (a3 * t2) + t3;
|
|
|
|
s0 = 0xFFFFFFFF & (s0 * a2) + t4;
|
|
|
|
}
|
2015-11-15 20:05:55 +00:00
|
|
|
else
|
|
|
|
{
|
2015-11-15 09:56:34 +00:00
|
|
|
a3 = a3 ^ t2 ^ t3;
|
|
|
|
s0 = s0 ^ a2 ^ t4;
|
|
|
|
}
|
|
|
|
|
|
|
|
*(DWORD *)(m_ROMImage + 0x10) = a3;
|
|
|
|
*(DWORD *)(m_ROMImage + 0x14) = s0;
|
|
|
|
|
|
|
|
VirtualProtect(m_ROMImage, m_RomFileSize, PAGE_READONLY, &OldProtect);
|
2015-06-15 13:08:07 +00:00
|
|
|
}
|
|
|
|
|
2015-04-28 22:19:02 +00:00
|
|
|
CICChip CN64Rom::CicChipID()
|
|
|
|
{
|
2015-11-15 09:56:34 +00:00
|
|
|
return m_CicChip;
|
2008-09-18 03:15:49 +00:00
|
|
|
}
|
|
|
|
|
2015-11-15 20:05:55 +00:00
|
|
|
bool CN64Rom::IsValidRomImage(uint8_t Test[4])
|
|
|
|
{
|
2015-11-15 09:56:34 +00:00
|
|
|
if (*((DWORD *)&Test[0]) == 0x40123780) { return true; }
|
|
|
|
if (*((DWORD *)&Test[0]) == 0x12408037) { return true; }
|
|
|
|
if (*((DWORD *)&Test[0]) == 0x80371240) { return true; }
|
|
|
|
if (*((DWORD *)&Test[0]) == 0x40072780) { return true; } //64DD IPL
|
|
|
|
return false;
|
2008-09-18 03:15:49 +00:00
|
|
|
}
|
|
|
|
|
2015-12-23 20:04:36 +00:00
|
|
|
void CN64Rom::NotificationCB(const char * Status, CN64Rom * /*_this*/)
|
2008-09-18 03:15:49 +00:00
|
|
|
{
|
2015-12-23 20:04:36 +00:00
|
|
|
g_Notify->DisplayMessage(5, stdstr_f("%s", Status).c_str());
|
2008-09-18 03:15:49 +00:00
|
|
|
}
|
|
|
|
|
2015-11-15 20:05:55 +00:00
|
|
|
bool CN64Rom::LoadN64Image(const char * FileLoc, bool LoadBootCodeOnly)
|
|
|
|
{
|
2015-11-15 09:56:34 +00:00
|
|
|
UnallocateRomImage();
|
|
|
|
m_ErrorMsg = EMPTY_STRING;
|
|
|
|
|
|
|
|
char drive[_MAX_DRIVE], dir[_MAX_DIR], fname[_MAX_FNAME], ext[_MAX_EXT];
|
|
|
|
_splitpath(FileLoc, drive, dir, fname, ext);
|
|
|
|
bool Loaded7zFile = false;
|
|
|
|
|
|
|
|
if (strstr(FileLoc, "?") != NULL || strcmp(ext, ".7z") == 0)
|
|
|
|
{
|
|
|
|
char FullPath[MAX_PATH + 100];
|
|
|
|
strcpy(FullPath, FileLoc);
|
|
|
|
|
|
|
|
//this should be a 7zip file
|
|
|
|
char * SubFile = strstr(FullPath, "?");
|
|
|
|
if (SubFile == NULL)
|
|
|
|
{
|
|
|
|
//Pop up a dialog and select file
|
|
|
|
//allocate memory for sub name and copy selected file name to var
|
|
|
|
//return false; //remove once dialog is done
|
|
|
|
}
|
2015-11-15 20:05:55 +00:00
|
|
|
else
|
|
|
|
{
|
2015-11-15 09:56:34 +00:00
|
|
|
*SubFile = '\0';
|
|
|
|
SubFile += 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
C7zip ZipFile(FullPath);
|
|
|
|
ZipFile.SetNotificationCallback((C7zip::LP7ZNOTIFICATION)NotificationCB, this);
|
|
|
|
for (int i = 0; i < ZipFile.NumFiles(); i++)
|
|
|
|
{
|
|
|
|
CSzFileItem * f = ZipFile.FileItem(i);
|
|
|
|
if (f->IsDir)
|
|
|
|
{
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
stdstr ZipFileName;
|
|
|
|
ZipFileName.FromUTF16(ZipFile.FileNameIndex(i).c_str());
|
|
|
|
if (SubFile != NULL)
|
|
|
|
{
|
|
|
|
if (_stricmp(ZipFileName.c_str(), SubFile) != 0)
|
|
|
|
{
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
//Get the size of the rom and try to allocate the memory needed.
|
|
|
|
DWORD RomFileSize = (DWORD)f->Size;
|
|
|
|
//if loading boot code then just load the first 0x1000 bytes
|
|
|
|
if (LoadBootCodeOnly) { RomFileSize = 0x1000; }
|
|
|
|
|
2015-11-15 20:05:55 +00:00
|
|
|
uint8_t * Image = (uint8_t *)VirtualAlloc(NULL, RomFileSize, MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE);
|
|
|
|
if (Image == NULL)
|
|
|
|
{
|
2015-11-15 09:56:34 +00:00
|
|
|
SetError(MSG_MEM_ALLOC_ERROR);
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
//Load the n64 rom to the allocated memory
|
|
|
|
g_Notify->DisplayMessage(5, MSG_LOADING);
|
|
|
|
if (!ZipFile.GetFile(i, Image, RomFileSize))
|
|
|
|
{
|
|
|
|
VirtualFree(Image, 0, MEM_RELEASE);
|
|
|
|
SetError(MSG_FAIL_IMAGE);
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!IsValidRomImage(Image))
|
|
|
|
{
|
|
|
|
VirtualFree(Image, 0, MEM_RELEASE);
|
|
|
|
SetError(MSG_FAIL_IMAGE);
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
//save information about the rom loaded
|
|
|
|
m_ROMImage = Image;
|
|
|
|
m_RomFileSize = RomFileSize;
|
|
|
|
|
|
|
|
g_Notify->DisplayMessage(5, MSG_BYTESWAP);
|
|
|
|
ByteSwapRom();
|
|
|
|
|
|
|
|
//Protect the memory so that it can not be written to.
|
|
|
|
DWORD OldProtect;
|
|
|
|
VirtualProtect(m_ROMImage, m_RomFileSize, PAGE_READONLY, &OldProtect);
|
|
|
|
|
|
|
|
Loaded7zFile = true;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
if (!Loaded7zFile)
|
|
|
|
{
|
|
|
|
SetError(MSG_7Z_FILE_NOT_FOUND);
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
//Try to open the file as a zip file
|
|
|
|
if (!Loaded7zFile)
|
|
|
|
{
|
2015-11-15 20:05:55 +00:00
|
|
|
if (!AllocateAndLoadZipImage(FileLoc, LoadBootCodeOnly))
|
|
|
|
{
|
|
|
|
if (m_ErrorMsg != EMPTY_STRING)
|
|
|
|
{
|
2015-11-15 09:56:34 +00:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
//other wise treat if normal file and open the passed file
|
|
|
|
HANDLE hFile = CreateFile(FileLoc, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING,
|
|
|
|
FILE_ATTRIBUTE_NORMAL | FILE_FLAG_RANDOM_ACCESS, NULL);
|
|
|
|
if (hFile == INVALID_HANDLE_VALUE) { SetError(MSG_FAIL_OPEN_IMAGE); return false; }
|
|
|
|
|
|
|
|
//Create a file map
|
|
|
|
HANDLE hFileMapping = CreateFileMapping(hFile, NULL, PAGE_READONLY, 0, 0, NULL);
|
2015-11-15 20:05:55 +00:00
|
|
|
if (hFileMapping == NULL)
|
|
|
|
{
|
2015-11-15 09:56:34 +00:00
|
|
|
CloseHandle(hFile);
|
|
|
|
SetError(MSG_FAIL_OPEN_IMAGE);
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
//Map the file to a memory pointer .. ie a way of pretending to load the rom
|
|
|
|
//loose the bonus of being able to flip it on the fly tho.
|
2015-11-15 20:05:55 +00:00
|
|
|
uint8_t * Image = (PBYTE)MapViewOfFile(hFileMapping, FILE_MAP_READ, 0, 0, 0);
|
|
|
|
if (Image == NULL)
|
|
|
|
{
|
2015-11-15 09:56:34 +00:00
|
|
|
CloseHandle(hFileMapping);
|
|
|
|
CloseHandle(hFile);
|
|
|
|
SetError(MSG_FAIL_OPEN_IMAGE);
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2015-11-15 20:05:55 +00:00
|
|
|
if (!IsValidRomImage(Image))
|
|
|
|
{
|
2015-11-15 09:56:34 +00:00
|
|
|
UnmapViewOfFile(Image);
|
|
|
|
CloseHandle(hFileMapping);
|
|
|
|
CloseHandle(hFile);
|
|
|
|
SetError(MSG_FAIL_IMAGE);
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2015-11-15 20:05:55 +00:00
|
|
|
if (*((DWORD *)Image) == 0x80371240)
|
|
|
|
{
|
2015-11-15 09:56:34 +00:00
|
|
|
m_hRomFile = hFile;
|
|
|
|
m_hRomFileMapping = hFileMapping;
|
|
|
|
m_ROMImage = Image;
|
|
|
|
m_RomFileSize = GetFileSize(hFile, NULL);
|
|
|
|
}
|
2015-11-15 20:05:55 +00:00
|
|
|
else
|
|
|
|
{
|
2015-11-15 09:56:34 +00:00
|
|
|
if (!AllocateAndLoadN64Image(FileLoc, LoadBootCodeOnly)) { return false; }
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
char RomName[260];
|
|
|
|
int count;
|
|
|
|
//Get the header from the rom image
|
|
|
|
memcpy(&RomName[0], (void *)(m_ROMImage + 0x20), 20);
|
2015-11-15 20:05:55 +00:00
|
|
|
for (count = 0; count < 20; count += 4)
|
|
|
|
{
|
2015-11-15 09:56:34 +00:00
|
|
|
RomName[count] ^= RomName[count + 3];
|
|
|
|
RomName[count + 3] ^= RomName[count];
|
|
|
|
RomName[count] ^= RomName[count + 3];
|
|
|
|
RomName[count + 1] ^= RomName[count + 2];
|
|
|
|
RomName[count + 2] ^= RomName[count + 1];
|
|
|
|
RomName[count + 1] ^= RomName[count + 2];
|
|
|
|
}
|
|
|
|
|
|
|
|
//truncate all the spaces at the end of the string
|
2015-11-15 20:05:55 +00:00
|
|
|
for (count = 19; count >= 0; count--)
|
|
|
|
{
|
|
|
|
if (RomName[count] == ' ')
|
|
|
|
{
|
2015-11-15 09:56:34 +00:00
|
|
|
RomName[count] = '\0';
|
|
|
|
}
|
2015-11-15 20:05:55 +00:00
|
|
|
else if (RomName[count] == '\0')
|
|
|
|
{
|
2015-11-15 09:56:34 +00:00
|
|
|
}
|
2015-11-15 20:05:55 +00:00
|
|
|
else
|
|
|
|
{
|
2015-11-15 09:56:34 +00:00
|
|
|
count = -1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
RomName[20] = '\0';
|
2015-11-15 20:05:55 +00:00
|
|
|
if (strlen(RomName) == 0)
|
|
|
|
{
|
2015-11-15 09:56:34 +00:00
|
|
|
char drive[_MAX_DRIVE], dir[_MAX_DIR], fname[_MAX_FNAME], ext[_MAX_EXT];
|
|
|
|
_splitpath(FileLoc, drive, dir, fname, ext);
|
|
|
|
strcpy(RomName, fname);
|
|
|
|
}
|
|
|
|
|
|
|
|
//remove all /,\,: from the string
|
2015-11-15 20:05:55 +00:00
|
|
|
for (count = 0; count < (int)strlen(RomName); count++)
|
|
|
|
{
|
|
|
|
switch (RomName[count])
|
|
|
|
{
|
2015-11-15 09:56:34 +00:00
|
|
|
case '/': case '\\': RomName[count] = '-'; break;
|
|
|
|
case ':': RomName[count] = ';'; break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
m_RomName = RomName;
|
|
|
|
m_FileName = FileLoc;
|
|
|
|
m_MD5 = "";
|
|
|
|
|
2015-11-15 20:05:55 +00:00
|
|
|
if (!LoadBootCodeOnly)
|
|
|
|
{
|
2015-11-15 09:56:34 +00:00
|
|
|
//Calculate files MD5
|
|
|
|
m_MD5 = MD5((const unsigned char *)m_ROMImage, m_RomFileSize).hex_digest();
|
|
|
|
}
|
|
|
|
|
|
|
|
m_Country = (Country)m_ROMImage[0x3D];
|
|
|
|
m_RomIdent.Format("%08X-%08X-C:%X", *(DWORD *)(&m_ROMImage[0x10]), *(DWORD *)(&m_ROMImage[0x14]), m_ROMImage[0x3D]);
|
|
|
|
CalculateCicChip();
|
|
|
|
|
|
|
|
if (!LoadBootCodeOnly && g_Rom == this)
|
|
|
|
{
|
2015-11-15 20:05:55 +00:00
|
|
|
g_Settings->SaveBool(GameRunning_LoadingInProgress, false);
|
2015-11-15 09:56:34 +00:00
|
|
|
SaveRomSettingID(false);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (g_Settings->LoadBool(Game_CRC_Recalc))
|
|
|
|
{
|
|
|
|
//Calculate ROM Header CRC
|
|
|
|
CalculateRomCrc();
|
|
|
|
}
|
|
|
|
|
|
|
|
return true;
|
2008-09-18 03:15:49 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
//Save the settings of the loaded rom, so all loaded settings about rom will be identified with
|
|
|
|
//this rom
|
2015-11-15 09:56:34 +00:00
|
|
|
void CN64Rom::SaveRomSettingID(bool temp)
|
2008-11-14 20:51:06 +00:00
|
|
|
{
|
2015-11-15 09:56:34 +00:00
|
|
|
g_Settings->SaveBool(Game_TempLoaded, temp);
|
|
|
|
g_Settings->SaveString(Game_GameName, m_RomName.c_str());
|
|
|
|
g_Settings->SaveString(Game_IniKey, m_RomIdent.c_str());
|
|
|
|
|
|
|
|
switch (GetCountry())
|
|
|
|
{
|
|
|
|
case Germany: case french: case Italian:
|
|
|
|
case Europe: case Spanish: case Australia:
|
|
|
|
case X_PAL: case Y_PAL:
|
|
|
|
g_Settings->SaveDword(Game_SystemType, SYSTEM_PAL);
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
g_Settings->SaveDword(Game_SystemType, SYSTEM_NTSC);
|
|
|
|
break;
|
|
|
|
}
|
2008-11-14 20:51:06 +00:00
|
|
|
}
|
|
|
|
|
2015-04-28 22:19:02 +00:00
|
|
|
void CN64Rom::ClearRomSettingID()
|
2008-11-14 20:51:06 +00:00
|
|
|
{
|
2015-11-15 09:56:34 +00:00
|
|
|
g_Settings->SaveString(Game_GameName, "");
|
|
|
|
g_Settings->SaveString(Game_IniKey, "");
|
2008-09-18 03:15:49 +00:00
|
|
|
}
|
|
|
|
|
2015-04-28 22:19:02 +00:00
|
|
|
void CN64Rom::SetError(LanguageStringID ErrorMsg)
|
|
|
|
{
|
2015-11-15 09:56:34 +00:00
|
|
|
m_ErrorMsg = ErrorMsg;
|
2008-09-18 03:15:49 +00:00
|
|
|
}
|
|
|
|
|
2015-04-28 22:19:02 +00:00
|
|
|
void CN64Rom::UnallocateRomImage()
|
|
|
|
{
|
2015-11-15 20:05:55 +00:00
|
|
|
if (m_hRomFileMapping)
|
|
|
|
{
|
2015-11-15 09:56:34 +00:00
|
|
|
UnmapViewOfFile(m_ROMImage);
|
2008-09-18 03:15:49 +00:00
|
|
|
CloseHandle(m_hRomFileMapping);
|
2015-11-15 09:56:34 +00:00
|
|
|
m_ROMImage = NULL;
|
|
|
|
m_hRomFileMapping = NULL;
|
|
|
|
}
|
2015-11-15 20:05:55 +00:00
|
|
|
if (m_hRomFile)
|
|
|
|
{
|
2008-09-18 03:15:49 +00:00
|
|
|
CloseHandle(m_hRomFile);
|
2015-11-15 09:56:34 +00:00
|
|
|
m_hRomFile = NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
//if this value is still set then the image was not created a map
|
|
|
|
//file but created with VirtualAllocate
|
2015-11-15 20:05:55 +00:00
|
|
|
if (m_ROMImage)
|
|
|
|
{
|
2015-11-15 09:56:34 +00:00
|
|
|
VirtualFree(m_ROMImage, 0, MEM_RELEASE);
|
|
|
|
m_ROMImage = NULL;
|
|
|
|
}
|
|
|
|
}
|