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.
This commit is contained in:
Stephen Anthony 2021-05-03 20:35:11 -02:30
parent e5287ae125
commit bc877443c1
12 changed files with 64 additions and 41 deletions

View File

@ -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) 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 // For now, we just read into a buffer and store in the stream
// TODO: maybe there's a more efficient way to do this? // TODO: maybe there's a more efficient way to do this?
ByteBuffer buffer; ByteBuffer buffer;
size_t size = read(buffer); size_t size = read(buffer, 0);
if(size > 0) if(size > 0)
image.write(reinterpret_cast<char*>(buffer.get()), size); image.write(reinterpret_cast<char*>(buffer.get()), size);

View File

@ -62,8 +62,8 @@ class FilesystemNodeZIP : public AbstractFSNode
bool getChildren(AbstractFSList& list, ListMode mode) const override; bool getChildren(AbstractFSList& list, ListMode mode) const override;
AbstractFSNodePtr getParent() const override; AbstractFSNodePtr getParent() const override;
size_t read(ByteBuffer& image) const override; size_t read(ByteBuffer& buffer, size_t size) const override;
size_t read(stringstream& image) const override; size_t read(stringstream& buffer) const override;
size_t write(const ByteBuffer& buffer, size_t size) const override; size_t write(const ByteBuffer& buffer, size_t size) const override;
size_t write(const stringstream& buffer) const override; size_t write(const stringstream& buffer) const override;

View File

@ -45,7 +45,7 @@ class Bankswitch
_DPCP, _E0, _E7, _E78K, _EF, _EFSC, _F0, _DPCP, _E0, _E7, _E78K, _EF, _EFSC, _F0,
_F4, _F4SC, _F6, _F6SC, _F8, _F8SC, _FA, _F4, _F4SC, _F6, _F6SC, _F8, _F8SC, _FA,
_FA2, _FC, _FE, _MDM, _MVC, _SB, _TVBOY, _FA2, _FC, _FE, _MDM, _MVC, _SB, _TVBOY,
_UA, _UASW, _WD, _WDSW, _X07, _UA, _UASW, _WD, _WDSW, _X07,
#ifdef CUSTOM_ARM #ifdef CUSTOM_ARM
_CUSTOM, _CUSTOM,
#endif #endif

View File

@ -697,31 +697,31 @@ bool CartDetector::isProbablyMVC(const ByteBuffer& image, size_t size)
{ {
// MVC version 0 // MVC version 0
uInt8 sig[] = { 'M', 'V', 'C', 0 }; uInt8 sig[] = { 'M', 'V', 'C', 0 };
int sigSize = sizeof(sig); int sigSize = sizeof(sig);
return searchForBytes(image, std::min<size_t>(size, sigSize+1), sig, sigSize); return searchForBytes(image, std::min<size_t>(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; constexpr size_t frameSize = 2 * CartridgeMVC::MVC_FIELD_PAD_SIZE;
bool found = false;
// 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<uInt8[]>(frameSize); uInt8 image[frameSize];
in.read(reinterpret_cast<char*>(image.get()), frameSize); s.getByteArray(image, frameSize);
in.seekg(pos); uInt8 sig[] = { 'M', 'V', 'C', 0 }; // MVC version 0
return searchForBytes(image, frameSize, sig, 4) ? frameSize : 0;
found = isProbablyMVC(image, frameSize);
} }
return 0;
return found ? frameSize : 0;
} }
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

View File

@ -19,6 +19,7 @@
#define CARTRIDGE_DETECTOR_HXX #define CARTRIDGE_DETECTOR_HXX
#include "Bankswitch.hxx" #include "Bankswitch.hxx"
#include "FSNode.hxx"
#include "bspf.hxx" #include "bspf.hxx"
/** /**
@ -40,12 +41,11 @@ class CartDetector
*/ */
static Bankswitch::Type autodetectType(const ByteBuffer& image, size_t size); 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 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: private:
/** /**

View File

@ -1340,3 +1340,15 @@ bool CartridgeMVC::poke(uInt16 address, uInt8 value)
{ {
return myMovie->process(address); 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
}

View File

@ -51,7 +51,7 @@ class CartridgeMVC : public Cartridge
@param bsSize The size specified by the bankswitching scheme @param bsSize The size specified by the bankswitching scheme
*/ */
CartridgeMVC(const string& path, size_t size, const string& md5, 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; ~CartridgeMVC() override;
/** /**
@ -113,7 +113,7 @@ class CartridgeMVC : public Cartridge
@param out The Serializer object to use @param out The Serializer object to use
@return False on any errors, else true @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. 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 @param in The Serializer object to use
@return False on any errors, else true @return False on any errors, else true
*/ */
bool load(Serializer& in) override { return false; } bool load(Serializer& in) override;
private: private:
// Currently not used: // Currently not used:

View File

@ -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; size_t sizeRead = 0;
@ -342,7 +342,7 @@ size_t FilesystemNode::read(ByteBuffer& buffer) const
throw runtime_error("File not found/readable"); throw runtime_error("File not found/readable");
// First let the private subclass attempt to open the file // 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; return sizeRead;
// Otherwise, the default behaviour is to read from a normal C++ ifstream // 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) if (sizeRead == 0)
throw runtime_error("Zero-byte file"); throw runtime_error("Zero-byte file");
else if (size != 0)
// In the case of MVC (MovieCart) files, contents are streaming data sizeRead = size;
// of arbitrary length, so just read first frame.
size_t subSize = CartDetector::isProbablyMVC(in, sizeRead);
if (subSize > 0)
sizeRead = subSize;
buffer = make_unique<uInt8[]>(sizeRead); buffer = make_unique<uInt8[]>(sizeRead);
in.read(reinterpret_cast<char*>(buffer.get()), sizeRead); in.read(reinterpret_cast<char*>(buffer.get()), sizeRead);

View File

@ -244,12 +244,13 @@ class FilesystemNode
* Read data (binary format) into the given buffer. * Read data (binary format) into the given buffer.
* *
* @param buffer The buffer to contain the data (allocated in this method). * @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) * @return The number of bytes read (0 in the case of failure)
* This method can throw exceptions, and should be used inside * This method can throw exceptions, and should be used inside
* a try-catch block. * 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. * Read data (text format) into the given stream.
@ -438,12 +439,13 @@ class AbstractFSNode
* Read data (binary format) into the given buffer. * Read data (binary format) into the given buffer.
* *
* @param buffer The buffer to contain the data (allocated in this method). * @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) * @return The number of bytes read (0 in the case of failure)
* This method can throw exceptions, and should be used inside * This method can throw exceptions, and should be used inside
* a try-catch block. * 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. * Read data (text format) into the given stream.

View File

@ -44,6 +44,7 @@
#include "MD5.hxx" #include "MD5.hxx"
#include "Cart.hxx" #include "Cart.hxx"
#include "CartCreator.hxx" #include "CartCreator.hxx"
#include "CartDetector.hxx"
#include "FrameBuffer.hxx" #include "FrameBuffer.hxx"
#include "TIASurface.hxx" #include "TIASurface.hxx"
#include "TIAConstants.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 // but also adds a properties entry if the one for the ROM doesn't
// contain a valid name // 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; ByteBuffer image;
if((size = rom.read(image)) == 0) if((size = rom.read(image, sizeToRead)) == 0)
return nullptr; return nullptr;
// If we get to this point, we know we have a valid file to open // If we get to this point, we know we have a valid file to open

View File

@ -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;
} }
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

View File

@ -70,9 +70,9 @@ class Serializer
void rewind(); 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. Reads a byte value (unsigned 8-bit) from the current input stream.