mirror of https://github.com/stella-emu/stella.git
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:
parent
e5287ae125
commit
bc877443c1
|
@ -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);
|
||||||
|
|
||||||
|
|
|
@ -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;
|
||||||
|
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
|
|
|
@ -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:
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -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
|
||||||
|
}
|
||||||
|
|
|
@ -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:
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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.
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
|
|
|
@ -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.
|
||||||
|
|
Loading…
Reference in New Issue