mirror of
https://github.com/libretro/Mesen.git
synced 2024-11-24 01:29:41 +00:00
237 lines
4.4 KiB
C++
237 lines
4.4 KiB
C++
#pragma once
|
|
|
|
#include "stdafx.h"
|
|
#include "../Utilities/FolderUtilities.h"
|
|
#include "../Utilities/ZIPReader.h"
|
|
#include "../Utilities/CRC32.h"
|
|
|
|
enum class MirroringType
|
|
{
|
|
Horizontal,
|
|
Vertical,
|
|
ScreenAOnly,
|
|
ScreenBOnly,
|
|
FourScreens,
|
|
};
|
|
|
|
struct NESHeader
|
|
{
|
|
char NES[4];
|
|
uint8_t ROMCount;
|
|
uint8_t VROMCount;
|
|
uint8_t Flags1;
|
|
uint8_t Flags2;
|
|
uint8_t RAMCount;
|
|
uint8_t CartType;
|
|
uint8_t Reserved[6];
|
|
|
|
uint8_t GetMapperID()
|
|
{
|
|
return (Flags2 & 0xF0) | (Flags1 >> 4);
|
|
}
|
|
|
|
bool HasBattery()
|
|
{
|
|
return (Flags1 & 0x02) == 0x02;
|
|
}
|
|
|
|
bool HasTrainer()
|
|
{
|
|
return (Flags1 & 0x04) == 0x04;
|
|
}
|
|
|
|
MirroringType GetMirroringType()
|
|
{
|
|
if(Flags1 & 0x08) {
|
|
return MirroringType::FourScreens;
|
|
} else {
|
|
return Flags1 & 0x01 ? MirroringType::Vertical : MirroringType::Horizontal;
|
|
}
|
|
}
|
|
};
|
|
|
|
class ROMLoader
|
|
{
|
|
private:
|
|
NESHeader _header;
|
|
wstring _filename;
|
|
uint8_t* _prgRAM = nullptr;
|
|
uint8_t* _chrRAM = nullptr;
|
|
uint32_t _crc32;
|
|
|
|
bool LoadFromZIP(ifstream &zipFile)
|
|
{
|
|
bool result = false;
|
|
|
|
uint32_t fileSize;
|
|
uint8_t* buffer = ReadFile(zipFile, fileSize);
|
|
|
|
ZIPReader reader;
|
|
reader.LoadZIPArchive(buffer, fileSize);
|
|
|
|
vector<string> fileList = reader.GetFileList();
|
|
for(string filename : fileList) {
|
|
std::transform(filename.begin(), filename.end(), filename.begin(), ::tolower);
|
|
if(filename.length() > 4) {
|
|
if(filename.substr(filename.length() - 4, 4).compare(".nes") == 0) {
|
|
uint8_t* fileBuffer = nullptr;
|
|
size_t fileSize = 0;
|
|
reader.ExtractFile(filename, &fileBuffer, fileSize);
|
|
if(fileBuffer) {
|
|
result = LoadFromMemory(fileBuffer, fileSize);
|
|
delete[] fileBuffer;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
delete[] buffer;
|
|
return result;
|
|
}
|
|
|
|
bool LoadFromFile(ifstream &romFile)
|
|
{
|
|
uint32_t fileSize;
|
|
uint8_t* buffer = ReadFile(romFile, fileSize);
|
|
bool result = LoadFromMemory(buffer, fileSize);
|
|
delete[] buffer;
|
|
|
|
return result;
|
|
}
|
|
|
|
uint32_t GetFileSize(ifstream &file)
|
|
{
|
|
file.seekg(0, ios::end);
|
|
uint32_t fileSize = (uint32_t)file.tellg();
|
|
file.seekg(0, ios::beg);
|
|
|
|
return fileSize;
|
|
}
|
|
|
|
uint8_t* ReadFile(ifstream &file, uint32_t &fileSize)
|
|
{
|
|
fileSize = GetFileSize(file);
|
|
|
|
uint8_t* buffer = new uint8_t[fileSize];
|
|
file.read((char*)buffer, fileSize);
|
|
return buffer;
|
|
}
|
|
|
|
bool LoadFromMemory(uint8_t* buffer, uint32_t length)
|
|
{
|
|
_crc32 = CRC32::GetCRC(buffer, length);
|
|
if(memcmp(buffer, "NES", 3) == 0) {
|
|
memcpy((char*)&_header, buffer, sizeof(NESHeader));
|
|
|
|
_prgRAM = new uint8_t[0x4000 * _header.ROMCount];
|
|
_chrRAM = new uint8_t[0x2000 * _header.VROMCount];
|
|
|
|
buffer += sizeof(NESHeader);
|
|
memcpy(_prgRAM, buffer, 0x4000 * _header.ROMCount);
|
|
|
|
buffer += 0x4000 * _header.ROMCount;
|
|
memcpy(_chrRAM, buffer, 0x2000 * _header.VROMCount);
|
|
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
public:
|
|
ROMLoader()
|
|
{
|
|
}
|
|
|
|
~ROMLoader()
|
|
{
|
|
if(_prgRAM) {
|
|
delete[] _prgRAM;
|
|
_prgRAM = nullptr;
|
|
}
|
|
if(_chrRAM) {
|
|
delete[] _chrRAM;
|
|
_chrRAM = nullptr;
|
|
}
|
|
}
|
|
|
|
bool LoadFile(wstring filename)
|
|
{
|
|
bool result = false;
|
|
ifstream file(filename, ios::in | ios::binary);
|
|
if(file) {
|
|
char header[3];
|
|
file.read(header, 3);
|
|
if(memcmp(header, "NES", 3) == 0) {
|
|
_filename = FolderUtilities::GetFilename(filename, false);
|
|
file.seekg(0, ios::beg);
|
|
result = LoadFromFile(file);
|
|
file.close();
|
|
} else if(memcmp(header, "PK", 2) == 0) {
|
|
_filename = FolderUtilities::GetFilename(filename, false);
|
|
file.seekg(0, ios::beg);
|
|
result = LoadFromZIP(file);
|
|
} else {
|
|
//Unsupported file format
|
|
file.close();
|
|
}
|
|
file.close();
|
|
}
|
|
return result;
|
|
}
|
|
|
|
void GetPRGRam(uint8_t** buffer)
|
|
{
|
|
*buffer = new uint8_t[GetPRGSize()];
|
|
memcpy(*buffer, _prgRAM, GetPRGSize());
|
|
}
|
|
|
|
void GetCHRRam(uint8_t** buffer)
|
|
{
|
|
*buffer = new uint8_t[GetCHRSize()];
|
|
memcpy(*buffer, _chrRAM, GetCHRSize());
|
|
}
|
|
|
|
uint32_t GetPRGSize()
|
|
{
|
|
return _header.ROMCount * 0x4000;
|
|
}
|
|
|
|
uint32_t GetCHRSize()
|
|
{
|
|
return _header.VROMCount * 0x2000;
|
|
}
|
|
|
|
MirroringType GetMirroringType()
|
|
{
|
|
return _header.GetMirroringType();
|
|
}
|
|
|
|
uint8_t GetMapperID()
|
|
{
|
|
return _header.GetMapperID();
|
|
}
|
|
|
|
bool HasBattery()
|
|
{
|
|
return _header.HasBattery();
|
|
}
|
|
|
|
wstring GetFilename()
|
|
{
|
|
return _filename;
|
|
}
|
|
|
|
static uint32_t GetCRC32(wstring filename)
|
|
{
|
|
ROMLoader loader;
|
|
uint32_t crc = 0;
|
|
if(loader.LoadFile(filename)) {
|
|
crc = loader._crc32;
|
|
}
|
|
return crc;
|
|
}
|
|
};
|
|
|