Code refactoring (patch/archive handling) + allow HD packs to be loaded from archives
This commit is contained in:
parent
119ccd5881
commit
4455178da2
56 changed files with 890 additions and 685 deletions
|
@ -521,9 +521,9 @@ void BaseMapper::Initialize(RomData &romData)
|
|||
|
||||
_gameSystem = romData.System;
|
||||
_hashInfo.Crc32Hash = romData.Crc32;
|
||||
_hashInfo.PrgCrc32Hash = romData.PrgCrc32;
|
||||
_hashInfo.Sha1Hash = romData.Sha1;
|
||||
_hashInfo.PrgChrMd5Hash = romData.PrgChrMd5;
|
||||
_prgCrc32 = romData.PrgCrc32;
|
||||
switch(romData.BusConflicts) {
|
||||
case BusConflictType::Default: _hasBusConflicts = HasBusConflicts(); break;
|
||||
case BusConflictType::Yes: _hasBusConflicts = true; break;
|
||||
|
@ -717,11 +717,6 @@ HashInfo BaseMapper::GetHashInfo()
|
|||
return _hashInfo;
|
||||
}
|
||||
|
||||
uint32_t BaseMapper::GetPrgCrc32()
|
||||
{
|
||||
return _prgCrc32;
|
||||
}
|
||||
|
||||
MirroringType BaseMapper::GetMirroringType()
|
||||
{
|
||||
return _mirroringType;
|
||||
|
|
|
@ -46,7 +46,6 @@ private:
|
|||
uint32_t _chrPageNumbers[64];
|
||||
|
||||
HashInfo _hashInfo;
|
||||
uint32_t _prgCrc32 = 0;
|
||||
|
||||
vector<uint8_t> _originalPrgRom;
|
||||
|
||||
|
@ -164,7 +163,6 @@ public:
|
|||
|
||||
GameSystem GetGameSystem();
|
||||
HashInfo GetHashInfo();
|
||||
uint32_t GetPrgCrc32();
|
||||
string GetRomName();
|
||||
RomFormat GetRomFormat();
|
||||
|
||||
|
|
|
@ -81,8 +81,9 @@ bool BizhawkMovie::InitializeGameData(ZipReader & reader)
|
|||
std::getline(ss, line);
|
||||
if(line.compare(0, 4, "SHA1", 4) == 0) {
|
||||
if(line.size() >= 45) {
|
||||
string sha1 = line.substr(5, 40);
|
||||
if(Console::LoadROM("", sha1)) {
|
||||
HashInfo hashInfo;
|
||||
hashInfo.Sha1Hash = line.substr(5, 40);
|
||||
if(Console::LoadROM("", hashInfo)) {
|
||||
result = true;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
#include "stdafx.h"
|
||||
#include <thread>
|
||||
#include "Console.h"
|
||||
#include "FileLoader.h"
|
||||
#include "CPU.h"
|
||||
#include "PPU.h"
|
||||
#include "APU.h"
|
||||
|
@ -19,6 +18,7 @@
|
|||
#include "../Utilities/Timer.h"
|
||||
#include "../Utilities/FolderUtilities.h"
|
||||
#include "../Utilities/PlatformUtilities.h"
|
||||
#include "../Utilities/VirtualFile.h"
|
||||
#include "HdBuilderPpu.h"
|
||||
#include "HdPpu.h"
|
||||
#include "NsfPpu.h"
|
||||
|
@ -36,7 +36,6 @@ Console::Console()
|
|||
{
|
||||
_resetRequested = false;
|
||||
_lagCounter = 0;
|
||||
_archiveFileIndex = -1;
|
||||
}
|
||||
|
||||
Console::~Console()
|
||||
|
@ -55,7 +54,7 @@ void Console::Release()
|
|||
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();
|
||||
|
||||
|
@ -64,26 +63,30 @@ bool Console::Initialize(string romFilename, stringstream *filestream, string pa
|
|||
_mapper->SaveBattery();
|
||||
|
||||
//Save current game state before loading another one
|
||||
SaveStateManager::SaveRecentGame(_mapper->GetRomName(), _romFilepath, _patchFilename, _archiveFileIndex);
|
||||
SaveStateManager::SaveRecentGame(_mapper->GetRomName(), _romFilepath, _patchFilename);
|
||||
}
|
||||
|
||||
vector<uint8_t> fileData;
|
||||
if(FileLoader::LoadFile(romFilename, filestream, archiveFileIndex, fileData)) {
|
||||
LoadHdPack(romFilename, fileData, patchFilename);
|
||||
if(!patchFilename.empty()) {
|
||||
FileLoader::ApplyPatch(patchFilename, fileData);
|
||||
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;
|
||||
romFile.ReadFile(fileData);
|
||||
|
||||
shared_ptr<BaseMapper> mapper = MapperFactory::InitializeFromFile(romFilename, fileData);
|
||||
shared_ptr<BaseMapper> mapper = MapperFactory::InitializeFromFile(romFile.GetFileName(), fileData);
|
||||
if(mapper) {
|
||||
if(_mapper) {
|
||||
//Send notification only if a game was already running and we successfully loaded the new one
|
||||
MessageManager::SendNotification(ConsoleNotificationType::GameStopped);
|
||||
}
|
||||
|
||||
_romFilepath = romFilename;
|
||||
_patchFilename = patchFilename;
|
||||
_archiveFileIndex = archiveFileIndex;
|
||||
_romFilepath = romFile;
|
||||
_patchFilename = patchFile;
|
||||
|
||||
_autoSaveManager.reset(new AutoSaveManager());
|
||||
VideoDecoder::GetInstance()->StopThread();
|
||||
|
@ -128,7 +131,7 @@ bool Console::Initialize(string romFilename, stringstream *filestream, string pa
|
|||
|
||||
VideoDecoder::GetInstance()->StartThread();
|
||||
|
||||
FolderUtilities::AddKnownGameFolder(FolderUtilities::GetFolderName(romFilename));
|
||||
FolderUtilities::AddKnownGameFolder(romFile.GetFolderPath());
|
||||
|
||||
string modelName = _model == NesModel::PAL ? "PAL" : (_model == NesModel::Dendy ? "Dendy" : "NTSC");
|
||||
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;
|
||||
}
|
||||
|
||||
bool Console::LoadROM(string filepath, stringstream *filestream, int32_t archiveFileIndex, string patchFilepath)
|
||||
bool Console::LoadROM(VirtualFile romFile, VirtualFile patchFile)
|
||||
{
|
||||
Console::Pause();
|
||||
bool result = Instance->Initialize(filepath, filestream, patchFilepath, archiveFileIndex);
|
||||
bool result = Instance->Initialize(romFile, patchFile);
|
||||
Console::Resume();
|
||||
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)
|
||||
{
|
||||
string currentRomFilepath = Console::GetROMPath();
|
||||
string currentRomFilepath = Console::GetRomPath();
|
||||
string currentFolder = FolderUtilities::GetFolderName(currentRomFilepath);
|
||||
if(!currentRomFilepath.empty()) {
|
||||
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()) {
|
||||
string match = RomLoader::FindMatchingRomInFolder(folder, romName, hashInfo, true, archiveFileIndex);
|
||||
string match = RomLoader::FindMatchingRomInFolder(folder, romName, hashInfo, true);
|
||||
if(!match.empty()) {
|
||||
return Console::LoadROM(match, nullptr, archiveFileIndex);
|
||||
return Console::LoadROM(match);
|
||||
}
|
||||
}
|
||||
|
||||
//Perform slow CRC32 search for ROM
|
||||
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()) {
|
||||
return Console::LoadROM(match, nullptr, archiveFileIndex);
|
||||
return Console::LoadROM(match);
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
string Console::GetROMPath()
|
||||
string Console::GetRomPath()
|
||||
{
|
||||
return Instance->_romFilepath;
|
||||
return static_cast<VirtualFile>(Instance->_romFilepath).GetFilePath();
|
||||
}
|
||||
|
||||
string Console::GetRomName()
|
||||
|
@ -229,24 +217,14 @@ bool Console::IsChrRam()
|
|||
}
|
||||
}
|
||||
|
||||
uint32_t Console::GetCrc32()
|
||||
HashInfo Console::GetHashInfo()
|
||||
{
|
||||
if(Instance->_mapper) {
|
||||
return Instance->_mapper->GetHashInfo().Crc32Hash;
|
||||
return Instance->_mapper->GetHashInfo();
|
||||
} else {
|
||||
return 0;
|
||||
return {};
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t Console::GetPrgCrc32()
|
||||
{
|
||||
if(Instance->_mapper) {
|
||||
return Instance->_mapper->GetPrgCrc32();
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
NesModel Console::GetModel()
|
||||
{
|
||||
return Instance->_model;
|
||||
|
@ -255,7 +233,7 @@ NesModel Console::GetModel()
|
|||
void Console::PowerCycle()
|
||||
{
|
||||
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);
|
||||
} else {
|
||||
//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();
|
||||
}
|
||||
|
@ -458,7 +436,7 @@ void Console::Run()
|
|||
}
|
||||
|
||||
if(!crashed) {
|
||||
SaveStateManager::SaveRecentGame(_mapper->GetRomName(), _romFilepath, _patchFilename, _archiveFileIndex);
|
||||
SaveStateManager::SaveRecentGame(_mapper->GetRomName(), _romFilepath, _patchFilename);
|
||||
}
|
||||
|
||||
MessageManager::SendNotification(ConsoleNotificationType::GameStopped);
|
||||
|
@ -641,20 +619,17 @@ HdPackData* Console::GetHdData()
|
|||
return Instance->_hdData.get();
|
||||
}
|
||||
|
||||
void Console::LoadHdPack(string romFilename, vector<uint8_t> &fileData, string &patchFilename)
|
||||
void Console::LoadHdPack(VirtualFile &romFile, VirtualFile &patchFile)
|
||||
{
|
||||
_hdData.reset();
|
||||
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());
|
||||
if(!HdPackLoader::LoadHdNesPack(hdPackDefinitionFile, *_hdData.get())) {
|
||||
if(!HdPackLoader::LoadHdNesPack(romFile, *_hdData.get())) {
|
||||
_hdData.reset();
|
||||
} else {
|
||||
string sha1hash = SHA1::GetHash(fileData);
|
||||
auto result = _hdData->PatchesByHash.find(sha1hash);
|
||||
auto result = _hdData->PatchesByHash.find(romFile.GetSha1Hash());
|
||||
if(result != _hdData->PatchesByHash.end()) {
|
||||
patchFilename = FolderUtilities::CombinePath(hdPackFolder, result->second);
|
||||
patchFile = result->second;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
#include "stdafx.h"
|
||||
#include <atomic>
|
||||
#include "../Utilities/SimpleLock.h"
|
||||
#include "../Utilities/VirtualFile.h"
|
||||
#include "RomData.h"
|
||||
|
||||
class Debugger;
|
||||
|
@ -46,7 +47,6 @@ class Console
|
|||
|
||||
string _romFilepath;
|
||||
string _patchFilename;
|
||||
int32_t _archiveFileIndex;
|
||||
|
||||
bool _stop = false;
|
||||
|
||||
|
@ -57,10 +57,10 @@ class Console
|
|||
|
||||
bool _initialized = false;
|
||||
|
||||
void LoadHdPack(string romFilename, vector<uint8_t> &fileData, string &patchFilename);
|
||||
void LoadHdPack(VirtualFile &romFile, VirtualFile &patchFile);
|
||||
|
||||
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);
|
||||
double GetFrameDelay();
|
||||
|
||||
|
@ -86,16 +86,13 @@ class Console
|
|||
static void LoadState(istream &loadStream);
|
||||
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, uint32_t crc32Hash);
|
||||
static bool LoadROM(string romName, string sha1Hash);
|
||||
static string GetROMPath();
|
||||
static string GetRomPath();
|
||||
static string GetRomName();
|
||||
static bool IsChrRam();
|
||||
static RomFormat GetRomFormat();
|
||||
static uint32_t GetCrc32();
|
||||
static uint32_t GetPrgCrc32();
|
||||
static HashInfo GetHashInfo();
|
||||
static NesModel GetModel();
|
||||
|
||||
static uint32_t GetLagCounter();
|
||||
|
|
|
@ -413,7 +413,6 @@
|
|||
<ClInclude Include="AutomaticRomTest.h" />
|
||||
<ClInclude Include="BaseRenderer.h" />
|
||||
<ClInclude Include="FceuxMovie.h" />
|
||||
<ClInclude Include="FileLoader.h" />
|
||||
<ClInclude Include="HdBuilderPpu.h" />
|
||||
<ClInclude Include="HdData.h" />
|
||||
<ClInclude Include="HdPackBuilder.h" />
|
||||
|
@ -779,7 +778,6 @@
|
|||
<ClCompile Include="AutomaticRomTest.cpp" />
|
||||
<ClCompile Include="BaseRenderer.cpp" />
|
||||
<ClCompile Include="FceuxMovie.cpp" />
|
||||
<ClCompile Include="FileLoader.cpp" />
|
||||
<ClCompile Include="HdNesPack.cpp" />
|
||||
<ClCompile Include="HdPackBuilder.cpp" />
|
||||
<ClCompile Include="HdPackLoader.cpp" />
|
||||
|
|
|
@ -1192,9 +1192,6 @@
|
|||
<ClInclude Include="HdPackLoader.h">
|
||||
<Filter>VideoDecoder\HD</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="FileLoader.h">
|
||||
<Filter>Nes\RomLoader</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="stdafx.cpp">
|
||||
|
@ -1428,8 +1425,5 @@
|
|||
<ClCompile Include="HdNesPack.cpp">
|
||||
<Filter>VideoDecoder\HD</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="FileLoader.cpp">
|
||||
<Filter>Misc</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
</Project>
|
|
@ -152,7 +152,10 @@ public:
|
|||
{
|
||||
//Apply save data (saved as an IPS file), if found
|
||||
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;
|
||||
|
||||
|
|
|
@ -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{};
|
||||
}
|
|
@ -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);
|
||||
};
|
|
@ -39,7 +39,9 @@ public:
|
|||
{
|
||||
string filename = _romFilename;
|
||||
if(filename.size() > 0) {
|
||||
if(Console::LoadROM(filename, _crc32Hash)) {
|
||||
HashInfo hashInfo;
|
||||
hashInfo.Crc32Hash = _crc32Hash;
|
||||
if(Console::LoadROM(filename, hashInfo)) {
|
||||
return true;
|
||||
} else {
|
||||
MessageManager::DisplayMessage("NetPlay", "CouldNotFindRom");
|
||||
|
|
|
@ -38,7 +38,7 @@ GameServerConnection::~GameServerConnection()
|
|||
void GameServerConnection::SendGameInformation()
|
||||
{
|
||||
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);
|
||||
SaveStateMessage saveState;
|
||||
SendNetMessage(saveState);
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
#include <algorithm>
|
||||
#include "stdafx.h"
|
||||
#include "../Utilities/VirtualFile.h"
|
||||
#include "HdPackBuilder.h"
|
||||
|
||||
HdPackBuilder* HdPackBuilder::_instance = nullptr;
|
||||
|
@ -197,6 +198,7 @@ void HdPackBuilder::SaveHdPack()
|
|||
int pngIndex = 0;
|
||||
ss << "<ver>100" << std::endl;
|
||||
ss << "<scale>" << _hdData.Scale << std::endl;
|
||||
ss << "<supportedRom>" << Console::GetRomName() << std::endl;
|
||||
|
||||
int tileDimension = 8 * _hdData.Scale;
|
||||
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) {
|
||||
/*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) {
|
||||
for(int i = 0; i < 256; i++) {
|
||||
vector<std::pair<uint32_t, HdPackTileInfo*>> tiles;
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
#include "stdafx.h"
|
||||
#include <algorithm>
|
||||
#include <unordered_map>
|
||||
#include "../Utilities/ZipReader.h"
|
||||
#include "../Utilities/FolderUtilities.h"
|
||||
#include "../Utilities/StringUtilities.h"
|
||||
#include "../Utilities/HexUtilities.h"
|
||||
|
@ -8,32 +9,110 @@
|
|||
#include "Console.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);
|
||||
return loader.LoadPack();
|
||||
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 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()
|
||||
{
|
||||
try {
|
||||
ifstream packDefinition(_hdPackDefinitionFile, ios::in | ios::binary);
|
||||
if(!packDefinition.good()) {
|
||||
vector<uint8_t> hdDefinition;
|
||||
if(!LoadFile("hires.txt", hdDefinition)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
while(packDefinition.good()) {
|
||||
string lineContent;
|
||||
std::getline(packDefinition, lineContent);
|
||||
for(string lineContent : StringUtilities::Split(string(hdDefinition.data(), hdDefinition.data() + hdDefinition.size()), '\n')) {
|
||||
lineContent = lineContent.substr(0, lineContent.length() - 1);
|
||||
|
||||
vector<HdPackCondition*> conditions;
|
||||
|
@ -51,10 +130,9 @@ bool HdPackLoader::LoadPack()
|
|||
_data->Scale = std::stoi(lineContent);
|
||||
} else if(lineContent.substr(0, 5) == "<img>") {
|
||||
lineContent = lineContent.substr(5);
|
||||
HdPackBitmapInfo bitmapInfo;
|
||||
string imageFile = FolderUtilities::CombinePath(_hdPackFolder, lineContent);
|
||||
PNGHelper::ReadPNG(imageFile, bitmapInfo.PixelData, bitmapInfo.Width, bitmapInfo.Height);
|
||||
_hdNesBitmaps.push_back(bitmapInfo);
|
||||
if(!ProcessImgTag(lineContent)) {
|
||||
return false;
|
||||
}
|
||||
} else if(lineContent.substr(0, 7) == "<patch>") {
|
||||
tokens = StringUtilities::Split(lineContent.substr(7), ',');
|
||||
ProcessPatchTag(tokens);
|
||||
|
@ -76,7 +154,6 @@ bool HdPackLoader::LoadPack()
|
|||
LoadCustomPalette();
|
||||
InitializeHdPack();
|
||||
|
||||
packDefinition.close();
|
||||
return true;
|
||||
} catch(std::exception ex) {
|
||||
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)
|
||||
{
|
||||
if(tokens[1].size() != 40) {
|
||||
MessageManager::Log(string("[HDPack] Invalid SHA1 hash for patch (" + tokens[0] + "): " + tokens[1]));
|
||||
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]));
|
||||
return;
|
||||
}
|
||||
|
||||
std::transform(tokens[1].begin(), tokens[1].end(), tokens[1].begin(), ::toupper);
|
||||
_data->PatchesByHash[tokens[1]] = tokens[0];
|
||||
std::transform(tokens[1].begin(), tokens[1].end(), tokens[1].begin(), ::tolower);
|
||||
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)
|
||||
|
@ -231,30 +327,32 @@ void HdPackLoader::ProcessConditionTag(vector<string> &tokens)
|
|||
|
||||
void HdPackLoader::ProcessBackgroundTag(vector<string> &tokens, vector<HdPackCondition*> conditions)
|
||||
{
|
||||
HdBackgroundFileData* fileData = nullptr;
|
||||
HdBackgroundFileData* bgFileData = nullptr;
|
||||
for(unique_ptr<HdBackgroundFileData> &bgData : _data->BackgroundFileData) {
|
||||
if(bgData->PngName == tokens[0]) {
|
||||
fileData = bgData.get();
|
||||
bgFileData = bgData.get();
|
||||
}
|
||||
}
|
||||
|
||||
if(!fileData) {
|
||||
if(!bgFileData) {
|
||||
vector<uint8_t> pixelData;
|
||||
uint32_t width, height;
|
||||
string imageFile = FolderUtilities::CombinePath(_hdPackFolder, tokens[0]);
|
||||
if(PNGHelper::ReadPNG(imageFile, pixelData, width, height)) {
|
||||
_data->BackgroundFileData.push_back(unique_ptr<HdBackgroundFileData>(new HdBackgroundFileData()));
|
||||
fileData = _data->BackgroundFileData.back().get();
|
||||
fileData->PixelData = pixelData;
|
||||
fileData->Width = width;
|
||||
fileData->Height = height;
|
||||
fileData->PngName = tokens[0];
|
||||
vector<uint8_t> fileContent;
|
||||
if(LoadFile(tokens[0], fileContent)) {
|
||||
if(PNGHelper::ReadPNG(fileContent, pixelData, width, height)) {
|
||||
_data->BackgroundFileData.push_back(unique_ptr<HdBackgroundFileData>(new HdBackgroundFileData()));
|
||||
bgFileData = _data->BackgroundFileData.back().get();
|
||||
bgFileData->PixelData = pixelData;
|
||||
bgFileData->Width = width;
|
||||
bgFileData->Height = height;
|
||||
bgFileData->PngName = tokens[0];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
HdBackgroundInfo backgroundInfo;
|
||||
if(fileData) {
|
||||
backgroundInfo.Data = fileData;
|
||||
if(bgFileData) {
|
||||
backgroundInfo.Data = bgFileData;
|
||||
backgroundInfo.Brightness = (uint8_t)(std::stof(tokens[1]) * 255);
|
||||
backgroundInfo.Conditions = conditions;
|
||||
|
||||
|
@ -297,17 +395,12 @@ vector<HdPackCondition*> HdPackLoader::ParseConditionString(string conditionStri
|
|||
|
||||
void HdPackLoader::LoadCustomPalette()
|
||||
{
|
||||
string customPalettePath = FolderUtilities::CombinePath(_hdPackFolder, "palette.dat");
|
||||
ifstream file(customPalettePath, ios::binary);
|
||||
if(file.good()) {
|
||||
vector<uint8_t> fileData;
|
||||
if(LoadFile("palette.dat", fileData)) {
|
||||
vector<uint32_t> paletteData;
|
||||
|
||||
uint8_t rgb[3];
|
||||
while(!file.eof()) {
|
||||
file.read((char*)rgb, 3);
|
||||
if(!file.eof()) {
|
||||
paletteData.push_back(0xFF000000 | (rgb[0] << 16) | (rgb[1] << 8) | rgb[2]);
|
||||
}
|
||||
for(int i = 0; i < fileData.size(); i+= 3){
|
||||
paletteData.push_back(0xFF000000 | (fileData[i] << 16) | (fileData[i+1] << 8) | fileData[i+2]);
|
||||
}
|
||||
|
||||
if(paletteData.size() == 0x40) {
|
||||
|
|
|
@ -1,24 +1,33 @@
|
|||
#pragma once
|
||||
#include "stdafx.h"
|
||||
#include "HdData.h"
|
||||
#include "../Utilities/ZipReader.h"
|
||||
#include "../Utilities/VirtualFile.h"
|
||||
|
||||
class HdPackLoader
|
||||
{
|
||||
public:
|
||||
static bool LoadHdNesPack(string hdPackDefinitionFile, HdPackData &data);
|
||||
static bool LoadHdNesPack(string definitionFile, HdPackData &outData);
|
||||
static bool LoadHdNesPack(VirtualFile &romFile, HdPackData &outData);
|
||||
|
||||
private:
|
||||
HdPackData* _data;
|
||||
bool _loadFromZip = false;
|
||||
ZipReader _reader;
|
||||
string _hdPackDefinitionFile;
|
||||
string _hdPackFolder;
|
||||
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();
|
||||
void InitializeHdPack();
|
||||
void LoadCustomPalette();
|
||||
|
||||
bool ProcessImgTag(string src);
|
||||
void ProcessPatchTag(vector<string> &tokens);
|
||||
void ProcessConditionTag(vector<string> &tokens);
|
||||
void ProcessTileTag(vector<string> &tokens, vector<HdPackCondition*> conditions);
|
||||
|
|
|
@ -174,7 +174,7 @@ bool MesenMovie::Save()
|
|||
header.MesenVersion = EmulationSettings::GetMesenVersion();
|
||||
header.MovieFormatVersion = MesenMovie::MovieFormatVersion;
|
||||
header.SaveStateFormatVersion = SaveStateManager::FileFormatVersion;
|
||||
header.RomCrc32 = Console::GetCrc32();
|
||||
header.RomCrc32 = Console::GetHashInfo().Crc32Hash;
|
||||
header.Region = (uint32_t)Console::GetModel();
|
||||
header.ConsoleType = (uint32_t)EmulationSettings::GetConsoleType();
|
||||
header.ExpansionDevice = (uint32_t)EmulationSettings::GetExpansionDevice();
|
||||
|
@ -336,9 +336,11 @@ bool MesenMovie::Load(std::stringstream &file, bool autoLoadRom)
|
|||
bool loadedGame = true;
|
||||
if(autoLoadRom) {
|
||||
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
|
||||
loadedGame = Console::LoadROM(romFilename, header.RomCrc32);
|
||||
HashInfo hashInfo;
|
||||
hashInfo.Crc32Hash = header.RomCrc32;
|
||||
loadedGame = Console::LoadROM(romFilename, hashInfo);
|
||||
} else {
|
||||
Console::Reset(false);
|
||||
}
|
||||
|
|
|
@ -172,7 +172,7 @@ void RecordedRomTest::RecordFromTest(string newTestFilename, string existingTest
|
|||
|
||||
if(testMovie && testRom) {
|
||||
Console::Pause();
|
||||
Console::LoadROM("TestRom", &testRom);
|
||||
Console::LoadROM(testRom);
|
||||
testRom.seekg(0, ios::beg);
|
||||
_romStream << testRom.rdbuf();
|
||||
|
||||
|
@ -236,7 +236,7 @@ int32_t RecordedRomTest::Run(string filename)
|
|||
_runningTest = true;
|
||||
|
||||
//Start playing movie
|
||||
Console::LoadROM(testName, &testRom);
|
||||
Console::LoadROM(testRom);
|
||||
MovieManager::Play(testMovie, false);
|
||||
|
||||
Console::Resume();
|
||||
|
@ -300,7 +300,7 @@ void RecordedRomTest::Save()
|
|||
writer.AddFile(mmoFilename, "TestMovie.mmo");
|
||||
std::remove(mmoFilename.c_str());
|
||||
|
||||
writer.AddFile(Console::GetROMPath(), "TestRom.nes");
|
||||
writer.AddFile(Console::GetRomPath(), "TestRom.nes");
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -40,6 +40,7 @@ enum class BusConflictType
|
|||
struct HashInfo
|
||||
{
|
||||
uint32_t Crc32Hash = 0;
|
||||
uint32_t PrgCrc32Hash = 0;
|
||||
string Sha1Hash;
|
||||
string PrgChrMd5Hash;
|
||||
};
|
||||
|
|
|
@ -1,21 +1,23 @@
|
|||
#include "stdafx.h"
|
||||
#include <algorithm>
|
||||
#include <unordered_set>
|
||||
#include "../Utilities/VirtualFile.h"
|
||||
#include "../Utilities/FolderUtilities.h"
|
||||
#include "../Utilities/CRC32.h"
|
||||
#include "../Utilities/sha1.h"
|
||||
#include "RomLoader.h"
|
||||
#include "FileLoader.h"
|
||||
#include "iNesLoader.h"
|
||||
#include "FdsLoader.h"
|
||||
#include "NsfLoader.h"
|
||||
#include "NsfeLoader.h"
|
||||
#include "UnifLoader.h"
|
||||
|
||||
bool RomLoader::LoadFile(string filename, int32_t archiveFileIndex)
|
||||
bool RomLoader::LoadFile(VirtualFile romFile)
|
||||
{
|
||||
vector<uint8_t> fileData;
|
||||
if(FileLoader::LoadFile(filename, nullptr, archiveFileIndex, fileData)) {
|
||||
return LoadFile(filename, fileData);
|
||||
if(romFile.IsValid()) {
|
||||
romFile.ReadFile(fileData);
|
||||
return LoadFile(romFile.GetFileName(), fileData);
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
|
@ -23,6 +25,10 @@ bool RomLoader::LoadFile(string filename, int32_t archiveFileIndex)
|
|||
|
||||
bool RomLoader::LoadFile(string filename, vector<uint8_t> &fileData)
|
||||
{
|
||||
if(fileData.size() < 10) {
|
||||
return false;
|
||||
}
|
||||
|
||||
_filename = filename;
|
||||
|
||||
string romName = FolderUtilities::GetFilename(filename, true);
|
||||
|
@ -88,56 +94,58 @@ RomData RomLoader::GetRomData()
|
|||
return _romData;
|
||||
}
|
||||
|
||||
int32_t RomLoader::FindMatchingRomInFile(string filename, HashInfo hashInfo)
|
||||
string RomLoader::FindMatchingRomInFile(string filePath, HashInfo hashInfo)
|
||||
{
|
||||
vector<uint8_t> fileData;
|
||||
int fileIndex = 0;
|
||||
while(FileLoader::LoadFile(filename, nullptr, fileIndex, fileData)) {
|
||||
RomLoader loader;
|
||||
if(loader.LoadFile(filename, fileData)) {
|
||||
if(hashInfo.Crc32Hash == loader._romData.Crc32 || hashInfo.Sha1Hash.compare(loader._romData.Sha1) == 0) {
|
||||
return fileIndex;
|
||||
shared_ptr<ArchiveReader> reader = ArchiveReader::GetReader(filePath);
|
||||
if(reader) {
|
||||
for(string file : reader->GetFileList({ ".nes", ".fds", "*.unif", "*.unif", "*.nsf", "*.nsfe" })) {
|
||||
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+"\n"+file;
|
||||
}
|
||||
}
|
||||
}
|
||||
} 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;
|
||||
}
|
||||
fileIndex++;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
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);
|
||||
vector<string> validExtensions = { { ".nes", ".zip", ".7z", ".fds" } };
|
||||
vector<string> romFiles;
|
||||
|
||||
for(string extension : validExtensions) {
|
||||
for(string file : FolderUtilities::GetFilesInFolder(folder, extension, true)) {
|
||||
romFiles.push_back(file);
|
||||
}
|
||||
}
|
||||
std::unordered_set<string> validExtensions = { { ".nes", ".fds", "*.unif", "*.unif", "*.nsf", "*.nsfe", "*.7z", "*.zip" } };
|
||||
vector<string> romFiles = FolderUtilities::GetFilesInFolder(folder, validExtensions, true);
|
||||
|
||||
if(useFastSearch) {
|
||||
for(string romFile : romFiles) {
|
||||
//Quick search by filename
|
||||
string originalFilename = romFile;
|
||||
std::transform(romFile.begin(), romFile.end(), romFile.begin(), ::tolower);
|
||||
if(FolderUtilities::GetFilename(romFile, true).compare(romFilename) == 0) {
|
||||
archiveFileIndex = RomLoader::FindMatchingRomInFile(romFile, hashInfo);
|
||||
if(archiveFileIndex >= 0) {
|
||||
return originalFilename;
|
||||
string lcRomFile = romFile;
|
||||
std::transform(lcRomFile.begin(), lcRomFile.end(), lcRomFile.begin(), ::tolower);
|
||||
if(FolderUtilities::GetFilename(lcRomFile, false).compare(FolderUtilities::GetFilename(romFilename, false)) == 0) {
|
||||
string match = RomLoader::FindMatchingRomInFile(romFile, hashInfo);
|
||||
if(!match.empty()) {
|
||||
return match;
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
for(string romFile : romFiles) {
|
||||
//Slower search by CRC value
|
||||
archiveFileIndex = RomLoader::FindMatchingRomInFile(romFile, hashInfo);
|
||||
if(archiveFileIndex >= 0) {
|
||||
return romFile;
|
||||
string match = RomLoader::FindMatchingRomInFile(romFile, hashInfo);
|
||||
if(!match.empty()) {
|
||||
return match;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
archiveFileIndex = -1;
|
||||
return "";
|
||||
}
|
|
@ -1,5 +1,6 @@
|
|||
#pragma once
|
||||
#include "stdafx.h"
|
||||
#include "../Utilities/VirtualFile.h"
|
||||
#include "RomData.h"
|
||||
class ArchiveReader;
|
||||
|
||||
|
@ -9,12 +10,12 @@ class RomLoader
|
|||
RomData _romData;
|
||||
string _filename;
|
||||
|
||||
static int32_t FindMatchingRomInFile(string filename, HashInfo hashInfo);
|
||||
static string FindMatchingRomInFile(string filePath, HashInfo hashInfo);
|
||||
|
||||
public:
|
||||
bool LoadFile(string filename, int32_t archiveFileIndex);
|
||||
bool LoadFile(VirtualFile romFile);
|
||||
bool LoadFile(string filename, vector<uint8_t> &fileData);
|
||||
|
||||
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);
|
||||
};
|
||||
|
|
|
@ -134,7 +134,7 @@ bool SaveStateManager::LoadState(int stateIndex)
|
|||
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) {
|
||||
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 << romPath << std::endl;
|
||||
romInfoStream << patchPath << std::endl;
|
||||
romInfoStream << std::to_string(archiveFileIndex) << std::endl;
|
||||
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 stateStream = reader.GetStream("Savestate.mst");
|
||||
|
||||
string romName, romPath, patchPath, archiveIndex;
|
||||
string romName, romPath, patchPath;
|
||||
std::getline(romInfoStream, romName);
|
||||
std::getline(romInfoStream, romPath);
|
||||
std::getline(romInfoStream, patchPath);
|
||||
std::getline(romInfoStream, archiveIndex);
|
||||
|
||||
Console::Pause();
|
||||
try {
|
||||
Console::LoadROM(romPath, nullptr, std::stoi(archiveIndex.c_str()), patchPath);
|
||||
Console::LoadROM(romPath, patchPath);
|
||||
if(!resetGame) {
|
||||
SaveStateManager::LoadState(stateStream);
|
||||
}
|
||||
|
|
|
@ -23,7 +23,7 @@ public:
|
|||
static bool LoadState(istream &stream);
|
||||
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 MoveToNextSlot();
|
||||
|
|
|
@ -191,7 +191,7 @@ public:
|
|||
|
||||
uint8_t value = 0;
|
||||
|
||||
uint32_t crc = Console::GetPrgCrc32();
|
||||
uint32_t crc = Console::GetHashInfo().PrgCrc32Hash;
|
||||
|
||||
switch(addr) {
|
||||
case 0x4016:
|
||||
|
|
|
@ -6,6 +6,7 @@ using System.Linq;
|
|||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using System.Xml.Serialization;
|
||||
using Mesen.GUI.Forms;
|
||||
|
||||
namespace Mesen.GUI.Config
|
||||
{
|
||||
|
@ -87,13 +88,13 @@ namespace Mesen.GUI.Config
|
|||
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) {
|
||||
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);
|
||||
if(RecentFiles.Count > Configuration.MaxRecentFiles) {
|
||||
|
@ -149,8 +150,16 @@ namespace Mesen.GUI.Config
|
|||
|
||||
public class RecentItem
|
||||
{
|
||||
public string Path;
|
||||
public string RomName;
|
||||
public int ArchiveFileIndex;
|
||||
public ResourcePath RomFile;
|
||||
public ResourcePath? PatchFile;
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
string text = Path.GetFileName(RomFile.FileName).Replace("&", "&&");
|
||||
if(PatchFile.HasValue) {
|
||||
text += " [" + Path.GetFileName(PatchFile.Value) + "]";
|
||||
}
|
||||
return text;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -11,6 +11,7 @@ using System.IO;
|
|||
using Mesen.GUI.Config;
|
||||
using System.Drawing.Text;
|
||||
using System.IO.Compression;
|
||||
using Mesen.GUI.Forms;
|
||||
|
||||
namespace Mesen.GUI.Controls
|
||||
{
|
||||
|
@ -37,7 +38,7 @@ namespace Mesen.GUI.Controls
|
|||
{
|
||||
public string FileName { get; set; }
|
||||
public string RomName { get; set; }
|
||||
public string RomPath { get; set; }
|
||||
public ResourcePath RomPath { get; set; }
|
||||
public DateTime Timestamp { get; set; }
|
||||
}
|
||||
|
||||
|
@ -106,7 +107,7 @@ namespace Mesen.GUI.Controls
|
|||
info.Timestamp = new FileInfo(file).LastWriteTime;
|
||||
info.FileName = file;
|
||||
|
||||
if(File.Exists(info.RomPath)) {
|
||||
if(info.RomPath.Exists) {
|
||||
_recentGames.Add(info);
|
||||
}
|
||||
} catch { }
|
||||
|
|
|
@ -158,7 +158,7 @@ namespace Mesen.GUI.Debugger
|
|||
private void AutoLoadDbgFile(bool silent)
|
||||
{
|
||||
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)) {
|
||||
Ld65DbgImporter dbgImporter = new Ld65DbgImporter();
|
||||
dbgImporter.Import(dbgPath, silent);
|
||||
|
|
|
@ -66,9 +66,9 @@ namespace Mesen.GUI.Forms.Cheats
|
|||
|
||||
private void LoadGame(string romPath)
|
||||
{
|
||||
int archiveFileIndex = -1;
|
||||
if(frmSelectRom.SelectRom(romPath, ref archiveFileIndex)) {
|
||||
RomInfo romInfo = InteropEmu.GetRomInfo(romPath, archiveFileIndex);
|
||||
ResourcePath resource = romPath;
|
||||
if(frmSelectRom.SelectRom(ref resource)) {
|
||||
RomInfo romInfo = InteropEmu.GetRomInfo(resource);
|
||||
_gameCrc = romInfo.GetPrgCrcString();
|
||||
if(_gameCrc != null) {
|
||||
((CheatInfo)Entity).GameName = Path.GetFileNameWithoutExtension(romInfo.RomName);
|
||||
|
|
|
@ -41,9 +41,9 @@ namespace Mesen.GUI.Forms.Cheats
|
|||
|
||||
private void LoadGame(string romPath)
|
||||
{
|
||||
int archiveFileIndex = -1;
|
||||
if(frmSelectRom.SelectRom(romPath, ref archiveFileIndex)) {
|
||||
RomInfo romInfo = InteropEmu.GetRomInfo(romPath, archiveFileIndex);
|
||||
ResourcePath resource = romPath;
|
||||
if(frmSelectRom.SelectRom(ref resource)) {
|
||||
RomInfo romInfo = InteropEmu.GetRomInfo(resource);
|
||||
_gameCrc = romInfo.GetPrgCrcString();
|
||||
_gameName = romInfo.GetRomName();
|
||||
txtGameName.Text = _gameName;
|
||||
|
|
45
GUI.NET/Forms/ResourcePath.cs
Normal file
45
GUI.NET/Forms/ResourcePath.cs
Normal 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();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -30,8 +30,7 @@ namespace Mesen.GUI.Forms
|
|||
private frmLogWindow _logWindow;
|
||||
private frmCheatList _cheatListWindow;
|
||||
private frmHdPackEditor _hdPackEditorWindow;
|
||||
private string _currentRomPath = null;
|
||||
private int _currentRomArchiveIndex = -1;
|
||||
private ResourcePath? _currentRomPath = null;
|
||||
private string _currentGame = null;
|
||||
private bool _customSize = false;
|
||||
private FormWindowState _originalWindowState;
|
||||
|
@ -65,7 +64,7 @@ namespace Mesen.GUI.Forms
|
|||
lblVersion.Font = new Font(_fonts.Families[0], 11);
|
||||
|
||||
_commandLineArgs = args;
|
||||
|
||||
|
||||
Application.AddMessageFilter(this);
|
||||
this.Resize += ResizeRecentGames;
|
||||
this.FormClosed += (s, e) => Application.RemoveMessageFilter(this);
|
||||
|
@ -123,22 +122,22 @@ namespace Mesen.GUI.Forms
|
|||
{
|
||||
base.OnLoad(e);
|
||||
|
||||
#if HIDETESTMENU
|
||||
#if HIDETESTMENU
|
||||
mnuTests.Visible = false;
|
||||
#endif
|
||||
#endif
|
||||
|
||||
_notifListener = new InteropEmu.NotificationListener();
|
||||
_notifListener.OnNotification += _notifListener_OnNotification;
|
||||
|
||||
menuTimer.Start();
|
||||
|
||||
|
||||
this.ProcessCommandLineArguments(_commandLineArgs, true);
|
||||
|
||||
VideoInfo.ApplyConfig();
|
||||
InitializeVsSystemMenu();
|
||||
InitializeFdsDiskMenu();
|
||||
InitializeEmulationSpeedMenu();
|
||||
|
||||
|
||||
UpdateVideoSettings();
|
||||
|
||||
InitializeEmu();
|
||||
|
@ -158,7 +157,7 @@ namespace Mesen.GUI.Forms
|
|||
CheckForUpdates(false);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
protected override void OnDeactivate(EventArgs e)
|
||||
{
|
||||
base.OnDeactivate(e);
|
||||
|
@ -224,6 +223,8 @@ namespace Mesen.GUI.Forms
|
|||
//0.9.0's "Auto" has been renamed to "NoStretching"
|
||||
ConfigManager.Config.VideoInfo.AspectRatio = VideoAspectRatio.NoStretching;
|
||||
}
|
||||
|
||||
ConfigManager.Config.RecentFiles.Clear();
|
||||
}
|
||||
|
||||
if(oldVersion <= new Version("0.5.3")) {
|
||||
|
@ -264,14 +265,14 @@ namespace Mesen.GUI.Forms
|
|||
{
|
||||
InteropEmu.InitializeEmu(ConfigManager.HomeFolder, this.Handle, this.ctrlRenderer.Handle, _noAudio, _noVideo, _noInput);
|
||||
foreach(RecentItem recentItem in ConfigManager.Config.RecentFiles) {
|
||||
InteropEmu.AddKnownGameFolder(Path.GetDirectoryName(recentItem.Path));
|
||||
InteropEmu.AddKnownGameFolder(recentItem.RomFile.Folder);
|
||||
}
|
||||
|
||||
ConfigManager.Config.InitializeDefaults();
|
||||
ConfigManager.ApplyChanges();
|
||||
|
||||
ConfigManager.Config.ApplyConfig();
|
||||
|
||||
|
||||
UpdateEmulationFlags();
|
||||
}
|
||||
|
||||
|
@ -391,7 +392,7 @@ namespace Mesen.GUI.Forms
|
|||
ctrlRenderer.Top = (panelRenderer.Height - ctrlRenderer.Height) / 2;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private void SetScaleBasedOnWindowSize()
|
||||
{
|
||||
_customSize = true;
|
||||
|
@ -421,7 +422,7 @@ namespace Mesen.GUI.Forms
|
|||
this.SetScale(_regularScale);
|
||||
this.UpdateScaleMenu(_regularScale);
|
||||
this.UpdateViewerSize();
|
||||
VideoInfo.ApplyConfig();
|
||||
VideoInfo.ApplyConfig();
|
||||
}
|
||||
this.Resize += frmMain_Resize;
|
||||
mnuFullscreen.Checked = enabled;
|
||||
|
@ -553,7 +554,7 @@ namespace Mesen.GUI.Forms
|
|||
using(OpenFileDialog ofd = new OpenFileDialog()) {
|
||||
ofd.SetFilter(ResourceHelper.GetMessage("FilterRomIps"));
|
||||
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) {
|
||||
LoadFile(ofd.FileName);
|
||||
|
@ -595,62 +596,56 @@ namespace Mesen.GUI.Forms
|
|||
using(OpenFileDialog ofd = new OpenFileDialog()) {
|
||||
ofd.SetFilter(ResourceHelper.GetMessage("FilterRom"));
|
||||
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) {
|
||||
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) {
|
||||
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;
|
||||
_currentRomArchiveIndex = -1;
|
||||
if(File.Exists(filename)) {
|
||||
string romName;
|
||||
if(frmSelectRom.SelectRom(filename, ref archiveFileIndex, out romName)) {
|
||||
_currentRomArchiveIndex = archiveFileIndex;
|
||||
if(archiveFileIndex >= 0) {
|
||||
if(romFile.Exists) {
|
||||
if(frmSelectRom.SelectRom(ref romFile)) {
|
||||
_currentRomPath = romFile;
|
||||
|
||||
if(romFile.Compressed) {
|
||||
Interlocked.Increment(ref _romLoadCounter);
|
||||
ctrlNsfPlayer.Visible = false;
|
||||
ctrlLoading.Visible = true;
|
||||
}
|
||||
|
||||
string patchFile = patchFileToApply;
|
||||
if(patchFile == null) {
|
||||
ResourcePath? patchFile = patchFileToApply;
|
||||
if(patchFile == null && autoLoadPatches) {
|
||||
string[] extensions = new string[3] { ".ips", ".ups", ".bps" };
|
||||
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)) {
|
||||
patchFile = file;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(!File.Exists(patchFile)) {
|
||||
autoLoadPatches = false;
|
||||
}
|
||||
|
||||
Task loadRomTask = new Task(() => {
|
||||
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) => {
|
||||
this.BeginInvoke((MethodInvoker)(() => {
|
||||
if(archiveFileIndex >= 0) {
|
||||
if(romFile.Compressed) {
|
||||
Interlocked.Decrement(ref _romLoadCounter);
|
||||
}
|
||||
|
||||
ConfigManager.Config.AddRecentFile(filename, romName, archiveFileIndex);
|
||||
ConfigManager.Config.AddRecentFile(romFile, patchFileToApply);
|
||||
UpdateRecentFiles();
|
||||
}));
|
||||
});
|
||||
|
@ -658,10 +653,10 @@ namespace Mesen.GUI.Forms
|
|||
loadRomTask.Start();
|
||||
}
|
||||
} else {
|
||||
MesenMsgBox.Show("FileNotFound", MessageBoxButtons.OK, MessageBoxIcon.Error, filename);
|
||||
MesenMsgBox.Show("FileNotFound", MessageBoxButtons.OK, MessageBoxIcon.Error, romFile.Path);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private void UpdateFocusFlag()
|
||||
{
|
||||
bool hasFocus = false;
|
||||
|
@ -688,7 +683,6 @@ namespace Mesen.GUI.Forms
|
|||
} else {
|
||||
panelInfo.Visible = _emuThread == null;
|
||||
ctrlRecentGames.Visible = _emuThread == null;
|
||||
mnuPowerOff.Enabled = _emuThread != null;
|
||||
|
||||
ctrlLoading.Visible = (_romLoadCounter > 0);
|
||||
|
||||
|
@ -697,7 +691,7 @@ namespace Mesen.GUI.Forms
|
|||
|
||||
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());
|
||||
mnuLoadState.Enabled = (_emuThread != null && !isNetPlayClient && !InteropEmu.IsNsf() && !InteropEmu.MoviePlaying() && !InteropEmu.MovieRecording());
|
||||
|
||||
|
@ -782,7 +776,7 @@ namespace Mesen.GUI.Forms
|
|||
mnuRegionPal.Checked = ConfigManager.Config.Region == NesModel.PAL;
|
||||
mnuRegionDendy.Checked = ConfigManager.Config.Region == NesModel.Dendy;
|
||||
|
||||
bool autoInsertDisabled = !InteropEmu.FdsIsAutoInsertDiskEnabled();
|
||||
bool autoInsertDisabled = !InteropEmu.FdsIsAutoInsertDiskEnabled();
|
||||
mnuSelectDisk.Enabled = autoInsertDisabled;
|
||||
mnuEjectDisk.Enabled = autoInsertDisabled;
|
||||
mnuSwitchDiskSide.Enabled = autoInsertDisabled;
|
||||
|
@ -807,9 +801,9 @@ namespace Mesen.GUI.Forms
|
|||
mnuRecentFiles.DropDownItems.Clear();
|
||||
foreach(RecentItem recentItem in ConfigManager.Config.RecentFiles) {
|
||||
ToolStripMenuItem tsmi = new ToolStripMenuItem();
|
||||
tsmi.Text = recentItem.RomName.Replace("&", "&&");
|
||||
tsmi.Text = recentItem.ToString();
|
||||
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);
|
||||
}
|
||||
|
@ -833,7 +827,7 @@ namespace Mesen.GUI.Forms
|
|||
}
|
||||
UpdateMenus();
|
||||
}
|
||||
|
||||
|
||||
private void StopEmu()
|
||||
{
|
||||
InteropEmu.Stop();
|
||||
|
@ -893,7 +887,7 @@ namespace Mesen.GUI.Forms
|
|||
}
|
||||
}
|
||||
|
||||
#if !HIDETESTMENU
|
||||
#if !HIDETESTMENU
|
||||
if(keyData == Keys.Pause) {
|
||||
if(InteropEmu.RomTestRecording()) {
|
||||
InteropEmu.RomTestStop();
|
||||
|
@ -901,7 +895,7 @@ namespace Mesen.GUI.Forms
|
|||
InteropEmu.RomTestRecord(ConfigManager.TestFolder + "\\" + InteropEmu.GetRomInfo().GetRomName() + ".mtp", true);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
|
||||
if(keyData == Keys.Escape && _emuThread != null && mnuPause.Enabled) {
|
||||
PauseEmu();
|
||||
|
@ -1027,12 +1021,12 @@ namespace Mesen.GUI.Forms
|
|||
frm.ShowDialog(sender);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private void mnuExit_Click(object sender, EventArgs e)
|
||||
{
|
||||
this.Close();
|
||||
}
|
||||
|
||||
|
||||
private void mnuVideoConfig_Click(object sender, EventArgs e)
|
||||
{
|
||||
using(frmVideoConfig frm = new frmVideoConfig()) {
|
||||
|
@ -1040,7 +1034,7 @@ namespace Mesen.GUI.Forms
|
|||
}
|
||||
UpdateVideoSettings();
|
||||
}
|
||||
|
||||
|
||||
private void mnuDebugger_Click(object sender, EventArgs e)
|
||||
{
|
||||
if(_debugger == null) {
|
||||
|
@ -1053,7 +1047,7 @@ namespace Mesen.GUI.Forms
|
|||
_debugger.Focus();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private void mnuSaveState_DropDownOpening(object sender, EventArgs e)
|
||||
{
|
||||
InitializeStateMenu(mnuSaveState, true);
|
||||
|
@ -1070,7 +1064,7 @@ namespace Mesen.GUI.Forms
|
|||
}
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
private void RecordMovie(bool resetEmu)
|
||||
{
|
||||
using(SaveFileDialog sfd = new SaveFileDialog()) {
|
||||
|
@ -1262,7 +1256,7 @@ namespace Mesen.GUI.Forms
|
|||
if(_cheatListWindow.DialogResult == DialogResult.OK) {
|
||||
CheatInfo.ApplyCheats();
|
||||
}
|
||||
_cheatListWindow = null;
|
||||
_cheatListWindow = null;
|
||||
};
|
||||
} else {
|
||||
_cheatListWindow.Focus();
|
||||
|
@ -1325,7 +1319,7 @@ namespace Mesen.GUI.Forms
|
|||
ofd.SetFilter("*.nes|*.nes");
|
||||
if(ofd.ShowDialog() == System.Windows.Forms.DialogResult.OK) {
|
||||
string filename = ofd.FileName;
|
||||
|
||||
|
||||
Task.Run(() => {
|
||||
int result = InteropEmu.RunAutomaticTest(filename);
|
||||
});
|
||||
|
@ -1341,7 +1335,7 @@ namespace Mesen.GUI.Forms
|
|||
startInfo.WorkingDirectory = workingDirectory;
|
||||
Process.Start(startInfo);
|
||||
}
|
||||
|
||||
|
||||
private void mnuRunAllGameTests_Click(object sender, EventArgs e)
|
||||
{
|
||||
string workingDirectory = Path.Combine(Path.GetDirectoryName(System.Reflection.Assembly.GetExecutingAssembly().Location));
|
||||
|
@ -1440,7 +1434,7 @@ namespace Mesen.GUI.Forms
|
|||
{
|
||||
SetVideoFilter(VideoFilterType.xBRZ2x);
|
||||
}
|
||||
|
||||
|
||||
private void mnuXBRZ3xFilter_Click(object sender, EventArgs e)
|
||||
{
|
||||
SetVideoFilter(VideoFilterType.xBRZ3x);
|
||||
|
@ -1505,7 +1499,7 @@ namespace Mesen.GUI.Forms
|
|||
{
|
||||
SetVideoFilter(VideoFilterType.SuperEagle);
|
||||
}
|
||||
|
||||
|
||||
private void mnuPrescale2xFilter_Click(object sender, EventArgs e)
|
||||
{
|
||||
SetVideoFilter(VideoFilterType.Prescale2x);
|
||||
|
@ -1600,7 +1594,7 @@ namespace Mesen.GUI.Forms
|
|||
string hash = MD5Helper.GetMD5Hash(ofd.FileName).ToLowerInvariant();
|
||||
if(hash == "ca30b50f880eb660a320674ed365ef7a" || hash == "c1a9e9415a6adde3c8563c622d4c9fce") {
|
||||
File.Copy(ofd.FileName, Path.Combine(ConfigManager.HomeFolder, "FdsBios.bin"));
|
||||
LoadROM(_currentRomPath, ConfigManager.Config.PreferenceInfo.AutoLoadIpsPatches);
|
||||
LoadROM(_currentRomPath.Value, ConfigManager.Config.PreferenceInfo.AutoLoadIpsPatches);
|
||||
} else {
|
||||
MesenMsgBox.Show("InvalidFdsBios", MessageBoxButtons.OK, MessageBoxIcon.Error);
|
||||
}
|
||||
|
@ -1742,7 +1736,7 @@ namespace Mesen.GUI.Forms
|
|||
{
|
||||
CheckForUpdates(true);
|
||||
}
|
||||
|
||||
|
||||
private void mnuReportBug_Click(object sender, EventArgs e)
|
||||
{
|
||||
Process.Start("http://www.mesen.ca/ReportBug.php");
|
||||
|
@ -1842,7 +1836,7 @@ namespace Mesen.GUI.Forms
|
|||
}
|
||||
this.ctrlNsfPlayer.Visible = true;
|
||||
this.ctrlNsfPlayer.Focus();
|
||||
|
||||
|
||||
_currentGame = InteropEmu.NsfGetHeader().GetSongName();
|
||||
} else if(this._isNsfPlayerMode) {
|
||||
this.MinimumSize = new Size(335, 320);
|
||||
|
@ -1855,7 +1849,7 @@ namespace Mesen.GUI.Forms
|
|||
|
||||
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>();
|
||||
|
||||
foreach(string folder in gameFolders) {
|
||||
|
|
|
@ -3,6 +3,7 @@ using System.Collections.Generic;
|
|||
using System.ComponentModel;
|
||||
using System.Data;
|
||||
using System.Drawing;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
@ -72,34 +73,25 @@ namespace Mesen.GUI.Forms
|
|||
txtSearch.Focus();
|
||||
}
|
||||
|
||||
public static bool SelectRom(string filename, ref int archiveFileIndex)
|
||||
public static bool SelectRom(ref ResourcePath resource)
|
||||
{
|
||||
string romName;
|
||||
return SelectRom(filename, ref archiveFileIndex, out romName);
|
||||
}
|
||||
List<string> archiveRomList = InteropEmu.GetArchiveRomList(resource.Path);
|
||||
|
||||
public static bool SelectRom(string filename, ref int archiveFileIndex, out string romName)
|
||||
{
|
||||
romName = "";
|
||||
if(archiveRomList.Contains(resource.InnerFile)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
List<string> archiveRomList = InteropEmu.GetArchiveRomList(filename);
|
||||
if(archiveRomList.Count > 1) {
|
||||
if(archiveFileIndex >= 0 && archiveFileIndex < archiveRomList.Count) {
|
||||
romName = System.IO.Path.GetFileName(archiveRomList[archiveFileIndex]);
|
||||
return true;
|
||||
frmSelectRom frm = new frmSelectRom(archiveRomList);
|
||||
if(frm.ShowDialog(null, Application.OpenForms[0]) == DialogResult.OK) {
|
||||
resource.InnerFile = frm.lstRoms.SelectedItem.ToString();
|
||||
} else {
|
||||
frmSelectRom frm = new frmSelectRom(archiveRomList);
|
||||
if(frm.ShowDialog(null, Application.OpenForms[0]) == DialogResult.OK) {
|
||||
archiveFileIndex = frm.SelectedIndex;
|
||||
romName = System.IO.Path.GetFileName(frm.lstRoms.SelectedItem.ToString());
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
} else if(archiveRomList.Count == 1) {
|
||||
romName = System.IO.Path.GetFileName(archiveRomList[0]);
|
||||
resource.InnerFile = archiveRomList[0];
|
||||
} else {
|
||||
romName = System.IO.Path.GetFileName(filename);
|
||||
resource.InnerFile = "";
|
||||
}
|
||||
|
||||
return true;
|
||||
|
|
|
@ -676,6 +676,7 @@
|
|||
</Compile>
|
||||
<Compile Include="Forms\OpenSaveFileDialogExtensions.cs" />
|
||||
<Compile Include="Forms\ResourceHelper.cs" />
|
||||
<Compile Include="Forms\ResourcePath.cs" />
|
||||
<Compile Include="GoogleDriveIntegration\CloudSyncHelper.cs" />
|
||||
<Compile Include="GoogleDriveIntegration\GoogleDriveAccessor.cs" />
|
||||
<Compile Include="GoogleDriveIntegration\MesenCodeReceiver.cs" />
|
||||
|
|
|
@ -26,7 +26,7 @@ namespace Mesen.GUI
|
|||
|
||||
[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 LoadRecentGame([MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(UTF8Marshaler))]string filepath, [MarshalAs(UnmanagedType.I1)]bool resetGame);
|
||||
|
||||
|
@ -553,10 +553,10 @@ namespace Mesen.GUI
|
|||
return header;
|
||||
}
|
||||
|
||||
public static RomInfo GetRomInfo(string filename = "", Int32 archiveFileIndex = -1)
|
||||
public static RomInfo GetRomInfo(string filename = "")
|
||||
{
|
||||
InteropRomInfo romInfo = new InteropRomInfo();
|
||||
InteropEmu.GetRomInfoWrapper(ref romInfo, filename, archiveFileIndex);
|
||||
InteropEmu.GetRomInfoWrapper(ref romInfo, filename);
|
||||
return new RomInfo(romInfo);
|
||||
}
|
||||
|
||||
|
|
|
@ -15,7 +15,6 @@
|
|||
#include "../Core/FDS.h"
|
||||
#include "../Core/VsControlManager.h"
|
||||
#include "../Core/SoundMixer.h"
|
||||
#include "../Core/FileLoader.h"
|
||||
#include "../Core/RomLoader.h"
|
||||
#include "../Core/NsfMapper.h"
|
||||
#include "../Core/IRenderingDevice.h"
|
||||
|
@ -116,14 +115,17 @@ namespace InteropEmu {
|
|||
|
||||
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 LoadRecentGame(char* filepath, bool resetGame) { SaveStateManager::LoadRecentGame(filepath, resetGame); }
|
||||
|
||||
DllExport const char* __stdcall GetArchiveRomList(char* filename) {
|
||||
std::ostringstream out;
|
||||
for(string romName : FileLoader::GetArchiveRomList(filename)) {
|
||||
out << romName << "[!|!]";
|
||||
shared_ptr<ArchiveReader> reader = ArchiveReader::GetReader(filename);
|
||||
if(reader) {
|
||||
for(string romName : reader->GetFileList({ ".nes", ".fds", ".nsf", ".nsfe", "*.unf" })) {
|
||||
out << romName << "[!|!]";
|
||||
}
|
||||
}
|
||||
_returnString = out.str();
|
||||
return _returnString.c_str();
|
||||
|
@ -174,23 +176,25 @@ namespace InteropEmu {
|
|||
DllExport void __stdcall Stop()
|
||||
{
|
||||
if(Console::GetInstance()) {
|
||||
GameServer::StopServer();
|
||||
GameClient::Disconnect();
|
||||
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;
|
||||
if(romPath.empty()) {
|
||||
_returnString = Console::GetRomName();
|
||||
romInfo.RomName = _returnString.c_str();
|
||||
romInfo.Crc32 = Console::GetCrc32();
|
||||
romInfo.PrgCrc32 = Console::GetPrgCrc32();
|
||||
romInfo.Crc32 = Console::GetHashInfo().Crc32Hash;
|
||||
romInfo.PrgCrc32 = Console::GetHashInfo().PrgCrc32Hash;
|
||||
romInfo.Format = Console::GetRomFormat();
|
||||
romInfo.IsChrRam = Console::IsChrRam();
|
||||
} else {
|
||||
RomLoader romLoader;
|
||||
if(romLoader.LoadFile(filename, archiveFileIndex)) {
|
||||
if(romLoader.LoadFile(romPath)) {
|
||||
RomData romData = romLoader.GetRomData();
|
||||
|
||||
_returnString = romData.RomName;
|
||||
|
|
|
@ -38,7 +38,7 @@ extern "C" {
|
|||
void __stdcall SetFlags(uint64_t flags);
|
||||
void __stdcall SetVideoFilter(VideoFilterType filter);
|
||||
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 Stop();
|
||||
}
|
||||
|
@ -67,7 +67,7 @@ int main(int argc, char* argv[])
|
|||
|
||||
SetFlags(0x8000000000000000); //EmulationFlags::ConsoleMode
|
||||
InitializeEmu("C:\\Windows\\Temp\\Mesen", nullptr, nullptr, false, false, false);
|
||||
LoadROM(testRoms[0], -1, "");
|
||||
LoadROM(testRoms[0], "");
|
||||
std::cout << "Running: " << testRoms[0] << std::endl;
|
||||
|
||||
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::cout << "Running: " << testRoms[i] << std::endl;
|
||||
SetVideoFilter(filterTypes[i % 13]);
|
||||
LoadROM(testRoms[i], -1, "");
|
||||
LoadROM(testRoms[i], "");
|
||||
}
|
||||
std::this_thread::sleep_for(std::chrono::duration<int, std::milli>(5000));
|
||||
Stop();
|
||||
|
|
|
@ -50,7 +50,6 @@ extern "C" {
|
|||
void __stdcall SetControllerType(uint32_t port, ControllerType type);
|
||||
int __stdcall RunAutomaticTest(char* filename);
|
||||
int __stdcall RunRecordedTest(char* filename);
|
||||
void __stdcall LoadROM(char* filename);
|
||||
void __stdcall Run();
|
||||
void __stdcall Stop();
|
||||
INotificationListener* __stdcall RegisterNotificationCallback(NotificationListenerCallback callback);
|
||||
|
@ -154,7 +153,7 @@ int main(int argc, char* argv[])
|
|||
|
||||
if(argc >= 3 && strcmp(argv[1], "/auto") == 0) {
|
||||
string romFolder = argv[2];
|
||||
testFilenames = FolderUtilities::GetFilesInFolder(romFolder, ".nes", true);
|
||||
testFilenames = FolderUtilities::GetFilesInFolder(romFolder, { ".nes" }, true);
|
||||
automaticTests = true;
|
||||
} else if(argc <= 2) {
|
||||
string testFolder;
|
||||
|
@ -163,7 +162,7 @@ int main(int argc, char* argv[])
|
|||
} else {
|
||||
testFolder = argv[1];
|
||||
}
|
||||
testFilenames = FolderUtilities::GetFilesInFolder(testFolder, ".mtp", true);
|
||||
testFilenames = FolderUtilities::GetFilesInFolder(testFolder, { ".mtp" }, true);
|
||||
automaticTests = false;
|
||||
}
|
||||
|
||||
|
|
|
@ -4,6 +4,8 @@
|
|||
#include <sstream>
|
||||
#include <algorithm>
|
||||
#include "FolderUtilities.h"
|
||||
#include "ZipReader.h"
|
||||
#include "SZReader.h"
|
||||
|
||||
ArchiveReader::~ArchiveReader()
|
||||
{
|
||||
|
@ -26,13 +28,17 @@ std::stringstream ArchiveReader::GetStream(string filename)
|
|||
|
||||
vector<string> ArchiveReader::GetFileList(std::initializer_list<string> extensions)
|
||||
{
|
||||
if(extensions.size() == 0) {
|
||||
return InternalGetFileList();
|
||||
}
|
||||
|
||||
vector<string> filenames;
|
||||
for(string filename : InternalGetFileList()) {
|
||||
string lcFilename = filename;
|
||||
std::transform(lcFilename.begin(), lcFilename.end(), lcFilename.begin(), ::tolower);
|
||||
if(filename.length() > 4) {
|
||||
for(string ext : extensions) {
|
||||
if(lcFilename.substr(lcFilename.length() - 4, 4).compare(ext) == 0) {
|
||||
for(string ext : extensions) {
|
||||
if(lcFilename.size() >= ext.size()) {
|
||||
if(lcFilename.substr(lcFilename.length() - ext.size(), ext.size()).compare(ext) == 0) {
|
||||
filenames.push_back(filename);
|
||||
}
|
||||
}
|
||||
|
@ -76,4 +82,27 @@ bool ArchiveReader::LoadArchive(string filename)
|
|||
in.close();
|
||||
}
|
||||
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;
|
||||
}
|
|
@ -17,7 +17,9 @@ public:
|
|||
|
||||
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);
|
||||
};
|
|
@ -4,7 +4,7 @@
|
|||
#include "BpsPatcher.h"
|
||||
#include "CRC32.h"
|
||||
|
||||
uint64_t BpsPatcher::ReadBase128Number(ifstream &file)
|
||||
uint64_t BpsPatcher::ReadBase128Number(std::istream &file)
|
||||
{
|
||||
uint64_t result = 0;
|
||||
int shift = 0;
|
||||
|
@ -25,103 +25,104 @@ uint64_t BpsPatcher::ReadBase128Number(ifstream &file)
|
|||
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);
|
||||
|
||||
if(bpsFile) {
|
||||
bpsFile.seekg(0, std::ios::end);
|
||||
size_t fileSize = (size_t)bpsFile.tellg();
|
||||
bpsFile.seekg(0, std::ios::beg);
|
||||
return PatchBuffer(bpsFile, input, output);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
char header[4];
|
||||
bpsFile.read((char*)&header, 4);
|
||||
if(memcmp((char*)&header, "BPS1", 4) != 0) {
|
||||
//Invalid BPS file
|
||||
return input;
|
||||
}
|
||||
bool BpsPatcher::PatchBuffer(std::istream &bpsFile, vector<uint8_t> &input, vector<uint8_t> &output)
|
||||
{
|
||||
bpsFile.seekg(0, std::ios::end);
|
||||
size_t fileSize = (size_t)bpsFile.tellg();
|
||||
bpsFile.seekg(0, std::ios::beg);
|
||||
|
||||
uint64_t inputFileSize = ReadBase128Number(bpsFile);
|
||||
uint64_t outputFileSize = ReadBase128Number(bpsFile);
|
||||
if(inputFileSize == -1 || outputFileSize == -1) {
|
||||
char header[4];
|
||||
bpsFile.read((char*)&header, 4);
|
||||
if(memcmp((char*)&header, "BPS1", 4) != 0) {
|
||||
//Invalid BPS file
|
||||
return false;
|
||||
}
|
||||
|
||||
uint64_t inputFileSize = ReadBase128Number(bpsFile);
|
||||
uint64_t outputFileSize = ReadBase128Number(bpsFile);
|
||||
if(inputFileSize == -1 || outputFileSize == -1) {
|
||||
//Invalid file
|
||||
return false;
|
||||
}
|
||||
|
||||
uint64_t metadataSize = ReadBase128Number(bpsFile);
|
||||
bpsFile.seekg(metadataSize, std::ios::cur);
|
||||
|
||||
output.resize((size_t)outputFileSize);
|
||||
|
||||
uint32_t outputOffset = 0;
|
||||
uint32_t inputRelativeOffset = 0;
|
||||
uint32_t outputRelativeOffset = 0;
|
||||
while((size_t)bpsFile.tellg() < fileSize - 12) {
|
||||
uint64_t data = ReadBase128Number(bpsFile);
|
||||
if(data == -1) {
|
||||
//Invalid file
|
||||
return input;
|
||||
return false;
|
||||
}
|
||||
|
||||
uint64_t metadataSize = ReadBase128Number(bpsFile);
|
||||
bpsFile.seekg(metadataSize, std::ios::cur);
|
||||
uint8_t command = data & 0x03;
|
||||
uint64_t length = (data >> 2) + 1;
|
||||
switch(command) {
|
||||
case 0:
|
||||
//SourceRead
|
||||
while(length--) {
|
||||
output[outputOffset] = input[outputOffset];
|
||||
outputOffset++;
|
||||
}
|
||||
break;
|
||||
|
||||
vector<uint8_t> output;
|
||||
output.resize((size_t)outputFileSize);
|
||||
case 1:
|
||||
//TargetRead
|
||||
while(length--) {
|
||||
uint8_t value = 0;
|
||||
bpsFile.read((char*)&value, 1);
|
||||
|
||||
uint32_t outputOffset = 0;
|
||||
uint32_t inputRelativeOffset = 0;
|
||||
uint32_t outputRelativeOffset = 0;
|
||||
while((size_t)bpsFile.tellg() < fileSize - 12) {
|
||||
uint64_t data = ReadBase128Number(bpsFile);
|
||||
if(data == -1) {
|
||||
//Invalid file
|
||||
return input;
|
||||
output[outputOffset++] = value;
|
||||
}
|
||||
break;
|
||||
|
||||
case 2: {
|
||||
//SourceCopy
|
||||
uint32_t data = (uint32_t)ReadBase128Number(bpsFile);
|
||||
inputRelativeOffset += (data & 1 ? -1 : +1) * (data >> 1);
|
||||
while(length--) {
|
||||
output[outputOffset++] = input[inputRelativeOffset++];
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
uint8_t command = data & 0x03;
|
||||
uint64_t length = (data >> 2) + 1;
|
||||
switch(command) {
|
||||
case 0:
|
||||
//SourceRead
|
||||
while(length--) {
|
||||
output[outputOffset] = input[outputOffset];
|
||||
outputOffset++;
|
||||
}
|
||||
break;
|
||||
|
||||
case 1:
|
||||
//TargetRead
|
||||
while(length--) {
|
||||
uint8_t value = 0;
|
||||
bpsFile.read((char*)&value, 1);
|
||||
|
||||
output[outputOffset++] = value;
|
||||
}
|
||||
break;
|
||||
|
||||
case 2: {
|
||||
//SourceCopy
|
||||
uint32_t data = (uint32_t)ReadBase128Number(bpsFile);
|
||||
inputRelativeOffset += (data & 1 ? -1 : +1) * (data >> 1);
|
||||
while(length--) {
|
||||
output[outputOffset++] = input[inputRelativeOffset++];
|
||||
}
|
||||
break;
|
||||
case 3: {
|
||||
//TargetCopy
|
||||
uint32_t data = (uint32_t)ReadBase128Number(bpsFile);
|
||||
outputRelativeOffset += (data & 1 ? -1 : +1) * (data >> 1);
|
||||
while(length--) {
|
||||
output[outputOffset++] = output[outputRelativeOffset++];
|
||||
}
|
||||
|
||||
case 3: {
|
||||
//TargetCopy
|
||||
uint32_t data = (uint32_t)ReadBase128Number(bpsFile);
|
||||
outputRelativeOffset += (data & 1 ? -1 : +1) * (data >> 1);
|
||||
while(length--) {
|
||||
output[outputOffset++] = output[outputRelativeOffset++];
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
uint8_t inputChecksum[4];
|
||||
uint8_t outputChecksum[4];
|
||||
bpsFile.read((char*)inputChecksum, 4);
|
||||
bpsFile.read((char*)outputChecksum, 4);
|
||||
uint32_t patchInputCrc = inputChecksum[0] | (inputChecksum[1] << 8) | (inputChecksum[2] << 16) | (inputChecksum[3] << 24);
|
||||
uint32_t patchOutputCrc = outputChecksum[0] | (outputChecksum[1] << 8) | (outputChecksum[2] << 16) | (outputChecksum[3] << 24);
|
||||
uint32_t inputCrc = CRC32::GetCRC(input.data(), input.size());
|
||||
uint32_t outputCrc = CRC32::GetCRC(output.data(), output.size());
|
||||
|
||||
if(patchInputCrc != inputCrc || patchOutputCrc != outputCrc) {
|
||||
return input;
|
||||
}
|
||||
|
||||
bpsFile.close();
|
||||
return output;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return input;
|
||||
|
||||
uint8_t inputChecksum[4];
|
||||
uint8_t outputChecksum[4];
|
||||
bpsFile.read((char*)inputChecksum, 4);
|
||||
bpsFile.read((char*)outputChecksum, 4);
|
||||
uint32_t patchInputCrc = inputChecksum[0] | (inputChecksum[1] << 8) | (inputChecksum[2] << 16) | (inputChecksum[3] << 24);
|
||||
uint32_t patchOutputCrc = outputChecksum[0] | (outputChecksum[1] << 8) | (outputChecksum[2] << 16) | (outputChecksum[3] << 24);
|
||||
uint32_t inputCrc = CRC32::GetCRC(input.data(), input.size());
|
||||
uint32_t outputCrc = CRC32::GetCRC(output.data(), output.size());
|
||||
|
||||
if(patchInputCrc != inputCrc || patchOutputCrc != outputCrc) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
|
|
@ -5,8 +5,9 @@
|
|||
class BpsPatcher
|
||||
{
|
||||
private:
|
||||
static uint64_t ReadBase128Number(ifstream &file);
|
||||
static uint64_t ReadBase128Number(std::istream &file);
|
||||
|
||||
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);
|
||||
};
|
|
@ -4,6 +4,7 @@
|
|||
#include <experimental/filesystem>
|
||||
namespace fs = std::experimental::filesystem;
|
||||
|
||||
#include <unordered_set>
|
||||
#include <algorithm>
|
||||
#include "FolderUtilities.h"
|
||||
#include "UTF8Util.h"
|
||||
|
@ -120,7 +121,7 @@ vector<string> FolderUtilities::GetFolders(string rootFolder)
|
|||
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> 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++) {
|
||||
string extension = i->path().extension().u8string();
|
||||
std::transform(extension.begin(), extension.end(), extension.begin(), ::tolower);
|
||||
if(extension == mask) {
|
||||
if(extensions.find(extension) != extensions.end()) {
|
||||
files.push_back(i->path().u8string());
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
#pragma once
|
||||
|
||||
#include "stdafx.h"
|
||||
#include <unordered_set>
|
||||
|
||||
class FolderUtilities
|
||||
{
|
||||
|
@ -24,7 +25,7 @@ public:
|
|||
static string GetRecentGamesFolder();
|
||||
|
||||
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 GetFolderName(string filepath);
|
||||
|
|
|
@ -14,7 +14,7 @@ public:
|
|||
uint16_t RepeatCount = 0;
|
||||
uint8_t Value = 0;
|
||||
|
||||
bool ReadRecord(ifstream &ipsFile)
|
||||
bool ReadRecord(std::istream &ipsFile)
|
||||
{
|
||||
uint8_t buffer[3];
|
||||
|
||||
|
@ -60,60 +60,61 @@ 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);
|
||||
|
||||
if(ipsFile) {
|
||||
char header[5];
|
||||
ipsFile.read((char*)&header, 5);
|
||||
if(memcmp((char*)&header, "PATCH", 5) != 0) {
|
||||
//Invalid ips file
|
||||
return input;
|
||||
}
|
||||
|
||||
vector<IpsRecord> records;
|
||||
int32_t truncateOffset = -1;
|
||||
size_t maxOutputSize = input.size();
|
||||
while(!ipsFile.eof()) {
|
||||
IpsRecord record;
|
||||
if(record.ReadRecord(ipsFile)) {
|
||||
if(record.Address + record.Length + record.RepeatCount > maxOutputSize) {
|
||||
maxOutputSize = record.Address + record.Length + record.RepeatCount;
|
||||
}
|
||||
records.push_back(record);
|
||||
} else {
|
||||
//EOF, try to read truncate offset record if it exists
|
||||
uint8_t buffer[3];
|
||||
ipsFile.read((char*)buffer, 3);
|
||||
if(!ipsFile.eof()) {
|
||||
truncateOffset = buffer[2] | (buffer[1] << 8) | (buffer[0] << 16);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
vector<uint8_t> output;
|
||||
output.resize(maxOutputSize);
|
||||
std::copy(input.begin(), input.end(), output.begin());
|
||||
|
||||
for(IpsRecord record : records) {
|
||||
if(record.Length == 0) {
|
||||
std::fill(&output[record.Address], &output[record.Address]+record.RepeatCount, record.Value);
|
||||
} else {
|
||||
std::copy(record.Replacement.begin(), record.Replacement.end(), output.begin()+record.Address);
|
||||
}
|
||||
}
|
||||
|
||||
if(truncateOffset != -1 && (int32_t)output.size() > truncateOffset) {
|
||||
output.resize(truncateOffset);
|
||||
}
|
||||
|
||||
ipsFile.close();
|
||||
|
||||
return output;
|
||||
return PatchBuffer(ipsFile, input, output);
|
||||
}
|
||||
return input;
|
||||
return false;
|
||||
}
|
||||
|
||||
bool IpsPatcher::PatchBuffer(std::istream &ipsFile, vector<uint8_t> &input, vector<uint8_t> &output)
|
||||
{
|
||||
char header[5];
|
||||
ipsFile.read((char*)&header, 5);
|
||||
if(memcmp((char*)&header, "PATCH", 5) != 0) {
|
||||
//Invalid ips file
|
||||
return false;
|
||||
}
|
||||
|
||||
vector<IpsRecord> records;
|
||||
int32_t truncateOffset = -1;
|
||||
size_t maxOutputSize = input.size();
|
||||
while(!ipsFile.eof()) {
|
||||
IpsRecord record;
|
||||
if(record.ReadRecord(ipsFile)) {
|
||||
if(record.Address + record.Length + record.RepeatCount > maxOutputSize) {
|
||||
maxOutputSize = record.Address + record.Length + record.RepeatCount;
|
||||
}
|
||||
records.push_back(record);
|
||||
} else {
|
||||
//EOF, try to read truncate offset record if it exists
|
||||
uint8_t buffer[3];
|
||||
ipsFile.read((char*)buffer, 3);
|
||||
if(!ipsFile.eof()) {
|
||||
truncateOffset = buffer[2] | (buffer[1] << 8) | (buffer[0] << 16);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
output.resize(maxOutputSize);
|
||||
std::copy(input.begin(), input.end(), output.begin());
|
||||
|
||||
for(IpsRecord record : records) {
|
||||
if(record.Length == 0) {
|
||||
std::fill(&output[record.Address], &output[record.Address]+record.RepeatCount, record.Value);
|
||||
} else {
|
||||
std::copy(record.Replacement.begin(), record.Replacement.end(), output.begin()+record.Address);
|
||||
}
|
||||
}
|
||||
|
||||
if(truncateOffset != -1 && (int32_t)output.size() > truncateOffset) {
|
||||
output.resize(truncateOffset);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
vector<uint8_t> IpsPatcher::CreatePatch(vector<uint8_t> originalData, vector<uint8_t> newData)
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
class IpsPatcher
|
||||
{
|
||||
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);
|
||||
};
|
|
@ -38,11 +38,31 @@ bool PNGHelper::WritePNG(string filename, uint32_t* buffer, uint32_t xSize, uint
|
|||
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)
|
||||
{
|
||||
unsigned long width;
|
||||
unsigned long height;
|
||||
|
||||
pngWidth = 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();
|
||||
pngFile.seekg(0, std::ios::beg);
|
||||
|
||||
uint8_t* buffer = new uint8_t[fileSize];
|
||||
pngFile.read((char*)buffer, fileSize);
|
||||
DecodePNG(pngData, width, height, buffer, fileSize);
|
||||
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;
|
||||
vector<uint8_t> fileData(fileSize, 0);
|
||||
pngFile.read((char*)fileData.data(), fileData.size());
|
||||
return ReadPNG(fileData, pngData, pngWidth, pngHeight);
|
||||
}
|
||||
|
||||
return false;
|
||||
|
|
|
@ -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(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(vector<uint8_t> input, vector<uint8_t> &output, uint32_t &pngWidth, uint32_t &pngHeight);
|
||||
};
|
|
@ -16,6 +16,11 @@ SZReader::~SZReader()
|
|||
|
||||
bool SZReader::InternalLoadArchive(void* buffer, size_t size)
|
||||
{
|
||||
if(_initialized) {
|
||||
SzArEx_Free(&_archive, &_allocImp);
|
||||
_initialized = false;
|
||||
}
|
||||
|
||||
ISzAlloc allocImp{ SzAlloc, SzFree };
|
||||
ISzAlloc allocTempImp{ SzAllocTemp, SzFreeTemp };
|
||||
|
||||
|
@ -26,8 +31,9 @@ bool SZReader::InternalLoadArchive(void* buffer, size_t size)
|
|||
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) {
|
||||
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) {
|
||||
uint8_t* buf = new uint8_t[outSizeProcessed];
|
||||
output = vector<uint8_t>(outBuffer+offset, outBuffer+offset+outSizeProcessed);
|
||||
result = true;
|
||||
}
|
||||
IAlloc_Free(&_allocImp, outBuffer);
|
||||
break;
|
||||
|
@ -57,6 +64,8 @@ void SZReader::ExtractFile(string filename, vector<uint8_t> &output)
|
|||
}
|
||||
SzFree(nullptr, utf16Filename);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
vector<string> SZReader::InternalGetFileList()
|
||||
|
|
|
@ -24,5 +24,5 @@ public:
|
|||
SZReader();
|
||||
virtual ~SZReader();
|
||||
|
||||
void ExtractFile(string filename, vector<uint8_t> &output);
|
||||
bool ExtractFile(string filename, vector<uint8_t> &output);
|
||||
};
|
|
@ -4,7 +4,7 @@
|
|||
#include "UpsPatcher.h"
|
||||
#include "CRC32.h"
|
||||
|
||||
uint64_t UpsPatcher::ReadBase128Number(ifstream &file)
|
||||
uint64_t UpsPatcher::ReadBase128Number(std::istream &file)
|
||||
{
|
||||
uint64_t result = 0;
|
||||
int shift = 0;
|
||||
|
@ -25,75 +25,76 @@ uint64_t UpsPatcher::ReadBase128Number(ifstream &file)
|
|||
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);
|
||||
|
||||
if(upsFile) {
|
||||
upsFile.seekg(0, std::ios::end);
|
||||
size_t fileSize = (size_t)upsFile.tellg();
|
||||
upsFile.seekg(0, std::ios::beg);
|
||||
|
||||
char header[4];
|
||||
upsFile.read((char*)&header, 4);
|
||||
if(memcmp((char*)&header, "UPS1", 4) != 0) {
|
||||
//Invalid UPS file
|
||||
return input;
|
||||
}
|
||||
|
||||
uint64_t inputFileSize = ReadBase128Number(upsFile);
|
||||
uint64_t outputFileSize = ReadBase128Number(upsFile);
|
||||
if(inputFileSize == -1 || outputFileSize == -1) {
|
||||
//Invalid file
|
||||
return input;
|
||||
}
|
||||
|
||||
vector<uint8_t> output;
|
||||
output.resize((size_t)outputFileSize);
|
||||
std::copy(input.begin(), input.end(), output.begin());
|
||||
|
||||
uint32_t pos = 0;
|
||||
while((size_t)upsFile.tellg() < fileSize - 12) {
|
||||
uint32_t offset = (uint32_t)ReadBase128Number(upsFile);
|
||||
if(offset == -1) {
|
||||
//Invalid file
|
||||
return input;
|
||||
}
|
||||
|
||||
pos += offset;
|
||||
|
||||
while(true) {
|
||||
uint8_t xorValue = 0;
|
||||
upsFile.read((char*)&xorValue, 1);
|
||||
if((size_t)upsFile.tellg() > fileSize - 12) {
|
||||
//Invalid file
|
||||
return input;
|
||||
}
|
||||
|
||||
output[pos] ^= xorValue;
|
||||
pos++;
|
||||
|
||||
if(!xorValue) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
uint8_t inputChecksum[4];
|
||||
uint8_t outputChecksum[4];
|
||||
upsFile.read((char*)inputChecksum, 4);
|
||||
upsFile.read((char*)outputChecksum, 4);
|
||||
uint32_t patchInputCrc = inputChecksum[0] | (inputChecksum[1] << 8) | (inputChecksum[2] << 16) | (inputChecksum[3] << 24);
|
||||
uint32_t patchOutputCrc = outputChecksum[0] | (outputChecksum[1] << 8) | (outputChecksum[2] << 16) | (outputChecksum[3] << 24);
|
||||
uint32_t inputCrc = CRC32::GetCRC(input.data(), input.size());
|
||||
uint32_t outputCrc = CRC32::GetCRC(output.data(), output.size());
|
||||
|
||||
if(patchInputCrc != inputCrc || patchOutputCrc != outputCrc) {
|
||||
return input;
|
||||
}
|
||||
|
||||
upsFile.close();
|
||||
return output;
|
||||
return PatchBuffer(upsFile, input, output);
|
||||
}
|
||||
return input;
|
||||
return false;
|
||||
}
|
||||
|
||||
bool UpsPatcher::PatchBuffer(std::istream &upsFile, vector<uint8_t> &input, vector<uint8_t> &output)
|
||||
{
|
||||
upsFile.seekg(0, std::ios::end);
|
||||
size_t fileSize = (size_t)upsFile.tellg();
|
||||
upsFile.seekg(0, std::ios::beg);
|
||||
|
||||
char header[4];
|
||||
upsFile.read((char*)&header, 4);
|
||||
if(memcmp((char*)&header, "UPS1", 4) != 0) {
|
||||
//Invalid UPS file
|
||||
return false;
|
||||
}
|
||||
|
||||
uint64_t inputFileSize = ReadBase128Number(upsFile);
|
||||
uint64_t outputFileSize = ReadBase128Number(upsFile);
|
||||
if(inputFileSize == -1 || outputFileSize == -1) {
|
||||
//Invalid file
|
||||
return false;
|
||||
}
|
||||
|
||||
output.resize((size_t)outputFileSize);
|
||||
std::copy(input.begin(), input.end(), output.begin());
|
||||
|
||||
uint32_t pos = 0;
|
||||
while((size_t)upsFile.tellg() < fileSize - 12) {
|
||||
uint32_t offset = (uint32_t)ReadBase128Number(upsFile);
|
||||
if(offset == -1) {
|
||||
//Invalid file
|
||||
return false;
|
||||
}
|
||||
|
||||
pos += offset;
|
||||
|
||||
while(true) {
|
||||
uint8_t xorValue = 0;
|
||||
upsFile.read((char*)&xorValue, 1);
|
||||
if((size_t)upsFile.tellg() > fileSize - 12) {
|
||||
//Invalid file
|
||||
return false;
|
||||
}
|
||||
|
||||
output[pos] ^= xorValue;
|
||||
pos++;
|
||||
|
||||
if(!xorValue) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
uint8_t inputChecksum[4];
|
||||
uint8_t outputChecksum[4];
|
||||
upsFile.read((char*)inputChecksum, 4);
|
||||
upsFile.read((char*)outputChecksum, 4);
|
||||
uint32_t patchInputCrc = inputChecksum[0] | (inputChecksum[1] << 8) | (inputChecksum[2] << 16) | (inputChecksum[3] << 24);
|
||||
uint32_t patchOutputCrc = outputChecksum[0] | (outputChecksum[1] << 8) | (outputChecksum[2] << 16) | (outputChecksum[3] << 24);
|
||||
uint32_t inputCrc = CRC32::GetCRC(input.data(), input.size());
|
||||
uint32_t outputCrc = CRC32::GetCRC(output.data(), output.size());
|
||||
|
||||
if(patchInputCrc != inputCrc || patchOutputCrc != outputCrc) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
|
|
@ -5,8 +5,9 @@
|
|||
class UpsPatcher
|
||||
{
|
||||
private:
|
||||
static uint64_t ReadBase128Number(ifstream &file);
|
||||
static uint64_t ReadBase128Number(std::istream &file);
|
||||
|
||||
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);
|
||||
};
|
|
@ -359,6 +359,7 @@
|
|||
<ClInclude Include="Timer.h" />
|
||||
<ClInclude Include="UpsPatcher.h" />
|
||||
<ClInclude Include="UTF8Util.h" />
|
||||
<ClInclude Include="VirtualFile.h" />
|
||||
<ClInclude Include="xBRZ\config.h" />
|
||||
<ClInclude Include="xBRZ\xbrz.h" />
|
||||
<ClInclude Include="ZipReader.h" />
|
||||
|
|
|
@ -116,9 +116,6 @@
|
|||
<ClInclude Include="SZReader.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="ArchiveReader.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="PlatformUtilities.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
|
@ -158,6 +155,12 @@
|
|||
<ClInclude Include="sha1.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="ArchiveReader.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="VirtualFile.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="stdafx.cpp">
|
||||
|
|
155
Utilities/VirtualFile.h
Normal file
155
Utilities/VirtualFile.h
Normal 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;
|
||||
}
|
||||
};
|
|
@ -17,6 +17,12 @@ ZipReader::~ZipReader()
|
|||
|
||||
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;
|
||||
}
|
||||
|
||||
|
@ -36,18 +42,23 @@ vector<string> ZipReader::InternalGetFileList()
|
|||
return fileList;
|
||||
}
|
||||
|
||||
void ZipReader::ExtractFile(string filename, vector<uint8_t> &output)
|
||||
bool ZipReader::ExtractFile(string filename, vector<uint8_t> &output)
|
||||
{
|
||||
if(_initialized) {
|
||||
size_t uncompSize;
|
||||
void *p = mz_zip_reader_extract_file_to_heap(&_zipArchive, filename.c_str(), &uncompSize, 0);
|
||||
if(!p) {
|
||||
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);
|
||||
|
||||
// We're done.
|
||||
mz_free(p);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
|
@ -16,5 +16,5 @@ public:
|
|||
ZipReader();
|
||||
virtual ~ZipReader();
|
||||
|
||||
void ExtractFile(string filename, vector<uint8_t> &output);
|
||||
bool ExtractFile(string filename, vector<uint8_t> &output);
|
||||
};
|
|
@ -34,7 +34,8 @@ void ZipWriter::AddFile(std::stringstream &filestream, string zipFilename)
|
|||
uint8_t* buffer = new uint8_t[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;
|
||||
}
|
||||
delete[] buffer;
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue