mirror of https://github.com/stella-emu/stella.git
Fix parsing large MVC files causing lockup/crash in GUI (fixes # 829).
Still TODO is deal with large files other than MVC, and also ZIP files. At least the logic for analyzing size is now in one method (OSystem::openROM).
This commit is contained in:
parent
df4900828c
commit
fed3fa2241
|
@ -351,8 +351,8 @@ size_t FilesystemNode::read(ByteBuffer& buffer, size_t size) const
|
||||||
|
|
||||||
if (sizeRead == 0)
|
if (sizeRead == 0)
|
||||||
throw runtime_error("Zero-byte file");
|
throw runtime_error("Zero-byte file");
|
||||||
else if (size != 0)
|
else if (size > 0) // If a requested size to read is provided, honour it
|
||||||
sizeRead = size;
|
sizeRead = std::min(sizeRead, size);
|
||||||
|
|
||||||
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);
|
||||||
|
|
|
@ -317,7 +317,7 @@ string hash(const ByteBuffer& buffer, size_t length)
|
||||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
string hash(const uInt8* buffer, size_t length)
|
string hash(const uInt8* buffer, size_t length)
|
||||||
{
|
{
|
||||||
constexpr char hex[] = "0123456789abcdef";
|
static constexpr char hex[] = "0123456789abcdef";
|
||||||
MD5_CTX context{};
|
MD5_CTX context{};
|
||||||
uInt8 md5[16] = {0};
|
uInt8 md5[16] = {0};
|
||||||
const uInt32 len32 = static_cast<uInt32>(length); // Always use 32-bit for now
|
const uInt32 len32 = static_cast<uInt32>(length); // Always use 32-bit for now
|
||||||
|
@ -336,22 +336,4 @@ string hash(const uInt8* buffer, size_t length)
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
|
||||||
string hash(const FilesystemNode& node)
|
|
||||||
{
|
|
||||||
ByteBuffer image;
|
|
||||||
size_t size = 0;
|
|
||||||
try
|
|
||||||
{
|
|
||||||
size = node.read(image);
|
|
||||||
}
|
|
||||||
catch(...)
|
|
||||||
{
|
|
||||||
return EmptyString;
|
|
||||||
}
|
|
||||||
|
|
||||||
const string& md5 = hash(image, size);
|
|
||||||
return md5;
|
|
||||||
}
|
|
||||||
|
|
||||||
} // Namespace MD5
|
} // Namespace MD5
|
||||||
|
|
|
@ -35,6 +35,7 @@ namespace MD5 {
|
||||||
|
|
||||||
@param buffer The message to compute the digest of
|
@param buffer The message to compute the digest of
|
||||||
@param length The length of the message
|
@param length The length of the message
|
||||||
|
|
||||||
@return The message-digest
|
@return The message-digest
|
||||||
*/
|
*/
|
||||||
string hash(const ByteBuffer& buffer, size_t length);
|
string hash(const ByteBuffer& buffer, size_t length);
|
||||||
|
@ -43,19 +44,11 @@ namespace MD5 {
|
||||||
Dito.
|
Dito.
|
||||||
|
|
||||||
@param buffer The message to compute the digest of
|
@param buffer The message to compute the digest of
|
||||||
|
|
||||||
@return The message - digest
|
@return The message - digest
|
||||||
*/
|
*/
|
||||||
string hash(const string& buffer);
|
string hash(const string& buffer);
|
||||||
|
|
||||||
/**
|
|
||||||
Get the MD5 Message-Digest of the file contained in 'node'.
|
|
||||||
The digest consists of 32 hexadecimal digits.
|
|
||||||
|
|
||||||
@param node The file node to compute the digest of
|
|
||||||
@return The message-digest
|
|
||||||
*/
|
|
||||||
string hash(const FilesystemNode& node);
|
|
||||||
|
|
||||||
} // Namespace MD5
|
} // Namespace MD5
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -753,6 +753,34 @@ 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
|
||||||
|
|
||||||
|
ByteBuffer image = openROM(rom, size);
|
||||||
|
if(image)
|
||||||
|
{
|
||||||
|
// If we get to this point, we know we have a valid file to open
|
||||||
|
// Now we make sure that the file has a valid properties entry
|
||||||
|
// To save time, only generate an MD5 if we really need one
|
||||||
|
if(md5 == "")
|
||||||
|
md5 = MD5::hash(image, size);
|
||||||
|
|
||||||
|
// Make sure to load a per-ROM properties entry, if one exists
|
||||||
|
myPropSet->loadPerROM(rom, md5);
|
||||||
|
}
|
||||||
|
|
||||||
|
return image;
|
||||||
|
}
|
||||||
|
|
||||||
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
|
string OSystem::getROMMD5(const FilesystemNode& rom) const
|
||||||
|
{
|
||||||
|
size_t size = 0;
|
||||||
|
const ByteBuffer image = openROM(rom, size);
|
||||||
|
|
||||||
|
return image ? MD5::hash(image, size) : EmptyString;
|
||||||
|
}
|
||||||
|
|
||||||
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
|
ByteBuffer OSystem::openROM(const FilesystemNode& rom, size_t& size) const
|
||||||
|
{
|
||||||
// First check if this is a 'streaming' ROM (one where we only read
|
// First check if this is a 'streaming' ROM (one where we only read
|
||||||
// a portion of the file)
|
// a portion of the file)
|
||||||
const size_t sizeToRead = CartDetector::isProbablyMVC(rom);
|
const size_t sizeToRead = CartDetector::isProbablyMVC(rom);
|
||||||
|
@ -762,17 +790,15 @@ ByteBuffer OSystem::openROM(const FilesystemNode& rom, string& md5, size_t& size
|
||||||
// if it's not a ZIP file (that size should be higher; still TBD)
|
// if it's not a ZIP file (that size should be higher; still TBD)
|
||||||
|
|
||||||
ByteBuffer image;
|
ByteBuffer image;
|
||||||
|
try
|
||||||
|
{
|
||||||
if((size = rom.read(image, sizeToRead)) == 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
|
catch(const runtime_error& e)
|
||||||
// Now we make sure that the file has a valid properties entry
|
{
|
||||||
// To save time, only generate an MD5 if we really need one
|
cerr << "ERROR: Couldn't open ROM (" << e.what() << ")";
|
||||||
if(md5 == "")
|
}
|
||||||
md5 = MD5::hash(image, size);
|
|
||||||
|
|
||||||
// Make sure to load a per-ROM properties entry, if one exists
|
|
||||||
myPropSet->loadPerROM(rom, md5);
|
|
||||||
|
|
||||||
return image;
|
return image;
|
||||||
}
|
}
|
||||||
|
|
|
@ -338,6 +338,15 @@ class OSystem
|
||||||
*/
|
*/
|
||||||
ByteBuffer openROM(const FilesystemNode& rom, string& md5, size_t& size);
|
ByteBuffer openROM(const FilesystemNode& rom, string& md5, size_t& size);
|
||||||
|
|
||||||
|
/**
|
||||||
|
Open the given ROM and return the MD5sum of the data.
|
||||||
|
|
||||||
|
@param rom The file node of the ROM to open (contains path)
|
||||||
|
|
||||||
|
@return MD5 of the ROM image (if valid), otherwise EmptyString
|
||||||
|
*/
|
||||||
|
string getROMMD5(const FilesystemNode& rom) const;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Creates a new game console from the specified romfile, and correctly
|
Creates a new game console from the specified romfile, and correctly
|
||||||
initializes the system state to start emulation of the Console.
|
initializes the system state to start emulation of the Console.
|
||||||
|
@ -596,7 +605,6 @@ class OSystem
|
||||||
static bool ourOverrideBaseDirWithApp;
|
static bool ourOverrideBaseDirWithApp;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
/**
|
/**
|
||||||
This method should be called to initiate the process of loading settings
|
This method should be called to initiate the process of loading settings
|
||||||
from the config file. It takes care of loading settings, applying
|
from the config file. It takes care of loading settings, applying
|
||||||
|
@ -609,13 +617,24 @@ class OSystem
|
||||||
*/
|
*/
|
||||||
void createSound();
|
void createSound();
|
||||||
|
|
||||||
|
/**
|
||||||
|
Open the given ROM and return an array containing its contents.
|
||||||
|
This method takes care of using only a valid size for the
|
||||||
|
|
||||||
|
@param romfile The file node of the ROM to open (contains path)
|
||||||
|
@param size The amount of data read into the image array
|
||||||
|
|
||||||
|
@return Unique pointer to the array, otherwise nullptr
|
||||||
|
*/
|
||||||
|
ByteBuffer openROM(const FilesystemNode& romfile, size_t& size) const;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
Creates an actual Console object based on the given info.
|
Creates an actual Console object based on the given info.
|
||||||
|
|
||||||
@param romfile The file node of the ROM to use (contains path)
|
@param romfile The file node of the ROM to use (contains path)
|
||||||
@param md5 The MD5sum of the ROM
|
@param md5 The MD5sum of the ROM
|
||||||
|
|
||||||
@return The actual Console object, otherwise nullptr.
|
@return The actual Console object, otherwise nullptr
|
||||||
*/
|
*/
|
||||||
unique_ptr<Console> openConsole(const FilesystemNode& romfile, string& md5);
|
unique_ptr<Console> openConsole(const FilesystemNode& romfile, string& md5);
|
||||||
|
|
||||||
|
|
|
@ -395,7 +395,7 @@ const string& LauncherDialog::selectedRomMD5()
|
||||||
// Lookup MD5, and if not present, cache it
|
// Lookup MD5, and if not present, cache it
|
||||||
const auto iter = myMD5List.find(currentNode().getPath());
|
const auto iter = myMD5List.find(currentNode().getPath());
|
||||||
if(iter == myMD5List.end())
|
if(iter == myMD5List.end())
|
||||||
myMD5List[currentNode().getPath()] = MD5::hash(currentNode());
|
myMD5List[currentNode().getPath()] = instance().getROMMD5(currentNode());
|
||||||
|
|
||||||
return myMD5List[currentNode().getPath()];
|
return myMD5List[currentNode().getPath()];
|
||||||
}
|
}
|
||||||
|
|
|
@ -139,7 +139,7 @@ void RomAuditDialog::auditRoms()
|
||||||
|
|
||||||
// Calculate the MD5 so we can get the rest of the info
|
// Calculate the MD5 so we can get the rest of the info
|
||||||
// from the PropertiesSet (stella.pro)
|
// from the PropertiesSet (stella.pro)
|
||||||
const string& md5 = MD5::hash(files[idx]);
|
const string& md5 = instance().getROMMD5(files[idx]);
|
||||||
if(instance().propSet().getMD5(md5, props))
|
if(instance().propSet().getMD5(md5, props))
|
||||||
{
|
{
|
||||||
const string& name = props.get(PropType::Cart_Name);
|
const string& name = props.get(PropType::Cart_Name);
|
||||||
|
|
Loading…
Reference in New Issue