From 194d933685cd9a224d362ed7c00b384b143da3ed Mon Sep 17 00:00:00 2001 From: Souryo Date: Sat, 22 Apr 2017 13:19:21 -0400 Subject: [PATCH] Movies: bk2 movie format support (incomplete + sync issues vs NesHawk) --- Core/BaseMapper.cpp | 5 +- Core/BaseMapper.h | 3 +- Core/BizhawkMovie.cpp | 190 +++++++++++++++++ Core/BizhawkMovie.h | 34 +++ Core/Console.cpp | 23 +- Core/Console.h | 2 + Core/Core.vcxproj | 2 + Core/Core.vcxproj.filters | 6 + Core/MesenMovie.cpp | 17 +- Core/MesenMovie.h | 2 +- Core/MovieManager.cpp | 25 ++- Core/MovieManager.h | 16 +- Core/PPU.cpp | 2 +- Core/RomData.h | 7 + Core/RomLoader.cpp | 12 +- Core/RomLoader.h | 4 +- Core/VsControlManager.h | 3 +- Utilities/ArchiveReader.cpp | 34 +-- Utilities/ArchiveReader.h | 2 + Utilities/Utilities.vcxproj | 2 + Utilities/Utilities.vcxproj.filters | 6 + Utilities/sha1.cpp | 319 ++++++++++++++++++++++++++++ Utilities/sha1.h | 41 ++++ 23 files changed, 705 insertions(+), 52 deletions(-) create mode 100644 Core/BizhawkMovie.cpp create mode 100644 Core/BizhawkMovie.h create mode 100644 Utilities/sha1.cpp create mode 100644 Utilities/sha1.h diff --git a/Core/BaseMapper.cpp b/Core/BaseMapper.cpp index 0ebd05ed..65db9efe 100644 --- a/Core/BaseMapper.cpp +++ b/Core/BaseMapper.cpp @@ -521,6 +521,7 @@ void BaseMapper::Initialize(RomData &romData) _gameSystem = romData.System; _crc32 = romData.Crc32; + _sha1Hash = romData.Sha1; _prgCrc32 = romData.PrgCrc32; switch(romData.BusConflicts) { case BusConflictType::Default: _hasBusConflicts = HasBusConflicts(); break; @@ -707,9 +708,9 @@ RomFormat BaseMapper::GetRomFormat() return _romFormat; } -uint32_t BaseMapper::GetCrc32() +HashInfo BaseMapper::GetHashInfo() { - return _crc32; + return { _crc32, _sha1Hash }; } uint32_t BaseMapper::GetPrgCrc32() diff --git a/Core/BaseMapper.h b/Core/BaseMapper.h index dceb6b13..628bb778 100644 --- a/Core/BaseMapper.h +++ b/Core/BaseMapper.h @@ -46,6 +46,7 @@ private: uint32_t _chrPageNumbers[64]; uint32_t _crc32 = 0; + string _sha1Hash = ""; uint32_t _prgCrc32 = 0; vector _originalPrgRom; @@ -164,7 +165,7 @@ public: virtual void SetDefaultNametables(uint8_t* nametableA, uint8_t* nametableB); GameSystem GetGameSystem(); - uint32_t GetCrc32(); + HashInfo GetHashInfo(); uint32_t GetPrgCrc32(); string GetRomName(); RomFormat GetRomFormat(); diff --git a/Core/BizhawkMovie.cpp b/Core/BizhawkMovie.cpp new file mode 100644 index 00000000..f41d0728 --- /dev/null +++ b/Core/BizhawkMovie.cpp @@ -0,0 +1,190 @@ +#include "stdafx.h" +#include "BizhawkMovie.h" +#include "VsControlManager.h" +#include "FDS.h" + +BizhawkMovie::BizhawkMovie() +{ + _originalPowerOnState = EmulationSettings::GetRamPowerOnState(); + MessageManager::RegisterNotificationListener(this); +} + +BizhawkMovie::~BizhawkMovie() +{ + MessageManager::UnregisterNotificationListener(this); + EmulationSettings::SetRamPowerOnState(_originalPowerOnState); +} + +void BizhawkMovie::ProcessNotification(ConsoleNotificationType type, void* parameter) +{ + if(type == ConsoleNotificationType::PpuFrameDone) { + int32_t frameNumber = PPU::GetFrameCount() - 1; + if(frameNumber < _systemActionByFrame.size()) { + uint32_t systemAction = _systemActionByFrame[frameNumber]; + if(systemAction & 0x01) { + //Power, not implemented yet + } + if(systemAction & 0x02) { + //Reset, not implemented yet + } + + if(_gameSystem == GameSystem::FDS) { + //FDS timings between NesHawk & Mesen are currently significantly different + //So FDS games will always go out of sync + if(systemAction & 0x04) { + FDS::EjectDisk(); + } else if(systemAction >= 8) { + systemAction >>= 3; + uint32_t diskNumber = 0; + while(!(systemAction & 0x01)) { + systemAction >>= 1; + diskNumber++; + } + FDS::InsertDisk(diskNumber); + } + } else if(_gameSystem == GameSystem::VsUniSystem) { + if(VsControlManager::GetInstance()) { + if(systemAction & 0x04) { + VsControlManager::GetInstance()->InsertCoin(0); + } + if(systemAction & 0x08) { + VsControlManager::GetInstance()->InsertCoin(1); + } + VsControlManager::GetInstance()->SetServiceButtonState(systemAction & 0x10 ? true : false); + } + } + } + } +} + +uint8_t BizhawkMovie::GetState(uint8_t port) +{ + int32_t frameNumber = PPU::GetFrameCount() - 1; + if(frameNumber < _dataByFrame[0].size()) { + return _dataByFrame[port][frameNumber]; + } else { + EndMovie(); + EmulationSettings::SetRamPowerOnState(_originalPowerOnState); + _isPlaying = false; + return 0; + } +} + +bool BizhawkMovie::InitializeGameData(ZipReader & reader) +{ + std::stringstream ss = reader.GetStream("Header.txt"); + + _gameSystem = GameSystem::NesNtsc; + + bool result = false; + while(!ss.eof()) { + string line; + 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)) { + result = true; + } + } + } else if(line.compare(0, 9, "BoardName", 9) == 0) { + if(line.compare(10, 8, "MAPPER99", 8) == 0) { + //VS System + _gameSystem = GameSystem::VsUniSystem; + } else if(line.compare(10, 3, "FDS", 3) == 0) { + //FDS + _gameSystem = GameSystem::FDS; + } + } + } + return result; +} + +bool BizhawkMovie::InitializeInputData(ZipReader & reader) +{ + const uint8_t orValues[8] = { 0x10, 0x20, 0x40, 0x80, 0x08, 0x04, 0x02, 0x01 }; + std::stringstream ss = reader.GetStream("Input Log.txt"); + + int systemActionCount = 2; + if(_gameSystem == GameSystem::FDS) { + //Eject disk + Insert Disk #XX + systemActionCount += FDS::GetSideCount() + 1; + } else if(_gameSystem == GameSystem::VsUniSystem) { + //Insert coin 1, 2 + service button + systemActionCount += 3; + } + + while(!ss.eof()) { + string line; + std::getline(ss, line); + + if(line.size() > 0 && line[0] == '|') { + line.erase(std::remove(line.begin(), line.end(), '|'), line.end()); + line = line.substr(0, line.size() - 1); + + //Read power/reset/FDS/VS/etc. commands + uint32_t systemAction = 0; + for(int i = 0; i < systemActionCount; i++) { + if(line[i] != '.') { + systemAction |= (1 << i); + } + } + _systemActionByFrame.push_back(systemAction); + + //Only supports regular controllers (up to 4 of them) + for(int i = 0; i < 8*4; i++) { + uint8_t port = i / 8; + + if(port <= 3) { + uint8_t portValue = 0; + for(int j = 0; j < 8 && i + j + systemActionCount < line.size(); j++) { + if(line[i+j+systemActionCount] != '.') { + portValue |= orValues[j]; + } + } + i += 7; + _dataByFrame[port].push_back(portValue); + } + } + } + } + + return _dataByFrame[0].size() > 0; +} + +bool BizhawkMovie::Play(stringstream & filestream, bool autoLoadRom) +{ + Console::Pause(); + ZipReader reader; + reader.LoadArchive(filestream); + if(InitializeGameData(reader)) { + if(InitializeInputData(reader)) { + //NesHawk initializes memory to 1s + EmulationSettings::SetRamPowerOnState(RamPowerOnState::AllOnes); + Console::Reset(false); + _isPlaying = true; + } + } + Console::Resume(); + return _isPlaying; +} + +bool BizhawkMovie::IsRecording() +{ + return false; +} + +bool BizhawkMovie::IsPlaying() +{ + return _isPlaying; +} + +void BizhawkMovie::RecordState(uint8_t port, uint8_t value) +{ + //Not implemented +} + +void BizhawkMovie::Record(string filename, bool reset) +{ + //Not implemented +} diff --git a/Core/BizhawkMovie.h b/Core/BizhawkMovie.h new file mode 100644 index 00000000..f3e895f5 --- /dev/null +++ b/Core/BizhawkMovie.h @@ -0,0 +1,34 @@ +#include "../Utilities/ZipReader.h" +#include "../Utilities/StringUtilities.h" +#include "Console.h" +#include "MovieManager.h" +#include "PPU.h" + +class BizhawkMovie : public IMovie, public INotificationListener +{ +private: + vector _systemActionByFrame; + vector _dataByFrame[4]; + bool _isPlaying = false; + RamPowerOnState _originalPowerOnState; + GameSystem _gameSystem; + + bool InitializeGameData(ZipReader &reader); + bool InitializeInputData(ZipReader &reader); + +public: + BizhawkMovie(); + virtual ~BizhawkMovie(); + + void RecordState(uint8_t port, uint8_t value) override; + void Record(string filename, bool reset); + + uint8_t GetState(uint8_t port) override; + + bool Play(stringstream &filestream, bool autoLoadRom) override; + + bool IsRecording() override; + bool IsPlaying() override; + + void ProcessNotification(ConsoleNotificationType type, void* parameter); +}; \ No newline at end of file diff --git a/Core/Console.cpp b/Core/Console.cpp index a4f7e1a6..b879d02f 100644 --- a/Core/Console.cpp +++ b/Core/Console.cpp @@ -117,12 +117,25 @@ void Console::LoadROM(string filepath, stringstream *filestream, int32_t archive Console::Resume(); } -bool Console::LoadROM(string filename, uint32_t crc32Hash) +bool Console::LoadROM(string romName, uint32_t crc32Hash) +{ + HashInfo hashInfo{ crc32Hash, "" }; + return Console::LoadROM(romName, hashInfo); +} + +bool Console::LoadROM(string romName, string sha1Hash) +{ + HashInfo hashInfo{ 0, sha1Hash }; + return Console::LoadROM(romName, hashInfo); +} + +bool Console::LoadROM(string romName, HashInfo hashInfo) { string currentRomFilepath = Console::GetROMPath(); string currentFolder = FolderUtilities::GetFolderName(currentRomFilepath); if(!currentRomFilepath.empty()) { - if(Console::GetCrc32() == crc32Hash) { + HashInfo gameHashInfo = Instance->_mapper->GetHashInfo(); + if(gameHashInfo.Crc32Hash == hashInfo.Crc32Hash || gameHashInfo.Sha1Hash.compare(hashInfo.Sha1Hash) == 0) { //Current game matches, no need to do anything return true; } @@ -130,7 +143,7 @@ bool Console::LoadROM(string filename, uint32_t crc32Hash) int32_t archiveFileIndex = -1; for(string folder : FolderUtilities::GetKnownGameFolders()) { - string match = RomLoader::FindMatchingRomInFolder(folder, filename, crc32Hash, true, archiveFileIndex); + string match = RomLoader::FindMatchingRomInFolder(folder, romName, hashInfo, true, archiveFileIndex); if(!match.empty()) { Console::LoadROM(match, nullptr, archiveFileIndex); return true; @@ -139,7 +152,7 @@ bool Console::LoadROM(string filename, uint32_t crc32Hash) //Perform slow CRC32 search for ROM for(string folder : FolderUtilities::GetKnownGameFolders()) { - string match = RomLoader::FindMatchingRomInFolder(folder, filename, crc32Hash, false, archiveFileIndex); + string match = RomLoader::FindMatchingRomInFolder(folder, romName, hashInfo, false, archiveFileIndex); if(!match.empty()) { Console::LoadROM(match, nullptr, archiveFileIndex); return true; @@ -175,7 +188,7 @@ RomFormat Console::GetRomFormat() uint32_t Console::GetCrc32() { if(Instance->_mapper) { - return Instance->_mapper->GetCrc32(); + return Instance->_mapper->GetHashInfo().Crc32Hash; } else { return 0; } diff --git a/Core/Console.h b/Core/Console.h index aebccebe..cecdb4bb 100644 --- a/Core/Console.h +++ b/Core/Console.h @@ -74,7 +74,9 @@ class Console static void LoadState(uint8_t *buffer, uint32_t bufferSize); static void LoadROM(string filepath, stringstream *filestream = nullptr, int32_t archiveFileIndex = -1, string patchFilepath = ""); + 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 GetRomName(); static RomFormat GetRomFormat(); diff --git a/Core/Core.vcxproj b/Core/Core.vcxproj index 04c0b73f..3dddf80f 100644 --- a/Core/Core.vcxproj +++ b/Core/Core.vcxproj @@ -424,6 +424,7 @@ + @@ -769,6 +770,7 @@ + diff --git a/Core/Core.vcxproj.filters b/Core/Core.vcxproj.filters index 22787dfb..54a34887 100644 --- a/Core/Core.vcxproj.filters +++ b/Core/Core.vcxproj.filters @@ -1153,6 +1153,9 @@ Nes\Mappers + + Movies + @@ -1359,5 +1362,8 @@ Debugger + + Movies + \ No newline at end of file diff --git a/Core/MesenMovie.cpp b/Core/MesenMovie.cpp index 6747c12a..8f21d34a 100644 --- a/Core/MesenMovie.cpp +++ b/Core/MesenMovie.cpp @@ -61,11 +61,7 @@ uint8_t MesenMovie::GetState(uint8_t port) if(_readPosition[port] >= _data.DataSize[port]) { //End of movie file - MessageManager::DisplayMessage("Movies", "MovieEnded"); - MessageManager::SendNotification(ConsoleNotificationType::MovieEnded); - if(EmulationSettings::CheckFlag(EmulationFlags::PauseOnMovieEnd)) { - EmulationSettings::SetFlags(EmulationFlags::Paused); - } + EndMovie(); _playing = false; } @@ -124,13 +120,9 @@ void MesenMovie::Stop() } Save(); } - if(_playing) { - MessageManager::DisplayMessage("Movies", "MovieEnded"); - _playing = false; - } } -void MesenMovie::Play(stringstream &filestream, bool autoLoadRom, string filename) +bool MesenMovie::Play(stringstream &filestream, bool autoLoadRom) { Stop(); @@ -145,12 +137,9 @@ void MesenMovie::Play(stringstream &filestream, bool autoLoadRom, string filenam CheatManager::SetCheats(_cheatList); _playing = true; - - if(!filename.empty()) { - MessageManager::DisplayMessage("Movies", "MoviePlaying", FolderUtilities::GetFilename(filename, true)); - } } Console::Resume(); + return _playing; } struct MovieHeader diff --git a/Core/MesenMovie.h b/Core/MesenMovie.h index de719fe7..5ccfd3b2 100644 --- a/Core/MesenMovie.h +++ b/Core/MesenMovie.h @@ -35,7 +35,7 @@ private: protected: void PushState(uint8_t port); void Record(string filename, bool reset); - void Play(stringstream &filestream, bool autoLoadRom, string filename = ""); + bool Play(stringstream &filestream, bool autoLoadRom); bool IsPlaying(); bool IsRecording(); diff --git a/Core/MovieManager.cpp b/Core/MovieManager.cpp index c0859356..f42f157d 100644 --- a/Core/MovieManager.cpp +++ b/Core/MovieManager.cpp @@ -1,6 +1,8 @@ #include "stdafx.h" +#include "../Utilities/FolderUtilities.h" #include "MovieManager.h" #include "MesenMovie.h" +#include "BizhawkMovie.h" shared_ptr MovieManager::_instance; @@ -18,11 +20,13 @@ void MovieManager::Play(string filename) std::stringstream ss; ss << file.rdbuf(); file.close(); - MovieManager::Play(ss, true); + if(MovieManager::Play(ss, true)) { + MessageManager::DisplayMessage("Movies", "MoviePlaying", FolderUtilities::GetFilename(filename, true)); + } } } -void MovieManager::Play(std::stringstream &filestream, bool autoLoadRom) +bool MovieManager::Play(std::stringstream &filestream, bool autoLoadRom) { char header[3] = { }; filestream.read(header, 3); @@ -30,13 +34,26 @@ void MovieManager::Play(std::stringstream &filestream, bool autoLoadRom) if(memcmp(header, "MMO", 3) == 0) { shared_ptr movie(new MesenMovie()); - movie->Play(filestream, autoLoadRom); - _instance = movie; + if(movie->Play(filestream, autoLoadRom)) { + _instance = movie; + return true; + } + } else if(memcmp(header, "PK", 2) == 0) { + shared_ptr movie(new BizhawkMovie()); + if(movie->Play(filestream, autoLoadRom)) { + _instance = movie; + return true; + } } + + return false; } void MovieManager::Stop() { + if(_instance && _instance->IsPlaying()) { + MessageManager::DisplayMessage("Movies", "MovieEnded"); + } _instance.reset(); } diff --git a/Core/MovieManager.h b/Core/MovieManager.h index f9ec9aaa..4be169fd 100644 --- a/Core/MovieManager.h +++ b/Core/MovieManager.h @@ -1,14 +1,26 @@ #pragma once #include "stdafx.h" +#include "MessageManager.h" +#include "EmulationSettings.h" class IMovie { +protected: + void EndMovie() + { + MessageManager::DisplayMessage("Movies", "MovieEnded"); + MessageManager::SendNotification(ConsoleNotificationType::MovieEnded); + if(EmulationSettings::CheckFlag(EmulationFlags::PauseOnMovieEnd)) { + EmulationSettings::SetFlags(EmulationFlags::Paused); + } + } + public: virtual void RecordState(uint8_t port, uint8_t value) = 0; virtual uint8_t GetState(uint8_t port) = 0; virtual void Record(string filename, bool reset) = 0; - virtual void Play(stringstream &filestream, bool autoLoadRom, string filename = "") = 0; + virtual bool Play(stringstream &filestream, bool autoLoadRom) = 0; virtual bool IsRecording() = 0; virtual bool IsPlaying() = 0; @@ -22,7 +34,7 @@ private: public: static void Record(string filename, bool reset); static void Play(string filename); - static void Play(std::stringstream &filestream, bool autoLoadRom); + static bool Play(std::stringstream &filestream, bool autoLoadRom); static void Stop(); static bool Playing(); static bool Recording(); diff --git a/Core/PPU.cpp b/Core/PPU.cpp index c912e81a..f9dd0af8 100644 --- a/Core/PPU.cpp +++ b/Core/PPU.cpp @@ -982,6 +982,7 @@ void PPU::SendFrame() void PPU::BeginVBlank() { + _frameCount++; SendFrame(); TriggerNmi(); } @@ -1000,7 +1001,6 @@ void PPU::Exec() _cycle = 0; if(++_scanline > _vblankEnd) { _lastUpdatedPixel = -1; - _frameCount++; _scanline = -1; UpdateMinimumDrawCycles(); } diff --git a/Core/RomData.h b/Core/RomData.h index 2cffba66..72541f1f 100644 --- a/Core/RomData.h +++ b/Core/RomData.h @@ -37,6 +37,12 @@ enum class BusConflictType No }; +struct HashInfo +{ + uint32_t Crc32Hash; + string Sha1Hash; +}; + struct NESHeader { /* @@ -311,6 +317,7 @@ struct RomData vector> FdsDiskData; vector RawData; + string Sha1; uint32_t Crc32 = 0; uint32_t PrgCrc32 = 0; uint32_t PrgChrCrc32 = 0; diff --git a/Core/RomLoader.cpp b/Core/RomLoader.cpp index dd2477ba..d8fc6b70 100644 --- a/Core/RomLoader.cpp +++ b/Core/RomLoader.cpp @@ -2,6 +2,7 @@ #include "../Utilities/FolderUtilities.h" #include "../Utilities/ArchiveReader.h" #include "../Utilities/CRC32.h" +#include "../Utilities/sha1.h" #include "../Utilities/BpsPatcher.h" #include "../Utilities/IpsPatcher.h" #include "../Utilities/UpsPatcher.h" @@ -158,6 +159,7 @@ bool RomLoader::LoadFromMemory(uint8_t* buffer, size_t length, string romName) } _romData.Crc32 = crc; + _romData.Sha1 = SHA1::GetHash(fileData); _romData.RawData = fileData; _romData.RomName = romName; _romData.Filename = _filename; @@ -217,12 +219,12 @@ RomData RomLoader::GetRomData() return _romData; } -int32_t RomLoader::FindMatchingRomInFile(string filename, uint32_t crc32Hash) +int32_t RomLoader::FindMatchingRomInFile(string filename, HashInfo hashInfo) { RomLoader loader; int32_t fileIndex = 0; while(loader.LoadFile(filename, nullptr, "", fileIndex)) { - if(crc32Hash == loader._romData.Crc32) { + if(hashInfo.Crc32Hash == loader._romData.Crc32 || hashInfo.Sha1Hash.compare(loader._romData.Sha1) == 0) { return fileIndex; } fileIndex++; @@ -230,7 +232,7 @@ int32_t RomLoader::FindMatchingRomInFile(string filename, uint32_t crc32Hash) return -1; } -string RomLoader::FindMatchingRomInFolder(string folder, string romFilename, uint32_t crc32Hash, bool useFastSearch, int32_t &archiveFileIndex) +string RomLoader::FindMatchingRomInFolder(string folder, string romFilename, HashInfo hashInfo, bool useFastSearch, int32_t &archiveFileIndex) { std::transform(romFilename.begin(), romFilename.end(), romFilename.begin(), ::tolower); vector validExtensions = { { ".nes", ".zip", ".7z", ".fds" } }; @@ -248,7 +250,7 @@ string RomLoader::FindMatchingRomInFolder(string folder, string romFilename, uin string originalFilename = romFile; std::transform(romFile.begin(), romFile.end(), romFile.begin(), ::tolower); if(FolderUtilities::GetFilename(romFile, true).compare(romFilename) == 0) { - archiveFileIndex = RomLoader::FindMatchingRomInFile(romFile, crc32Hash); + archiveFileIndex = RomLoader::FindMatchingRomInFile(romFile, hashInfo); if(archiveFileIndex >= 0) { return originalFilename; } @@ -257,7 +259,7 @@ string RomLoader::FindMatchingRomInFolder(string folder, string romFilename, uin } else { for(string romFile : romFiles) { //Slower search by CRC value - archiveFileIndex = RomLoader::FindMatchingRomInFile(romFile, crc32Hash); + archiveFileIndex = RomLoader::FindMatchingRomInFile(romFile, hashInfo); if(archiveFileIndex >= 0) { return romFile; } diff --git a/Core/RomLoader.h b/Core/RomLoader.h index 53702f7b..64b87b0f 100644 --- a/Core/RomLoader.h +++ b/Core/RomLoader.h @@ -16,12 +16,12 @@ class RomLoader uint8_t* ReadFile(istream &file, uint32_t &fileSize); bool LoadFromMemory(uint8_t* buffer, size_t length, string romName); - static int32_t FindMatchingRomInFile(string filename, uint32_t crc32Hash); + static int32_t FindMatchingRomInFile(string filename, HashInfo hashInfo); void ApplyPatch(string patchPath, vector &data); public: bool LoadFile(string filename, istream *filestream = nullptr, string patchFilename = "", int32_t archiveFileIndex = -1); RomData GetRomData(); - static string FindMatchingRomInFolder(string folder, string romFilename, uint32_t crc32Hash, bool useFastSearch, int32_t &archiveFileIndex); + static string FindMatchingRomInFolder(string folder, string romFilename, HashInfo hashInfo, bool useFastSearch, int32_t &archiveFileIndex); static vector GetArchiveRomList(string filename); }; diff --git a/Core/VsControlManager.h b/Core/VsControlManager.h index 48fd083e..7e829a1f 100644 --- a/Core/VsControlManager.h +++ b/Core/VsControlManager.h @@ -6,6 +6,7 @@ #include "VsZapper.h" #include #include "StandardController.h" +#include "MovieManager.h" enum class VsInputType { @@ -179,7 +180,7 @@ public: void RefreshAllPorts() override { ControlManager::RefreshAllPorts(); - if(_inputType != VsInputType::Default) { + if(!MovieManager::Playing() && _inputType != VsInputType::Default) { RemapControllerButtons(); } } diff --git a/Utilities/ArchiveReader.cpp b/Utilities/ArchiveReader.cpp index 6e36b6fb..503dc060 100644 --- a/Utilities/ArchiveReader.cpp +++ b/Utilities/ArchiveReader.cpp @@ -47,6 +47,23 @@ vector ArchiveReader::GetFileList(std::initializer_list extensio return filenames; } +bool ArchiveReader::LoadArchive(std::istream &in) +{ + in.seekg(0, std::ios::end); + std::streampos filesize = in.tellg(); + in.seekg(0, std::ios::beg); + + if(_buffer) { + delete[] _buffer; + _buffer = nullptr; + } + + _buffer = new uint8_t[(uint32_t)filesize]; + in.read((char*)_buffer, filesize); + bool result = LoadArchive(_buffer, (size_t)filesize); + return result; +} + bool ArchiveReader::LoadArchive(void* buffer, size_t size) { if(InternalLoadArchive(buffer, size)) { @@ -59,20 +76,9 @@ bool ArchiveReader::LoadArchive(void* buffer, size_t size) bool ArchiveReader::LoadArchive(string filename) { ifstream in(filename, std::ios::binary | std::ios::in); - if(in) { - in.seekg(0, std::ios::end); - std::streampos filesize = in.tellg(); - in.seekg(0, std::ios::beg); - - if(_buffer) { - delete[] _buffer; - _buffer = nullptr; - } - - _buffer = new uint8_t[(uint32_t)filesize]; - in.read((char*)_buffer, filesize); - bool result = LoadArchive(_buffer, (size_t)filesize); - return result; + if(in.good()) { + LoadArchive(in); + in.close(); } return false; } \ No newline at end of file diff --git a/Utilities/ArchiveReader.h b/Utilities/ArchiveReader.h index 837b5f72..54deb3e7 100644 --- a/Utilities/ArchiveReader.h +++ b/Utilities/ArchiveReader.h @@ -13,6 +13,8 @@ public: bool LoadArchive(void* buffer, size_t size); bool LoadArchive(string filename); + bool LoadArchive(std::istream &in); + std::stringstream GetStream(string filename); vector GetFileList(std::initializer_list extensions); diff --git a/Utilities/Utilities.vcxproj b/Utilities/Utilities.vcxproj index 1fb05c24..51f7e333 100644 --- a/Utilities/Utilities.vcxproj +++ b/Utilities/Utilities.vcxproj @@ -348,6 +348,7 @@ + @@ -480,6 +481,7 @@ NotUsing NotUsing + diff --git a/Utilities/Utilities.vcxproj.filters b/Utilities/Utilities.vcxproj.filters index 0da9dc48..faad3576 100644 --- a/Utilities/Utilities.vcxproj.filters +++ b/Utilities/Utilities.vcxproj.filters @@ -155,6 +155,9 @@ Header Files + + Header Files + @@ -268,5 +271,8 @@ Patches + + Source Files + \ No newline at end of file diff --git a/Utilities/sha1.cpp b/Utilities/sha1.cpp new file mode 100644 index 00000000..1cb68af6 --- /dev/null +++ b/Utilities/sha1.cpp @@ -0,0 +1,319 @@ +/* + sha1.cpp - source code of + + ============ + SHA-1 in C++ + ============ + + 100% Public Domain. + + Original C Code + -- Steve Reid + Small changes to fit into bglibs + -- Bruce Guenter + Translation to simpler C++ Code + -- Volker Grabsch + Safety fixes + -- Eugene Hopkinson +*/ + +#include "stdafx.h" +#include "sha1.h" +#include +#include +#include + + +static const size_t BLOCK_INTS = 16; /* number of 32bit integers per SHA1 block */ +static const size_t BLOCK_BYTES = BLOCK_INTS * 4; + + +static void reset(uint32_t digest[], std::string &buffer, uint64_t &transforms) +{ + /* SHA1 initialization constants */ + digest[0] = 0x67452301; + digest[1] = 0xefcdab89; + digest[2] = 0x98badcfe; + digest[3] = 0x10325476; + digest[4] = 0xc3d2e1f0; + + /* Reset counters */ + buffer = ""; + transforms = 0; +} + + +static uint32_t rol(const uint32_t value, const size_t bits) +{ + return (value << bits) | (value >> (32 - bits)); +} + + +static uint32_t blk(const uint32_t block[BLOCK_INTS], const size_t i) +{ + return rol(block[(i + 13) & 15] ^ block[(i + 8) & 15] ^ block[(i + 2) & 15] ^ block[i], 1); +} + + +/* + * (R0+R1), R2, R3, R4 are the different operations used in SHA1 + */ + +static void R0(const uint32_t block[BLOCK_INTS], const uint32_t v, uint32_t &w, const uint32_t x, const uint32_t y, uint32_t &z, const size_t i) +{ + z += ((w&(x^y)) ^ y) + block[i] + 0x5a827999 + rol(v, 5); + w = rol(w, 30); +} + + +static void R1(uint32_t block[BLOCK_INTS], const uint32_t v, uint32_t &w, const uint32_t x, const uint32_t y, uint32_t &z, const size_t i) +{ + block[i] = blk(block, i); + z += ((w&(x^y)) ^ y) + block[i] + 0x5a827999 + rol(v, 5); + w = rol(w, 30); +} + + +static void R2(uint32_t block[BLOCK_INTS], const uint32_t v, uint32_t &w, const uint32_t x, const uint32_t y, uint32_t &z, const size_t i) +{ + block[i] = blk(block, i); + z += (w^x^y) + block[i] + 0x6ed9eba1 + rol(v, 5); + w = rol(w, 30); +} + + +static void R3(uint32_t block[BLOCK_INTS], const uint32_t v, uint32_t &w, const uint32_t x, const uint32_t y, uint32_t &z, const size_t i) +{ + block[i] = blk(block, i); + z += (((w | x)&y) | (w&x)) + block[i] + 0x8f1bbcdc + rol(v, 5); + w = rol(w, 30); +} + + +static void R4(uint32_t block[BLOCK_INTS], const uint32_t v, uint32_t &w, const uint32_t x, const uint32_t y, uint32_t &z, const size_t i) +{ + block[i] = blk(block, i); + z += (w^x^y) + block[i] + 0xca62c1d6 + rol(v, 5); + w = rol(w, 30); +} + + +/* + * Hash a single 512-bit block. This is the core of the algorithm. + */ + +static void transform(uint32_t digest[], uint32_t block[BLOCK_INTS], uint64_t &transforms) +{ + /* Copy digest[] to working vars */ + uint32_t a = digest[0]; + uint32_t b = digest[1]; + uint32_t c = digest[2]; + uint32_t d = digest[3]; + uint32_t e = digest[4]; + + /* 4 rounds of 20 operations each. Loop unrolled. */ + R0(block, a, b, c, d, e, 0); + R0(block, e, a, b, c, d, 1); + R0(block, d, e, a, b, c, 2); + R0(block, c, d, e, a, b, 3); + R0(block, b, c, d, e, a, 4); + R0(block, a, b, c, d, e, 5); + R0(block, e, a, b, c, d, 6); + R0(block, d, e, a, b, c, 7); + R0(block, c, d, e, a, b, 8); + R0(block, b, c, d, e, a, 9); + R0(block, a, b, c, d, e, 10); + R0(block, e, a, b, c, d, 11); + R0(block, d, e, a, b, c, 12); + R0(block, c, d, e, a, b, 13); + R0(block, b, c, d, e, a, 14); + R0(block, a, b, c, d, e, 15); + R1(block, e, a, b, c, d, 0); + R1(block, d, e, a, b, c, 1); + R1(block, c, d, e, a, b, 2); + R1(block, b, c, d, e, a, 3); + R2(block, a, b, c, d, e, 4); + R2(block, e, a, b, c, d, 5); + R2(block, d, e, a, b, c, 6); + R2(block, c, d, e, a, b, 7); + R2(block, b, c, d, e, a, 8); + R2(block, a, b, c, d, e, 9); + R2(block, e, a, b, c, d, 10); + R2(block, d, e, a, b, c, 11); + R2(block, c, d, e, a, b, 12); + R2(block, b, c, d, e, a, 13); + R2(block, a, b, c, d, e, 14); + R2(block, e, a, b, c, d, 15); + R2(block, d, e, a, b, c, 0); + R2(block, c, d, e, a, b, 1); + R2(block, b, c, d, e, a, 2); + R2(block, a, b, c, d, e, 3); + R2(block, e, a, b, c, d, 4); + R2(block, d, e, a, b, c, 5); + R2(block, c, d, e, a, b, 6); + R2(block, b, c, d, e, a, 7); + R3(block, a, b, c, d, e, 8); + R3(block, e, a, b, c, d, 9); + R3(block, d, e, a, b, c, 10); + R3(block, c, d, e, a, b, 11); + R3(block, b, c, d, e, a, 12); + R3(block, a, b, c, d, e, 13); + R3(block, e, a, b, c, d, 14); + R3(block, d, e, a, b, c, 15); + R3(block, c, d, e, a, b, 0); + R3(block, b, c, d, e, a, 1); + R3(block, a, b, c, d, e, 2); + R3(block, e, a, b, c, d, 3); + R3(block, d, e, a, b, c, 4); + R3(block, c, d, e, a, b, 5); + R3(block, b, c, d, e, a, 6); + R3(block, a, b, c, d, e, 7); + R3(block, e, a, b, c, d, 8); + R3(block, d, e, a, b, c, 9); + R3(block, c, d, e, a, b, 10); + R3(block, b, c, d, e, a, 11); + R4(block, a, b, c, d, e, 12); + R4(block, e, a, b, c, d, 13); + R4(block, d, e, a, b, c, 14); + R4(block, c, d, e, a, b, 15); + R4(block, b, c, d, e, a, 0); + R4(block, a, b, c, d, e, 1); + R4(block, e, a, b, c, d, 2); + R4(block, d, e, a, b, c, 3); + R4(block, c, d, e, a, b, 4); + R4(block, b, c, d, e, a, 5); + R4(block, a, b, c, d, e, 6); + R4(block, e, a, b, c, d, 7); + R4(block, d, e, a, b, c, 8); + R4(block, c, d, e, a, b, 9); + R4(block, b, c, d, e, a, 10); + R4(block, a, b, c, d, e, 11); + R4(block, e, a, b, c, d, 12); + R4(block, d, e, a, b, c, 13); + R4(block, c, d, e, a, b, 14); + R4(block, b, c, d, e, a, 15); + + /* Add the working vars back into digest[] */ + digest[0] += a; + digest[1] += b; + digest[2] += c; + digest[3] += d; + digest[4] += e; + + /* Count the number of transformations */ + transforms++; +} + + +static void buffer_to_block(const std::string &buffer, uint32_t block[BLOCK_INTS]) +{ + /* Convert the std::string (byte buffer) to a uint32_t array (MSB) */ + for(size_t i = 0; i < BLOCK_INTS; i++) { + block[i] = (buffer[4 * i + 3] & 0xff) + | (buffer[4 * i + 2] & 0xff) << 8 + | (buffer[4 * i + 1] & 0xff) << 16 + | (buffer[4 * i + 0] & 0xff) << 24; + } +} + + +SHA1::SHA1() +{ + reset(digest, buffer, transforms); +} + + +void SHA1::update(const std::string &s) +{ + std::istringstream is(s); + update(is); +} + + +void SHA1::update(std::istream &is) +{ + char sbuf[BLOCK_BYTES]; + uint32_t block[BLOCK_INTS]; + + while(true) { + is.read(sbuf, BLOCK_BYTES - buffer.size()); + buffer.append(sbuf, is.gcount()); + if(buffer.size() != BLOCK_BYTES) { + return; + } + + buffer_to_block(buffer, block); + transform(digest, block, transforms); + buffer.clear(); + } +} + + +/* + * Add padding and return the message digest. + */ + +std::string SHA1::final() +{ + /* Total number of hashed bits */ + uint64_t total_bits = (transforms*BLOCK_BYTES + buffer.size()) * 8; + + /* Padding */ + buffer += (char)0x80; + size_t orig_size = buffer.size(); + while(buffer.size() < BLOCK_BYTES) { + buffer += (char)0x00; + } + + uint32_t block[BLOCK_INTS]; + buffer_to_block(buffer, block); + + if(orig_size > BLOCK_BYTES - 8) { + transform(digest, block, transforms); + for(size_t i = 0; i < BLOCK_INTS - 2; i++) { + block[i] = 0; + } + } + + /* Append total_bits, split this uint64_t into two uint32_t */ + block[BLOCK_INTS - 1] = (uint32_t)total_bits; + block[BLOCK_INTS - 2] = (uint32_t)(total_bits >> 32); + transform(digest, block, transforms); + + /* Hex std::string */ + std::ostringstream result; + for(size_t i = 0; i < sizeof(digest) / sizeof(digest[0]); i++) { + result << std::uppercase << std::hex << std::setfill('0') << std::setw(8); + result << digest[i]; + } + + /* Reset for next run */ + reset(digest, buffer, transforms); + + return result.str(); +} + +std::string SHA1::GetHash(vector &data) +{ + std::stringstream ss; + ss.write((char*)data.data(), data.size()); + + SHA1 checksum; + checksum.update(ss); + return checksum.final(); +} + +std::string SHA1::GetHash(std::istream &stream) +{ + SHA1 checksum; + checksum.update(stream); + return checksum.final(); +} + +std::string SHA1::GetHash(const std::string &filename) +{ + std::ifstream stream(filename.c_str(), std::ios::binary); + SHA1 checksum; + checksum.update(stream); + return checksum.final(); +} diff --git a/Utilities/sha1.h b/Utilities/sha1.h new file mode 100644 index 00000000..22b968f1 --- /dev/null +++ b/Utilities/sha1.h @@ -0,0 +1,41 @@ +/* + sha1.h - header of + + ============ + SHA-1 in C++ + ============ + + 100% Public Domain. + + Original C Code + -- Steve Reid + Small changes to fit into bglibs + -- Bruce Guenter + Translation to simpler C++ Code + -- Volker Grabsch + Safety fixes + -- Eugene Hopkinson +*/ + +#pragma once + +#include +#include +#include + +class SHA1 +{ +public: + SHA1(); + void update(const std::string &s); + void update(std::istream &is); + std::string final(); + static std::string GetHash(const std::string &filename); + static std::string GetHash(std::istream &stream); + static std::string GetHash(vector &data); + +private: + uint32_t digest[5]; + std::string buffer; + uint64_t transforms; +};