ZIP files now show nested files and directories instead of everything

being compressed into one level.  In the process, moved all ZIP-related
functionality from OSystem into FSNodeZIP, since it's the only thing
that actually uses it.


git-svn-id: svn://svn.code.sf.net/p/stella/code/trunk@3129 8b62c5a3-ac7e-4cc8-8f21-d9a121418aba
This commit is contained in:
stephena 2015-01-01 02:05:28 +00:00
parent b729a8013f
commit abd4c9efa8
9 changed files with 235 additions and 167 deletions

View File

@ -12,7 +12,7 @@
Release History Release History
=========================================================================== ===========================================================================
4.2 to 4.5: (December xx, 2014) 4.2 to 4.5: (January 1, 2015)
* The conversion to C++11 has begun :) From this point on, to build * The conversion to C++11 has begun :) From this point on, to build
Stella you will need a C++11 compatible compiler (Visual Studio 2013, Stella you will need a C++11 compatible compiler (Visual Studio 2013,
@ -27,7 +27,10 @@
(currently unplugged) joysticks from this database. (currently unplugged) joysticks from this database.
* Added preliminary support for 'WD' (Wickstead Design) bankswitching * Added preliminary support for 'WD' (Wickstead Design) bankswitching
scheme. scheme, used for a previously unreleased prototype ROM.
* Improved ZIP file handling, so that it now works as a normal
filesystem does (it properly shows nested files and directories).
* The debugger 'reset' command now does a complete system reset, * The debugger 'reset' command now does a complete system reset,
instead of simply setting the PC to the reset vector address. instead of simply setting the PC to the reset vector address.

View File

@ -54,7 +54,7 @@
<br><br><br> <br><br><br>
<center><b>February 1999 - December 2014</b></center> <center><b>February 1999 - January 2015</b></center>
<center><b>The Stella Team</b></center> <center><b>The Stella Team</b></center>
<center><b><a href="http://stella.sourceforge.net">Stella Homepage</a></b></center> <center><b><a href="http://stella.sourceforge.net">Stella Homepage</a></b></center>
@ -316,7 +316,7 @@
<p> <p>
<h3><b><u>General</u> (required for all versions of Stella)</b></h3> <h3><b><u>General</u> (required for all versions of Stella)</b></h3>
<ul> <ul>
<li>SDL version 2.0.1 or greater, latest version highly recommended</li> <li>SDL version 2.0.3 or greater, latest version highly recommended</li>
<li>15/16 bit color minimum; 24/32 bit color graphics card highly recommended</li> <li>15/16 bit color minimum; 24/32 bit color graphics card highly recommended</li>
<li>Enough RAM for the OS + 256MB RAM for the emulation; 512MB+ highly recommended</li> <li>Enough RAM for the OS + 256MB RAM for the emulation; 512MB+ highly recommended</li>
<li>Joysticks or gamepads are highly recommended</li> <li>Joysticks or gamepads are highly recommended</li>
@ -335,7 +335,7 @@
<li>OpenGL capable video card</li> <li>OpenGL capable video card</li>
<li>Other architectures (MIPS, PPC, PPC64, etc) have been confirmed to work, <li>Other architectures (MIPS, PPC, PPC64, etc) have been confirmed to work,
but aren't as well tested as i386/x86_64</li> but aren't as well tested as i386/x86_64</li>
<li>GNU g++ v/4.7 or Clang v/3.3 (with C++11 support) and the make utility are required for compiling <li>GNU g++ v/4.9 or Clang v/3.3 (with C++11 support) and the make utility are required for compiling
the Stella source code</li> the Stella source code</li>
</ul> </ul>

View File

@ -17,6 +17,8 @@
// $Id$ // $Id$
//============================================================================ //============================================================================
#include <set>
#include "bspf.hxx" #include "bspf.hxx"
#include "OSystem.hxx" #include "OSystem.hxx"
#include "FSNodeFactory.hxx" #include "FSNodeFactory.hxx"
@ -25,18 +27,29 @@
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
FilesystemNodeZIP::FilesystemNodeZIP() FilesystemNodeZIP::FilesystemNodeZIP()
: _error(ZIPERR_NOT_A_FILE), : _error(ZIPERR_NOT_A_FILE),
_numFiles(0) _numFiles(0),
_isDirectory(false),
_isFile(false)
{ {
// We need a name, else the node is invalid // We need a name, else the node is invalid
AbstractFSNode* tmp = nullptr; _realNode = shared_ptr<AbstractFSNode>(nullptr);
_realNode = shared_ptr<AbstractFSNode>(tmp);
} }
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
FilesystemNodeZIP::FilesystemNodeZIP(const string& p) FilesystemNodeZIP::FilesystemNodeZIP(const string& p)
: _error(ZIPERR_NONE), : _error(ZIPERR_NONE),
_numFiles(0) _numFiles(0),
_isDirectory(false),
_isFile(false)
{ {
// Is this a valid file?
auto isFile = [](const string& file)
{
return BSPF_endsWithIgnoreCase(file, ".a26") ||
BSPF_endsWithIgnoreCase(file, ".bin") ||
BSPF_endsWithIgnoreCase(file, ".rom");
};
// Extract ZIP file and virtual file (if specified) // Extract ZIP file and virtual file (if specified)
size_t pos = BSPF_findIgnoreCase(p, ".zip"); size_t pos = BSPF_findIgnoreCase(p, ".zip");
if(pos == string::npos) if(pos == string::npos)
@ -53,61 +66,71 @@ FilesystemNodeZIP::FilesystemNodeZIP(const string& p)
return; return;
} }
// We always need a virtual file // We always need a virtual file/path
// Either one is given, or we use the first one // Either one is given, or we use the first one
if(pos+5 < p.length()) if(pos+5 < p.length())
_virtualFile = p.substr(pos+5); {
_virtualPath = p.substr(pos+5);
_isFile = isFile(_virtualPath);
_isDirectory = !_isFile;
}
else if(_numFiles == 1) else if(_numFiles == 1)
{ {
bool found = false; bool found = false;
while(zip.hasNext() && !found) while(zip.hasNext() && !found)
{ {
const std::string& file = zip.next(); const string& file = zip.next();
if(BSPF_endsWithIgnoreCase(file, ".a26") || if(isFile(file))
BSPF_endsWithIgnoreCase(file, ".bin") ||
BSPF_endsWithIgnoreCase(file, ".rom"))
{ {
_virtualFile = file; _virtualPath = file;
_isFile = true;
found = true; found = true;
} }
} }
if(!found) if(!found)
return; return;
} }
else
_isDirectory = true;
AbstractFSNode* tmp = AbstractFSNode* tmp =
FilesystemNodeFactory::create(_zipFile, FilesystemNodeFactory::SYSTEM); FilesystemNodeFactory::create(_zipFile, FilesystemNodeFactory::SYSTEM);
_realNode = shared_ptr<AbstractFSNode>(tmp); _realNode = shared_ptr<AbstractFSNode>(tmp);
setFlags(_zipFile, _virtualFile, _realNode); setFlags(_zipFile, _virtualPath, _realNode);
} }
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
FilesystemNodeZIP::FilesystemNodeZIP(const string& zipfile, const string& virtualfile, FilesystemNodeZIP::FilesystemNodeZIP(
shared_ptr<AbstractFSNode> realnode) const string& zipfile, const string& virtualpath,
shared_ptr<AbstractFSNode> realnode, bool isdir)
: _isDirectory(isdir),
_isFile(!isdir)
{ {
setFlags(zipfile, virtualfile, realnode); setFlags(zipfile, virtualpath, realnode);
} }
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void FilesystemNodeZIP::setFlags(const string& zipfile, void FilesystemNodeZIP::setFlags(const string& zipfile,
const string& virtualfile, const string& virtualpath,
shared_ptr<AbstractFSNode> realnode) shared_ptr<AbstractFSNode> realnode)
{ {
_zipFile = zipfile; _zipFile = zipfile;
_virtualFile = virtualfile; _virtualPath = virtualpath;
_realNode = realnode; _realNode = realnode;
_path = _realNode->getPath(); _path = _realNode->getPath();
_shortPath = _realNode->getShortPath(); _shortPath = _realNode->getShortPath();
// Is a file component present? // Is a file component present?
if(_virtualFile.size() != 0) if(_virtualPath.size() != 0)
{ {
_path += ("/" + _virtualFile); _path += ("/" + _virtualPath);
_shortPath += ("/" + _virtualFile); _shortPath += ("/" + _virtualPath);
_numFiles = 1; _name = lastPathComponent(_path);
} }
_error = ZIPERR_NONE; _error = ZIPERR_NONE;
if(!_realNode->isFile()) if(!_realNode->isFile())
_error = ZIPERR_NOT_A_FILE; _error = ZIPERR_NOT_A_FILE;
@ -123,11 +146,29 @@ bool FilesystemNodeZIP::getChildren(AbstractFSList& myList, ListMode mode,
if(!isDirectory() || _error != ZIPERR_NONE) if(!isDirectory() || _error != ZIPERR_NONE)
return false; return false;
set<string> dirs;
ZipHandler& zip = open(_zipFile); ZipHandler& zip = open(_zipFile);
while(zip.hasNext()) while(zip.hasNext())
{ {
FilesystemNodeZIP entry(_path, zip.next(), _realNode); // Only consider entries that start with '_virtualPath'
myList.emplace_back(new FilesystemNodeZIP(entry)); const string& next = zip.next();
if(BSPF_startsWithIgnoreCase(next, _virtualPath))
{
// First strip off the leading directory
const string& curr = next.substr(_virtualPath == "" ? 0 : _virtualPath.size()+1);
// Only add sub-directory entries once
auto pos = curr.find_first_of("/\\");
if(pos != string::npos)
dirs.emplace(curr.substr(0, pos));
else
myList.emplace_back(new FilesystemNodeZIP(_zipFile, next, _realNode, false));
}
}
for(const auto& dir: dirs)
{
// Prepend previous path
const string& vpath = _virtualPath != "" ? _virtualPath + "/" + dir : dir;
myList.emplace_back(new FilesystemNodeZIP(_zipFile, vpath, _realNode, true));
} }
return true; return true;
@ -148,7 +189,7 @@ uInt32 FilesystemNodeZIP::read(uInt8*& image) const
bool found = false; bool found = false;
while(zip.hasNext() && !found) while(zip.hasNext() && !found)
found = zip.next() == _virtualFile; found = zip.next() == _virtualPath;
return found ? zip.decompress(image) : 0; return found ? zip.decompress(image) : 0;
} }
@ -156,7 +197,13 @@ uInt32 FilesystemNodeZIP::read(uInt8*& image) const
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
AbstractFSNode* FilesystemNodeZIP::getParent() const AbstractFSNode* FilesystemNodeZIP::getParent() const
{ {
if(_virtualPath == "")
return _realNode ? _realNode->getParent() : nullptr; return _realNode ? _realNode->getParent() : nullptr;
const char* start = _path.c_str();
const char* end = lastPathComponent(_path);
return new FilesystemNodeZIP(string(start, end - start - 1));
} }
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

View File

@ -49,11 +49,11 @@ class FilesystemNodeZIP : public AbstractFSNode
FilesystemNodeZIP(const string& path); FilesystemNodeZIP(const string& path);
bool exists() const { return _realNode && _realNode->exists(); } bool exists() const { return _realNode && _realNode->exists(); }
const string& getName() const { return _virtualFile; } const string& getName() const { return _name; }
const string& getPath() const { return _path; } const string& getPath() const { return _path; }
string getShortPath() const { return _shortPath; } string getShortPath() const { return _shortPath; }
bool isDirectory() const { return _numFiles > 1; } bool isDirectory() const { return _isDirectory; }
bool isFile() const { return _numFiles == 1; } bool isFile() const { return _isFile; }
bool isReadable() const { return _realNode && _realNode->isReadable(); } bool isReadable() const { return _realNode && _realNode->isReadable(); }
bool isWritable() const { return false; } bool isWritable() const { return false; }
@ -69,16 +69,16 @@ class FilesystemNodeZIP : public AbstractFSNode
uInt32 read(uInt8*& image) const; uInt32 read(uInt8*& image) const;
private: private:
FilesystemNodeZIP(const string& zipfile, const string& virtualfile, FilesystemNodeZIP(const string& zipfile, const string& virtualpath,
shared_ptr<AbstractFSNode> realnode); shared_ptr<AbstractFSNode> realnode, bool isdir);
void setFlags(const string& zipfile, const string& virtualfile, void setFlags(const string& zipfile, const string& virtualpath,
shared_ptr<AbstractFSNode> realnode); shared_ptr<AbstractFSNode> realnode);
friend ostream& operator<<(ostream& os, const FilesystemNodeZIP& node) friend ostream& operator<<(ostream& os, const FilesystemNodeZIP& node)
{ {
os << "_zipFile: " << node._zipFile << endl os << "_zipFile: " << node._zipFile << endl
<< "_virtualFile: " << node._virtualFile << endl << "_virtualPath: " << node._virtualPath << endl
<< "_path: " << node._path << endl << "_path: " << node._path << endl
<< "_shortPath: " << node._shortPath << endl; << "_shortPath: " << node._shortPath << endl;
return os; return os;
@ -95,18 +95,35 @@ class FilesystemNodeZIP : public AbstractFSNode
}; };
shared_ptr<AbstractFSNode> _realNode; shared_ptr<AbstractFSNode> _realNode;
string _zipFile, _virtualFile; string _zipFile, _virtualPath;
string _path, _shortPath; string _name, _path, _shortPath;
zip_error _error; zip_error _error;
uInt32 _numFiles; uInt32 _numFiles;
// ZIP static reference variable responsible for accessing ZIP files bool _isDirectory, _isFile;
// ZipHandler static reference variable responsible for accessing ZIP files
static unique_ptr<ZipHandler> myZipHandler; static unique_ptr<ZipHandler> myZipHandler;
static ZipHandler& open(const string& file) inline static ZipHandler& open(const string& file)
{ {
myZipHandler->open(file); myZipHandler->open(file);
return *myZipHandler; return *myZipHandler;
} }
// Get last component of path
static const char* lastPathComponent(const string& str)
{
if(str.empty())
return "";
const char* start = str.c_str();
const char* cur = start + str.size() - 2;
while (cur >= start && !(*cur == '/' || *cur == '\\'))
--cur;
return cur + 1;
}
}; };
#endif #endif

View File

@ -27,7 +27,7 @@
ZipHandler::ZipHandler() ZipHandler::ZipHandler()
: myZip(nullptr) : myZip(nullptr)
{ {
for(int cachenum = 0; cachenum < ZIP_CACHE_SIZE; cachenum++) for(int cachenum = 0; cachenum < ZIP_CACHE_SIZE; ++cachenum)
myZipCache[cachenum] = nullptr; myZipCache[cachenum] = nullptr;
} }
@ -53,7 +53,7 @@ void ZipHandler::open(const string& filename)
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void ZipHandler::reset() void ZipHandler::reset()
{ {
/* reset the position and go from there */ // Reset the position and go from there
if(myZip) if(myZip)
myZip->cd_pos = 0; myZip->cd_pos = 0;
} }
@ -183,25 +183,25 @@ bool ZipHandler::stream_read(fstream* stream, void* buffer, uInt64 offset,
/*------------------------------------------------- /*-------------------------------------------------
zip_file_open - opens a ZIP file for reading zip_file_open - opens a ZIP file for reading
-------------------------------------------------*/ -------------------------------------------------*/
ZipHandler::zip_error ZipHandler::zip_file_open(const char *filename, zip_file **zip) ZipHandler::zip_error ZipHandler::zip_file_open(const char* filename, zip_file** zip)
{ {
zip_error ziperr = ZIPERR_NONE; zip_error ziperr = ZIPERR_NONE;
uInt32 read_length; uInt32 read_length;
zip_file *newzip; zip_file* newzip;
char *string; char* string;
int cachenum; int cachenum;
bool success; bool success;
/* ensure we start with a NULL result */ // Ensure we start with a NULL result
*zip = nullptr; *zip = nullptr;
/* see if we are in the cache, and reopen if so */ // See if we are in the cache, and reopen if so
for(cachenum = 0; cachenum < ZIP_CACHE_SIZE; cachenum++) for(cachenum = 0; cachenum < ZIP_CACHE_SIZE; ++cachenum)
{ {
zip_file *cached = myZipCache[cachenum]; zip_file* cached = myZipCache[cachenum];
/* if we have a valid entry and it matches our filename, use it and remove // If we have a valid entry and it matches our filename, use it and remove
from the cache */ // from the cache
if(cached != nullptr && cached->filename != nullptr && if(cached != nullptr && cached->filename != nullptr &&
strcmp(filename, cached->filename) == 0) strcmp(filename, cached->filename) == 0)
{ {
@ -211,25 +211,25 @@ ZipHandler::zip_error ZipHandler::zip_file_open(const char *filename, zip_file *
} }
} }
/* allocate memory for the zip_file structure */ // Allocate memory for the zip_file structure
newzip = (zip_file *)malloc(sizeof(*newzip)); newzip = (zip_file*)malloc(sizeof(*newzip));
if (newzip == nullptr) if (newzip == nullptr)
return ZIPERR_OUT_OF_MEMORY; return ZIPERR_OUT_OF_MEMORY;
memset(newzip, 0, sizeof(*newzip)); memset(newzip, 0, sizeof(*newzip));
/* open the file */ // Open the file
if(!stream_open(filename, &newzip->file, newzip->length)) if(!stream_open(filename, &newzip->file, newzip->length))
{ {
ziperr = ZIPERR_FILE_ERROR; ziperr = ZIPERR_FILE_ERROR;
goto error; goto error;
} }
/* read ecd data */ // Read ecd data
ziperr = read_ecd(newzip); ziperr = read_ecd(newzip);
if(ziperr != ZIPERR_NONE) if(ziperr != ZIPERR_NONE)
goto error; goto error;
/* verify that we can work with this zipfile (no disk spanning allowed) */ // Verify that we can work with this zipfile (no disk spanning allowed)
if (newzip->ecd.disk_number != newzip->ecd.cd_start_disk_number || if (newzip->ecd.disk_number != newzip->ecd.cd_start_disk_number ||
newzip->ecd.cd_disk_entries != newzip->ecd.cd_total_entries) newzip->ecd.cd_disk_entries != newzip->ecd.cd_total_entries)
{ {
@ -237,15 +237,15 @@ ZipHandler::zip_error ZipHandler::zip_file_open(const char *filename, zip_file *
goto error; goto error;
} }
/* allocate memory for the central directory */ // Allocate memory for the central directory
newzip->cd = (uInt8 *)malloc(newzip->ecd.cd_size + 1); newzip->cd = (uInt8*)malloc(newzip->ecd.cd_size + 1);
if(newzip->cd == nullptr) if(newzip->cd == nullptr)
{ {
ziperr = ZIPERR_OUT_OF_MEMORY; ziperr = ZIPERR_OUT_OF_MEMORY;
goto error; goto error;
} }
/* read the central directory */ // Read the central directory
success = stream_read(newzip->file, newzip->cd, newzip->ecd.cd_start_disk_offset, success = stream_read(newzip->file, newzip->cd, newzip->ecd.cd_start_disk_offset,
newzip->ecd.cd_size, read_length); newzip->ecd.cd_size, read_length);
if(!success || read_length != newzip->ecd.cd_size) if(!success || read_length != newzip->ecd.cd_size)
@ -254,8 +254,8 @@ ZipHandler::zip_error ZipHandler::zip_file_open(const char *filename, zip_file *
goto error; goto error;
} }
/* make a copy of the filename for caching purposes */ // Make a copy of the filename for caching purposes
string = (char *)malloc(strlen(filename) + 1); string = (char*)malloc(strlen(filename) + 1);
if (string == nullptr) if (string == nullptr)
{ {
ziperr = ZIPERR_OUT_OF_MEMORY; ziperr = ZIPERR_OUT_OF_MEMORY;
@ -288,24 +288,24 @@ error:
zip_file_close - close a ZIP file and add it zip_file_close - close a ZIP file and add it
to the cache to the cache
-------------------------------------------------*/ -------------------------------------------------*/
void ZipHandler::zip_file_close(zip_file *zip) void ZipHandler::zip_file_close(zip_file* zip)
{ {
int cachenum; int cachenum;
/* close the open files */ // Close the open files
if(zip->file) if(zip->file)
stream_close(&zip->file); stream_close(&zip->file);
/* find the first NULL entry in the cache */ // Find the first NULL entry in the cache
for(cachenum = 0; cachenum < ZIP_CACHE_SIZE; cachenum++) for(cachenum = 0; cachenum < ZIP_CACHE_SIZE; ++cachenum)
if (myZipCache[cachenum] == nullptr) if(myZipCache[cachenum] == nullptr)
break; break;
/* if no room left in the cache, free the bottommost entry */ // If no room left in the cache, free the bottommost entry
if(cachenum == ZIP_CACHE_SIZE) if(cachenum == ZIP_CACHE_SIZE)
free_zip_file(myZipCache[--cachenum]); free_zip_file(myZipCache[--cachenum]);
/* move everyone else down and place us at the top */ // Move everyone else down and place us at the top
if(cachenum != 0) if(cachenum != 0)
memmove(&myZipCache[1], &myZipCache[0], cachenum * sizeof(myZipCache[0])); memmove(&myZipCache[1], &myZipCache[0], cachenum * sizeof(myZipCache[0]));
myZipCache[0] = zip; myZipCache[0] = zip;
@ -316,15 +316,17 @@ void ZipHandler::zip_file_close(zip_file *zip)
zip_file_cache_clear - clear the ZIP file zip_file_cache_clear - clear the ZIP file
cache and free all memory cache and free all memory
-------------------------------------------------*/ -------------------------------------------------*/
void ZipHandler::zip_file_cache_clear(void) void ZipHandler::zip_file_cache_clear()
{ {
/* clear call cache entries */ // Clear call cache entries
for(int cachenum = 0; cachenum < ZIP_CACHE_SIZE; cachenum++) for(int cachenum = 0; cachenum < ZIP_CACHE_SIZE; ++cachenum)
{
if(myZipCache[cachenum] != nullptr) if(myZipCache[cachenum] != nullptr)
{ {
free_zip_file(myZipCache[cachenum]); free_zip_file(myZipCache[cachenum]);
myZipCache[cachenum] = nullptr; myZipCache[cachenum] = nullptr;
} }
}
} }
@ -336,20 +338,20 @@ void ZipHandler::zip_file_cache_clear(void)
zip_file_next_entry - return the next entry zip_file_next_entry - return the next entry
in the ZIP in the ZIP
-------------------------------------------------*/ -------------------------------------------------*/
const ZipHandler::zip_file_header* ZipHandler::zip_file_next_file(zip_file *zip) const ZipHandler::zip_file_header* ZipHandler::zip_file_next_file(zip_file* zip)
{ {
/* fix up any modified data */ // Fix up any modified data
if(zip->header.raw != nullptr) if(zip->header.raw != nullptr)
{ {
zip->header.raw[ZIPCFN + zip->header.filename_length] = zip->header.saved; zip->header.raw[ZIPCFN + zip->header.filename_length] = zip->header.saved;
zip->header.raw = nullptr; zip->header.raw = nullptr;
} }
/* if we're at or past the end, we're done */ // If we're at or past the end, we're done
if(zip->cd_pos >= zip->ecd.cd_size) if(zip->cd_pos >= zip->ecd.cd_size)
return nullptr; return nullptr;
/* extract file header info */ // Extract file header info
zip->header.raw = zip->cd + zip->cd_pos; zip->header.raw = zip->cd + zip->cd_pos;
zip->header.rawlength = ZIPCFN; zip->header.rawlength = ZIPCFN;
zip->header.signature = read_dword(zip->header.raw + ZIPCENSIG); zip->header.signature = read_dword(zip->header.raw + ZIPCENSIG);
@ -369,20 +371,20 @@ const ZipHandler::zip_file_header* ZipHandler::zip_file_next_file(zip_file *zip)
zip->header.internal_attributes = read_word (zip->header.raw + ZIPINT); zip->header.internal_attributes = read_word (zip->header.raw + ZIPINT);
zip->header.external_attributes = read_dword(zip->header.raw + ZIPEXT); zip->header.external_attributes = read_dword(zip->header.raw + ZIPEXT);
zip->header.local_header_offset = read_dword(zip->header.raw + ZIPOFST); zip->header.local_header_offset = read_dword(zip->header.raw + ZIPOFST);
zip->header.filename = (char *)zip->header.raw + ZIPCFN; zip->header.filename = (char*)zip->header.raw + ZIPCFN;
/* make sure we have enough data */ // Make sure we have enough data
zip->header.rawlength += zip->header.filename_length; zip->header.rawlength += zip->header.filename_length;
zip->header.rawlength += zip->header.extra_field_length; zip->header.rawlength += zip->header.extra_field_length;
zip->header.rawlength += zip->header.file_comment_length; zip->header.rawlength += zip->header.file_comment_length;
if(zip->cd_pos + zip->header.rawlength > zip->ecd.cd_size) if(zip->cd_pos + zip->header.rawlength > zip->ecd.cd_size)
return nullptr; return nullptr;
/* NULL terminate the filename */ // NULL terminate the filename
zip->header.saved = zip->header.raw[ZIPCFN + zip->header.filename_length]; zip->header.saved = zip->header.raw[ZIPCFN + zip->header.filename_length];
zip->header.raw[ZIPCFN + zip->header.filename_length] = 0; zip->header.raw[ZIPCFN + zip->header.filename_length] = 0;
/* advance the position */ // Advance the position
zip->cd_pos += zip->header.rawlength; zip->cd_pos += zip->header.rawlength;
return &zip->header; return &zip->header;
} }
@ -392,25 +394,25 @@ const ZipHandler::zip_file_header* ZipHandler::zip_file_next_file(zip_file *zip)
from a ZIP into the target buffer from a ZIP into the target buffer
-------------------------------------------------*/ -------------------------------------------------*/
ZipHandler::zip_error ZipHandler::zip_error
ZipHandler::zip_file_decompress(zip_file *zip, void *buffer, uInt32 length) ZipHandler::zip_file_decompress(zip_file* zip, void* buffer, uInt32 length)
{ {
zip_error ziperr; zip_error ziperr;
uInt64 offset; uInt64 offset;
/* if we don't have enough buffer, error */ // If we don't have enough buffer, error
if(length < zip->header.uncompressed_length) if(length < zip->header.uncompressed_length)
return ZIPERR_BUFFER_TOO_SMALL; return ZIPERR_BUFFER_TOO_SMALL;
/* make sure the info in the header aligns with what we know */ // Make sure the info in the header aligns with what we know
if(zip->header.start_disk_number != zip->ecd.disk_number) if(zip->header.start_disk_number != zip->ecd.disk_number)
return ZIPERR_UNSUPPORTED; return ZIPERR_UNSUPPORTED;
/* get the compressed data offset */ // Get the compressed data offset
ziperr = get_compressed_data_offset(zip, &offset); ziperr = get_compressed_data_offset(zip, offset);
if(ziperr != ZIPERR_NONE) if(ziperr != ZIPERR_NONE)
return ziperr; return ziperr;
/* handle compression types */ // Handle compression types
switch(zip->header.compression) switch(zip->header.compression)
{ {
case 0: case 0:
@ -436,14 +438,14 @@ ZipHandler::zip_error
free_zip_file - free all the data for a free_zip_file - free all the data for a
zip_file zip_file
-------------------------------------------------*/ -------------------------------------------------*/
void ZipHandler::free_zip_file(zip_file *zip) void ZipHandler::free_zip_file(zip_file* zip)
{ {
if(zip != nullptr) if(zip != nullptr)
{ {
if(zip->file) if(zip->file)
stream_close(&zip->file); stream_close(&zip->file);
if(zip->filename != nullptr) if(zip->filename != nullptr)
free((void *)zip->filename); free((void*)zip->filename);
if(zip->ecd.raw != nullptr) if(zip->ecd.raw != nullptr)
free(zip->ecd.raw); free(zip->ecd.raw);
if(zip->cd != nullptr) if(zip->cd != nullptr)
@ -460,27 +462,27 @@ void ZipHandler::free_zip_file(zip_file *zip)
read_ecd - read the ECD data read_ecd - read the ECD data
-------------------------------------------------*/ -------------------------------------------------*/
ZipHandler::zip_error ZipHandler::read_ecd(zip_file *zip) ZipHandler::zip_error ZipHandler::read_ecd(zip_file* zip)
{ {
uInt32 buflen = 1024; uInt32 buflen = 1024;
uInt8 *buffer; uInt8* buffer;
/* we may need multiple tries */ // We may need multiple tries
while(buflen < 65536) while(buflen < 65536)
{ {
uInt32 read_length; uInt32 read_length;
Int32 offset; Int32 offset;
/* max out the buffer length at the size of the file */ // Max out the buffer length at the size of the file
if(buflen > zip->length) if(buflen > zip->length)
buflen = (uInt32)zip->length; buflen = (uInt32)zip->length;
/* allocate buffer */ // Allocate buffer
buffer = (uInt8 *)malloc(buflen + 1); buffer = (uInt8*)malloc(buflen + 1);
if(buffer == nullptr) if(buffer == nullptr)
return ZIPERR_OUT_OF_MEMORY; return ZIPERR_OUT_OF_MEMORY;
/* read in one buffers' worth of data */ // Read in one buffers' worth of data
bool success = stream_read(zip->file, buffer, zip->length - buflen, bool success = stream_read(zip->file, buffer, zip->length - buflen,
buflen, read_length); buflen, read_length);
if(!success || read_length != buflen) if(!success || read_length != buflen)
@ -489,24 +491,24 @@ ZipHandler::zip_error ZipHandler::read_ecd(zip_file *zip)
return ZIPERR_FILE_ERROR; return ZIPERR_FILE_ERROR;
} }
/* find the ECD signature */ // Find the ECD signature
for(offset = buflen - 22; offset >= 0; offset--) for(offset = buflen - 22; offset >= 0; offset--)
if(buffer[offset + 0] == 'P' && buffer[offset + 1] == 'K' && if(buffer[offset + 0] == 'P' && buffer[offset + 1] == 'K' &&
buffer[offset + 2] == 0x05 && buffer[offset + 3] == 0x06) buffer[offset + 2] == 0x05 && buffer[offset + 3] == 0x06)
break; break;
/* if we found it, fill out the data */ // If we found it, fill out the data
if(offset >= 0) if(offset >= 0)
{ {
/* reuse the buffer as our ECD buffer */ // Reuse the buffer as our ECD buffer
zip->ecd.raw = buffer; zip->ecd.raw = buffer;
zip->ecd.rawlength = buflen - offset; zip->ecd.rawlength = buflen - offset;
/* append a NULL terminator to the comment */ // Append a NULL terminator to the comment
memmove(&buffer[0], &buffer[offset], zip->ecd.rawlength); memmove(&buffer[0], &buffer[offset], zip->ecd.rawlength);
zip->ecd.raw[zip->ecd.rawlength] = 0; zip->ecd.raw[zip->ecd.rawlength] = 0;
/* extract ecd info */ // Extract ecd info
zip->ecd.signature = read_dword(zip->ecd.raw + ZIPESIG); zip->ecd.signature = read_dword(zip->ecd.raw + ZIPESIG);
zip->ecd.disk_number = read_word (zip->ecd.raw + ZIPEDSK); zip->ecd.disk_number = read_word (zip->ecd.raw + ZIPEDSK);
zip->ecd.cd_start_disk_number = read_word (zip->ecd.raw + ZIPECEN); zip->ecd.cd_start_disk_number = read_word (zip->ecd.raw + ZIPECEN);
@ -519,7 +521,7 @@ ZipHandler::zip_error ZipHandler::read_ecd(zip_file *zip)
return ZIPERR_NONE; return ZIPERR_NONE;
} }
/* didn't find it; free this buffer and expand our search */ // Didn't find it; free this buffer and expand our search
free(buffer); free(buffer);
if(buflen < zip->length) if(buflen < zip->length)
buflen *= 2; buflen *= 2;
@ -534,24 +536,24 @@ ZipHandler::zip_error ZipHandler::read_ecd(zip_file *zip)
offset of the compressed data offset of the compressed data
-------------------------------------------------*/ -------------------------------------------------*/
ZipHandler::zip_error ZipHandler::zip_error
ZipHandler::get_compressed_data_offset(zip_file *zip, uInt64 *offset) ZipHandler::get_compressed_data_offset(zip_file* zip, uInt64& offset)
{ {
uInt32 read_length; uInt32 read_length;
/* make sure the file handle is open */ // Make sure the file handle is open
if(zip->file == nullptr && !stream_open(zip->filename, &zip->file, zip->length)) if(zip->file == nullptr && !stream_open(zip->filename, &zip->file, zip->length))
return ZIPERR_FILE_ERROR; return ZIPERR_FILE_ERROR;
/* now go read the fixed-sized part of the local file header */ // Now go read the fixed-sized part of the local file header
bool success = stream_read(zip->file, zip->buffer, zip->header.local_header_offset, bool success = stream_read(zip->file, zip->buffer, zip->header.local_header_offset,
ZIPNAME, read_length); ZIPNAME, read_length);
if(!success || read_length != ZIPNAME) if(!success || read_length != ZIPNAME)
return success ? ZIPERR_FILE_TRUNCATED : ZIPERR_FILE_ERROR; return success ? ZIPERR_FILE_TRUNCATED : ZIPERR_FILE_ERROR;
/* compute the final offset */ // Compute the final offset
*offset = zip->header.local_header_offset + ZIPNAME; offset = zip->header.local_header_offset + ZIPNAME;
*offset += read_word(zip->buffer + ZIPFNLN); offset += read_word(zip->buffer + ZIPFNLN);
*offset += read_word(zip->buffer + ZIPXTRALN); offset += read_word(zip->buffer + ZIPXTRALN);
return ZIPERR_NONE; return ZIPERR_NONE;
} }
@ -565,14 +567,14 @@ ZipHandler::zip_error
type 0 data (which is uncompressed) type 0 data (which is uncompressed)
-------------------------------------------------*/ -------------------------------------------------*/
ZipHandler::zip_error ZipHandler::zip_error
ZipHandler::decompress_data_type_0(zip_file *zip, uInt64 offset, ZipHandler::decompress_data_type_0(zip_file* zip, uInt64 offset,
void *buffer, uInt32 length) void* buffer, uInt32 length)
{ {
uInt32 read_length; uInt32 read_length;
/* the data is uncompressed; just read it */ // The data is uncompressed; just read it
bool success = stream_read(zip->file, buffer, offset, zip->header.compressed_length, bool success = stream_read(zip->file, buffer, offset,
read_length); zip->header.compressed_length, read_length);
if(!success) if(!success)
return ZIPERR_FILE_ERROR; return ZIPERR_FILE_ERROR;
else if(read_length != zip->header.compressed_length) else if(read_length != zip->header.compressed_length)
@ -586,8 +588,8 @@ ZipHandler::zip_error
type 8 data (which is deflated) type 8 data (which is deflated)
-------------------------------------------------*/ -------------------------------------------------*/
ZipHandler::zip_error ZipHandler::zip_error
ZipHandler::decompress_data_type_8(zip_file *zip, uInt64 offset, ZipHandler::decompress_data_type_8(zip_file* zip, uInt64 offset,
void *buffer, uInt32 length) void* buffer, uInt32 length)
{ {
uInt32 input_remaining = zip->header.compressed_length; uInt32 input_remaining = zip->header.compressed_length;
uInt32 read_length; uInt32 read_length;
@ -597,25 +599,25 @@ ZipHandler::zip_error
#if 0 #if 0
// TODO - check newer versions of ZIP, and determine why this specific // TODO - check newer versions of ZIP, and determine why this specific
// version (0x14) is important // version (0x14) is important
/* make sure we don't need a newer mechanism */ // Make sure we don't need a newer mechanism
if (zip->header.version_needed > 0x14) if (zip->header.version_needed > 0x14)
return ZIPERR_UNSUPPORTED; return ZIPERR_UNSUPPORTED;
#endif #endif
/* reset the stream */ // Reset the stream
memset(&stream, 0, sizeof(stream)); memset(&stream, 0, sizeof(stream));
stream.next_out = (Bytef *)buffer; stream.next_out = (Bytef *)buffer;
stream.avail_out = length; stream.avail_out = length;
/* initialize the decompressor */ // Initialize the decompressor
zerr = inflateInit2(&stream, -MAX_WBITS); zerr = inflateInit2(&stream, -MAX_WBITS);
if(zerr != Z_OK) if(zerr != Z_OK)
return ZIPERR_DECOMPRESS_ERROR; return ZIPERR_DECOMPRESS_ERROR;
/* loop until we're done */ // Loop until we're done
while(1) for(;;)
{ {
/* read in the next chunk of data */ // Read in the next chunk of data
bool success = stream_read(zip->file, zip->buffer, offset, bool success = stream_read(zip->file, zip->buffer, offset,
BSPF_min(input_remaining, (uInt32)sizeof(zip->buffer)), BSPF_min(input_remaining, (uInt32)sizeof(zip->buffer)),
read_length); read_length);
@ -626,23 +628,23 @@ ZipHandler::zip_error
} }
offset += read_length; offset += read_length;
/* if we read nothing, but still have data left, the file is truncated */ // If we read nothing, but still have data left, the file is truncated
if(read_length == 0 && input_remaining > 0) if(read_length == 0 && input_remaining > 0)
{ {
inflateEnd(&stream); inflateEnd(&stream);
return ZIPERR_FILE_TRUNCATED; return ZIPERR_FILE_TRUNCATED;
} }
/* fill out the input data */ // Fill out the input data
stream.next_in = zip->buffer; stream.next_in = zip->buffer;
stream.avail_in = read_length; stream.avail_in = read_length;
input_remaining -= read_length; input_remaining -= read_length;
/* add a dummy byte at end of compressed data */ // Add a dummy byte at end of compressed data
if(input_remaining == 0) if(input_remaining == 0)
stream.avail_in++; stream.avail_in++;
/* now inflate */ // Now inflate
zerr = inflate(&stream, Z_NO_FLUSH); zerr = inflate(&stream, Z_NO_FLUSH);
if(zerr == Z_STREAM_END) if(zerr == Z_STREAM_END)
break; break;
@ -653,12 +655,12 @@ ZipHandler::zip_error
} }
} }
/* finish decompression */ // Finish decompression
zerr = inflateEnd(&stream); zerr = inflateEnd(&stream);
if(zerr != Z_OK) if(zerr != Z_OK)
return ZIPERR_DECOMPRESS_ERROR; return ZIPERR_DECOMPRESS_ERROR;
/* if anything looks funny, report an error */ // If anything looks funny, report an error
if(stream.avail_out > 0 || input_remaining > 0) if(stream.avail_out > 0 || input_remaining > 0)
return ZIPERR_DECOMPRESS_ERROR; return ZIPERR_DECOMPRESS_ERROR;

View File

@ -225,22 +225,22 @@ class ZipHandler
/* ----- ZIP file access ----- */ /* ----- ZIP file access ----- */
/* open a ZIP file and parse its central directory */ /* open a ZIP file and parse its central directory */
zip_error zip_file_open(const char *filename, zip_file **zip); zip_error zip_file_open(const char* filename, zip_file** zip);
/* close a ZIP file (may actually be left open due to caching) */ /* close a ZIP file (may actually be left open due to caching) */
void zip_file_close(zip_file *zip); void zip_file_close(zip_file* zip);
/* clear out all open ZIP files from the cache */ /* clear out all open ZIP files from the cache */
void zip_file_cache_clear(void); void zip_file_cache_clear();
/* ----- contained file access ----- */ /* ----- contained file access ----- */
/* find the next file in the ZIP */ /* find the next file in the ZIP */
const zip_file_header *zip_file_next_file(zip_file *zip); const zip_file_header* zip_file_next_file(zip_file* zip);
/* decompress the most recently found file in the ZIP */ /* decompress the most recently found file in the ZIP */
zip_error zip_file_decompress(zip_file *zip, void *buffer, uInt32 length); zip_error zip_file_decompress(zip_file* zip, void* buffer, uInt32 length);
inline static uInt16 read_word(uInt8* buf) inline static uInt16 read_word(uInt8* buf)
{ {
@ -253,17 +253,17 @@ class ZipHandler
} }
/* cache management */ /* cache management */
static void free_zip_file(zip_file *zip); static void free_zip_file(zip_file* zip);
/* ZIP file parsing */ /* ZIP file parsing */
static zip_error read_ecd(zip_file *zip); static zip_error read_ecd(zip_file* zip);
static zip_error get_compressed_data_offset(zip_file *zip, uInt64 *offset); static zip_error get_compressed_data_offset(zip_file* zip, uInt64& offset);
/* decompression interfaces */ /* decompression interfaces */
static zip_error decompress_data_type_0(zip_file *zip, uInt64 offset, static zip_error decompress_data_type_0(zip_file* zip, uInt64 offset,
void *buffer, uInt32 length); void* buffer, uInt32 length);
static zip_error decompress_data_type_8(zip_file *zip, uInt64 offset, static zip_error decompress_data_type_8(zip_file* zip, uInt64 offset,
void *buffer, uInt32 length); void* buffer, uInt32 length);
private: private:
zip_file* myZip; zip_file* myZip;

View File

@ -19,31 +19,6 @@
#include "FSNodePOSIX.hxx" #include "FSNodePOSIX.hxx"
/**
* Returns the last component of a given path.
*
* Examples:
* /foo/bar.txt would return /bar.txt
* /foo/bar/ would return /bar/
*
* @param str String containing the path.
* @return Pointer to the first char of the last component inside str.
*/
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
const char* lastPathComponent(const string& str)
{
if(str.empty())
return "";
const char *start = str.c_str();
const char *cur = start + str.size() - 2;
while (cur >= start && *cur != '/')
--cur;
return cur + 1;
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
void FilesystemNodePOSIX::setFlags() void FilesystemNodePOSIX::setFlags()
{ {

View File

@ -91,6 +91,30 @@ class FilesystemNodePOSIX : public AbstractFSNode
* using the stat() function. * using the stat() function.
*/ */
virtual void setFlags(); virtual void setFlags();
/**
* Returns the last component of a given path.
*
* Examples:
* /foo/bar.txt would return /bar.txt
* /foo/bar/ would return /bar/
*
* @param str String containing the path.
* @return Pointer to the first char of the last component inside str.
*/
static const char* lastPathComponent(const string& str)
{
if(str.empty())
return "";
const char* start = str.c_str();
const char* cur = start + str.size() - 2;
while (cur >= start && *cur != '/')
--cur;
return cur + 1;
}
}; };
#endif #endif

View File

@ -101,7 +101,7 @@ rm -rf $RPM_BUILD_DIR/%{name}-%{version}
%_datadir/icons/large/%{name}.png %_datadir/icons/large/%{name}.png
%changelog %changelog
* xxx Dec xx 2014 Stephen Anthony <stephena@users.sf.net> 4.5-1 * Thu Jan 1 2015 Stephen Anthony <stephena@users.sf.net> 4.5-1
- Version 4.5 release - Version 4.5 release
* Tue Oct 28 2014 Stephen Anthony <stephena@users.sf.net> 4.2-1 * Tue Oct 28 2014 Stephen Anthony <stephena@users.sf.net> 4.2-1