mirror of https://github.com/stella-emu/stella.git
Add ability to use .pro file stored in a ZIP file (containing the ROM, with the same name).
This commit is contained in:
parent
0a3d18ee65
commit
94d6715384
|
@ -18,6 +18,13 @@
|
|||
|
||||
* Extended global hotkeys for debug options.
|
||||
|
||||
* Added ability to load per-ROM properties file from a ZIP file containing
|
||||
the ROM. This allows to distribute ROM and properties in one file,
|
||||
which Stella can use directly.
|
||||
|
||||
-Have fun!
|
||||
|
||||
|
||||
6.2 to 6.2.1: (June 20, 2020)
|
||||
|
||||
* Fixed Pitfall II ROM not working correctly.
|
||||
|
@ -61,8 +68,6 @@
|
|||
* The codebase now compiles under gcc6 again. Future versions will
|
||||
require gcc7, though.
|
||||
|
||||
-Have fun!
|
||||
|
||||
|
||||
6.1.2 to 6.2: (June 7, 2020)
|
||||
|
||||
|
|
|
@ -184,6 +184,19 @@ size_t FilesystemNodeZIP::read(ByteBuffer& image) const
|
|||
return found ? uInt32(myZipHandler->decompress(image)) : 0; // TODO: 64bit
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
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);
|
||||
if(size > 0)
|
||||
image.write(reinterpret_cast<char*>(buffer.get()), size);
|
||||
|
||||
return size;
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
AbstractFSNodePtr FilesystemNodeZIP::getParent() const
|
||||
{
|
||||
|
|
|
@ -63,6 +63,7 @@ class FilesystemNodeZIP : public AbstractFSNode
|
|||
AbstractFSNodePtr getParent() const override;
|
||||
|
||||
size_t read(ByteBuffer& image) const override;
|
||||
size_t read(stringstream& image) const override;
|
||||
|
||||
private:
|
||||
FilesystemNodeZIP(const string& zipfile, const string& virtualpath,
|
||||
|
|
|
@ -225,7 +225,7 @@ bool FilesystemNode::rename(const string& newfile)
|
|||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
size_t FilesystemNode::read(ByteBuffer& image) const
|
||||
size_t FilesystemNode::read(ByteBuffer& buffer) const
|
||||
{
|
||||
size_t size = 0;
|
||||
|
||||
|
@ -234,11 +234,11 @@ size_t FilesystemNode::read(ByteBuffer& image) const
|
|||
throw runtime_error("File not found/readable");
|
||||
|
||||
// First let the private subclass attempt to open the file
|
||||
if (_realNode && (size = _realNode->read(image)) > 0)
|
||||
if (_realNode && (size = _realNode->read(buffer)) > 0)
|
||||
return size;
|
||||
|
||||
// Otherwise, the default behaviour is to read from a normal C++ ifstream
|
||||
image = make_unique<uInt8[]>(Cartridge::maxSize());
|
||||
buffer = make_unique<uInt8[]>(Cartridge::maxSize());
|
||||
ifstream in(getPath(), std::ios::binary);
|
||||
if (in)
|
||||
{
|
||||
|
@ -250,7 +250,41 @@ size_t FilesystemNode::read(ByteBuffer& image) const
|
|||
throw runtime_error("Zero-byte file");
|
||||
|
||||
size = std::min<size_t>(length, Cartridge::maxSize());
|
||||
in.read(reinterpret_cast<char*>(image.get()), size);
|
||||
in.read(reinterpret_cast<char*>(buffer.get()), size);
|
||||
}
|
||||
else
|
||||
throw runtime_error("File open/read error");
|
||||
|
||||
return size;
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
size_t FilesystemNode::read(stringstream& buffer) const
|
||||
{
|
||||
size_t size = 0;
|
||||
|
||||
// File must actually exist
|
||||
if (!(exists() && isReadable()))
|
||||
throw runtime_error("File not found/readable");
|
||||
|
||||
// First let the private subclass attempt to open the file
|
||||
if (_realNode && (size = _realNode->read(buffer)) > 0)
|
||||
return size;
|
||||
|
||||
// Otherwise, the default behaviour is to read from a normal C++ ifstream
|
||||
// and convert to a stringstream
|
||||
ifstream in(getPath(), std::ios::binary);
|
||||
if (in)
|
||||
{
|
||||
in.seekg(0, std::ios::end);
|
||||
std::streampos length = in.tellg();
|
||||
in.seekg(0, std::ios::beg);
|
||||
|
||||
if (length == 0)
|
||||
throw runtime_error("Zero-byte file");
|
||||
|
||||
size = std::min<size_t>(length, Cartridge::maxSize());
|
||||
buffer << in.rdbuf();
|
||||
}
|
||||
else
|
||||
throw runtime_error("File open/read error");
|
||||
|
|
|
@ -241,6 +241,17 @@ class FilesystemNode
|
|||
*/
|
||||
size_t read(ByteBuffer& buffer) const;
|
||||
|
||||
/**
|
||||
* Read data (text format) into the given stream.
|
||||
*
|
||||
* @param buffer The buffer stream to contain the 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(stringstream& buffer) const;
|
||||
|
||||
/**
|
||||
* The following methods are almost exactly the same as the various
|
||||
* getXXXX() methods above. Internally, they call the respective methods
|
||||
|
@ -400,6 +411,17 @@ class AbstractFSNode
|
|||
* a try-catch block.
|
||||
*/
|
||||
virtual size_t read(ByteBuffer& buffer) const { return 0; }
|
||||
|
||||
/**
|
||||
* Read data (text format) into the given steam.
|
||||
*
|
||||
* @param buffer The buffer stream to containing the 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(stringstream& buffer) const { return 0; }
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
|
@ -132,7 +132,7 @@ bool OSystem::create()
|
|||
<< FilesystemNode(myConfigFile).getShortPath() << "'" << endl;
|
||||
|
||||
buf << "Game properties: '"
|
||||
<< FilesystemNode(myPropertiesFile).getShortPath() << "'" << endl
|
||||
<< myPropertiesFile.getShortPath() << "'" << endl
|
||||
<< "Cheat file: '"
|
||||
<< FilesystemNode(myCheatFile).getShortPath() << "'" << endl
|
||||
<< "Palette file: '"
|
||||
|
@ -251,7 +251,7 @@ void OSystem::saveConfig()
|
|||
Logger::debug("Saving config options ...");
|
||||
mySettings->save();
|
||||
|
||||
if(myPropSet && myPropSet->save(myPropertiesFile))
|
||||
if(myPropSet && myPropSet->save(myPropertiesFile.getPath()))
|
||||
Logger::debug("Saving properties set ...");
|
||||
}
|
||||
|
||||
|
@ -286,7 +286,7 @@ void OSystem::setConfigPaths()
|
|||
|
||||
myCheatFile = FilesystemNode(myBaseDir + "stella.cht").getPath();
|
||||
myPaletteFile = FilesystemNode(myBaseDir + "stella.pal").getPath();
|
||||
myPropertiesFile = FilesystemNode(myBaseDir + "stella.pro").getPath();
|
||||
myPropertiesFile = FilesystemNode(myBaseDir + "stella.pro");
|
||||
|
||||
#if 0
|
||||
// Debug code
|
||||
|
|
|
@ -545,7 +545,7 @@ class OSystem
|
|||
string myCheatFile;
|
||||
string myConfigFile;
|
||||
string myPaletteFile;
|
||||
string myPropertiesFile;
|
||||
FilesystemNode myPropertiesFile;
|
||||
|
||||
FilesystemNode myRomFile;
|
||||
string myRomMD5;
|
||||
|
|
|
@ -24,13 +24,21 @@
|
|||
#include "PropsSet.hxx"
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void PropertiesSet::load(const string& filename, bool save)
|
||||
void PropertiesSet::load(const FilesystemNode& file, bool save)
|
||||
{
|
||||
ifstream in(filename);
|
||||
|
||||
Properties prop;
|
||||
while(in >> prop)
|
||||
insert(prop, save);
|
||||
try
|
||||
{
|
||||
stringstream in;
|
||||
if(file.exists() && file.read(in) > 0)
|
||||
{
|
||||
Properties prop;
|
||||
while(in >> prop)
|
||||
insert(prop, save);
|
||||
}
|
||||
}
|
||||
catch(...)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
|
@ -166,8 +174,9 @@ void PropertiesSet::loadPerROM(const FilesystemNode& rom, const string& md5)
|
|||
// First, does this ROM have a per-ROM properties entry?
|
||||
// If so, load it into the database
|
||||
FilesystemNode propsNode(rom.getPathWithExt(".pro"));
|
||||
if(propsNode.exists() && propsNode.isFile())
|
||||
load(propsNode.getPath(), false);
|
||||
|
||||
if(propsNode.exists())
|
||||
load(propsNode, false);
|
||||
|
||||
// Next, make sure we have a valid md5 and name
|
||||
Properties props;
|
||||
|
|
|
@ -48,11 +48,11 @@ class PropertiesSet
|
|||
Load properties from the specified file, and create an internal
|
||||
searchable list.
|
||||
|
||||
@param filename Full pathname of input file to use
|
||||
@param save Indicates whether the properties should be saved
|
||||
when the program exits
|
||||
@param file The node representing the input file to use
|
||||
@param save Indicates whether the properties should be saved
|
||||
when the program exits
|
||||
*/
|
||||
void load(const string& filename, bool save = true);
|
||||
void load(const FilesystemNode& file, bool save = true);
|
||||
|
||||
/**
|
||||
Save properties to the specified file.
|
||||
|
|
Loading…
Reference in New Issue