diff --git a/Source/ISO9660/File.cpp b/Source/ISO9660/File.cpp index fc9e2852a..8894dacfa 100644 --- a/Source/ISO9660/File.cpp +++ b/Source/ISO9660/File.cpp @@ -36,11 +36,7 @@ void CFile::Seek(int64 amount, Framework::STREAM_SEEK_DIRECTION whence) case Framework::STREAM_SEEK_END: //Cannot seek from end with unbounded files assert(m_end != ULLONG_MAX); - // We need to abs the amount, as the seek end works with both - // positive and negative offsets, which do the same. - // e.g. Shadow of Ganymede uses a positive offset, while it - // should be negative. - m_position = size - std::abs(amount); + m_position = size + amount; break; } m_position = std::max(m_position, 0); diff --git a/Source/iop/ioman/OpticalMediaDevice.cpp b/Source/iop/ioman/OpticalMediaDevice.cpp index 305fab7ef..fcca88ab5 100644 --- a/Source/iop/ioman/OpticalMediaDevice.cpp +++ b/Source/iop/ioman/OpticalMediaDevice.cpp @@ -40,7 +40,12 @@ Framework::CStream* COpticalMediaDevice::GetFile(uint32 mode, const char* device std::transform(fixedString.begin(), fixedString.end(), fixedString.begin(), &COpticalMediaDevice::FixSlashes); fixedString = RemoveExtraVersionSpecifiers(fixedString); auto fileSystem = m_opticalMedia->GetFileSystem(); - return fileSystem->Open(fixedString.c_str()); + auto fileStream = std::unique_ptr(fileSystem->Open(fixedString.c_str())); + if(!fileStream) + { + return nullptr; + } + return new COpticalMediaFile(std::move(fileStream)); } DirectoryIteratorPtr COpticalMediaDevice::GetDirectory(const char* devicePath) @@ -58,3 +63,40 @@ DirectoryIteratorPtr COpticalMediaDevice::GetDirectory(const char* devicePath) } return std::make_unique(directoryStream); } + +COpticalMediaFile::COpticalMediaFile(std::unique_ptr baseStream) + : m_baseStream(std::move(baseStream)) +{ +} + +void COpticalMediaFile::Seek(int64 offset, Framework::STREAM_SEEK_DIRECTION whence) +{ + if((whence == Framework::STREAM_SEEK_END) && (offset > 0)) + { + //Some games from Phoenix Games relies on a positive offset seeking backwards when using SEEK_END: + //- Shadow of Ganymede + //- Guerrilla Strike + offset = -offset; + } + m_baseStream->Seek(offset, whence); +} + +uint64 COpticalMediaFile::Tell() +{ + return m_baseStream->Tell(); +} + +uint64 COpticalMediaFile::Read(void* buffer, uint64 size) +{ + return m_baseStream->Read(buffer, size); +} + +uint64 COpticalMediaFile::Write(const void* buffer, uint64 size) +{ + return m_baseStream->Write(buffer, size); +} + +bool COpticalMediaFile::IsEOF() +{ + return m_baseStream->IsEOF(); +} diff --git a/Source/iop/ioman/OpticalMediaDevice.h b/Source/iop/ioman/OpticalMediaDevice.h index 79301901c..5270b953d 100644 --- a/Source/iop/ioman/OpticalMediaDevice.h +++ b/Source/iop/ioman/OpticalMediaDevice.h @@ -25,5 +25,21 @@ namespace Iop OpticalMediaPtr& m_opticalMedia; }; + + class COpticalMediaFile : public Framework::CStream + { + public: + COpticalMediaFile(std::unique_ptr); + virtual ~COpticalMediaFile() = default; + + void Seek(int64, Framework::STREAM_SEEK_DIRECTION) override; + uint64 Tell() override; + uint64 Read(void*, uint64) override; + uint64 Write(const void*, uint64) override; + bool IsEOF() override; + + private: + std::unique_ptr m_baseStream; + }; } }