From 9c17d43c6fae10af551a64fce70ca2a666bb8640 Mon Sep 17 00:00:00 2001 From: stephena Date: Tue, 8 May 2012 13:24:10 +0000 Subject: [PATCH] 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 --- src/emucore/OSystem.cxx | 167 +++++++++++++++++++++------------------- src/emucore/OSystem.hxx | 15 ++++ 2 files changed, 103 insertions(+), 79 deletions(-) diff --git a/src/emucore/OSystem.cxx b/src/emucore/OSystem.cxx index 6ba2697fa..15843901d 100644 --- a/src/emucore/OSystem.cxx +++ b/src/emucore/OSystem.cxx @@ -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) { diff --git a/src/emucore/OSystem.hxx b/src/emucore/OSystem.hxx index e906f8b74..fb122e664 100644 --- a/src/emucore/OSystem.hxx +++ b/src/emucore/OSystem.hxx @@ -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.