Code refactoring (patch/archive handling) + allow HD packs to be loaded from archives

This commit is contained in:
Souryo 2017-07-30 09:03:54 -04:00
parent 119ccd5881
commit 4455178da2
56 changed files with 890 additions and 685 deletions

View file

@ -521,9 +521,9 @@ void BaseMapper::Initialize(RomData &romData)
_gameSystem = romData.System; _gameSystem = romData.System;
_hashInfo.Crc32Hash = romData.Crc32; _hashInfo.Crc32Hash = romData.Crc32;
_hashInfo.PrgCrc32Hash = romData.PrgCrc32;
_hashInfo.Sha1Hash = romData.Sha1; _hashInfo.Sha1Hash = romData.Sha1;
_hashInfo.PrgChrMd5Hash = romData.PrgChrMd5; _hashInfo.PrgChrMd5Hash = romData.PrgChrMd5;
_prgCrc32 = romData.PrgCrc32;
switch(romData.BusConflicts) { switch(romData.BusConflicts) {
case BusConflictType::Default: _hasBusConflicts = HasBusConflicts(); break; case BusConflictType::Default: _hasBusConflicts = HasBusConflicts(); break;
case BusConflictType::Yes: _hasBusConflicts = true; break; case BusConflictType::Yes: _hasBusConflicts = true; break;
@ -717,11 +717,6 @@ HashInfo BaseMapper::GetHashInfo()
return _hashInfo; return _hashInfo;
} }
uint32_t BaseMapper::GetPrgCrc32()
{
return _prgCrc32;
}
MirroringType BaseMapper::GetMirroringType() MirroringType BaseMapper::GetMirroringType()
{ {
return _mirroringType; return _mirroringType;

View file

@ -46,7 +46,6 @@ private:
uint32_t _chrPageNumbers[64]; uint32_t _chrPageNumbers[64];
HashInfo _hashInfo; HashInfo _hashInfo;
uint32_t _prgCrc32 = 0;
vector<uint8_t> _originalPrgRom; vector<uint8_t> _originalPrgRom;
@ -164,7 +163,6 @@ public:
GameSystem GetGameSystem(); GameSystem GetGameSystem();
HashInfo GetHashInfo(); HashInfo GetHashInfo();
uint32_t GetPrgCrc32();
string GetRomName(); string GetRomName();
RomFormat GetRomFormat(); RomFormat GetRomFormat();

View file

@ -81,8 +81,9 @@ bool BizhawkMovie::InitializeGameData(ZipReader & reader)
std::getline(ss, line); std::getline(ss, line);
if(line.compare(0, 4, "SHA1", 4) == 0) { if(line.compare(0, 4, "SHA1", 4) == 0) {
if(line.size() >= 45) { if(line.size() >= 45) {
string sha1 = line.substr(5, 40); HashInfo hashInfo;
if(Console::LoadROM("", sha1)) { hashInfo.Sha1Hash = line.substr(5, 40);
if(Console::LoadROM("", hashInfo)) {
result = true; result = true;
} }
} }

View file

@ -1,7 +1,6 @@
#include "stdafx.h" #include "stdafx.h"
#include <thread> #include <thread>
#include "Console.h" #include "Console.h"
#include "FileLoader.h"
#include "CPU.h" #include "CPU.h"
#include "PPU.h" #include "PPU.h"
#include "APU.h" #include "APU.h"
@ -19,6 +18,7 @@
#include "../Utilities/Timer.h" #include "../Utilities/Timer.h"
#include "../Utilities/FolderUtilities.h" #include "../Utilities/FolderUtilities.h"
#include "../Utilities/PlatformUtilities.h" #include "../Utilities/PlatformUtilities.h"
#include "../Utilities/VirtualFile.h"
#include "HdBuilderPpu.h" #include "HdBuilderPpu.h"
#include "HdPpu.h" #include "HdPpu.h"
#include "NsfPpu.h" #include "NsfPpu.h"
@ -36,7 +36,6 @@ Console::Console()
{ {
_resetRequested = false; _resetRequested = false;
_lagCounter = 0; _lagCounter = 0;
_archiveFileIndex = -1;
} }
Console::~Console() Console::~Console()
@ -55,7 +54,7 @@ void Console::Release()
Console::Instance.reset(new Console()); Console::Instance.reset(new Console());
} }
bool Console::Initialize(string romFilename, stringstream *filestream, string patchFilename, int32_t archiveFileIndex) bool Console::Initialize(VirtualFile &romFile, VirtualFile &patchFile)
{ {
SoundMixer::StopAudio(); SoundMixer::StopAudio();
@ -64,26 +63,30 @@ bool Console::Initialize(string romFilename, stringstream *filestream, string pa
_mapper->SaveBattery(); _mapper->SaveBattery();
//Save current game state before loading another one //Save current game state before loading another one
SaveStateManager::SaveRecentGame(_mapper->GetRomName(), _romFilepath, _patchFilename, _archiveFileIndex); SaveStateManager::SaveRecentGame(_mapper->GetRomName(), _romFilepath, _patchFilename);
} }
if(romFile.IsValid()) {
LoadHdPack(romFile, patchFile);
if(patchFile.IsValid()) {
if(romFile.ApplyPatch(patchFile)) {
MessageManager::DisplayMessage("Patch", "ApplyingPatch", FolderUtilities::GetFilename(patchFile.GetFilePath(), true));
} else {
//Patch failed
}
}
vector<uint8_t> fileData; vector<uint8_t> fileData;
if(FileLoader::LoadFile(romFilename, filestream, archiveFileIndex, fileData)) { romFile.ReadFile(fileData);
LoadHdPack(romFilename, fileData, patchFilename);
if(!patchFilename.empty()) {
FileLoader::ApplyPatch(patchFilename, fileData);
}
shared_ptr<BaseMapper> mapper = MapperFactory::InitializeFromFile(romFilename, fileData); shared_ptr<BaseMapper> mapper = MapperFactory::InitializeFromFile(romFile.GetFileName(), fileData);
if(mapper) { if(mapper) {
if(_mapper) { if(_mapper) {
//Send notification only if a game was already running and we successfully loaded the new one //Send notification only if a game was already running and we successfully loaded the new one
MessageManager::SendNotification(ConsoleNotificationType::GameStopped); MessageManager::SendNotification(ConsoleNotificationType::GameStopped);
} }
_romFilepath = romFilename; _romFilepath = romFile;
_patchFilename = patchFilename; _patchFilename = patchFile;
_archiveFileIndex = archiveFileIndex;
_autoSaveManager.reset(new AutoSaveManager()); _autoSaveManager.reset(new AutoSaveManager());
VideoDecoder::GetInstance()->StopThread(); VideoDecoder::GetInstance()->StopThread();
@ -128,7 +131,7 @@ bool Console::Initialize(string romFilename, stringstream *filestream, string pa
VideoDecoder::GetInstance()->StartThread(); VideoDecoder::GetInstance()->StartThread();
FolderUtilities::AddKnownGameFolder(FolderUtilities::GetFolderName(romFilename)); FolderUtilities::AddKnownGameFolder(romFile.GetFolderPath());
string modelName = _model == NesModel::PAL ? "PAL" : (_model == NesModel::Dendy ? "Dendy" : "NTSC"); string modelName = _model == NesModel::PAL ? "PAL" : (_model == NesModel::Dendy ? "Dendy" : "NTSC");
string messageTitle = MessageManager::Localize("GameLoaded") + " (" + modelName + ")"; string messageTitle = MessageManager::Localize("GameLoaded") + " (" + modelName + ")";
@ -140,35 +143,21 @@ bool Console::Initialize(string romFilename, stringstream *filestream, string pa
} }
} }
MessageManager::DisplayMessage("Error", "CouldNotLoadFile", FolderUtilities::GetFilename(romFilename, true)); MessageManager::DisplayMessage("Error", "CouldNotLoadFile", romFile.GetFileName());
return false; return false;
} }
bool Console::LoadROM(string filepath, stringstream *filestream, int32_t archiveFileIndex, string patchFilepath) bool Console::LoadROM(VirtualFile romFile, VirtualFile patchFile)
{ {
Console::Pause(); Console::Pause();
bool result = Instance->Initialize(filepath, filestream, patchFilepath, archiveFileIndex); bool result = Instance->Initialize(romFile, patchFile);
Console::Resume(); Console::Resume();
return result; return result;
} }
bool Console::LoadROM(string romName, uint32_t crc32Hash)
{
HashInfo hashInfo;
hashInfo.Crc32Hash = crc32Hash;
return Console::LoadROM(romName, hashInfo);
}
bool Console::LoadROM(string romName, string sha1Hash)
{
HashInfo hashInfo;
hashInfo.Sha1Hash = sha1Hash;
return Console::LoadROM(romName, hashInfo);
}
bool Console::LoadROM(string romName, HashInfo hashInfo) bool Console::LoadROM(string romName, HashInfo hashInfo)
{ {
string currentRomFilepath = Console::GetROMPath(); string currentRomFilepath = Console::GetRomPath();
string currentFolder = FolderUtilities::GetFolderName(currentRomFilepath); string currentFolder = FolderUtilities::GetFolderName(currentRomFilepath);
if(!currentRomFilepath.empty()) { if(!currentRomFilepath.empty()) {
HashInfo gameHashInfo = Instance->_mapper->GetHashInfo(); HashInfo gameHashInfo = Instance->_mapper->GetHashInfo();
@ -178,28 +167,27 @@ bool Console::LoadROM(string romName, HashInfo hashInfo)
} }
} }
int32_t archiveFileIndex = -1;
for(string folder : FolderUtilities::GetKnownGameFolders()) { for(string folder : FolderUtilities::GetKnownGameFolders()) {
string match = RomLoader::FindMatchingRomInFolder(folder, romName, hashInfo, true, archiveFileIndex); string match = RomLoader::FindMatchingRomInFolder(folder, romName, hashInfo, true);
if(!match.empty()) { if(!match.empty()) {
return Console::LoadROM(match, nullptr, archiveFileIndex); return Console::LoadROM(match);
} }
} }
//Perform slow CRC32 search for ROM //Perform slow CRC32 search for ROM
for(string folder : FolderUtilities::GetKnownGameFolders()) { for(string folder : FolderUtilities::GetKnownGameFolders()) {
string match = RomLoader::FindMatchingRomInFolder(folder, romName, hashInfo, false, archiveFileIndex); string match = RomLoader::FindMatchingRomInFolder(folder, romName, hashInfo, false);
if(!match.empty()) { if(!match.empty()) {
return Console::LoadROM(match, nullptr, archiveFileIndex); return Console::LoadROM(match);
} }
} }
return false; return false;
} }
string Console::GetROMPath() string Console::GetRomPath()
{ {
return Instance->_romFilepath; return static_cast<VirtualFile>(Instance->_romFilepath).GetFilePath();
} }
string Console::GetRomName() string Console::GetRomName()
@ -229,24 +217,14 @@ bool Console::IsChrRam()
} }
} }
uint32_t Console::GetCrc32() HashInfo Console::GetHashInfo()
{ {
if(Instance->_mapper) { if(Instance->_mapper) {
return Instance->_mapper->GetHashInfo().Crc32Hash; return Instance->_mapper->GetHashInfo();
} else { } else {
return 0; return {};
} }
} }
uint32_t Console::GetPrgCrc32()
{
if(Instance->_mapper) {
return Instance->_mapper->GetPrgCrc32();
} else {
return 0;
}
}
NesModel Console::GetModel() NesModel Console::GetModel()
{ {
return Instance->_model; return Instance->_model;
@ -255,7 +233,7 @@ NesModel Console::GetModel()
void Console::PowerCycle() void Console::PowerCycle()
{ {
if(Instance->_initialized && !Instance->_romFilepath.empty()) { if(Instance->_initialized && !Instance->_romFilepath.empty()) {
LoadROM(Instance->_romFilepath, nullptr, Instance->_archiveFileIndex, Instance->_patchFilename); LoadROM(Instance->_romFilepath, Instance->_patchFilename);
} }
} }
@ -274,7 +252,7 @@ void Console::Reset(bool softReset)
Instance->ResetComponents(softReset); Instance->ResetComponents(softReset);
} else { } else {
//Full reset of all objects to ensure the emulator always starts in the exact same state //Full reset of all objects to ensure the emulator always starts in the exact same state
Instance->Initialize(Instance->_romFilepath); LoadROM(Instance->_romFilepath, Instance->_patchFilename);
} }
Console::Resume(); Console::Resume();
} }
@ -458,7 +436,7 @@ void Console::Run()
} }
if(!crashed) { if(!crashed) {
SaveStateManager::SaveRecentGame(_mapper->GetRomName(), _romFilepath, _patchFilename, _archiveFileIndex); SaveStateManager::SaveRecentGame(_mapper->GetRomName(), _romFilepath, _patchFilename);
} }
MessageManager::SendNotification(ConsoleNotificationType::GameStopped); MessageManager::SendNotification(ConsoleNotificationType::GameStopped);
@ -641,20 +619,17 @@ HdPackData* Console::GetHdData()
return Instance->_hdData.get(); return Instance->_hdData.get();
} }
void Console::LoadHdPack(string romFilename, vector<uint8_t> &fileData, string &patchFilename) void Console::LoadHdPack(VirtualFile &romFile, VirtualFile &patchFile)
{ {
_hdData.reset(); _hdData.reset();
if(EmulationSettings::CheckFlag(EmulationFlags::UseHdPacks)) { if(EmulationSettings::CheckFlag(EmulationFlags::UseHdPacks)) {
string hdPackFolder = FolderUtilities::CombinePath(FolderUtilities::GetHdPackFolder(), FolderUtilities::GetFilename(romFilename, false));
string hdPackDefinitionFile = FolderUtilities::CombinePath(hdPackFolder, "hires.txt");
_hdData.reset(new HdPackData()); _hdData.reset(new HdPackData());
if(!HdPackLoader::LoadHdNesPack(hdPackDefinitionFile, *_hdData.get())) { if(!HdPackLoader::LoadHdNesPack(romFile, *_hdData.get())) {
_hdData.reset(); _hdData.reset();
} else { } else {
string sha1hash = SHA1::GetHash(fileData); auto result = _hdData->PatchesByHash.find(romFile.GetSha1Hash());
auto result = _hdData->PatchesByHash.find(sha1hash);
if(result != _hdData->PatchesByHash.end()) { if(result != _hdData->PatchesByHash.end()) {
patchFilename = FolderUtilities::CombinePath(hdPackFolder, result->second); patchFile = result->second;
} }
} }
} }

View file

@ -3,6 +3,7 @@
#include "stdafx.h" #include "stdafx.h"
#include <atomic> #include <atomic>
#include "../Utilities/SimpleLock.h" #include "../Utilities/SimpleLock.h"
#include "../Utilities/VirtualFile.h"
#include "RomData.h" #include "RomData.h"
class Debugger; class Debugger;
@ -46,7 +47,6 @@ class Console
string _romFilepath; string _romFilepath;
string _patchFilename; string _patchFilename;
int32_t _archiveFileIndex;
bool _stop = false; bool _stop = false;
@ -57,10 +57,10 @@ class Console
bool _initialized = false; bool _initialized = false;
void LoadHdPack(string romFilename, vector<uint8_t> &fileData, string &patchFilename); void LoadHdPack(VirtualFile &romFile, VirtualFile &patchFile);
void ResetComponents(bool softReset); void ResetComponents(bool softReset);
bool Initialize(string filename, stringstream *filestream = nullptr, string patchFilename = "", int32_t archiveFileIndex = -1); bool Initialize(VirtualFile &romFile, VirtualFile &patchFile);
void UpdateNesModel(bool sendNotification); void UpdateNesModel(bool sendNotification);
double GetFrameDelay(); double GetFrameDelay();
@ -86,16 +86,13 @@ class Console
static void LoadState(istream &loadStream); static void LoadState(istream &loadStream);
static void LoadState(uint8_t *buffer, uint32_t bufferSize); static void LoadState(uint8_t *buffer, uint32_t bufferSize);
static bool LoadROM(string filepath, stringstream *filestream = nullptr, int32_t archiveFileIndex = -1, string patchFilepath = ""); static bool LoadROM(VirtualFile romFile, VirtualFile patchFile = {});
static bool LoadROM(string romName, HashInfo hashInfo); static bool LoadROM(string romName, HashInfo hashInfo);
static bool LoadROM(string romName, uint32_t crc32Hash); static string GetRomPath();
static bool LoadROM(string romName, string sha1Hash);
static string GetROMPath();
static string GetRomName(); static string GetRomName();
static bool IsChrRam(); static bool IsChrRam();
static RomFormat GetRomFormat(); static RomFormat GetRomFormat();
static uint32_t GetCrc32(); static HashInfo GetHashInfo();
static uint32_t GetPrgCrc32();
static NesModel GetModel(); static NesModel GetModel();
static uint32_t GetLagCounter(); static uint32_t GetLagCounter();

View file

@ -413,7 +413,6 @@
<ClInclude Include="AutomaticRomTest.h" /> <ClInclude Include="AutomaticRomTest.h" />
<ClInclude Include="BaseRenderer.h" /> <ClInclude Include="BaseRenderer.h" />
<ClInclude Include="FceuxMovie.h" /> <ClInclude Include="FceuxMovie.h" />
<ClInclude Include="FileLoader.h" />
<ClInclude Include="HdBuilderPpu.h" /> <ClInclude Include="HdBuilderPpu.h" />
<ClInclude Include="HdData.h" /> <ClInclude Include="HdData.h" />
<ClInclude Include="HdPackBuilder.h" /> <ClInclude Include="HdPackBuilder.h" />
@ -779,7 +778,6 @@
<ClCompile Include="AutomaticRomTest.cpp" /> <ClCompile Include="AutomaticRomTest.cpp" />
<ClCompile Include="BaseRenderer.cpp" /> <ClCompile Include="BaseRenderer.cpp" />
<ClCompile Include="FceuxMovie.cpp" /> <ClCompile Include="FceuxMovie.cpp" />
<ClCompile Include="FileLoader.cpp" />
<ClCompile Include="HdNesPack.cpp" /> <ClCompile Include="HdNesPack.cpp" />
<ClCompile Include="HdPackBuilder.cpp" /> <ClCompile Include="HdPackBuilder.cpp" />
<ClCompile Include="HdPackLoader.cpp" /> <ClCompile Include="HdPackLoader.cpp" />

View file

@ -1192,9 +1192,6 @@
<ClInclude Include="HdPackLoader.h"> <ClInclude Include="HdPackLoader.h">
<Filter>VideoDecoder\HD</Filter> <Filter>VideoDecoder\HD</Filter>
</ClInclude> </ClInclude>
<ClInclude Include="FileLoader.h">
<Filter>Nes\RomLoader</Filter>
</ClInclude>
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<ClCompile Include="stdafx.cpp"> <ClCompile Include="stdafx.cpp">
@ -1428,8 +1425,5 @@
<ClCompile Include="HdNesPack.cpp"> <ClCompile Include="HdNesPack.cpp">
<Filter>VideoDecoder\HD</Filter> <Filter>VideoDecoder\HD</Filter>
</ClCompile> </ClCompile>
<ClCompile Include="FileLoader.cpp">
<Filter>Misc</Filter>
</ClCompile>
</ItemGroup> </ItemGroup>
</Project> </Project>

View file

@ -152,7 +152,10 @@ public:
{ {
//Apply save data (saved as an IPS file), if found //Apply save data (saved as an IPS file), if found
string fdsSaveFilepath = FolderUtilities::CombinePath(FolderUtilities::GetSaveFolder(), FolderUtilities::GetFilename(filename, false) + ".ips"); string fdsSaveFilepath = FolderUtilities::CombinePath(FolderUtilities::GetSaveFolder(), FolderUtilities::GetFilename(filename, false) + ".ips");
romFile = IpsPatcher::PatchBuffer(fdsSaveFilepath, romFile); vector<uint8_t> patchedData;
if(IpsPatcher::PatchBuffer(fdsSaveFilepath, romFile, patchedData)) {
romFile = patchedData;
}
RomData romData; RomData romData;

View file

@ -1,112 +0,0 @@
#include "stdafx.h"
#include "FileLoader.h"
#include "../Utilities/ZipReader.h"
#include "../Utilities/SZReader.h"
#include "../Utilities/BpsPatcher.h"
#include "../Utilities/IpsPatcher.h"
#include "../Utilities/UpsPatcher.h"
#include "../Utilities/FolderUtilities.h"
#include "MessageManager.h"
void FileLoader::ReadFile(istream &file, vector<uint8_t> &fileData)
{
file.seekg(0, ios::end);
uint32_t fileSize = (uint32_t)file.tellg();
file.seekg(0, ios::beg);
fileData = vector<uint8_t>(fileSize, 0);
file.read((char*)fileData.data(), fileSize);
}
bool FileLoader::LoadFromArchive(istream &zipFile, ArchiveReader &reader, int32_t archiveFileIndex, vector<uint8_t> &fileData)
{
ReadFile(zipFile, fileData);
reader.LoadArchive(fileData.data(), fileData.size());
vector<string> fileList = reader.GetFileList({ ".nes", ".fds", ".nsf", ".nsfe", ".unf" });
if(fileList.empty() || archiveFileIndex > (int32_t)fileList.size()) {
return false;
}
if(archiveFileIndex == -1) {
archiveFileIndex = 0;
}
reader.ExtractFile(fileList[archiveFileIndex], fileData);
return true;
}
bool FileLoader::LoadFile(string filename, istream *filestream, int32_t archiveFileIndex, vector<uint8_t> &fileData)
{
ifstream file;
istream* input = nullptr;
if(!filestream) {
file.open(filename, ios::in | ios::binary);
if(file) {
input = &file;
}
} else {
input = filestream;
}
if(input) {
char header[15];
input->seekg(0, ios::beg);
input->read(header, 15);
input->seekg(0, ios::beg);
if(memcmp(header, "PK", 2) == 0) {
ZipReader reader;
return LoadFromArchive(*input, reader, archiveFileIndex, fileData);
} else if(memcmp(header, "7z", 2) == 0) {
SZReader reader;
return LoadFromArchive(*input, reader, archiveFileIndex, fileData);
} else {
if(archiveFileIndex > 0) {
return false;
}
ReadFile(*input, fileData);
return true;
}
}
return false;
}
void FileLoader::ApplyPatch(string patchPath, vector<uint8_t> &fileData)
{
//Apply patch file
MessageManager::DisplayMessage("Patch", "ApplyingPatch", FolderUtilities::GetFilename(patchPath, true));
ifstream patchFile(patchPath, ios::binary | ios::in);
if(patchFile.good()) {
char buffer[5] = {};
patchFile.read(buffer, 5);
patchFile.close();
if(memcmp(buffer, "PATCH", 5) == 0) {
fileData = IpsPatcher::PatchBuffer(patchPath, fileData);
} else if(memcmp(buffer, "UPS1", 4) == 0) {
fileData = UpsPatcher::PatchBuffer(patchPath, fileData);
} else if(memcmp(buffer, "BPS1", 4) == 0) {
fileData = BpsPatcher::PatchBuffer(patchPath, fileData);
}
}
}
vector<string> FileLoader::GetArchiveRomList(string filename)
{
ifstream in(filename, ios::in | ios::binary);
if(in) {
uint8_t header[2];
in.read((char*)header, 2);
in.close();
if(memcmp(header, "PK", 2) == 0) {
ZipReader reader;
reader.LoadArchive(filename);
return reader.GetFileList({ ".nes", ".fds", ".nsf", ".nsfe", "*.unf" });
} else if(memcmp(header, "7z", 2) == 0) {
SZReader reader;
reader.LoadArchive(filename);
return reader.GetFileList({ ".nes", ".fds", ".nsf", ".nsfe", "*.unf" });
}
}
return{};
}

View file

@ -1,15 +0,0 @@
#pragma once
#include "stdafx.h"
#include "../Utilities/ArchiveReader.h"
class FileLoader
{
private:
static void ReadFile(istream &file, vector<uint8_t> &fileData);
static bool LoadFromArchive(istream &zipFile, ArchiveReader& reader, int32_t archiveFileIndex, vector<uint8_t> &fileData);
public:
static bool LoadFile(string filename, istream *filestream, int32_t archiveFileIndex, vector<uint8_t> &fileData);
static void ApplyPatch(string patchPath, vector<uint8_t> &fileData);
static vector<string> GetArchiveRomList(string filename);
};

View file

@ -39,7 +39,9 @@ public:
{ {
string filename = _romFilename; string filename = _romFilename;
if(filename.size() > 0) { if(filename.size() > 0) {
if(Console::LoadROM(filename, _crc32Hash)) { HashInfo hashInfo;
hashInfo.Crc32Hash = _crc32Hash;
if(Console::LoadROM(filename, hashInfo)) {
return true; return true;
} else { } else {
MessageManager::DisplayMessage("NetPlay", "CouldNotFindRom"); MessageManager::DisplayMessage("NetPlay", "CouldNotFindRom");

View file

@ -38,7 +38,7 @@ GameServerConnection::~GameServerConnection()
void GameServerConnection::SendGameInformation() void GameServerConnection::SendGameInformation()
{ {
Console::Pause(); Console::Pause();
GameInformationMessage gameInfo(Console::GetRomName(), Console::GetCrc32(), _controllerPort, EmulationSettings::CheckFlag(EmulationFlags::Paused)); GameInformationMessage gameInfo(Console::GetRomName(), Console::GetHashInfo().Crc32Hash, _controllerPort, EmulationSettings::CheckFlag(EmulationFlags::Paused));
SendNetMessage(gameInfo); SendNetMessage(gameInfo);
SaveStateMessage saveState; SaveStateMessage saveState;
SendNetMessage(saveState); SendNetMessage(saveState);

View file

@ -1,5 +1,6 @@
#include <algorithm> #include <algorithm>
#include "stdafx.h" #include "stdafx.h"
#include "../Utilities/VirtualFile.h"
#include "HdPackBuilder.h" #include "HdPackBuilder.h"
HdPackBuilder* HdPackBuilder::_instance = nullptr; HdPackBuilder* HdPackBuilder::_instance = nullptr;
@ -197,6 +198,7 @@ void HdPackBuilder::SaveHdPack()
int pngIndex = 0; int pngIndex = 0;
ss << "<ver>100" << std::endl; ss << "<ver>100" << std::endl;
ss << "<scale>" << _hdData.Scale << std::endl; ss << "<scale>" << _hdData.Scale << std::endl;
ss << "<supportedRom>" << Console::GetRomName() << std::endl;
int tileDimension = 8 * _hdData.Scale; int tileDimension = 8 * _hdData.Scale;
int pngDimension = 16 * tileDimension; int pngDimension = 16 * tileDimension;
@ -238,26 +240,6 @@ void HdPackBuilder::SaveHdPack()
}; };
for(std::pair<const uint32_t, std::map<uint32_t, vector<HdPackTileInfo*>>> &kvp : _tilesByChrBankByPalette) { for(std::pair<const uint32_t, std::map<uint32_t, vector<HdPackTileInfo*>>> &kvp : _tilesByChrBankByPalette) {
/*if(true) { //flatten palette
for(int i = 0; i < 256; i++) {
auto readItt = kvp.second.begin();
auto writeItt = kvp.second.begin();
while(writeItt != kvp.second.end() && writeItt->second[i]) {
readItt++;
writeItt++;
}
for(; readItt != kvp.second.end() && writeItt != kvp.second.end(); readItt++) {
if(writeItt->second[i] == nullptr && readItt->second[i] != nullptr) {
writeItt->second[i] = readItt->second[i];
readItt->second[i] = nullptr;
while(writeItt != kvp.second.end() && writeItt->second[i]) {
writeItt++;
}
}
}
}
}*/
if(_flags & HdPackRecordFlags::SortByUsageFrequency) { if(_flags & HdPackRecordFlags::SortByUsageFrequency) {
for(int i = 0; i < 256; i++) { for(int i = 0; i < 256; i++) {
vector<std::pair<uint32_t, HdPackTileInfo*>> tiles; vector<std::pair<uint32_t, HdPackTileInfo*>> tiles;

View file

@ -1,6 +1,7 @@
#include "stdafx.h" #include "stdafx.h"
#include <algorithm> #include <algorithm>
#include <unordered_map> #include <unordered_map>
#include "../Utilities/ZipReader.h"
#include "../Utilities/FolderUtilities.h" #include "../Utilities/FolderUtilities.h"
#include "../Utilities/StringUtilities.h" #include "../Utilities/StringUtilities.h"
#include "../Utilities/HexUtilities.h" #include "../Utilities/HexUtilities.h"
@ -8,32 +9,110 @@
#include "Console.h" #include "Console.h"
#include "HdPackLoader.h" #include "HdPackLoader.h"
HdPackLoader::HdPackLoader(string hdPackDefinitionFile, HdPackData *data) HdPackLoader::HdPackLoader()
{ {
_hdPackDefinitionFile = hdPackDefinitionFile;
_hdPackFolder = FolderUtilities::GetFolderName(_hdPackDefinitionFile);
_data = data;
} }
bool HdPackLoader::LoadHdNesPack(string hdPackDefinitionFile, HdPackData &outData) bool HdPackLoader::InitializeLoader(VirtualFile &romFile, HdPackData *data)
{ {
//outData = HdPackData(); _data = data;
HdPackLoader loader(hdPackDefinitionFile, &outData); string romName = FolderUtilities::GetFilename(romFile.GetFileName(), false);
string hdPackFolder = FolderUtilities::GetHdPackFolder();
string zipName = romName + ".hdn";
string definitionPath = FolderUtilities::CombinePath(romName, "hires.txt");
string legacyPath = FolderUtilities::CombinePath(hdPackFolder, definitionPath);
if(ifstream(legacyPath)) {
_loadFromZip = false;
_hdPackFolder = FolderUtilities::GetFolderName(legacyPath);
return true;
} else {
vector<string> hdnPackages = FolderUtilities::GetFilesInFolder(romFile.GetFolderPath(), { ".hdn" }, false);
vector<string> more = FolderUtilities::GetFilesInFolder(hdPackFolder, { ".hdn", ".zip" }, false);
hdnPackages.insert(hdnPackages.end(), more.begin(), more.end());
string sha1Hash = romFile.GetSha1Hash();
for(string path : hdnPackages) {
_reader.LoadArchive(path);
vector<uint8_t> hdDefinition;
if(_reader.ExtractFile("hires.txt", hdDefinition)) {
if(FolderUtilities::GetFilename(path, false) == romName) {
_loadFromZip = true;
_hdPackFolder = path;
return true;
} else {
for(string line : StringUtilities::Split(string(hdDefinition.data(), hdDefinition.data() + hdDefinition.size()), '\n')) {
std::transform(line.begin(), line.end(), line.begin(), ::tolower);
if(line.find("<supportedrom>") != string::npos && line.find(sha1Hash) != string::npos) {
_loadFromZip = true;
_hdPackFolder = path;
return true;
}
}
}
}
}
}
return false;
}
bool HdPackLoader::LoadHdNesPack(string definitionFile, HdPackData &outData)
{
HdPackLoader loader;
if(ifstream(definitionFile)) {
loader._data = &outData;
loader._loadFromZip = false;
loader._hdPackFolder = FolderUtilities::GetFolderName(definitionFile);
return loader.LoadPack(); return loader.LoadPack();
}
return false;
}
bool HdPackLoader::LoadHdNesPack(VirtualFile &romFile, HdPackData &outData)
{
HdPackLoader loader;
if(loader.InitializeLoader(romFile, &outData)) {
return loader.LoadPack();
}
return false;
}
bool HdPackLoader::LoadFile(string filename, vector<uint8_t> &fileData)
{
fileData.clear();
if(_loadFromZip) {
if(_reader.ExtractFile(filename, fileData)) {
return true;
}
} else {
ifstream file(FolderUtilities::CombinePath(_hdPackFolder, filename), ios::in | ios::binary);
if(file.good()) {
file.seekg(0, ios::end);
uint32_t fileSize = (uint32_t)file.tellg();
file.seekg(0, ios::beg);
fileData = vector<uint8_t>(fileSize, 0);
file.read((char*)fileData.data(), fileSize);
return true;
}
}
return false;
} }
bool HdPackLoader::LoadPack() bool HdPackLoader::LoadPack()
{ {
try { try {
ifstream packDefinition(_hdPackDefinitionFile, ios::in | ios::binary); vector<uint8_t> hdDefinition;
if(!packDefinition.good()) { if(!LoadFile("hires.txt", hdDefinition)) {
return false; return false;
} }
while(packDefinition.good()) { for(string lineContent : StringUtilities::Split(string(hdDefinition.data(), hdDefinition.data() + hdDefinition.size()), '\n')) {
string lineContent;
std::getline(packDefinition, lineContent);
lineContent = lineContent.substr(0, lineContent.length() - 1); lineContent = lineContent.substr(0, lineContent.length() - 1);
vector<HdPackCondition*> conditions; vector<HdPackCondition*> conditions;
@ -51,10 +130,9 @@ bool HdPackLoader::LoadPack()
_data->Scale = std::stoi(lineContent); _data->Scale = std::stoi(lineContent);
} else if(lineContent.substr(0, 5) == "<img>") { } else if(lineContent.substr(0, 5) == "<img>") {
lineContent = lineContent.substr(5); lineContent = lineContent.substr(5);
HdPackBitmapInfo bitmapInfo; if(!ProcessImgTag(lineContent)) {
string imageFile = FolderUtilities::CombinePath(_hdPackFolder, lineContent); return false;
PNGHelper::ReadPNG(imageFile, bitmapInfo.PixelData, bitmapInfo.Width, bitmapInfo.Height); }
_hdNesBitmaps.push_back(bitmapInfo);
} else if(lineContent.substr(0, 7) == "<patch>") { } else if(lineContent.substr(0, 7) == "<patch>") {
tokens = StringUtilities::Split(lineContent.substr(7), ','); tokens = StringUtilities::Split(lineContent.substr(7), ',');
ProcessPatchTag(tokens); ProcessPatchTag(tokens);
@ -76,7 +154,6 @@ bool HdPackLoader::LoadPack()
LoadCustomPalette(); LoadCustomPalette();
InitializeHdPack(); InitializeHdPack();
packDefinition.close();
return true; return true;
} catch(std::exception ex) { } catch(std::exception ex) {
MessageManager::Log(string("[HDPack] Error loading HDPack: ") + ex.what()); MessageManager::Log(string("[HDPack] Error loading HDPack: ") + ex.what());
@ -84,19 +161,38 @@ bool HdPackLoader::LoadPack()
} }
} }
bool HdPackLoader::ProcessImgTag(string src)
{
HdPackBitmapInfo bitmapInfo;
vector<uint8_t> fileData;
LoadFile(src, fileData);
if(PNGHelper::ReadPNG(fileData, bitmapInfo.PixelData, bitmapInfo.Width, bitmapInfo.Height)) {
_hdNesBitmaps.push_back(bitmapInfo);
return true;
} else {
MessageManager::Log("[HDPack] Error loading HDPack: PNG file " + src + " could not be read.");
return false;
}
}
void HdPackLoader::ProcessPatchTag(vector<string> &tokens) void HdPackLoader::ProcessPatchTag(vector<string> &tokens)
{ {
if(tokens[1].size() != 40) { if(tokens[1].size() != 40) {
MessageManager::Log(string("[HDPack] Invalid SHA1 hash for patch (" + tokens[0] + "): " + tokens[1])); MessageManager::Log(string("[HDPack] Invalid SHA1 hash for patch (" + tokens[0] + "): " + tokens[1]));
return; return;
} }
if(!ifstream(FolderUtilities::CombinePath(_hdPackFolder, tokens[0]))) { vector<uint8_t> fileData;
if(!LoadFile(tokens[0], fileData)) {
MessageManager::Log(string("[HDPack] Patch file not found: " + tokens[1])); MessageManager::Log(string("[HDPack] Patch file not found: " + tokens[1]));
return; return;
} }
std::transform(tokens[1].begin(), tokens[1].end(), tokens[1].begin(), ::toupper); std::transform(tokens[1].begin(), tokens[1].end(), tokens[1].begin(), ::tolower);
_data->PatchesByHash[tokens[1]] = tokens[0]; if(_loadFromZip) {
_data->PatchesByHash[tokens[1]] = VirtualFile(_hdPackFolder, tokens[0]);
} else {
_data->PatchesByHash[tokens[1]] = FolderUtilities::CombinePath(_hdPackFolder, tokens[0]);
}
} }
void HdPackLoader::ProcessTileTag(vector<string> &tokens, vector<HdPackCondition*> conditions) void HdPackLoader::ProcessTileTag(vector<string> &tokens, vector<HdPackCondition*> conditions)
@ -231,30 +327,32 @@ void HdPackLoader::ProcessConditionTag(vector<string> &tokens)
void HdPackLoader::ProcessBackgroundTag(vector<string> &tokens, vector<HdPackCondition*> conditions) void HdPackLoader::ProcessBackgroundTag(vector<string> &tokens, vector<HdPackCondition*> conditions)
{ {
HdBackgroundFileData* fileData = nullptr; HdBackgroundFileData* bgFileData = nullptr;
for(unique_ptr<HdBackgroundFileData> &bgData : _data->BackgroundFileData) { for(unique_ptr<HdBackgroundFileData> &bgData : _data->BackgroundFileData) {
if(bgData->PngName == tokens[0]) { if(bgData->PngName == tokens[0]) {
fileData = bgData.get(); bgFileData = bgData.get();
} }
} }
if(!fileData) { if(!bgFileData) {
vector<uint8_t> pixelData; vector<uint8_t> pixelData;
uint32_t width, height; uint32_t width, height;
string imageFile = FolderUtilities::CombinePath(_hdPackFolder, tokens[0]); vector<uint8_t> fileContent;
if(PNGHelper::ReadPNG(imageFile, pixelData, width, height)) { if(LoadFile(tokens[0], fileContent)) {
if(PNGHelper::ReadPNG(fileContent, pixelData, width, height)) {
_data->BackgroundFileData.push_back(unique_ptr<HdBackgroundFileData>(new HdBackgroundFileData())); _data->BackgroundFileData.push_back(unique_ptr<HdBackgroundFileData>(new HdBackgroundFileData()));
fileData = _data->BackgroundFileData.back().get(); bgFileData = _data->BackgroundFileData.back().get();
fileData->PixelData = pixelData; bgFileData->PixelData = pixelData;
fileData->Width = width; bgFileData->Width = width;
fileData->Height = height; bgFileData->Height = height;
fileData->PngName = tokens[0]; bgFileData->PngName = tokens[0];
}
} }
} }
HdBackgroundInfo backgroundInfo; HdBackgroundInfo backgroundInfo;
if(fileData) { if(bgFileData) {
backgroundInfo.Data = fileData; backgroundInfo.Data = bgFileData;
backgroundInfo.Brightness = (uint8_t)(std::stof(tokens[1]) * 255); backgroundInfo.Brightness = (uint8_t)(std::stof(tokens[1]) * 255);
backgroundInfo.Conditions = conditions; backgroundInfo.Conditions = conditions;
@ -297,17 +395,12 @@ vector<HdPackCondition*> HdPackLoader::ParseConditionString(string conditionStri
void HdPackLoader::LoadCustomPalette() void HdPackLoader::LoadCustomPalette()
{ {
string customPalettePath = FolderUtilities::CombinePath(_hdPackFolder, "palette.dat"); vector<uint8_t> fileData;
ifstream file(customPalettePath, ios::binary); if(LoadFile("palette.dat", fileData)) {
if(file.good()) {
vector<uint32_t> paletteData; vector<uint32_t> paletteData;
uint8_t rgb[3]; for(int i = 0; i < fileData.size(); i+= 3){
while(!file.eof()) { paletteData.push_back(0xFF000000 | (fileData[i] << 16) | (fileData[i+1] << 8) | fileData[i+2]);
file.read((char*)rgb, 3);
if(!file.eof()) {
paletteData.push_back(0xFF000000 | (rgb[0] << 16) | (rgb[1] << 8) | rgb[2]);
}
} }
if(paletteData.size() == 0x40) { if(paletteData.size() == 0x40) {

View file

@ -1,24 +1,33 @@
#pragma once #pragma once
#include "stdafx.h" #include "stdafx.h"
#include "HdData.h" #include "HdData.h"
#include "../Utilities/ZipReader.h"
#include "../Utilities/VirtualFile.h"
class HdPackLoader class HdPackLoader
{ {
public: public:
static bool LoadHdNesPack(string hdPackDefinitionFile, HdPackData &data); static bool LoadHdNesPack(string definitionFile, HdPackData &outData);
static bool LoadHdNesPack(VirtualFile &romFile, HdPackData &outData);
private: private:
HdPackData* _data; HdPackData* _data;
bool _loadFromZip = false;
ZipReader _reader;
string _hdPackDefinitionFile; string _hdPackDefinitionFile;
string _hdPackFolder; string _hdPackFolder;
vector<HdPackBitmapInfo> _hdNesBitmaps; vector<HdPackBitmapInfo> _hdNesBitmaps;
HdPackLoader(string hdPackDefinitionFile, HdPackData *data); HdPackLoader();
bool InitializeLoader(VirtualFile &romPath, HdPackData *data);
bool LoadFile(string filename, vector<uint8_t> &fileData);
bool LoadPack(); bool LoadPack();
void InitializeHdPack(); void InitializeHdPack();
void LoadCustomPalette(); void LoadCustomPalette();
bool ProcessImgTag(string src);
void ProcessPatchTag(vector<string> &tokens); void ProcessPatchTag(vector<string> &tokens);
void ProcessConditionTag(vector<string> &tokens); void ProcessConditionTag(vector<string> &tokens);
void ProcessTileTag(vector<string> &tokens, vector<HdPackCondition*> conditions); void ProcessTileTag(vector<string> &tokens, vector<HdPackCondition*> conditions);

View file

@ -174,7 +174,7 @@ bool MesenMovie::Save()
header.MesenVersion = EmulationSettings::GetMesenVersion(); header.MesenVersion = EmulationSettings::GetMesenVersion();
header.MovieFormatVersion = MesenMovie::MovieFormatVersion; header.MovieFormatVersion = MesenMovie::MovieFormatVersion;
header.SaveStateFormatVersion = SaveStateManager::FileFormatVersion; header.SaveStateFormatVersion = SaveStateManager::FileFormatVersion;
header.RomCrc32 = Console::GetCrc32(); header.RomCrc32 = Console::GetHashInfo().Crc32Hash;
header.Region = (uint32_t)Console::GetModel(); header.Region = (uint32_t)Console::GetModel();
header.ConsoleType = (uint32_t)EmulationSettings::GetConsoleType(); header.ConsoleType = (uint32_t)EmulationSettings::GetConsoleType();
header.ExpansionDevice = (uint32_t)EmulationSettings::GetExpansionDevice(); header.ExpansionDevice = (uint32_t)EmulationSettings::GetExpansionDevice();
@ -336,9 +336,11 @@ bool MesenMovie::Load(std::stringstream &file, bool autoLoadRom)
bool loadedGame = true; bool loadedGame = true;
if(autoLoadRom) { if(autoLoadRom) {
string currentRom = Console::GetRomName(); string currentRom = Console::GetRomName();
if(currentRom.empty() || header.RomCrc32 != Console::GetCrc32()) { if(currentRom.empty() || header.RomCrc32 != Console::GetHashInfo().Crc32Hash) {
//Loaded game isn't the same as the game used for the movie, attempt to load the correct game //Loaded game isn't the same as the game used for the movie, attempt to load the correct game
loadedGame = Console::LoadROM(romFilename, header.RomCrc32); HashInfo hashInfo;
hashInfo.Crc32Hash = header.RomCrc32;
loadedGame = Console::LoadROM(romFilename, hashInfo);
} else { } else {
Console::Reset(false); Console::Reset(false);
} }

View file

@ -172,7 +172,7 @@ void RecordedRomTest::RecordFromTest(string newTestFilename, string existingTest
if(testMovie && testRom) { if(testMovie && testRom) {
Console::Pause(); Console::Pause();
Console::LoadROM("TestRom", &testRom); Console::LoadROM(testRom);
testRom.seekg(0, ios::beg); testRom.seekg(0, ios::beg);
_romStream << testRom.rdbuf(); _romStream << testRom.rdbuf();
@ -236,7 +236,7 @@ int32_t RecordedRomTest::Run(string filename)
_runningTest = true; _runningTest = true;
//Start playing movie //Start playing movie
Console::LoadROM(testName, &testRom); Console::LoadROM(testRom);
MovieManager::Play(testMovie, false); MovieManager::Play(testMovie, false);
Console::Resume(); Console::Resume();
@ -300,7 +300,7 @@ void RecordedRomTest::Save()
writer.AddFile(mmoFilename, "TestMovie.mmo"); writer.AddFile(mmoFilename, "TestMovie.mmo");
std::remove(mmoFilename.c_str()); std::remove(mmoFilename.c_str());
writer.AddFile(Console::GetROMPath(), "TestRom.nes"); writer.AddFile(Console::GetRomPath(), "TestRom.nes");
} }

View file

@ -40,6 +40,7 @@ enum class BusConflictType
struct HashInfo struct HashInfo
{ {
uint32_t Crc32Hash = 0; uint32_t Crc32Hash = 0;
uint32_t PrgCrc32Hash = 0;
string Sha1Hash; string Sha1Hash;
string PrgChrMd5Hash; string PrgChrMd5Hash;
}; };

View file

@ -1,21 +1,23 @@
#include "stdafx.h" #include "stdafx.h"
#include <algorithm> #include <algorithm>
#include <unordered_set>
#include "../Utilities/VirtualFile.h"
#include "../Utilities/FolderUtilities.h" #include "../Utilities/FolderUtilities.h"
#include "../Utilities/CRC32.h" #include "../Utilities/CRC32.h"
#include "../Utilities/sha1.h" #include "../Utilities/sha1.h"
#include "RomLoader.h" #include "RomLoader.h"
#include "FileLoader.h"
#include "iNesLoader.h" #include "iNesLoader.h"
#include "FdsLoader.h" #include "FdsLoader.h"
#include "NsfLoader.h" #include "NsfLoader.h"
#include "NsfeLoader.h" #include "NsfeLoader.h"
#include "UnifLoader.h" #include "UnifLoader.h"
bool RomLoader::LoadFile(string filename, int32_t archiveFileIndex) bool RomLoader::LoadFile(VirtualFile romFile)
{ {
vector<uint8_t> fileData; vector<uint8_t> fileData;
if(FileLoader::LoadFile(filename, nullptr, archiveFileIndex, fileData)) { if(romFile.IsValid()) {
return LoadFile(filename, fileData); romFile.ReadFile(fileData);
return LoadFile(romFile.GetFileName(), fileData);
} else { } else {
return false; return false;
} }
@ -23,6 +25,10 @@ bool RomLoader::LoadFile(string filename, int32_t archiveFileIndex)
bool RomLoader::LoadFile(string filename, vector<uint8_t> &fileData) bool RomLoader::LoadFile(string filename, vector<uint8_t> &fileData)
{ {
if(fileData.size() < 10) {
return false;
}
_filename = filename; _filename = filename;
string romName = FolderUtilities::GetFilename(filename, true); string romName = FolderUtilities::GetFilename(filename, true);
@ -88,56 +94,58 @@ RomData RomLoader::GetRomData()
return _romData; return _romData;
} }
int32_t RomLoader::FindMatchingRomInFile(string filename, HashInfo hashInfo) string RomLoader::FindMatchingRomInFile(string filePath, HashInfo hashInfo)
{ {
vector<uint8_t> fileData; shared_ptr<ArchiveReader> reader = ArchiveReader::GetReader(filePath);
int fileIndex = 0; if(reader) {
while(FileLoader::LoadFile(filename, nullptr, fileIndex, fileData)) { for(string file : reader->GetFileList({ ".nes", ".fds", "*.unif", "*.unif", "*.nsf", "*.nsfe" })) {
RomLoader loader; RomLoader loader;
if(loader.LoadFile(filename, fileData)) { vector<uint8_t> fileData;
if(loader.LoadFile(filePath)) {
if(hashInfo.Crc32Hash == loader._romData.Crc32 || hashInfo.Sha1Hash.compare(loader._romData.Sha1) == 0) { if(hashInfo.Crc32Hash == loader._romData.Crc32 || hashInfo.Sha1Hash.compare(loader._romData.Sha1) == 0) {
return fileIndex; return filePath+"\n"+file;
}
fileIndex++;
} }
} }
return -1; }
} else {
RomLoader loader;
vector<uint8_t> fileData;
if(loader.LoadFile(filePath)) {
if(hashInfo.Crc32Hash == loader._romData.Crc32 || hashInfo.Sha1Hash.compare(loader._romData.Sha1) == 0) {
return filePath;
}
}
}
return "";
} }
string RomLoader::FindMatchingRomInFolder(string folder, string romFilename, HashInfo hashInfo, bool useFastSearch, int32_t &archiveFileIndex) string RomLoader::FindMatchingRomInFolder(string folder, string romFilename, HashInfo hashInfo, bool useFastSearch)
{ {
std::transform(romFilename.begin(), romFilename.end(), romFilename.begin(), ::tolower); std::transform(romFilename.begin(), romFilename.end(), romFilename.begin(), ::tolower);
vector<string> validExtensions = { { ".nes", ".zip", ".7z", ".fds" } }; std::unordered_set<string> validExtensions = { { ".nes", ".fds", "*.unif", "*.unif", "*.nsf", "*.nsfe", "*.7z", "*.zip" } };
vector<string> romFiles; vector<string> romFiles = FolderUtilities::GetFilesInFolder(folder, validExtensions, true);
for(string extension : validExtensions) {
for(string file : FolderUtilities::GetFilesInFolder(folder, extension, true)) {
romFiles.push_back(file);
}
}
if(useFastSearch) { if(useFastSearch) {
for(string romFile : romFiles) { for(string romFile : romFiles) {
//Quick search by filename //Quick search by filename
string originalFilename = romFile; string lcRomFile = romFile;
std::transform(romFile.begin(), romFile.end(), romFile.begin(), ::tolower); std::transform(lcRomFile.begin(), lcRomFile.end(), lcRomFile.begin(), ::tolower);
if(FolderUtilities::GetFilename(romFile, true).compare(romFilename) == 0) { if(FolderUtilities::GetFilename(lcRomFile, false).compare(FolderUtilities::GetFilename(romFilename, false)) == 0) {
archiveFileIndex = RomLoader::FindMatchingRomInFile(romFile, hashInfo); string match = RomLoader::FindMatchingRomInFile(romFile, hashInfo);
if(archiveFileIndex >= 0) { if(!match.empty()) {
return originalFilename; return match;
} }
} }
} }
} else { } else {
for(string romFile : romFiles) { for(string romFile : romFiles) {
//Slower search by CRC value //Slower search by CRC value
archiveFileIndex = RomLoader::FindMatchingRomInFile(romFile, hashInfo); string match = RomLoader::FindMatchingRomInFile(romFile, hashInfo);
if(archiveFileIndex >= 0) { if(!match.empty()) {
return romFile; return match;
} }
} }
} }
archiveFileIndex = -1;
return ""; return "";
} }

View file

@ -1,5 +1,6 @@
#pragma once #pragma once
#include "stdafx.h" #include "stdafx.h"
#include "../Utilities/VirtualFile.h"
#include "RomData.h" #include "RomData.h"
class ArchiveReader; class ArchiveReader;
@ -9,12 +10,12 @@ class RomLoader
RomData _romData; RomData _romData;
string _filename; string _filename;
static int32_t FindMatchingRomInFile(string filename, HashInfo hashInfo); static string FindMatchingRomInFile(string filePath, HashInfo hashInfo);
public: public:
bool LoadFile(string filename, int32_t archiveFileIndex); bool LoadFile(VirtualFile romFile);
bool LoadFile(string filename, vector<uint8_t> &fileData); bool LoadFile(string filename, vector<uint8_t> &fileData);
RomData GetRomData(); RomData GetRomData();
static string FindMatchingRomInFolder(string folder, string romFilename, HashInfo hashInfo, bool useFastSearch, int32_t &archiveFileIndex); static string FindMatchingRomInFolder(string folder, string romFilename, HashInfo hashInfo, bool useFastSearch);
}; };

View file

@ -134,7 +134,7 @@ bool SaveStateManager::LoadState(int stateIndex)
return result; return result;
} }
void SaveStateManager::SaveRecentGame(string romName, string romPath, string patchPath, int32_t archiveFileIndex) void SaveStateManager::SaveRecentGame(string romName, string romPath, string patchPath)
{ {
if(!EmulationSettings::CheckFlag(EmulationFlags::ConsoleMode) && !EmulationSettings::CheckFlag(EmulationFlags::DisableGameSelectionScreen) && Console::GetRomFormat() != RomFormat::Nsf) { if(!EmulationSettings::CheckFlag(EmulationFlags::ConsoleMode) && !EmulationSettings::CheckFlag(EmulationFlags::DisableGameSelectionScreen) && Console::GetRomFormat() != RomFormat::Nsf) {
string filename = FolderUtilities::GetFilename(Console::GetRomName(), false) + ".rgd"; string filename = FolderUtilities::GetFilename(Console::GetRomName(), false) + ".rgd";
@ -152,7 +152,6 @@ void SaveStateManager::SaveRecentGame(string romName, string romPath, string pat
romInfoStream << romName << std::endl; romInfoStream << romName << std::endl;
romInfoStream << romPath << std::endl; romInfoStream << romPath << std::endl;
romInfoStream << patchPath << std::endl; romInfoStream << patchPath << std::endl;
romInfoStream << std::to_string(archiveFileIndex) << std::endl;
writer.AddFile(romInfoStream, "RomInfo.txt"); writer.AddFile(romInfoStream, "RomInfo.txt");
} }
} }
@ -165,15 +164,14 @@ void SaveStateManager::LoadRecentGame(string filename, bool resetGame)
std::stringstream romInfoStream = reader.GetStream("RomInfo.txt"); std::stringstream romInfoStream = reader.GetStream("RomInfo.txt");
std::stringstream stateStream = reader.GetStream("Savestate.mst"); std::stringstream stateStream = reader.GetStream("Savestate.mst");
string romName, romPath, patchPath, archiveIndex; string romName, romPath, patchPath;
std::getline(romInfoStream, romName); std::getline(romInfoStream, romName);
std::getline(romInfoStream, romPath); std::getline(romInfoStream, romPath);
std::getline(romInfoStream, patchPath); std::getline(romInfoStream, patchPath);
std::getline(romInfoStream, archiveIndex);
Console::Pause(); Console::Pause();
try { try {
Console::LoadROM(romPath, nullptr, std::stoi(archiveIndex.c_str()), patchPath); Console::LoadROM(romPath, patchPath);
if(!resetGame) { if(!resetGame) {
SaveStateManager::LoadState(stateStream); SaveStateManager::LoadState(stateStream);
} }

View file

@ -23,7 +23,7 @@ public:
static bool LoadState(istream &stream); static bool LoadState(istream &stream);
static bool LoadState(int stateIndex); static bool LoadState(int stateIndex);
static void SaveRecentGame(string romName, string romPath, string patchPath, int32_t archiveFileIndex); static void SaveRecentGame(string romName, string romPath, string patchPath);
static void LoadRecentGame(string filename, bool resetGame); static void LoadRecentGame(string filename, bool resetGame);
static void MoveToNextSlot(); static void MoveToNextSlot();

View file

@ -191,7 +191,7 @@ public:
uint8_t value = 0; uint8_t value = 0;
uint32_t crc = Console::GetPrgCrc32(); uint32_t crc = Console::GetHashInfo().PrgCrc32Hash;
switch(addr) { switch(addr) {
case 0x4016: case 0x4016:

View file

@ -6,6 +6,7 @@ using System.Linq;
using System.Text; using System.Text;
using System.Threading.Tasks; using System.Threading.Tasks;
using System.Xml.Serialization; using System.Xml.Serialization;
using Mesen.GUI.Forms;
namespace Mesen.GUI.Config namespace Mesen.GUI.Config
{ {
@ -87,13 +88,13 @@ namespace Mesen.GUI.Config
PreferenceInfo.InitializeDefaults(); PreferenceInfo.InitializeDefaults();
} }
public void AddRecentFile(string filepath, string romName, int archiveFileIndex) public void AddRecentFile(ResourcePath romFile, ResourcePath? patchFile)
{ {
RecentItem existingItem = RecentFiles.Where((item) => item.Path == filepath && item.ArchiveFileIndex == archiveFileIndex).FirstOrDefault(); RecentItem existingItem = RecentFiles.Where((item) => item.RomFile == romFile && item.PatchFile == patchFile).FirstOrDefault();
if(existingItem != null) { if(existingItem != null) {
RecentFiles.Remove(existingItem); RecentFiles.Remove(existingItem);
} }
RecentItem recentItem = new RecentItem { RomName = romName, Path = filepath, ArchiveFileIndex = archiveFileIndex }; RecentItem recentItem = new RecentItem { RomFile = romFile, PatchFile = patchFile };
RecentFiles.Insert(0, recentItem); RecentFiles.Insert(0, recentItem);
if(RecentFiles.Count > Configuration.MaxRecentFiles) { if(RecentFiles.Count > Configuration.MaxRecentFiles) {
@ -149,8 +150,16 @@ namespace Mesen.GUI.Config
public class RecentItem public class RecentItem
{ {
public string Path; public ResourcePath RomFile;
public string RomName; public ResourcePath? PatchFile;
public int ArchiveFileIndex;
public override string ToString()
{
string text = Path.GetFileName(RomFile.FileName).Replace("&", "&&");
if(PatchFile.HasValue) {
text += " [" + Path.GetFileName(PatchFile.Value) + "]";
}
return text;
}
} }
} }

View file

@ -11,6 +11,7 @@ using System.IO;
using Mesen.GUI.Config; using Mesen.GUI.Config;
using System.Drawing.Text; using System.Drawing.Text;
using System.IO.Compression; using System.IO.Compression;
using Mesen.GUI.Forms;
namespace Mesen.GUI.Controls namespace Mesen.GUI.Controls
{ {
@ -37,7 +38,7 @@ namespace Mesen.GUI.Controls
{ {
public string FileName { get; set; } public string FileName { get; set; }
public string RomName { get; set; } public string RomName { get; set; }
public string RomPath { get; set; } public ResourcePath RomPath { get; set; }
public DateTime Timestamp { get; set; } public DateTime Timestamp { get; set; }
} }
@ -106,7 +107,7 @@ namespace Mesen.GUI.Controls
info.Timestamp = new FileInfo(file).LastWriteTime; info.Timestamp = new FileInfo(file).LastWriteTime;
info.FileName = file; info.FileName = file;
if(File.Exists(info.RomPath)) { if(info.RomPath.Exists) {
_recentGames.Add(info); _recentGames.Add(info);
} }
} catch { } } catch { }

View file

@ -158,7 +158,7 @@ namespace Mesen.GUI.Debugger
private void AutoLoadDbgFile(bool silent) private void AutoLoadDbgFile(bool silent)
{ {
if(ConfigManager.Config.DebugInfo.AutoLoadDbgFiles) { if(ConfigManager.Config.DebugInfo.AutoLoadDbgFiles) {
string dbgPath = Path.Combine(Path.GetDirectoryName(ConfigManager.Config.RecentFiles[0].Path), Path.GetFileNameWithoutExtension(ConfigManager.Config.RecentFiles[0].RomName) + ".dbg"); string dbgPath = Path.Combine(ConfigManager.Config.RecentFiles[0].RomFile.Folder, Path.GetFileNameWithoutExtension(ConfigManager.Config.RecentFiles[0].RomFile.FileName) + ".dbg");
if(File.Exists(dbgPath)) { if(File.Exists(dbgPath)) {
Ld65DbgImporter dbgImporter = new Ld65DbgImporter(); Ld65DbgImporter dbgImporter = new Ld65DbgImporter();
dbgImporter.Import(dbgPath, silent); dbgImporter.Import(dbgPath, silent);

View file

@ -66,9 +66,9 @@ namespace Mesen.GUI.Forms.Cheats
private void LoadGame(string romPath) private void LoadGame(string romPath)
{ {
int archiveFileIndex = -1; ResourcePath resource = romPath;
if(frmSelectRom.SelectRom(romPath, ref archiveFileIndex)) { if(frmSelectRom.SelectRom(ref resource)) {
RomInfo romInfo = InteropEmu.GetRomInfo(romPath, archiveFileIndex); RomInfo romInfo = InteropEmu.GetRomInfo(resource);
_gameCrc = romInfo.GetPrgCrcString(); _gameCrc = romInfo.GetPrgCrcString();
if(_gameCrc != null) { if(_gameCrc != null) {
((CheatInfo)Entity).GameName = Path.GetFileNameWithoutExtension(romInfo.RomName); ((CheatInfo)Entity).GameName = Path.GetFileNameWithoutExtension(romInfo.RomName);

View file

@ -41,9 +41,9 @@ namespace Mesen.GUI.Forms.Cheats
private void LoadGame(string romPath) private void LoadGame(string romPath)
{ {
int archiveFileIndex = -1; ResourcePath resource = romPath;
if(frmSelectRom.SelectRom(romPath, ref archiveFileIndex)) { if(frmSelectRom.SelectRom(ref resource)) {
RomInfo romInfo = InteropEmu.GetRomInfo(romPath, archiveFileIndex); RomInfo romInfo = InteropEmu.GetRomInfo(resource);
_gameCrc = romInfo.GetPrgCrcString(); _gameCrc = romInfo.GetPrgCrcString();
_gameName = romInfo.GetRomName(); _gameName = romInfo.GetRomName();
txtGameName.Text = _gameName; txtGameName.Text = _gameName;

View file

@ -0,0 +1,45 @@
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Mesen.GUI.Forms
{
public struct ResourcePath : IEquatable<ResourcePath>
{
public string Path { get; set; }
public string InnerFile { get; set; }
public bool Exists { get { return File.Exists(Path); } }
public bool Compressed { get { return !string.IsNullOrWhiteSpace(InnerFile); } }
public string FileName { get { return Compressed ? InnerFile : System.IO.Path.GetFileName(Path); } }
public string Folder { get { return System.IO.Path.GetDirectoryName(Path); } }
public override string ToString()
{
return Path + (Compressed ? ("\x1" + InnerFile) : "");
}
static public implicit operator ResourcePath(string path)
{
string[] tokens = path.Split('\x1');
return new ResourcePath() {
Path = tokens[0],
InnerFile = tokens.Length > 1 ? tokens[1] : ""
};
}
static public implicit operator string(ResourcePath resourcePath)
{
return resourcePath.ToString();
}
bool IEquatable<ResourcePath>.Equals(ResourcePath other)
{
return other.ToString() == this.ToString();
}
}
}

View file

@ -30,8 +30,7 @@ namespace Mesen.GUI.Forms
private frmLogWindow _logWindow; private frmLogWindow _logWindow;
private frmCheatList _cheatListWindow; private frmCheatList _cheatListWindow;
private frmHdPackEditor _hdPackEditorWindow; private frmHdPackEditor _hdPackEditorWindow;
private string _currentRomPath = null; private ResourcePath? _currentRomPath = null;
private int _currentRomArchiveIndex = -1;
private string _currentGame = null; private string _currentGame = null;
private bool _customSize = false; private bool _customSize = false;
private FormWindowState _originalWindowState; private FormWindowState _originalWindowState;
@ -123,9 +122,9 @@ namespace Mesen.GUI.Forms
{ {
base.OnLoad(e); base.OnLoad(e);
#if HIDETESTMENU #if HIDETESTMENU
mnuTests.Visible = false; mnuTests.Visible = false;
#endif #endif
_notifListener = new InteropEmu.NotificationListener(); _notifListener = new InteropEmu.NotificationListener();
_notifListener.OnNotification += _notifListener_OnNotification; _notifListener.OnNotification += _notifListener_OnNotification;
@ -224,6 +223,8 @@ namespace Mesen.GUI.Forms
//0.9.0's "Auto" has been renamed to "NoStretching" //0.9.0's "Auto" has been renamed to "NoStretching"
ConfigManager.Config.VideoInfo.AspectRatio = VideoAspectRatio.NoStretching; ConfigManager.Config.VideoInfo.AspectRatio = VideoAspectRatio.NoStretching;
} }
ConfigManager.Config.RecentFiles.Clear();
} }
if(oldVersion <= new Version("0.5.3")) { if(oldVersion <= new Version("0.5.3")) {
@ -264,7 +265,7 @@ namespace Mesen.GUI.Forms
{ {
InteropEmu.InitializeEmu(ConfigManager.HomeFolder, this.Handle, this.ctrlRenderer.Handle, _noAudio, _noVideo, _noInput); InteropEmu.InitializeEmu(ConfigManager.HomeFolder, this.Handle, this.ctrlRenderer.Handle, _noAudio, _noVideo, _noInput);
foreach(RecentItem recentItem in ConfigManager.Config.RecentFiles) { foreach(RecentItem recentItem in ConfigManager.Config.RecentFiles) {
InteropEmu.AddKnownGameFolder(Path.GetDirectoryName(recentItem.Path)); InteropEmu.AddKnownGameFolder(recentItem.RomFile.Folder);
} }
ConfigManager.Config.InitializeDefaults(); ConfigManager.Config.InitializeDefaults();
@ -553,7 +554,7 @@ namespace Mesen.GUI.Forms
using(OpenFileDialog ofd = new OpenFileDialog()) { using(OpenFileDialog ofd = new OpenFileDialog()) {
ofd.SetFilter(ResourceHelper.GetMessage("FilterRomIps")); ofd.SetFilter(ResourceHelper.GetMessage("FilterRomIps"));
if(ConfigManager.Config.RecentFiles.Count > 0) { if(ConfigManager.Config.RecentFiles.Count > 0) {
ofd.InitialDirectory = Path.GetDirectoryName(ConfigManager.Config.RecentFiles[0].Path); ofd.InitialDirectory = ConfigManager.Config.RecentFiles[0].RomFile.Folder;
} }
if(ofd.ShowDialog() == System.Windows.Forms.DialogResult.OK) { if(ofd.ShowDialog() == System.Windows.Forms.DialogResult.OK) {
LoadFile(ofd.FileName); LoadFile(ofd.FileName);
@ -595,38 +596,36 @@ namespace Mesen.GUI.Forms
using(OpenFileDialog ofd = new OpenFileDialog()) { using(OpenFileDialog ofd = new OpenFileDialog()) {
ofd.SetFilter(ResourceHelper.GetMessage("FilterRom")); ofd.SetFilter(ResourceHelper.GetMessage("FilterRom"));
if(ConfigManager.Config.RecentFiles.Count > 0) { if(ConfigManager.Config.RecentFiles.Count > 0) {
ofd.InitialDirectory = Path.GetDirectoryName(ConfigManager.Config.RecentFiles[0].Path); ofd.InitialDirectory = ConfigManager.Config.RecentFiles[0].RomFile.Folder;
} }
if(ofd.ShowDialog() == System.Windows.Forms.DialogResult.OK) { if(ofd.ShowDialog() == System.Windows.Forms.DialogResult.OK) {
LoadROM(ofd.FileName, true, -1, patchFile); LoadROM(ofd.FileName, true, patchFile);
} }
} }
} }
} else if(MesenMsgBox.Show("PatchAndReset", MessageBoxButtons.OKCancel, MessageBoxIcon.Question) == System.Windows.Forms.DialogResult.OK) { } else if(MesenMsgBox.Show("PatchAndReset", MessageBoxButtons.OKCancel, MessageBoxIcon.Question) == System.Windows.Forms.DialogResult.OK) {
LoadROM(_currentRomPath, true, _currentRomArchiveIndex, patchFile); LoadROM(_currentRomPath.Value, true, patchFile);
} }
} }
private void LoadROM(string filename, bool autoLoadPatches = false, int archiveFileIndex = -1, string patchFileToApply = null) private void LoadROM(ResourcePath romFile, bool autoLoadPatches = false, ResourcePath? patchFileToApply = null)
{ {
_currentRomPath = filename; if(romFile.Exists) {
_currentRomArchiveIndex = -1; if(frmSelectRom.SelectRom(ref romFile)) {
if(File.Exists(filename)) { _currentRomPath = romFile;
string romName;
if(frmSelectRom.SelectRom(filename, ref archiveFileIndex, out romName)) { if(romFile.Compressed) {
_currentRomArchiveIndex = archiveFileIndex;
if(archiveFileIndex >= 0) {
Interlocked.Increment(ref _romLoadCounter); Interlocked.Increment(ref _romLoadCounter);
ctrlNsfPlayer.Visible = false; ctrlNsfPlayer.Visible = false;
ctrlLoading.Visible = true; ctrlLoading.Visible = true;
} }
string patchFile = patchFileToApply; ResourcePath? patchFile = patchFileToApply;
if(patchFile == null) { if(patchFile == null && autoLoadPatches) {
string[] extensions = new string[3] { ".ips", ".ups", ".bps" }; string[] extensions = new string[3] { ".ips", ".ups", ".bps" };
foreach(string ext in extensions) { foreach(string ext in extensions) {
string file = Path.Combine(Path.GetDirectoryName(filename), Path.GetFileNameWithoutExtension(filename)) + ext; string file = Path.Combine(romFile.Folder, Path.GetFileNameWithoutExtension(romFile.FileName)) + ext;
if(File.Exists(file)) { if(File.Exists(file)) {
patchFile = file; patchFile = file;
break; break;
@ -634,23 +633,19 @@ namespace Mesen.GUI.Forms
} }
} }
if(!File.Exists(patchFile)) {
autoLoadPatches = false;
}
Task loadRomTask = new Task(() => { Task loadRomTask = new Task(() => {
lock(_loadRomLock) { lock(_loadRomLock) {
InteropEmu.LoadROM(filename, archiveFileIndex, autoLoadPatches ? patchFile : string.Empty); InteropEmu.LoadROM(romFile, (patchFile.HasValue && patchFile.Value.Exists) ? (string)patchFile.Value : string.Empty);
} }
}); });
loadRomTask.ContinueWith((Task prevTask) => { loadRomTask.ContinueWith((Task prevTask) => {
this.BeginInvoke((MethodInvoker)(() => { this.BeginInvoke((MethodInvoker)(() => {
if(archiveFileIndex >= 0) { if(romFile.Compressed) {
Interlocked.Decrement(ref _romLoadCounter); Interlocked.Decrement(ref _romLoadCounter);
} }
ConfigManager.Config.AddRecentFile(filename, romName, archiveFileIndex); ConfigManager.Config.AddRecentFile(romFile, patchFileToApply);
UpdateRecentFiles(); UpdateRecentFiles();
})); }));
}); });
@ -658,7 +653,7 @@ namespace Mesen.GUI.Forms
loadRomTask.Start(); loadRomTask.Start();
} }
} else { } else {
MesenMsgBox.Show("FileNotFound", MessageBoxButtons.OK, MessageBoxIcon.Error, filename); MesenMsgBox.Show("FileNotFound", MessageBoxButtons.OK, MessageBoxIcon.Error, romFile.Path);
} }
} }
@ -688,7 +683,6 @@ namespace Mesen.GUI.Forms
} else { } else {
panelInfo.Visible = _emuThread == null; panelInfo.Visible = _emuThread == null;
ctrlRecentGames.Visible = _emuThread == null; ctrlRecentGames.Visible = _emuThread == null;
mnuPowerOff.Enabled = _emuThread != null;
ctrlLoading.Visible = (_romLoadCounter > 0); ctrlLoading.Visible = (_romLoadCounter > 0);
@ -697,7 +691,7 @@ namespace Mesen.GUI.Forms
bool isNetPlayClient = InteropEmu.IsConnected(); bool isNetPlayClient = InteropEmu.IsConnected();
mnuPause.Enabled = mnuPowerCycle.Enabled = mnuReset.Enabled = (_emuThread != null && !isNetPlayClient); mnuPause.Enabled = mnuPowerCycle.Enabled = mnuReset.Enabled = mnuPowerOff.Enabled = (_emuThread != null && !isNetPlayClient);
mnuSaveState.Enabled = (_emuThread != null && !isNetPlayClient && !InteropEmu.IsNsf()); mnuSaveState.Enabled = (_emuThread != null && !isNetPlayClient && !InteropEmu.IsNsf());
mnuLoadState.Enabled = (_emuThread != null && !isNetPlayClient && !InteropEmu.IsNsf() && !InteropEmu.MoviePlaying() && !InteropEmu.MovieRecording()); mnuLoadState.Enabled = (_emuThread != null && !isNetPlayClient && !InteropEmu.IsNsf() && !InteropEmu.MoviePlaying() && !InteropEmu.MovieRecording());
@ -807,9 +801,9 @@ namespace Mesen.GUI.Forms
mnuRecentFiles.DropDownItems.Clear(); mnuRecentFiles.DropDownItems.Clear();
foreach(RecentItem recentItem in ConfigManager.Config.RecentFiles) { foreach(RecentItem recentItem in ConfigManager.Config.RecentFiles) {
ToolStripMenuItem tsmi = new ToolStripMenuItem(); ToolStripMenuItem tsmi = new ToolStripMenuItem();
tsmi.Text = recentItem.RomName.Replace("&", "&&"); tsmi.Text = recentItem.ToString();
tsmi.Click += (object sender, EventArgs args) => { tsmi.Click += (object sender, EventArgs args) => {
LoadROM(recentItem.Path, ConfigManager.Config.PreferenceInfo.AutoLoadIpsPatches, recentItem.ArchiveFileIndex); LoadROM(recentItem.RomFile, ConfigManager.Config.PreferenceInfo.AutoLoadIpsPatches, recentItem.PatchFile);
}; };
mnuRecentFiles.DropDownItems.Add(tsmi); mnuRecentFiles.DropDownItems.Add(tsmi);
} }
@ -893,7 +887,7 @@ namespace Mesen.GUI.Forms
} }
} }
#if !HIDETESTMENU #if !HIDETESTMENU
if(keyData == Keys.Pause) { if(keyData == Keys.Pause) {
if(InteropEmu.RomTestRecording()) { if(InteropEmu.RomTestRecording()) {
InteropEmu.RomTestStop(); InteropEmu.RomTestStop();
@ -901,7 +895,7 @@ namespace Mesen.GUI.Forms
InteropEmu.RomTestRecord(ConfigManager.TestFolder + "\\" + InteropEmu.GetRomInfo().GetRomName() + ".mtp", true); InteropEmu.RomTestRecord(ConfigManager.TestFolder + "\\" + InteropEmu.GetRomInfo().GetRomName() + ".mtp", true);
} }
} }
#endif #endif
if(keyData == Keys.Escape && _emuThread != null && mnuPause.Enabled) { if(keyData == Keys.Escape && _emuThread != null && mnuPause.Enabled) {
PauseEmu(); PauseEmu();
@ -1600,7 +1594,7 @@ namespace Mesen.GUI.Forms
string hash = MD5Helper.GetMD5Hash(ofd.FileName).ToLowerInvariant(); string hash = MD5Helper.GetMD5Hash(ofd.FileName).ToLowerInvariant();
if(hash == "ca30b50f880eb660a320674ed365ef7a" || hash == "c1a9e9415a6adde3c8563c622d4c9fce") { if(hash == "ca30b50f880eb660a320674ed365ef7a" || hash == "c1a9e9415a6adde3c8563c622d4c9fce") {
File.Copy(ofd.FileName, Path.Combine(ConfigManager.HomeFolder, "FdsBios.bin")); File.Copy(ofd.FileName, Path.Combine(ConfigManager.HomeFolder, "FdsBios.bin"));
LoadROM(_currentRomPath, ConfigManager.Config.PreferenceInfo.AutoLoadIpsPatches); LoadROM(_currentRomPath.Value, ConfigManager.Config.PreferenceInfo.AutoLoadIpsPatches);
} else { } else {
MesenMsgBox.Show("InvalidFdsBios", MessageBoxButtons.OK, MessageBoxIcon.Error); MesenMsgBox.Show("InvalidFdsBios", MessageBoxButtons.OK, MessageBoxIcon.Error);
} }
@ -1855,7 +1849,7 @@ namespace Mesen.GUI.Forms
private void mnuRandomGame_Click(object sender, EventArgs e) private void mnuRandomGame_Click(object sender, EventArgs e)
{ {
IEnumerable<string> gameFolders = ConfigManager.Config.RecentFiles.Select(recentFile => Path.GetDirectoryName(recentFile.Path).ToLowerInvariant()).Distinct(); IEnumerable<string> gameFolders = ConfigManager.Config.RecentFiles.Select(recentFile => recentFile.RomFile.Folder.ToLowerInvariant()).Distinct();
List<string> gameRoms = new List<string>(); List<string> gameRoms = new List<string>();
foreach(string folder in gameFolders) { foreach(string folder in gameFolders) {

View file

@ -3,6 +3,7 @@ using System.Collections.Generic;
using System.ComponentModel; using System.ComponentModel;
using System.Data; using System.Data;
using System.Drawing; using System.Drawing;
using System.IO;
using System.Linq; using System.Linq;
using System.Text; using System.Text;
using System.Threading.Tasks; using System.Threading.Tasks;
@ -72,34 +73,25 @@ namespace Mesen.GUI.Forms
txtSearch.Focus(); txtSearch.Focus();
} }
public static bool SelectRom(string filename, ref int archiveFileIndex) public static bool SelectRom(ref ResourcePath resource)
{ {
string romName; List<string> archiveRomList = InteropEmu.GetArchiveRomList(resource.Path);
return SelectRom(filename, ref archiveFileIndex, out romName);
if(archiveRomList.Contains(resource.InnerFile)) {
return true;
} }
public static bool SelectRom(string filename, ref int archiveFileIndex, out string romName)
{
romName = "";
List<string> archiveRomList = InteropEmu.GetArchiveRomList(filename);
if(archiveRomList.Count > 1) { if(archiveRomList.Count > 1) {
if(archiveFileIndex >= 0 && archiveFileIndex < archiveRomList.Count) {
romName = System.IO.Path.GetFileName(archiveRomList[archiveFileIndex]);
return true;
} else {
frmSelectRom frm = new frmSelectRom(archiveRomList); frmSelectRom frm = new frmSelectRom(archiveRomList);
if(frm.ShowDialog(null, Application.OpenForms[0]) == DialogResult.OK) { if(frm.ShowDialog(null, Application.OpenForms[0]) == DialogResult.OK) {
archiveFileIndex = frm.SelectedIndex; resource.InnerFile = frm.lstRoms.SelectedItem.ToString();
romName = System.IO.Path.GetFileName(frm.lstRoms.SelectedItem.ToString());
} else { } else {
return false; return false;
} }
}
} else if(archiveRomList.Count == 1) { } else if(archiveRomList.Count == 1) {
romName = System.IO.Path.GetFileName(archiveRomList[0]); resource.InnerFile = archiveRomList[0];
} else { } else {
romName = System.IO.Path.GetFileName(filename); resource.InnerFile = "";
} }
return true; return true;

View file

@ -676,6 +676,7 @@
</Compile> </Compile>
<Compile Include="Forms\OpenSaveFileDialogExtensions.cs" /> <Compile Include="Forms\OpenSaveFileDialogExtensions.cs" />
<Compile Include="Forms\ResourceHelper.cs" /> <Compile Include="Forms\ResourceHelper.cs" />
<Compile Include="Forms\ResourcePath.cs" />
<Compile Include="GoogleDriveIntegration\CloudSyncHelper.cs" /> <Compile Include="GoogleDriveIntegration\CloudSyncHelper.cs" />
<Compile Include="GoogleDriveIntegration\GoogleDriveAccessor.cs" /> <Compile Include="GoogleDriveIntegration\GoogleDriveAccessor.cs" />
<Compile Include="GoogleDriveIntegration\MesenCodeReceiver.cs" /> <Compile Include="GoogleDriveIntegration\MesenCodeReceiver.cs" />

View file

@ -26,7 +26,7 @@ namespace Mesen.GUI
[DllImport(DLLPath)] [return: MarshalAs(UnmanagedType.I1)] public static extern bool IsRunning(); [DllImport(DLLPath)] [return: MarshalAs(UnmanagedType.I1)] public static extern bool IsRunning();
[DllImport(DLLPath)] public static extern void LoadROM([MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(UTF8Marshaler))]string filename, Int32 archiveFileIndex, [MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(UTF8Marshaler))]string patchFile); [DllImport(DLLPath)] public static extern void LoadROM([MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(UTF8Marshaler))]string filename, [MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(UTF8Marshaler))]string patchFile);
[DllImport(DLLPath)] public static extern void AddKnownGameFolder([MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(UTF8Marshaler))]string folder); [DllImport(DLLPath)] public static extern void AddKnownGameFolder([MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(UTF8Marshaler))]string folder);
[DllImport(DLLPath)] public static extern void LoadRecentGame([MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(UTF8Marshaler))]string filepath, [MarshalAs(UnmanagedType.I1)]bool resetGame); [DllImport(DLLPath)] public static extern void LoadRecentGame([MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(UTF8Marshaler))]string filepath, [MarshalAs(UnmanagedType.I1)]bool resetGame);
@ -553,10 +553,10 @@ namespace Mesen.GUI
return header; return header;
} }
public static RomInfo GetRomInfo(string filename = "", Int32 archiveFileIndex = -1) public static RomInfo GetRomInfo(string filename = "")
{ {
InteropRomInfo romInfo = new InteropRomInfo(); InteropRomInfo romInfo = new InteropRomInfo();
InteropEmu.GetRomInfoWrapper(ref romInfo, filename, archiveFileIndex); InteropEmu.GetRomInfoWrapper(ref romInfo, filename);
return new RomInfo(romInfo); return new RomInfo(romInfo);
} }

View file

@ -15,7 +15,6 @@
#include "../Core/FDS.h" #include "../Core/FDS.h"
#include "../Core/VsControlManager.h" #include "../Core/VsControlManager.h"
#include "../Core/SoundMixer.h" #include "../Core/SoundMixer.h"
#include "../Core/FileLoader.h"
#include "../Core/RomLoader.h" #include "../Core/RomLoader.h"
#include "../Core/NsfMapper.h" #include "../Core/NsfMapper.h"
#include "../Core/IRenderingDevice.h" #include "../Core/IRenderingDevice.h"
@ -116,15 +115,18 @@ namespace InteropEmu {
DllExport bool __stdcall IsRunning() { return Console::IsRunning(); } DllExport bool __stdcall IsRunning() { return Console::IsRunning(); }
DllExport void __stdcall LoadROM(char* filename, int32_t archiveFileIndex, char* patchFile) { Console::LoadROM(filename, nullptr, archiveFileIndex, patchFile); } DllExport void __stdcall LoadROM(char* filename, char* patchFile) { Console::LoadROM((string)filename, (string)patchFile); }
DllExport void __stdcall AddKnownGameFolder(char* folder) { FolderUtilities::AddKnownGameFolder(folder); } DllExport void __stdcall AddKnownGameFolder(char* folder) { FolderUtilities::AddKnownGameFolder(folder); }
DllExport void __stdcall LoadRecentGame(char* filepath, bool resetGame) { SaveStateManager::LoadRecentGame(filepath, resetGame); } DllExport void __stdcall LoadRecentGame(char* filepath, bool resetGame) { SaveStateManager::LoadRecentGame(filepath, resetGame); }
DllExport const char* __stdcall GetArchiveRomList(char* filename) { DllExport const char* __stdcall GetArchiveRomList(char* filename) {
std::ostringstream out; std::ostringstream out;
for(string romName : FileLoader::GetArchiveRomList(filename)) { shared_ptr<ArchiveReader> reader = ArchiveReader::GetReader(filename);
if(reader) {
for(string romName : reader->GetFileList({ ".nes", ".fds", ".nsf", ".nsfe", "*.unf" })) {
out << romName << "[!|!]"; out << romName << "[!|!]";
} }
}
_returnString = out.str(); _returnString = out.str();
return _returnString.c_str(); return _returnString.c_str();
} }
@ -174,23 +176,25 @@ namespace InteropEmu {
DllExport void __stdcall Stop() DllExport void __stdcall Stop()
{ {
if(Console::GetInstance()) { if(Console::GetInstance()) {
GameServer::StopServer();
GameClient::Disconnect();
Console::GetInstance()->Stop(); Console::GetInstance()->Stop();
} }
} }
DllExport const void __stdcall GetRomInfo(RomInfo &romInfo, char* filename, int32_t archiveFileIndex) DllExport const void __stdcall GetRomInfo(RomInfo &romInfo, char* filename)
{ {
string romPath = filename; string romPath = filename;
if(romPath.empty()) { if(romPath.empty()) {
_returnString = Console::GetRomName(); _returnString = Console::GetRomName();
romInfo.RomName = _returnString.c_str(); romInfo.RomName = _returnString.c_str();
romInfo.Crc32 = Console::GetCrc32(); romInfo.Crc32 = Console::GetHashInfo().Crc32Hash;
romInfo.PrgCrc32 = Console::GetPrgCrc32(); romInfo.PrgCrc32 = Console::GetHashInfo().PrgCrc32Hash;
romInfo.Format = Console::GetRomFormat(); romInfo.Format = Console::GetRomFormat();
romInfo.IsChrRam = Console::IsChrRam(); romInfo.IsChrRam = Console::IsChrRam();
} else { } else {
RomLoader romLoader; RomLoader romLoader;
if(romLoader.LoadFile(filename, archiveFileIndex)) { if(romLoader.LoadFile(romPath)) {
RomData romData = romLoader.GetRomData(); RomData romData = romLoader.GetRomData();
_returnString = romData.RomName; _returnString = romData.RomName;

View file

@ -38,7 +38,7 @@ extern "C" {
void __stdcall SetFlags(uint64_t flags); void __stdcall SetFlags(uint64_t flags);
void __stdcall SetVideoFilter(VideoFilterType filter); void __stdcall SetVideoFilter(VideoFilterType filter);
void __stdcall InitializeEmu(char* homeFolder, void*, void*, bool, bool, bool); void __stdcall InitializeEmu(char* homeFolder, void*, void*, bool, bool, bool);
void __stdcall LoadROM(const char* filename, int32_t archiveFileIndex, char* patchFile); void __stdcall LoadROM(const char* filename, char* patchFile);
void __stdcall Run(); void __stdcall Run();
void __stdcall Stop(); void __stdcall Stop();
} }
@ -67,7 +67,7 @@ int main(int argc, char* argv[])
SetFlags(0x8000000000000000); //EmulationFlags::ConsoleMode SetFlags(0x8000000000000000); //EmulationFlags::ConsoleMode
InitializeEmu("C:\\Windows\\Temp\\Mesen", nullptr, nullptr, false, false, false); InitializeEmu("C:\\Windows\\Temp\\Mesen", nullptr, nullptr, false, false, false);
LoadROM(testRoms[0], -1, ""); LoadROM(testRoms[0], "");
std::cout << "Running: " << testRoms[0] << std::endl; std::cout << "Running: " << testRoms[0] << std::endl;
thread testThread([testRoms] { thread testThread([testRoms] {
@ -91,7 +91,7 @@ int main(int argc, char* argv[])
std::this_thread::sleep_for(std::chrono::duration<int, std::milli>(5000)); std::this_thread::sleep_for(std::chrono::duration<int, std::milli>(5000));
std::cout << "Running: " << testRoms[i] << std::endl; std::cout << "Running: " << testRoms[i] << std::endl;
SetVideoFilter(filterTypes[i % 13]); SetVideoFilter(filterTypes[i % 13]);
LoadROM(testRoms[i], -1, ""); LoadROM(testRoms[i], "");
} }
std::this_thread::sleep_for(std::chrono::duration<int, std::milli>(5000)); std::this_thread::sleep_for(std::chrono::duration<int, std::milli>(5000));
Stop(); Stop();

View file

@ -50,7 +50,6 @@ extern "C" {
void __stdcall SetControllerType(uint32_t port, ControllerType type); void __stdcall SetControllerType(uint32_t port, ControllerType type);
int __stdcall RunAutomaticTest(char* filename); int __stdcall RunAutomaticTest(char* filename);
int __stdcall RunRecordedTest(char* filename); int __stdcall RunRecordedTest(char* filename);
void __stdcall LoadROM(char* filename);
void __stdcall Run(); void __stdcall Run();
void __stdcall Stop(); void __stdcall Stop();
INotificationListener* __stdcall RegisterNotificationCallback(NotificationListenerCallback callback); INotificationListener* __stdcall RegisterNotificationCallback(NotificationListenerCallback callback);
@ -154,7 +153,7 @@ int main(int argc, char* argv[])
if(argc >= 3 && strcmp(argv[1], "/auto") == 0) { if(argc >= 3 && strcmp(argv[1], "/auto") == 0) {
string romFolder = argv[2]; string romFolder = argv[2];
testFilenames = FolderUtilities::GetFilesInFolder(romFolder, ".nes", true); testFilenames = FolderUtilities::GetFilesInFolder(romFolder, { ".nes" }, true);
automaticTests = true; automaticTests = true;
} else if(argc <= 2) { } else if(argc <= 2) {
string testFolder; string testFolder;
@ -163,7 +162,7 @@ int main(int argc, char* argv[])
} else { } else {
testFolder = argv[1]; testFolder = argv[1];
} }
testFilenames = FolderUtilities::GetFilesInFolder(testFolder, ".mtp", true); testFilenames = FolderUtilities::GetFilesInFolder(testFolder, { ".mtp" }, true);
automaticTests = false; automaticTests = false;
} }

View file

@ -4,6 +4,8 @@
#include <sstream> #include <sstream>
#include <algorithm> #include <algorithm>
#include "FolderUtilities.h" #include "FolderUtilities.h"
#include "ZipReader.h"
#include "SZReader.h"
ArchiveReader::~ArchiveReader() ArchiveReader::~ArchiveReader()
{ {
@ -26,13 +28,17 @@ std::stringstream ArchiveReader::GetStream(string filename)
vector<string> ArchiveReader::GetFileList(std::initializer_list<string> extensions) vector<string> ArchiveReader::GetFileList(std::initializer_list<string> extensions)
{ {
if(extensions.size() == 0) {
return InternalGetFileList();
}
vector<string> filenames; vector<string> filenames;
for(string filename : InternalGetFileList()) { for(string filename : InternalGetFileList()) {
string lcFilename = filename; string lcFilename = filename;
std::transform(lcFilename.begin(), lcFilename.end(), lcFilename.begin(), ::tolower); std::transform(lcFilename.begin(), lcFilename.end(), lcFilename.begin(), ::tolower);
if(filename.length() > 4) {
for(string ext : extensions) { for(string ext : extensions) {
if(lcFilename.substr(lcFilename.length() - 4, 4).compare(ext) == 0) { if(lcFilename.size() >= ext.size()) {
if(lcFilename.substr(lcFilename.length() - ext.size(), ext.size()).compare(ext) == 0) {
filenames.push_back(filename); filenames.push_back(filename);
} }
} }
@ -77,3 +83,26 @@ bool ArchiveReader::LoadArchive(string filename)
} }
return false; return false;
} }
shared_ptr<ArchiveReader> ArchiveReader::GetReader(string filepath)
{
ifstream in(filepath, std::ios::in | std::ios::binary);
if(in) {
uint8_t header[2] = { 0,0 };
in.read((char*)header, 2);
in.close();
shared_ptr<ArchiveReader> reader;
if(memcmp(header, "PK", 2) == 0) {
reader.reset(new ZipReader());
} else if(memcmp(header, "7z", 2) == 0) {
reader.reset(new SZReader());
}
if(reader) {
reader->LoadArchive(filepath);
return reader;
}
}
return nullptr;
}

View file

@ -17,7 +17,9 @@ public:
std::stringstream GetStream(string filename); std::stringstream GetStream(string filename);
vector<string> GetFileList(std::initializer_list<string> extensions); vector<string> GetFileList(std::initializer_list<string> extensions = {});
virtual void ExtractFile(string filename, vector<uint8_t> &output) = 0; virtual bool ExtractFile(string filename, vector<uint8_t> &output) = 0;
static shared_ptr<ArchiveReader> GetReader(string filepath);
}; };

View file

@ -4,7 +4,7 @@
#include "BpsPatcher.h" #include "BpsPatcher.h"
#include "CRC32.h" #include "CRC32.h"
uint64_t BpsPatcher::ReadBase128Number(ifstream &file) uint64_t BpsPatcher::ReadBase128Number(std::istream &file)
{ {
uint64_t result = 0; uint64_t result = 0;
int shift = 0; int shift = 0;
@ -25,11 +25,17 @@ uint64_t BpsPatcher::ReadBase128Number(ifstream &file)
return result; return result;
} }
vector<uint8_t> BpsPatcher::PatchBuffer(string bpsFilepath, vector<uint8_t> input) bool BpsPatcher::PatchBuffer(string bpsFilepath, vector<uint8_t> &input, vector<uint8_t> &output)
{ {
ifstream bpsFile(bpsFilepath, std::ios::in | std::ios::binary); ifstream bpsFile(bpsFilepath, std::ios::in | std::ios::binary);
if(bpsFile) { if(bpsFile) {
return PatchBuffer(bpsFile, input, output);
}
return false;
}
bool BpsPatcher::PatchBuffer(std::istream &bpsFile, vector<uint8_t> &input, vector<uint8_t> &output)
{
bpsFile.seekg(0, std::ios::end); bpsFile.seekg(0, std::ios::end);
size_t fileSize = (size_t)bpsFile.tellg(); size_t fileSize = (size_t)bpsFile.tellg();
bpsFile.seekg(0, std::ios::beg); bpsFile.seekg(0, std::ios::beg);
@ -38,20 +44,19 @@ vector<uint8_t> BpsPatcher::PatchBuffer(string bpsFilepath, vector<uint8_t> inpu
bpsFile.read((char*)&header, 4); bpsFile.read((char*)&header, 4);
if(memcmp((char*)&header, "BPS1", 4) != 0) { if(memcmp((char*)&header, "BPS1", 4) != 0) {
//Invalid BPS file //Invalid BPS file
return input; return false;
} }
uint64_t inputFileSize = ReadBase128Number(bpsFile); uint64_t inputFileSize = ReadBase128Number(bpsFile);
uint64_t outputFileSize = ReadBase128Number(bpsFile); uint64_t outputFileSize = ReadBase128Number(bpsFile);
if(inputFileSize == -1 || outputFileSize == -1) { if(inputFileSize == -1 || outputFileSize == -1) {
//Invalid file //Invalid file
return input; return false;
} }
uint64_t metadataSize = ReadBase128Number(bpsFile); uint64_t metadataSize = ReadBase128Number(bpsFile);
bpsFile.seekg(metadataSize, std::ios::cur); bpsFile.seekg(metadataSize, std::ios::cur);
vector<uint8_t> output;
output.resize((size_t)outputFileSize); output.resize((size_t)outputFileSize);
uint32_t outputOffset = 0; uint32_t outputOffset = 0;
@ -61,7 +66,7 @@ vector<uint8_t> BpsPatcher::PatchBuffer(string bpsFilepath, vector<uint8_t> inpu
uint64_t data = ReadBase128Number(bpsFile); uint64_t data = ReadBase128Number(bpsFile);
if(data == -1) { if(data == -1) {
//Invalid file //Invalid file
return input; return false;
} }
uint8_t command = data & 0x03; uint8_t command = data & 0x03;
@ -117,11 +122,7 @@ vector<uint8_t> BpsPatcher::PatchBuffer(string bpsFilepath, vector<uint8_t> inpu
uint32_t outputCrc = CRC32::GetCRC(output.data(), output.size()); uint32_t outputCrc = CRC32::GetCRC(output.data(), output.size());
if(patchInputCrc != inputCrc || patchOutputCrc != outputCrc) { if(patchInputCrc != inputCrc || patchOutputCrc != outputCrc) {
return input; return false;
} }
return true;
bpsFile.close();
return output;
}
return input;
} }

View file

@ -5,8 +5,9 @@
class BpsPatcher class BpsPatcher
{ {
private: private:
static uint64_t ReadBase128Number(ifstream &file); static uint64_t ReadBase128Number(std::istream &file);
public: public:
static vector<uint8_t> PatchBuffer(string bpsFilepath, vector<uint8_t> input); static bool PatchBuffer(std::istream &bpsFile, vector<uint8_t> &input, vector<uint8_t> &output);
static bool PatchBuffer(string bpsFilepath, vector<uint8_t> &input, vector<uint8_t> &output);
}; };

View file

@ -4,6 +4,7 @@
#include <experimental/filesystem> #include <experimental/filesystem>
namespace fs = std::experimental::filesystem; namespace fs = std::experimental::filesystem;
#include <unordered_set>
#include <algorithm> #include <algorithm>
#include "FolderUtilities.h" #include "FolderUtilities.h"
#include "UTF8Util.h" #include "UTF8Util.h"
@ -120,7 +121,7 @@ vector<string> FolderUtilities::GetFolders(string rootFolder)
return folders; return folders;
} }
vector<string> FolderUtilities::GetFilesInFolder(string rootFolder, string mask, bool recursive) vector<string> FolderUtilities::GetFilesInFolder(string rootFolder, std::unordered_set<string> extensions, bool recursive)
{ {
vector<string> files; vector<string> files;
vector<string> folders = { { rootFolder } }; vector<string> folders = { { rootFolder } };
@ -139,7 +140,7 @@ vector<string> FolderUtilities::GetFilesInFolder(string rootFolder, string mask,
for(fs::directory_iterator i(fs::u8path(folder.c_str())), end; i != end; i++) { for(fs::directory_iterator i(fs::u8path(folder.c_str())), end; i != end; i++) {
string extension = i->path().extension().u8string(); string extension = i->path().extension().u8string();
std::transform(extension.begin(), extension.end(), extension.begin(), ::tolower); std::transform(extension.begin(), extension.end(), extension.begin(), ::tolower);
if(extension == mask) { if(extensions.find(extension) != extensions.end()) {
files.push_back(i->path().u8string()); files.push_back(i->path().u8string());
} }
} }

View file

@ -1,6 +1,7 @@
#pragma once #pragma once
#include "stdafx.h" #include "stdafx.h"
#include <unordered_set>
class FolderUtilities class FolderUtilities
{ {
@ -24,7 +25,7 @@ public:
static string GetRecentGamesFolder(); static string GetRecentGamesFolder();
static vector<string> GetFolders(string rootFolder); static vector<string> GetFolders(string rootFolder);
static vector<string> GetFilesInFolder(string rootFolder, string mask, bool recursive); static vector<string> GetFilesInFolder(string rootFolder, std::unordered_set<string> extensions, bool recursive);
static string GetFilename(string filepath, bool includeExtension); static string GetFilename(string filepath, bool includeExtension);
static string GetFolderName(string filepath); static string GetFolderName(string filepath);

View file

@ -14,7 +14,7 @@ public:
uint16_t RepeatCount = 0; uint16_t RepeatCount = 0;
uint8_t Value = 0; uint8_t Value = 0;
bool ReadRecord(ifstream &ipsFile) bool ReadRecord(std::istream &ipsFile)
{ {
uint8_t buffer[3]; uint8_t buffer[3];
@ -60,16 +60,22 @@ public:
} }
}; };
vector<uint8_t> IpsPatcher::PatchBuffer(string ipsFilepath, vector<uint8_t> input) bool IpsPatcher::PatchBuffer(string ipsFilepath, vector<uint8_t> &input, vector<uint8_t> &output)
{ {
ifstream ipsFile(ipsFilepath, std::ios::in | std::ios::binary); ifstream ipsFile(ipsFilepath, std::ios::in | std::ios::binary);
if(ipsFile) { if(ipsFile) {
return PatchBuffer(ipsFile, input, output);
}
return false;
}
bool IpsPatcher::PatchBuffer(std::istream &ipsFile, vector<uint8_t> &input, vector<uint8_t> &output)
{
char header[5]; char header[5];
ipsFile.read((char*)&header, 5); ipsFile.read((char*)&header, 5);
if(memcmp((char*)&header, "PATCH", 5) != 0) { if(memcmp((char*)&header, "PATCH", 5) != 0) {
//Invalid ips file //Invalid ips file
return input; return false;
} }
vector<IpsRecord> records; vector<IpsRecord> records;
@ -93,7 +99,6 @@ vector<uint8_t> IpsPatcher::PatchBuffer(string ipsFilepath, vector<uint8_t> inpu
} }
} }
vector<uint8_t> output;
output.resize(maxOutputSize); output.resize(maxOutputSize);
std::copy(input.begin(), input.end(), output.begin()); std::copy(input.begin(), input.end(), output.begin());
@ -109,11 +114,7 @@ vector<uint8_t> IpsPatcher::PatchBuffer(string ipsFilepath, vector<uint8_t> inpu
output.resize(truncateOffset); output.resize(truncateOffset);
} }
ipsFile.close(); return true;
return output;
}
return input;
} }
vector<uint8_t> IpsPatcher::CreatePatch(vector<uint8_t> originalData, vector<uint8_t> newData) vector<uint8_t> IpsPatcher::CreatePatch(vector<uint8_t> originalData, vector<uint8_t> newData)

View file

@ -5,6 +5,7 @@
class IpsPatcher class IpsPatcher
{ {
public: public:
static vector<uint8_t> PatchBuffer(string ipsFilepath, vector<uint8_t> input); static bool PatchBuffer(string ipsFilepath, vector<uint8_t> &input, vector<uint8_t> &output);
static bool PatchBuffer(std::istream &ipsFile, vector<uint8_t> &input, vector<uint8_t> &output);
static vector<uint8_t> CreatePatch(vector<uint8_t> originalData, vector<uint8_t> newData); static vector<uint8_t> CreatePatch(vector<uint8_t> originalData, vector<uint8_t> newData);
}; };

View file

@ -38,11 +38,31 @@ bool PNGHelper::WritePNG(string filename, uint32_t* buffer, uint32_t xSize, uint
return false; return false;
} }
bool PNGHelper::ReadPNG(vector<uint8_t> input, vector<uint8_t> &output, uint32_t &pngWidth, uint32_t &pngHeight)
{
unsigned long width = 0;
unsigned long height = 0;
pngWidth = 0;
pngHeight = 0;
if(DecodePNG(output, width, height, input.data(), input.size()) == 0) {
uint32_t *pngDataPtr = (uint32_t*)output.data();
for(size_t i = 0, len = output.size() / 4; i < len; i++) {
//ABGR to ARGB
pngDataPtr[i] = (pngDataPtr[i] & 0xFF00FF00) | ((pngDataPtr[i] & 0xFF0000) >> 16) | ((pngDataPtr[i] & 0xFF) << 16);
}
pngWidth = width;
pngHeight = height;
return true;
} else {
return false;
}
}
bool PNGHelper::ReadPNG(string filename, vector<uint8_t> &pngData, uint32_t &pngWidth, uint32_t &pngHeight) bool PNGHelper::ReadPNG(string filename, vector<uint8_t> &pngData, uint32_t &pngWidth, uint32_t &pngHeight)
{ {
unsigned long width;
unsigned long height;
pngWidth = 0; pngWidth = 0;
pngHeight = 0; pngHeight = 0;
@ -52,19 +72,9 @@ bool PNGHelper::ReadPNG(string filename, vector<uint8_t> &pngData, uint32_t &png
size_t fileSize = (size_t)pngFile.tellg(); size_t fileSize = (size_t)pngFile.tellg();
pngFile.seekg(0, std::ios::beg); pngFile.seekg(0, std::ios::beg);
uint8_t* buffer = new uint8_t[fileSize]; vector<uint8_t> fileData(fileSize, 0);
pngFile.read((char*)buffer, fileSize); pngFile.read((char*)fileData.data(), fileData.size());
DecodePNG(pngData, width, height, buffer, fileSize); return ReadPNG(fileData, pngData, pngWidth, pngHeight);
uint32_t *pngDataPtr = (uint32_t*)&pngData[0];
for(size_t i = 0, len = pngData.size() / 4; i < len; i++) {
//ABGR to ARGB
pngDataPtr[i] = (pngDataPtr[i] & 0xFF00FF00) | ((pngDataPtr[i] & 0xFF0000) >> 16) | ((pngDataPtr[i] & 0xFF) << 16);
}
pngWidth = width;
pngHeight = height;
delete[] buffer;
return true;
} }
return false; return false;

View file

@ -10,4 +10,5 @@ public:
static bool WritePNG(std::stringstream &stream, uint32_t* buffer, uint32_t xSize, uint32_t ySize, uint32_t bitsPerPixel = 32); static bool WritePNG(std::stringstream &stream, uint32_t* buffer, uint32_t xSize, uint32_t ySize, uint32_t bitsPerPixel = 32);
static bool WritePNG(string filename, uint32_t* buffer, uint32_t xSize, uint32_t ySize, uint32_t bitsPerPixel = 32); static bool WritePNG(string filename, uint32_t* buffer, uint32_t xSize, uint32_t ySize, uint32_t bitsPerPixel = 32);
static bool ReadPNG(string filename, vector<uint8_t> &pngData, uint32_t &pngWidth, uint32_t &pngHeight); static bool ReadPNG(string filename, vector<uint8_t> &pngData, uint32_t &pngWidth, uint32_t &pngHeight);
static bool ReadPNG(vector<uint8_t> input, vector<uint8_t> &output, uint32_t &pngWidth, uint32_t &pngHeight);
}; };

View file

@ -16,6 +16,11 @@ SZReader::~SZReader()
bool SZReader::InternalLoadArchive(void* buffer, size_t size) bool SZReader::InternalLoadArchive(void* buffer, size_t size)
{ {
if(_initialized) {
SzArEx_Free(&_archive, &_allocImp);
_initialized = false;
}
ISzAlloc allocImp{ SzAlloc, SzFree }; ISzAlloc allocImp{ SzAlloc, SzFree };
ISzAlloc allocTempImp{ SzAllocTemp, SzFreeTemp }; ISzAlloc allocTempImp{ SzAllocTemp, SzFreeTemp };
@ -26,8 +31,9 @@ bool SZReader::InternalLoadArchive(void* buffer, size_t size)
return !SzArEx_Open(&_archive, &_lookStream.s, &allocImp, &allocTempImp); return !SzArEx_Open(&_archive, &_lookStream.s, &allocImp, &allocTempImp);
} }
void SZReader::ExtractFile(string filename, vector<uint8_t> &output) bool SZReader::ExtractFile(string filename, vector<uint8_t> &output)
{ {
bool result = false;
if(_initialized) { if(_initialized) {
char16_t *utf16Filename = (char16_t*)SzAlloc(nullptr, 2000); char16_t *utf16Filename = (char16_t*)SzAlloc(nullptr, 2000);
@ -50,6 +56,7 @@ void SZReader::ExtractFile(string filename, vector<uint8_t> &output)
if(res == SZ_OK) { if(res == SZ_OK) {
uint8_t* buf = new uint8_t[outSizeProcessed]; uint8_t* buf = new uint8_t[outSizeProcessed];
output = vector<uint8_t>(outBuffer+offset, outBuffer+offset+outSizeProcessed); output = vector<uint8_t>(outBuffer+offset, outBuffer+offset+outSizeProcessed);
result = true;
} }
IAlloc_Free(&_allocImp, outBuffer); IAlloc_Free(&_allocImp, outBuffer);
break; break;
@ -57,6 +64,8 @@ void SZReader::ExtractFile(string filename, vector<uint8_t> &output)
} }
SzFree(nullptr, utf16Filename); SzFree(nullptr, utf16Filename);
} }
return result;
} }
vector<string> SZReader::InternalGetFileList() vector<string> SZReader::InternalGetFileList()

View file

@ -24,5 +24,5 @@ public:
SZReader(); SZReader();
virtual ~SZReader(); virtual ~SZReader();
void ExtractFile(string filename, vector<uint8_t> &output); bool ExtractFile(string filename, vector<uint8_t> &output);
}; };

View file

@ -4,7 +4,7 @@
#include "UpsPatcher.h" #include "UpsPatcher.h"
#include "CRC32.h" #include "CRC32.h"
uint64_t UpsPatcher::ReadBase128Number(ifstream &file) uint64_t UpsPatcher::ReadBase128Number(std::istream &file)
{ {
uint64_t result = 0; uint64_t result = 0;
int shift = 0; int shift = 0;
@ -25,11 +25,17 @@ uint64_t UpsPatcher::ReadBase128Number(ifstream &file)
return result; return result;
} }
vector<uint8_t> UpsPatcher::PatchBuffer(string upsFilepath, vector<uint8_t> input) bool UpsPatcher::PatchBuffer(string upsFilepath, vector<uint8_t> &input, vector<uint8_t> &output)
{ {
ifstream upsFile(upsFilepath, std::ios::in | std::ios::binary); ifstream upsFile(upsFilepath, std::ios::in | std::ios::binary);
if(upsFile) { if(upsFile) {
return PatchBuffer(upsFile, input, output);
}
return false;
}
bool UpsPatcher::PatchBuffer(std::istream &upsFile, vector<uint8_t> &input, vector<uint8_t> &output)
{
upsFile.seekg(0, std::ios::end); upsFile.seekg(0, std::ios::end);
size_t fileSize = (size_t)upsFile.tellg(); size_t fileSize = (size_t)upsFile.tellg();
upsFile.seekg(0, std::ios::beg); upsFile.seekg(0, std::ios::beg);
@ -38,17 +44,16 @@ vector<uint8_t> UpsPatcher::PatchBuffer(string upsFilepath, vector<uint8_t> inpu
upsFile.read((char*)&header, 4); upsFile.read((char*)&header, 4);
if(memcmp((char*)&header, "UPS1", 4) != 0) { if(memcmp((char*)&header, "UPS1", 4) != 0) {
//Invalid UPS file //Invalid UPS file
return input; return false;
} }
uint64_t inputFileSize = ReadBase128Number(upsFile); uint64_t inputFileSize = ReadBase128Number(upsFile);
uint64_t outputFileSize = ReadBase128Number(upsFile); uint64_t outputFileSize = ReadBase128Number(upsFile);
if(inputFileSize == -1 || outputFileSize == -1) { if(inputFileSize == -1 || outputFileSize == -1) {
//Invalid file //Invalid file
return input; return false;
} }
vector<uint8_t> output;
output.resize((size_t)outputFileSize); output.resize((size_t)outputFileSize);
std::copy(input.begin(), input.end(), output.begin()); std::copy(input.begin(), input.end(), output.begin());
@ -57,7 +62,7 @@ vector<uint8_t> UpsPatcher::PatchBuffer(string upsFilepath, vector<uint8_t> inpu
uint32_t offset = (uint32_t)ReadBase128Number(upsFile); uint32_t offset = (uint32_t)ReadBase128Number(upsFile);
if(offset == -1) { if(offset == -1) {
//Invalid file //Invalid file
return input; return false;
} }
pos += offset; pos += offset;
@ -67,7 +72,7 @@ vector<uint8_t> UpsPatcher::PatchBuffer(string upsFilepath, vector<uint8_t> inpu
upsFile.read((char*)&xorValue, 1); upsFile.read((char*)&xorValue, 1);
if((size_t)upsFile.tellg() > fileSize - 12) { if((size_t)upsFile.tellg() > fileSize - 12) {
//Invalid file //Invalid file
return input; return false;
} }
output[pos] ^= xorValue; output[pos] ^= xorValue;
@ -89,11 +94,7 @@ vector<uint8_t> UpsPatcher::PatchBuffer(string upsFilepath, vector<uint8_t> inpu
uint32_t outputCrc = CRC32::GetCRC(output.data(), output.size()); uint32_t outputCrc = CRC32::GetCRC(output.data(), output.size());
if(patchInputCrc != inputCrc || patchOutputCrc != outputCrc) { if(patchInputCrc != inputCrc || patchOutputCrc != outputCrc) {
return input; return false;
} }
return true;
upsFile.close();
return output;
}
return input;
} }

View file

@ -5,8 +5,9 @@
class UpsPatcher class UpsPatcher
{ {
private: private:
static uint64_t ReadBase128Number(ifstream &file); static uint64_t ReadBase128Number(std::istream &file);
public: public:
static vector<uint8_t> PatchBuffer(string upsFilepath, vector<uint8_t> input); static bool PatchBuffer(std::istream &upsFile, vector<uint8_t> &input, vector<uint8_t> &output);
static bool PatchBuffer(string upsFilepath, vector<uint8_t> &input, vector<uint8_t> &output);
}; };

View file

@ -359,6 +359,7 @@
<ClInclude Include="Timer.h" /> <ClInclude Include="Timer.h" />
<ClInclude Include="UpsPatcher.h" /> <ClInclude Include="UpsPatcher.h" />
<ClInclude Include="UTF8Util.h" /> <ClInclude Include="UTF8Util.h" />
<ClInclude Include="VirtualFile.h" />
<ClInclude Include="xBRZ\config.h" /> <ClInclude Include="xBRZ\config.h" />
<ClInclude Include="xBRZ\xbrz.h" /> <ClInclude Include="xBRZ\xbrz.h" />
<ClInclude Include="ZipReader.h" /> <ClInclude Include="ZipReader.h" />

View file

@ -116,9 +116,6 @@
<ClInclude Include="SZReader.h"> <ClInclude Include="SZReader.h">
<Filter>Header Files</Filter> <Filter>Header Files</Filter>
</ClInclude> </ClInclude>
<ClInclude Include="ArchiveReader.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="PlatformUtilities.h"> <ClInclude Include="PlatformUtilities.h">
<Filter>Header Files</Filter> <Filter>Header Files</Filter>
</ClInclude> </ClInclude>
@ -158,6 +155,12 @@
<ClInclude Include="sha1.h"> <ClInclude Include="sha1.h">
<Filter>Header Files</Filter> <Filter>Header Files</Filter>
</ClInclude> </ClInclude>
<ClInclude Include="ArchiveReader.h">
<Filter>Header Files</Filter>
</ClInclude>
<ClInclude Include="VirtualFile.h">
<Filter>Header Files</Filter>
</ClInclude>
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<ClCompile Include="stdafx.cpp"> <ClCompile Include="stdafx.cpp">

155
Utilities/VirtualFile.h Normal file
View file

@ -0,0 +1,155 @@
#pragma once
#include "stdafx.h"
#include <algorithm>
#include <iterator>
#include <sstream>
#include "sha1.h"
#include "ArchiveReader.h"
#include "StringUtilities.h"
#include "FolderUtilities.h"
#include "BpsPatcher.h"
#include "IpsPatcher.h"
#include "UpsPatcher.h"
class VirtualFile
{
private:
string _path = "";
string _innerFile = "";
vector<uint8_t> _data;
void FromStream(std::istream &input, vector<uint8_t> &output)
{
input.seekg(0, std::ios::end);
uint32_t fileSize = (uint32_t)input.tellg();
input.seekg(0, std::ios::beg);
output.resize(fileSize, 0);
input.read((char*)output.data(), fileSize);
}
void LoadFile()
{
if(_data.size() == 0) {
if(!_innerFile.empty()) {
shared_ptr<ArchiveReader> reader = ArchiveReader::GetReader(_path);
if(reader) {
reader->ExtractFile(_innerFile, _data);
}
} else {
ifstream input(_path, std::ios::in | std::ios::binary);
if(input.good()) {
FromStream(input, _data);
}
}
}
}
public:
VirtualFile()
{
}
VirtualFile(const string &archivePath, const string innerFile)
{
_path = archivePath;
_innerFile = innerFile;
}
VirtualFile(const string &file)
{
vector<string> tokens = StringUtilities::Split(file, '\x1');
_path = tokens[0];
if(tokens.size() > 1) {
_innerFile = tokens[1];
}
}
VirtualFile(std::istream &input)
{
FromStream(input, _data);
}
operator std::string() const
{
if(_innerFile.empty()) {
return _path;
} else if(_path.empty()) {
throw std::runtime_error("Cannot convert to string");
} else {
return _path + "\x1" + _innerFile;
}
}
bool IsValid()
{
LoadFile();
return _data.size() > 0;
}
string GetFilePath()
{
return _path;
}
string GetFolderPath()
{
return FolderUtilities::GetFolderName(_path);
}
string GetFileName()
{
return _innerFile.empty() ? FolderUtilities::GetFilename(_path, false) : _innerFile;
}
string GetSha1Hash()
{
string hash = SHA1::GetHash(_data);
std::transform(hash.begin(), hash.end(), hash.begin(), ::tolower);
return hash;
}
bool ReadFile(vector<uint8_t> &out)
{
LoadFile();
if(_data.size() > 0) {
out.resize(_data.size(), 0);
std::copy(_data.begin(), _data.end(), out.begin());
return true;
}
return false;
}
bool ReadFile(std::stringstream &out)
{
LoadFile();
if(_data.size() > 0) {
out.write((char*)_data.data(), _data.size());
return true;
}
return false;
}
bool ApplyPatch(VirtualFile &patch)
{
//Apply patch file
bool result = false;
if(patch.IsValid() && patch._data.size() >= 5 ) {
vector<uint8_t> patchedData;
std::stringstream ss;
patch.ReadFile(ss);
if(memcmp(patch._data.data(), "PATCH", 5) == 0) {
result = IpsPatcher::PatchBuffer(ss, _data, patchedData);
} else if(memcmp(patch._data.data(), "UPS1", 4) == 0) {
result = UpsPatcher::PatchBuffer(ss, _data, patchedData);
} else if(memcmp(patch._data.data(), "BPS1", 4) == 0) {
result = BpsPatcher::PatchBuffer(ss, _data, patchedData);
}
if(result) {
_data = patchedData;
}
}
return result;
}
};

View file

@ -17,6 +17,12 @@ ZipReader::~ZipReader()
bool ZipReader::InternalLoadArchive(void* buffer, size_t size) bool ZipReader::InternalLoadArchive(void* buffer, size_t size)
{ {
if(_initialized) {
mz_zip_reader_end(&_zipArchive);
memset(&_zipArchive, 0, sizeof(mz_zip_archive));
_initialized = false;
}
return mz_zip_reader_init_mem(&_zipArchive, buffer, size, 0) != 0; return mz_zip_reader_init_mem(&_zipArchive, buffer, size, 0) != 0;
} }
@ -36,18 +42,23 @@ vector<string> ZipReader::InternalGetFileList()
return fileList; return fileList;
} }
void ZipReader::ExtractFile(string filename, vector<uint8_t> &output) bool ZipReader::ExtractFile(string filename, vector<uint8_t> &output)
{ {
if(_initialized) { if(_initialized) {
size_t uncompSize; size_t uncompSize;
void *p = mz_zip_reader_extract_file_to_heap(&_zipArchive, filename.c_str(), &uncompSize, 0); void *p = mz_zip_reader_extract_file_to_heap(&_zipArchive, filename.c_str(), &uncompSize, 0);
if(!p) { if(!p) {
std::cout << "mz_zip_reader_extract_file_to_heap() failed!" << std::endl; std::cout << "mz_zip_reader_extract_file_to_heap() failed!" << std::endl;
return false;
} }
output = vector<uint8_t>((uint8_t*)p, (uint8_t*)p + uncompSize); output = vector<uint8_t>((uint8_t*)p, (uint8_t*)p + uncompSize);
// We're done. // We're done.
mz_free(p); mz_free(p);
return true;
} }
return false;
} }

View file

@ -16,5 +16,5 @@ public:
ZipReader(); ZipReader();
virtual ~ZipReader(); virtual ~ZipReader();
void ExtractFile(string filename, vector<uint8_t> &output); bool ExtractFile(string filename, vector<uint8_t> &output);
}; };

View file

@ -34,7 +34,8 @@ void ZipWriter::AddFile(std::stringstream &filestream, string zipFilename)
uint8_t* buffer = new uint8_t[bufferSize]; uint8_t* buffer = new uint8_t[bufferSize];
filestream.read((char*)buffer, bufferSize); filestream.read((char*)buffer, bufferSize);
if(! mz_zip_writer_add_mem(&_zipArchive, zipFilename.c_str(), buffer, bufferSize, MZ_BEST_COMPRESSION)) { if(!mz_zip_writer_add_mem(&_zipArchive, zipFilename.c_str(), buffer, bufferSize, MZ_BEST_COMPRESSION)) {
std::cout << "mz_zip_writer_add_file() failed!" << std::endl; std::cout << "mz_zip_writer_add_file() failed!" << std::endl;
} }
delete[] buffer;
} }