mirror of https://github.com/stella-emu/stella.git
Added ability to descend into multi-ROM ZIP archives.
git-svn-id: svn://svn.code.sf.net/p/stella/code/trunk@2450 8b62c5a3-ac7e-4cc8-8f21-d9a121418aba
This commit is contained in:
parent
e3ba9f0ec2
commit
973a8edf30
|
@ -12,7 +12,7 @@
|
|||
Release History
|
||||
===========================================================================
|
||||
|
||||
3.6.1 to 3.7: (April xx, 2012)
|
||||
3.6.1 to 3.7: (May xx, 2012)
|
||||
|
||||
* Updated the CompuMate keyboard handler to recognize more keys on an
|
||||
actual keyboard, instead of having to remember the weird combinations
|
||||
|
@ -27,6 +27,11 @@
|
|||
* Updated FA2 bankswitch scheme (Star Castle) to emulate load/save
|
||||
high score functionality to the Harmony cart flash RAM.
|
||||
|
||||
* Added ability for ROM launcher to 'descend' into ZIP files when it
|
||||
contains more than one ROM file. This means you no longer have to unzip
|
||||
a multi-file archive before using each ROM. Thanks go to Roland
|
||||
Schabenberger (webOS maintainer) for this idea and sample code.
|
||||
|
||||
* Replaced commandline argument 'uselauncher' with 'exitlauncher'. The
|
||||
new option specifies the behaviour of the ROM launcher when exiting
|
||||
a ROM (always exit to launcher, or only when the launcher was actually
|
||||
|
|
|
@ -130,6 +130,20 @@ inline string BSPF_toString(int num)
|
|||
return buf.str();
|
||||
}
|
||||
|
||||
// Test whether two characters are equal (case insensitive)
|
||||
static bool BSPF_equalsIgnoreCaseChar(char ch1, char ch2)
|
||||
{
|
||||
return toupper((unsigned char)ch1) == toupper((unsigned char)ch2);
|
||||
}
|
||||
// Find location (if any) of the second string within the first,
|
||||
// starting from 'startpos' in the first string
|
||||
inline size_t BSPF_findIgnoreCase(const string& s1, const string& s2, int startpos = 0)
|
||||
{
|
||||
string::const_iterator pos = std::search(s1.begin()+startpos, s1.end(),
|
||||
s2.begin(), s2.end(), BSPF_equalsIgnoreCaseChar);
|
||||
return pos == s1.end() ? string::npos : pos - (s1.begin()+startpos);
|
||||
}
|
||||
|
||||
// Test whether two strings are equal (case insensitive)
|
||||
inline bool BSPF_equalsIgnoreCase(const string& s1, const string& s2)
|
||||
{
|
||||
|
@ -150,17 +164,12 @@ inline bool BSPF_startsWithIgnoreCase(const char* s1, const char* s2)
|
|||
return BSPF_strncasecmp(s1, s2, strlen(s2)) == 0;
|
||||
}
|
||||
|
||||
// Test whether two characters are equal (case insensitive)
|
||||
static bool BSPF_equalsIgnoreCaseChar(char ch1, char ch2)
|
||||
// Test whether the first string ends with the second one (case insensitive)
|
||||
inline bool BSPF_endsWithIgnoreCase(const string& s1, const string& s2)
|
||||
{
|
||||
return toupper((unsigned char)ch1) == toupper((unsigned char)ch2);
|
||||
}
|
||||
// Find location (if any) of the second string within the first
|
||||
inline size_t BSPF_findIgnoreCase(const string& s1, const string& s2)
|
||||
{
|
||||
string::const_iterator pos = std::search(s1.begin(), s1.end(),
|
||||
s2.begin(), s2.end(), BSPF_equalsIgnoreCaseChar);
|
||||
return pos == s1.end() ? string::npos : pos - s1.begin();
|
||||
return (s1.length() >= s2.length()) ?
|
||||
(BSPF_findIgnoreCase(s1, s2, s1.length() - s2.length()) != string::npos) :
|
||||
false;
|
||||
}
|
||||
|
||||
static const string EmptyString("");
|
||||
|
|
|
@ -758,6 +758,26 @@ 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())
|
||||
{
|
||||
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;
|
||||
|
@ -783,11 +803,14 @@ uInt8* OSystem::openROM(string file, string& md5, uInt32& size)
|
|||
|
||||
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)
|
||||
|
|
|
@ -44,6 +44,7 @@
|
|||
#include "StringList.hxx"
|
||||
#include "StringListWidget.hxx"
|
||||
#include "Widget.hxx"
|
||||
#include "unzip.h"
|
||||
|
||||
#include "LauncherDialog.hxx"
|
||||
|
||||
|
@ -341,12 +342,55 @@ void LauncherDialog::updateListing(const string& nameToSelect)
|
|||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void LauncherDialog::loadDirListing()
|
||||
{
|
||||
if(!myCurrentNode.isDirectory())
|
||||
if(!myCurrentNode.isDirectory() && !myCurrentNode.exists())
|
||||
return;
|
||||
|
||||
FSList files;
|
||||
files.reserve(2048);
|
||||
|
||||
if(myCurrentNode.isDirectory())
|
||||
{
|
||||
myCurrentNode.getChildren(files, FilesystemNode::kListAll);
|
||||
}
|
||||
else
|
||||
{
|
||||
unzFile tz;
|
||||
if((tz = unzOpen(myCurrentNode.getPath().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"))
|
||||
{
|
||||
FilesystemNode newFile(AbstractFilesystemNode::getAbsolutePath(
|
||||
filename, myCurrentNode.getPath(), ""));
|
||||
files.push_back(newFile);
|
||||
}
|
||||
}
|
||||
|
||||
// Scan the next file in the zip
|
||||
if(unzGoToNextFile(tz) != UNZ_OK)
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Add '[..]' to indicate previous folder
|
||||
if(myCurrentNode.hasParent())
|
||||
|
@ -364,7 +408,9 @@ void LauncherDialog::loadDirListing()
|
|||
// that we want - if there are no extensions, it implies show all files
|
||||
// In this way, showing all files is on the 'fast code path'
|
||||
if(isDir)
|
||||
{
|
||||
name = " [" + name + "]";
|
||||
}
|
||||
else if(myRomExts.size() > 0)
|
||||
{
|
||||
// Skip over those names we've filtered out
|
||||
|
@ -478,6 +524,46 @@ bool LauncherDialog::matchPattern(const string& s, const string& pattern) const
|
|||
return false;
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
int LauncherDialog::filesInArchive(const string& archive)
|
||||
{
|
||||
int count = -1;
|
||||
unzFile tz;
|
||||
if((tz = unzOpen(archive.c_str())) != NULL)
|
||||
{
|
||||
count = 0;
|
||||
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"))
|
||||
++count;
|
||||
}
|
||||
|
||||
// Scan the next file in the zip
|
||||
if(unzGoToNextFile(tz) != UNZ_OK)
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void LauncherDialog::handleKeyDown(StellaKey key, StellaMod mod, char ascii)
|
||||
{
|
||||
|
@ -519,8 +605,18 @@ void LauncherDialog::handleCommand(CommandSender* sender, int cmd,
|
|||
const string& md5 = myGameList->md5(item);
|
||||
string extension;
|
||||
|
||||
int numFilesInArchive = filesInArchive(rom);
|
||||
bool isArchive = !myGameList->isDir(item) &&
|
||||
BSPF_endsWithIgnoreCase(rom, ".zip");
|
||||
|
||||
// Directory's should be selected (ie, enter them and redisplay)
|
||||
if(myGameList->isDir(item))
|
||||
// Archives should be entered if they contain more than 1 file
|
||||
if(isArchive && numFilesInArchive < 1)
|
||||
{
|
||||
instance().frameBuffer().showMessage("Archive does not contain any valid ROM files",
|
||||
kMiddleCenter, true);
|
||||
}
|
||||
else if((isArchive && numFilesInArchive > 1) || myGameList->isDir(item))
|
||||
{
|
||||
string dirname = "";
|
||||
if(myGameList->name(item) == " [..]")
|
||||
|
|
|
@ -96,6 +96,7 @@ class LauncherDialog : public Dialog
|
|||
void handleContextMenu();
|
||||
void setListFilters();
|
||||
bool matchPattern(const string& s, const string& pattern) const;
|
||||
int filesInArchive(const string& archive);
|
||||
|
||||
private:
|
||||
ButtonWidget* myStartButton;
|
||||
|
|
Loading…
Reference in New Issue