Fixed bug in loading ROMs from a multi-file ZIP archive; ROMs

below the base directory weren't being detected.  The ROMs can
now be in any directory arrangement (although they'll still be
presented in the UI as if they're all in the base directory).


git-svn-id: svn://svn.code.sf.net/p/stella/code/trunk@2460 8b62c5a3-ac7e-4cc8-8f21-d9a121418aba
This commit is contained in:
stephena 2012-05-08 13:24:10 +00:00
parent 090390b415
commit 9c17d43c6f
2 changed files with 103 additions and 79 deletions

View File

@ -758,87 +758,13 @@ uInt8* OSystem::openROM(string file, string& md5, uInt32& size)
uInt8* image = 0;
// Split zip file path and file name within zip archive
string fileInZip = "";
FilesystemNode fileNode(file);
if (!fileNode.exists())
// First try to load as ZIP archive
if(loadFromZIP(file, &image, size))
{
size_t slashPos = file.rfind(BSPF_PATH_SEPARATOR);
if(slashPos != string::npos)
{
string parent = file.substr(0, slashPos);
string name = file.substr(slashPos+1);
FilesystemNode parentNode(parent);
if(parentNode.exists() && !parentNode.isDirectory() &&
BSPF_endsWithIgnoreCase(parent, ".zip"))
{
fileInZip = name;
file = parent;
}
}
}
// Try to open the file as a zipped archive
// If that fails, we assume it's just a gzipped or normal data file
unzFile tz;
if((tz = unzOpen(file.c_str())) != NULL)
{
if(unzGoToFirstFile(tz) == UNZ_OK)
{
unz_file_info ufo;
for(;;) // Loop through all files for valid 2600 images
{
// Longer filenames might be possible, but I don't
// think people would name files that long in zip files...
char filename[1024];
unzGetCurrentFileInfo(tz, &ufo, filename, 1024, 0, 0, 0, 0);
filename[1023] = '\0';
if(strlen(filename) >= 4)
{
// Grab 3-character extension
const char* ext = filename + strlen(filename) - 4;
if(BSPF_equalsIgnoreCase(ext, ".a26") || BSPF_equalsIgnoreCase(ext, ".bin") ||
BSPF_equalsIgnoreCase(ext, ".rom"))
{
if(fileInZip.empty() || fileInZip == filename)
{
file = filename;
break;
}
}
}
// Scan the next file in the zip
if(unzGoToNextFile(tz) != UNZ_OK)
break;
}
// Now see if we got a valid image
if(ufo.uncompressed_size <= 0)
{
unzClose(tz);
return image;
}
size = ufo.uncompressed_size;
image = new uInt8[size];
// We don't have to check for any return errors from these functions,
// since if there are, 'image' will not contain a valid ROM and the
// calling method can take care of it
unzOpenCurrentFile(tz);
unzReadCurrentFile(tz, image, size);
unzCloseCurrentFile(tz);
unzClose(tz);
}
else
{
unzClose(tz);
// Empty file means it *was* a ZIP file, but it didn't contain
// a valid ROM
if(image == 0)
return image;
}
}
else
{
@ -883,6 +809,89 @@ uInt8* OSystem::openROM(string file, string& md5, uInt32& size)
return image;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
bool OSystem::loadFromZIP(const string& filename, uInt8** image, uInt32& size)
{
// First determine if this actually is a ZIP file
// by seeing if it contains the '.zip' extension
size_t extpos = BSPF_findIgnoreCase(filename, ".zip");
if(extpos == string::npos)
return false;
// Now get the file after the .zip extension (if any)
string archive = filename, fileinzip = "";
if(filename.size() > extpos + 4)
{
archive = filename.substr(0, extpos + 4);
fileinzip = filename.substr(extpos + 5);
if(fileinzip.size() == 0)
return true; // This was a ZIP file, but invalid name
}
// Open archive
unzFile tz;
if((tz = unzOpen(archive.c_str())) != NULL)
{
if(unzGoToFirstFile(tz) == UNZ_OK)
{
unz_file_info ufo;
for(;;) // Loop through all files for valid 2600 images
{
// Longer filenames might be possible, but I don't
// think people would name files that long in zip files...
char currfile[1024];
unzGetCurrentFileInfo(tz, &ufo, currfile, 1024, 0, 0, 0, 0);
currfile[1023] = '\0';
if(strlen(currfile) >= 4)
{
// Grab 3-character extension
const char* ext = currfile + strlen(currfile) - 4;
if(BSPF_equalsIgnoreCase(ext, ".a26") || BSPF_equalsIgnoreCase(ext, ".bin") ||
BSPF_equalsIgnoreCase(ext, ".rom"))
{
// Either match the first file or the one we're looking for
if(fileinzip.empty() || fileinzip == currfile)
break;
}
}
// Scan the next file in the zip
if(unzGoToNextFile(tz) != UNZ_OK)
break;
}
// Now see if we got a valid image
if(ufo.uncompressed_size <= 0)
{
unzClose(tz);
return true;
}
size = ufo.uncompressed_size;
*image = new uInt8[size];
// We don't have to check for any return errors from these functions,
// since if there are, 'image' will not contain a valid ROM and the
// calling method can take care of it
unzOpenCurrentFile(tz);
unzReadCurrentFile(tz, *image, size);
unzCloseCurrentFile(tz);
unzClose(tz);
return true;
}
else
{
unzClose(tz);
return true;
}
}
return false;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
string OSystem::getROMInfo(const Console* console)
{

View File

@ -643,6 +643,21 @@ class OSystem
*/
uInt8* openROM(string rom, string& md5, uInt32& size);
/**
Open the given ZIP archive, parsing filename for the contents of the
desired file to load. If the filename ends in '.zip', use the first
file found in the archive, otherwise traverse the archive and use the
file specified after '.zip' in the filename.
@param name The absolute pathname of the file
@param image Pointer to the array, with size >=0 indicating valid data
@param size The amount of data read into the image array
@return True if this was a zip file (regardless of whether it
actually loaded any valid data, else false
*/
bool loadFromZIP(const string& filename, uInt8** image, uInt32& size);
/**
Gets all possible info about the given console.