From 9ac88c66626329fbb9173f4958b1192082876aad Mon Sep 17 00:00:00 2001 From: Stephen Anthony Date: Mon, 3 May 2021 20:35:11 -0230 Subject: [PATCH] Move detection of MVC file out of FSNode class. There are several reasons for this: - It more properly belongs in the class actually opening the ROM, since FSNode can represent more than just ROM files. - Some ports don't have proper FSNode support, so MVC would break there. - In general, it makes FSNode::read more general, able to read partial files. --- src/common/FSNodeZIP.cxx | 4 ++-- src/common/FSNodeZIP.hxx | 4 ++-- src/emucore/Bankswitch.hxx | 2 +- src/emucore/CartDetector.cxx | 28 ++++++++++++++-------------- src/emucore/CartDetector.hxx | 6 +++--- src/emucore/CartMVC.cxx | 12 ++++++++++++ src/emucore/CartMVC.hxx | 6 +++--- src/emucore/FSNode.cxx | 12 ++++-------- src/emucore/FSNode.hxx | 6 ++++-- src/emucore/OSystem.cxx | 11 ++++++++++- src/emucore/Serializer.cxx | 10 +++++++--- src/emucore/Serializer.hxx | 4 ++-- 12 files changed, 64 insertions(+), 41 deletions(-) diff --git a/src/common/FSNodeZIP.cxx b/src/common/FSNodeZIP.cxx index 754f848d6..f7720d72e 100644 --- a/src/common/FSNodeZIP.cxx +++ b/src/common/FSNodeZIP.cxx @@ -180,7 +180,7 @@ bool FilesystemNodeZIP::getChildren(AbstractFSList& myList, ListMode mode) const } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -size_t FilesystemNodeZIP::read(ByteBuffer& image) const +size_t FilesystemNodeZIP::read(ByteBuffer& image, size_t) const { switch(_error) { @@ -205,7 +205,7 @@ size_t FilesystemNodeZIP::read(stringstream& image) const // For now, we just read into a buffer and store in the stream // TODO: maybe there's a more efficient way to do this? ByteBuffer buffer; - size_t size = read(buffer); + size_t size = read(buffer, 0); if(size > 0) image.write(reinterpret_cast(buffer.get()), size); diff --git a/src/common/FSNodeZIP.hxx b/src/common/FSNodeZIP.hxx index 77246d35f..7747b7acc 100644 --- a/src/common/FSNodeZIP.hxx +++ b/src/common/FSNodeZIP.hxx @@ -62,8 +62,8 @@ class FilesystemNodeZIP : public AbstractFSNode bool getChildren(AbstractFSList& list, ListMode mode) const override; AbstractFSNodePtr getParent() const override; - size_t read(ByteBuffer& image) const override; - size_t read(stringstream& image) const override; + size_t read(ByteBuffer& buffer, size_t size) const override; + size_t read(stringstream& buffer) const override; size_t write(const ByteBuffer& buffer, size_t size) const override; size_t write(const stringstream& buffer) const override; diff --git a/src/emucore/Bankswitch.hxx b/src/emucore/Bankswitch.hxx index 2070ace36..38485d2ea 100644 --- a/src/emucore/Bankswitch.hxx +++ b/src/emucore/Bankswitch.hxx @@ -45,7 +45,7 @@ class Bankswitch _DPCP, _E0, _E7, _E78K, _EF, _EFSC, _F0, _F4, _F4SC, _F6, _F6SC, _F8, _F8SC, _FA, _FA2, _FC, _FE, _MDM, _MVC, _SB, _TVBOY, - _UA, _UASW, _WD, _WDSW, _X07, + _UA, _UASW, _WD, _WDSW, _X07, #ifdef CUSTOM_ARM _CUSTOM, #endif diff --git a/src/emucore/CartDetector.cxx b/src/emucore/CartDetector.cxx index 3414d5be9..d3206631b 100644 --- a/src/emucore/CartDetector.cxx +++ b/src/emucore/CartDetector.cxx @@ -697,31 +697,31 @@ bool CartDetector::isProbablyMVC(const ByteBuffer& image, size_t size) { // MVC version 0 uInt8 sig[] = { 'M', 'V', 'C', 0 }; - int sigSize = sizeof(sig); + int sigSize = sizeof(sig); return searchForBytes(image, std::min(size, sigSize+1), sig, sigSize); } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -size_t CartDetector::isProbablyMVC(std::istream &in, size_t maxSize) +size_t CartDetector::isProbablyMVC(const FilesystemNode& rom) { - const size_t frameSize = 2 * CartridgeMVC::MVC_FIELD_PAD_SIZE; - bool found = false; + constexpr size_t frameSize = 2 * CartridgeMVC::MVC_FIELD_PAD_SIZE; - // Returns size of field if stream is probably an MVC movie cartridge + if(Bankswitch::typeFromExtension(rom) == Bankswitch::Type::_MVC) + return frameSize; - if (maxSize >= frameSize) + Serializer s(rom.getPath(), Serializer::Mode::ReadOnly); + if(s) { - auto pos = in.tellg(); + if(s.size() < frameSize) + return 0; - ByteBuffer image = make_unique(frameSize); - in.read(reinterpret_cast(image.get()), frameSize); + uInt8 image[frameSize]; + s.getByteArray(image, frameSize); - in.seekg(pos); - - found = isProbablyMVC(image, frameSize); + uInt8 sig[] = { 'M', 'V', 'C', 0 }; // MVC version 0 + return searchForBytes(image, frameSize, sig, 4) ? frameSize : 0; } - - return found ? frameSize : 0; + return 0; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/src/emucore/CartDetector.hxx b/src/emucore/CartDetector.hxx index d845dad78..dc9025c76 100644 --- a/src/emucore/CartDetector.hxx +++ b/src/emucore/CartDetector.hxx @@ -19,6 +19,7 @@ #define CARTRIDGE_DETECTOR_HXX #include "Bankswitch.hxx" +#include "FSNode.hxx" #include "bspf.hxx" /** @@ -40,12 +41,11 @@ class CartDetector */ static Bankswitch::Type autodetectType(const ByteBuffer& image, size_t size); - /** - MVC cartridges are of arbitary large length + MVC cartridges are of arbitary large length Returns size of frame if stream is probably an MVC movie cartridge */ - static size_t isProbablyMVC(std::istream &in, size_t size); + static size_t isProbablyMVC(const FilesystemNode& rom); private: /** diff --git a/src/emucore/CartMVC.cxx b/src/emucore/CartMVC.cxx index 835090424..0562bca00 100644 --- a/src/emucore/CartMVC.cxx +++ b/src/emucore/CartMVC.cxx @@ -1340,3 +1340,15 @@ bool CartridgeMVC::poke(uInt16 address, uInt8 value) { return myMovie->process(address); } + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +bool CartridgeMVC::save(Serializer& out) const +{ + return false; // TODO: implement this +} + +// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +bool CartridgeMVC::load(Serializer& in) +{ + return false; // TODO: implement this +} diff --git a/src/emucore/CartMVC.hxx b/src/emucore/CartMVC.hxx index 3bac2e239..c03101b52 100644 --- a/src/emucore/CartMVC.hxx +++ b/src/emucore/CartMVC.hxx @@ -51,7 +51,7 @@ class CartridgeMVC : public Cartridge @param bsSize The size specified by the bankswitching scheme */ CartridgeMVC(const string& path, size_t size, const string& md5, - const Settings& settings, size_t bsSize = 1_KB); + const Settings& settings, size_t bsSize = 8_KB); ~CartridgeMVC() override; /** @@ -113,7 +113,7 @@ class CartridgeMVC : public Cartridge @param out The Serializer object to use @return False on any errors, else true */ - bool save(Serializer& out) const override { return false; } + bool save(Serializer& out) const override; /** Load the current state of this cart from the given Serializer. @@ -121,7 +121,7 @@ class CartridgeMVC : public Cartridge @param in The Serializer object to use @return False on any errors, else true */ - bool load(Serializer& in) override { return false; } + bool load(Serializer& in) override; private: // Currently not used: diff --git a/src/emucore/FSNode.cxx b/src/emucore/FSNode.cxx index 28a6100f5..f240ebadc 100644 --- a/src/emucore/FSNode.cxx +++ b/src/emucore/FSNode.cxx @@ -333,7 +333,7 @@ bool FilesystemNode::rename(const string& newfile) } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -size_t FilesystemNode::read(ByteBuffer& buffer) const +size_t FilesystemNode::read(ByteBuffer& buffer, size_t size) const { size_t sizeRead = 0; @@ -342,7 +342,7 @@ size_t FilesystemNode::read(ByteBuffer& buffer) const throw runtime_error("File not found/readable"); // First let the private subclass attempt to open the file - if (_realNode && (sizeRead = _realNode->read(buffer)) > 0) + if (_realNode && (sizeRead = _realNode->read(buffer, size)) > 0) return sizeRead; // Otherwise, the default behaviour is to read from a normal C++ ifstream @@ -355,12 +355,8 @@ size_t FilesystemNode::read(ByteBuffer& buffer) const if (sizeRead == 0) throw runtime_error("Zero-byte file"); - - // In the case of MVC (MovieCart) files, contents are streaming data - // of arbitrary length, so just read first frame. - size_t subSize = CartDetector::isProbablyMVC(in, sizeRead); - if (subSize > 0) - sizeRead = subSize; + else if (size != 0) + sizeRead = size; buffer = make_unique(sizeRead); in.read(reinterpret_cast(buffer.get()), sizeRead); diff --git a/src/emucore/FSNode.hxx b/src/emucore/FSNode.hxx index d2b9fbc00..8cb84944e 100644 --- a/src/emucore/FSNode.hxx +++ b/src/emucore/FSNode.hxx @@ -244,12 +244,13 @@ class FilesystemNode * Read data (binary format) into the given buffer. * * @param buffer The buffer to contain the data (allocated in this method). + * @param size The amount of data to read (0 means read all data). * * @return The number of bytes read (0 in the case of failure) * This method can throw exceptions, and should be used inside * a try-catch block. */ - size_t read(ByteBuffer& buffer) const; + size_t read(ByteBuffer& buffer, size_t size = 0) const; /** * Read data (text format) into the given stream. @@ -438,12 +439,13 @@ class AbstractFSNode * Read data (binary format) into the given buffer. * * @param buffer The buffer to contain the data (allocated in this method). + * @param size The amount of data to read (0 means read all data). * * @return The number of bytes read (0 in the case of failure) * This method can throw exceptions, and should be used inside * a try-catch block. */ - virtual size_t read(ByteBuffer& buffer) const { return 0; } + virtual size_t read(ByteBuffer& buffer, size_t size) const { return 0; } /** * Read data (text format) into the given stream. diff --git a/src/emucore/OSystem.cxx b/src/emucore/OSystem.cxx index 8f11211e0..4dbbbc653 100644 --- a/src/emucore/OSystem.cxx +++ b/src/emucore/OSystem.cxx @@ -44,6 +44,7 @@ #include "MD5.hxx" #include "Cart.hxx" #include "CartCreator.hxx" +#include "CartDetector.hxx" #include "FrameBuffer.hxx" #include "TIASurface.hxx" #include "TIAConstants.hxx" @@ -688,8 +689,16 @@ ByteBuffer OSystem::openROM(const FilesystemNode& rom, string& md5, size_t& size // but also adds a properties entry if the one for the ROM doesn't // contain a valid name + // First check if this is a 'streaming' ROM (one where we only read + // a portion of the file) + size_t sizeToRead = CartDetector::isProbablyMVC(rom); + + // Next check if rom is a valid size + // TODO: We should check if ROM is < Cart::maxSize(), but only + // if it's not a ZIP file (that size should be higher; still TBD) + ByteBuffer image; - if((size = rom.read(image)) == 0) + if((size = rom.read(image, sizeToRead)) == 0) return nullptr; // If we get to this point, we know we have a valid file to open diff --git a/src/emucore/Serializer.cxx b/src/emucore/Serializer.cxx index 1d45bc8d0..57657712a 100644 --- a/src/emucore/Serializer.cxx +++ b/src/emucore/Serializer.cxx @@ -94,11 +94,15 @@ void Serializer::rewind() } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -size_t Serializer::size() const +size_t Serializer::size() { - myStream->seekp(0, std::ios::end); + std::streampos oldPos = myStream->tellp(); - return myStream->tellp(); + myStream->seekp(0, std::ios::end); + size_t s = myStream->tellp(); + setPosition(oldPos); + + return s; } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/src/emucore/Serializer.hxx b/src/emucore/Serializer.hxx index 6faac1910..5f0b28eb1 100644 --- a/src/emucore/Serializer.hxx +++ b/src/emucore/Serializer.hxx @@ -70,9 +70,9 @@ class Serializer void rewind(); /** - Returns the current write pointer location. + Returns the current total size of the stream. */ - size_t size() const; + size_t size(); /** Reads a byte value (unsigned 8-bit) from the current input stream.