mirror of https://github.com/stella-emu/stella.git
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:
parent
b729a8013f
commit
abd4c9efa8
|
@ -12,7 +12,7 @@
|
|||
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
|
||||
Stella you will need a C++11 compatible compiler (Visual Studio 2013,
|
||||
|
@ -27,7 +27,10 @@
|
|||
(currently unplugged) joysticks from this database.
|
||||
|
||||
* 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,
|
||||
instead of simply setting the PC to the reset vector address.
|
||||
|
|
|
@ -54,7 +54,7 @@
|
|||
|
||||
<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><a href="http://stella.sourceforge.net">Stella Homepage</a></b></center>
|
||||
|
||||
|
@ -316,7 +316,7 @@
|
|||
<p>
|
||||
<h3><b><u>General</u> (required for all versions of Stella)</b></h3>
|
||||
<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>Enough RAM for the OS + 256MB RAM for the emulation; 512MB+ highly recommended</li>
|
||||
<li>Joysticks or gamepads are highly recommended</li>
|
||||
|
@ -335,7 +335,7 @@
|
|||
<li>OpenGL capable video card</li>
|
||||
<li>Other architectures (MIPS, PPC, PPC64, etc) have been confirmed to work,
|
||||
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>
|
||||
</ul>
|
||||
|
||||
|
|
|
@ -17,6 +17,8 @@
|
|||
// $Id$
|
||||
//============================================================================
|
||||
|
||||
#include <set>
|
||||
|
||||
#include "bspf.hxx"
|
||||
#include "OSystem.hxx"
|
||||
#include "FSNodeFactory.hxx"
|
||||
|
@ -25,18 +27,29 @@
|
|||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
FilesystemNodeZIP::FilesystemNodeZIP()
|
||||
: _error(ZIPERR_NOT_A_FILE),
|
||||
_numFiles(0)
|
||||
_numFiles(0),
|
||||
_isDirectory(false),
|
||||
_isFile(false)
|
||||
{
|
||||
// We need a name, else the node is invalid
|
||||
AbstractFSNode* tmp = nullptr;
|
||||
_realNode = shared_ptr<AbstractFSNode>(tmp);
|
||||
_realNode = shared_ptr<AbstractFSNode>(nullptr);
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
FilesystemNodeZIP::FilesystemNodeZIP(const string& p)
|
||||
: _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)
|
||||
size_t pos = BSPF_findIgnoreCase(p, ".zip");
|
||||
if(pos == string::npos)
|
||||
|
@ -53,61 +66,71 @@ FilesystemNodeZIP::FilesystemNodeZIP(const string& p)
|
|||
return;
|
||||
}
|
||||
|
||||
// We always need a virtual file
|
||||
// We always need a virtual file/path
|
||||
// Either one is given, or we use the first one
|
||||
if(pos+5 < p.length())
|
||||
_virtualFile = p.substr(pos+5);
|
||||
{
|
||||
_virtualPath = p.substr(pos+5);
|
||||
_isFile = isFile(_virtualPath);
|
||||
_isDirectory = !_isFile;
|
||||
}
|
||||
else if(_numFiles == 1)
|
||||
{
|
||||
bool found = false;
|
||||
while(zip.hasNext() && !found)
|
||||
{
|
||||
const std::string& file = zip.next();
|
||||
if(BSPF_endsWithIgnoreCase(file, ".a26") ||
|
||||
BSPF_endsWithIgnoreCase(file, ".bin") ||
|
||||
BSPF_endsWithIgnoreCase(file, ".rom"))
|
||||
const string& file = zip.next();
|
||||
if(isFile(file))
|
||||
{
|
||||
_virtualFile = file;
|
||||
_virtualPath = file;
|
||||
_isFile = true;
|
||||
|
||||
found = true;
|
||||
}
|
||||
}
|
||||
if(!found)
|
||||
return;
|
||||
}
|
||||
else
|
||||
_isDirectory = true;
|
||||
|
||||
AbstractFSNode* tmp =
|
||||
FilesystemNodeFactory::create(_zipFile, FilesystemNodeFactory::SYSTEM);
|
||||
_realNode = shared_ptr<AbstractFSNode>(tmp);
|
||||
|
||||
setFlags(_zipFile, _virtualFile, _realNode);
|
||||
setFlags(_zipFile, _virtualPath, _realNode);
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
FilesystemNodeZIP::FilesystemNodeZIP(const string& zipfile, const string& virtualfile,
|
||||
shared_ptr<AbstractFSNode> realnode)
|
||||
FilesystemNodeZIP::FilesystemNodeZIP(
|
||||
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,
|
||||
const string& virtualfile,
|
||||
const string& virtualpath,
|
||||
shared_ptr<AbstractFSNode> realnode)
|
||||
{
|
||||
_zipFile = zipfile;
|
||||
_virtualFile = virtualfile;
|
||||
_virtualPath = virtualpath;
|
||||
_realNode = realnode;
|
||||
|
||||
_path = _realNode->getPath();
|
||||
_shortPath = _realNode->getShortPath();
|
||||
|
||||
// Is a file component present?
|
||||
if(_virtualFile.size() != 0)
|
||||
if(_virtualPath.size() != 0)
|
||||
{
|
||||
_path += ("/" + _virtualFile);
|
||||
_shortPath += ("/" + _virtualFile);
|
||||
_numFiles = 1;
|
||||
_path += ("/" + _virtualPath);
|
||||
_shortPath += ("/" + _virtualPath);
|
||||
_name = lastPathComponent(_path);
|
||||
}
|
||||
|
||||
_error = ZIPERR_NONE;
|
||||
if(!_realNode->isFile())
|
||||
_error = ZIPERR_NOT_A_FILE;
|
||||
|
@ -123,11 +146,29 @@ bool FilesystemNodeZIP::getChildren(AbstractFSList& myList, ListMode mode,
|
|||
if(!isDirectory() || _error != ZIPERR_NONE)
|
||||
return false;
|
||||
|
||||
set<string> dirs;
|
||||
ZipHandler& zip = open(_zipFile);
|
||||
while(zip.hasNext())
|
||||
{
|
||||
FilesystemNodeZIP entry(_path, zip.next(), _realNode);
|
||||
myList.emplace_back(new FilesystemNodeZIP(entry));
|
||||
// Only consider entries that start with '_virtualPath'
|
||||
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;
|
||||
|
@ -148,7 +189,7 @@ uInt32 FilesystemNodeZIP::read(uInt8*& image) const
|
|||
|
||||
bool found = false;
|
||||
while(zip.hasNext() && !found)
|
||||
found = zip.next() == _virtualFile;
|
||||
found = zip.next() == _virtualPath;
|
||||
|
||||
return found ? zip.decompress(image) : 0;
|
||||
}
|
||||
|
@ -156,7 +197,13 @@ uInt32 FilesystemNodeZIP::read(uInt8*& image) const
|
|||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
AbstractFSNode* FilesystemNodeZIP::getParent() const
|
||||
{
|
||||
return _realNode ? _realNode->getParent() : nullptr;
|
||||
if(_virtualPath == "")
|
||||
return _realNode ? _realNode->getParent() : nullptr;
|
||||
|
||||
const char* start = _path.c_str();
|
||||
const char* end = lastPathComponent(_path);
|
||||
|
||||
return new FilesystemNodeZIP(string(start, end - start - 1));
|
||||
}
|
||||
|
||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
|
|
|
@ -49,11 +49,11 @@ class FilesystemNodeZIP : public AbstractFSNode
|
|||
FilesystemNodeZIP(const string& path);
|
||||
|
||||
bool exists() const { return _realNode && _realNode->exists(); }
|
||||
const string& getName() const { return _virtualFile; }
|
||||
const string& getPath() const { return _path; }
|
||||
string getShortPath() const { return _shortPath; }
|
||||
bool isDirectory() const { return _numFiles > 1; }
|
||||
bool isFile() const { return _numFiles == 1; }
|
||||
const string& getName() const { return _name; }
|
||||
const string& getPath() const { return _path; }
|
||||
string getShortPath() const { return _shortPath; }
|
||||
bool isDirectory() const { return _isDirectory; }
|
||||
bool isFile() const { return _isFile; }
|
||||
bool isReadable() const { return _realNode && _realNode->isReadable(); }
|
||||
bool isWritable() const { return false; }
|
||||
|
||||
|
@ -69,16 +69,16 @@ class FilesystemNodeZIP : public AbstractFSNode
|
|||
uInt32 read(uInt8*& image) const;
|
||||
|
||||
private:
|
||||
FilesystemNodeZIP(const string& zipfile, const string& virtualfile,
|
||||
shared_ptr<AbstractFSNode> realnode);
|
||||
FilesystemNodeZIP(const string& zipfile, const string& virtualpath,
|
||||
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);
|
||||
|
||||
friend ostream& operator<<(ostream& os, const FilesystemNodeZIP& node)
|
||||
{
|
||||
os << "_zipFile: " << node._zipFile << endl
|
||||
<< "_virtualFile: " << node._virtualFile << endl
|
||||
<< "_virtualPath: " << node._virtualPath << endl
|
||||
<< "_path: " << node._path << endl
|
||||
<< "_shortPath: " << node._shortPath << endl;
|
||||
return os;
|
||||
|
@ -95,18 +95,35 @@ class FilesystemNodeZIP : public AbstractFSNode
|
|||
};
|
||||
|
||||
shared_ptr<AbstractFSNode> _realNode;
|
||||
string _zipFile, _virtualFile;
|
||||
string _path, _shortPath;
|
||||
string _zipFile, _virtualPath;
|
||||
string _name, _path, _shortPath;
|
||||
zip_error _error;
|
||||
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 ZipHandler& open(const string& file)
|
||||
inline static ZipHandler& open(const string& file)
|
||||
{
|
||||
myZipHandler->open(file);
|
||||
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
|
||||
|
|
|
@ -27,7 +27,7 @@
|
|||
ZipHandler::ZipHandler()
|
||||
: myZip(nullptr)
|
||||
{
|
||||
for(int cachenum = 0; cachenum < ZIP_CACHE_SIZE; cachenum++)
|
||||
for(int cachenum = 0; cachenum < ZIP_CACHE_SIZE; ++cachenum)
|
||||
myZipCache[cachenum] = nullptr;
|
||||
}
|
||||
|
||||
|
@ -53,7 +53,7 @@ void ZipHandler::open(const string& filename)
|
|||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||
void ZipHandler::reset()
|
||||
{
|
||||
/* reset the position and go from there */
|
||||
// Reset the position and go from there
|
||||
if(myZip)
|
||||
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
|
||||
-------------------------------------------------*/
|
||||
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;
|
||||
uInt32 read_length;
|
||||
zip_file *newzip;
|
||||
char *string;
|
||||
zip_file* newzip;
|
||||
char* string;
|
||||
int cachenum;
|
||||
bool success;
|
||||
|
||||
/* ensure we start with a NULL result */
|
||||
// Ensure we start with a NULL result
|
||||
*zip = nullptr;
|
||||
|
||||
/* see if we are in the cache, and reopen if so */
|
||||
for(cachenum = 0; cachenum < ZIP_CACHE_SIZE; cachenum++)
|
||||
// See if we are in the cache, and reopen if so
|
||||
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
|
||||
from the cache */
|
||||
// If we have a valid entry and it matches our filename, use it and remove
|
||||
// from the cache
|
||||
if(cached != nullptr && cached->filename != nullptr &&
|
||||
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 */
|
||||
newzip = (zip_file *)malloc(sizeof(*newzip));
|
||||
// Allocate memory for the zip_file structure
|
||||
newzip = (zip_file*)malloc(sizeof(*newzip));
|
||||
if (newzip == nullptr)
|
||||
return ZIPERR_OUT_OF_MEMORY;
|
||||
memset(newzip, 0, sizeof(*newzip));
|
||||
|
||||
/* open the file */
|
||||
// Open the file
|
||||
if(!stream_open(filename, &newzip->file, newzip->length))
|
||||
{
|
||||
ziperr = ZIPERR_FILE_ERROR;
|
||||
goto error;
|
||||
}
|
||||
|
||||
/* read ecd data */
|
||||
// Read ecd data
|
||||
ziperr = read_ecd(newzip);
|
||||
if(ziperr != ZIPERR_NONE)
|
||||
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 ||
|
||||
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;
|
||||
}
|
||||
|
||||
/* allocate memory for the central directory */
|
||||
newzip->cd = (uInt8 *)malloc(newzip->ecd.cd_size + 1);
|
||||
// Allocate memory for the central directory
|
||||
newzip->cd = (uInt8*)malloc(newzip->ecd.cd_size + 1);
|
||||
if(newzip->cd == nullptr)
|
||||
{
|
||||
ziperr = ZIPERR_OUT_OF_MEMORY;
|
||||
goto error;
|
||||
}
|
||||
|
||||
/* read the central directory */
|
||||
// Read the central directory
|
||||
success = stream_read(newzip->file, newzip->cd, newzip->ecd.cd_start_disk_offset,
|
||||
newzip->ecd.cd_size, read_length);
|
||||
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;
|
||||
}
|
||||
|
||||
/* make a copy of the filename for caching purposes */
|
||||
string = (char *)malloc(strlen(filename) + 1);
|
||||
// Make a copy of the filename for caching purposes
|
||||
string = (char*)malloc(strlen(filename) + 1);
|
||||
if (string == nullptr)
|
||||
{
|
||||
ziperr = ZIPERR_OUT_OF_MEMORY;
|
||||
|
@ -288,24 +288,24 @@ error:
|
|||
zip_file_close - close a ZIP file and add it
|
||||
to the cache
|
||||
-------------------------------------------------*/
|
||||
void ZipHandler::zip_file_close(zip_file *zip)
|
||||
void ZipHandler::zip_file_close(zip_file* zip)
|
||||
{
|
||||
int cachenum;
|
||||
|
||||
/* close the open files */
|
||||
// Close the open files
|
||||
if(zip->file)
|
||||
stream_close(&zip->file);
|
||||
|
||||
/* find the first NULL entry in the cache */
|
||||
for(cachenum = 0; cachenum < ZIP_CACHE_SIZE; cachenum++)
|
||||
if (myZipCache[cachenum] == nullptr)
|
||||
// Find the first NULL entry in the cache
|
||||
for(cachenum = 0; cachenum < ZIP_CACHE_SIZE; ++cachenum)
|
||||
if(myZipCache[cachenum] == nullptr)
|
||||
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)
|
||||
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)
|
||||
memmove(&myZipCache[1], &myZipCache[0], cachenum * sizeof(myZipCache[0]));
|
||||
myZipCache[0] = zip;
|
||||
|
@ -316,15 +316,17 @@ void ZipHandler::zip_file_close(zip_file *zip)
|
|||
zip_file_cache_clear - clear the ZIP file
|
||||
cache and free all memory
|
||||
-------------------------------------------------*/
|
||||
void ZipHandler::zip_file_cache_clear(void)
|
||||
void ZipHandler::zip_file_cache_clear()
|
||||
{
|
||||
/* clear call cache entries */
|
||||
for(int cachenum = 0; cachenum < ZIP_CACHE_SIZE; cachenum++)
|
||||
// Clear call cache entries
|
||||
for(int cachenum = 0; cachenum < ZIP_CACHE_SIZE; ++cachenum)
|
||||
{
|
||||
if(myZipCache[cachenum] != nullptr)
|
||||
{
|
||||
free_zip_file(myZipCache[cachenum]);
|
||||
myZipCache[cachenum] = nullptr;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
@ -336,20 +338,20 @@ void ZipHandler::zip_file_cache_clear(void)
|
|||
zip_file_next_entry - return the next entry
|
||||
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)
|
||||
{
|
||||
zip->header.raw[ZIPCFN + zip->header.filename_length] = zip->header.saved;
|
||||
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)
|
||||
return nullptr;
|
||||
|
||||
/* extract file header info */
|
||||
// Extract file header info
|
||||
zip->header.raw = zip->cd + zip->cd_pos;
|
||||
zip->header.rawlength = ZIPCFN;
|
||||
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.external_attributes = read_dword(zip->header.raw + ZIPEXT);
|
||||
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.extra_field_length;
|
||||
zip->header.rawlength += zip->header.file_comment_length;
|
||||
if(zip->cd_pos + zip->header.rawlength > zip->ecd.cd_size)
|
||||
return nullptr;
|
||||
|
||||
/* NULL terminate the filename */
|
||||
// NULL terminate the filename
|
||||
zip->header.saved = zip->header.raw[ZIPCFN + zip->header.filename_length];
|
||||
zip->header.raw[ZIPCFN + zip->header.filename_length] = 0;
|
||||
|
||||
/* advance the position */
|
||||
// Advance the position
|
||||
zip->cd_pos += zip->header.rawlength;
|
||||
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
|
||||
-------------------------------------------------*/
|
||||
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;
|
||||
uInt64 offset;
|
||||
|
||||
/* if we don't have enough buffer, error */
|
||||
// If we don't have enough buffer, error
|
||||
if(length < zip->header.uncompressed_length)
|
||||
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)
|
||||
return ZIPERR_UNSUPPORTED;
|
||||
|
||||
/* get the compressed data offset */
|
||||
ziperr = get_compressed_data_offset(zip, &offset);
|
||||
// Get the compressed data offset
|
||||
ziperr = get_compressed_data_offset(zip, offset);
|
||||
if(ziperr != ZIPERR_NONE)
|
||||
return ziperr;
|
||||
|
||||
/* handle compression types */
|
||||
// Handle compression types
|
||||
switch(zip->header.compression)
|
||||
{
|
||||
case 0:
|
||||
|
@ -436,14 +438,14 @@ ZipHandler::zip_error
|
|||
free_zip_file - free all the data for a
|
||||
zip_file
|
||||
-------------------------------------------------*/
|
||||
void ZipHandler::free_zip_file(zip_file *zip)
|
||||
void ZipHandler::free_zip_file(zip_file* zip)
|
||||
{
|
||||
if(zip != nullptr)
|
||||
{
|
||||
if(zip->file)
|
||||
stream_close(&zip->file);
|
||||
if(zip->filename != nullptr)
|
||||
free((void *)zip->filename);
|
||||
free((void*)zip->filename);
|
||||
if(zip->ecd.raw != nullptr)
|
||||
free(zip->ecd.raw);
|
||||
if(zip->cd != nullptr)
|
||||
|
@ -460,27 +462,27 @@ void ZipHandler::free_zip_file(zip_file *zip)
|
|||
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;
|
||||
uInt8 *buffer;
|
||||
uInt8* buffer;
|
||||
|
||||
/* we may need multiple tries */
|
||||
// We may need multiple tries
|
||||
while(buflen < 65536)
|
||||
{
|
||||
uInt32 read_length;
|
||||
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)
|
||||
buflen = (uInt32)zip->length;
|
||||
|
||||
/* allocate buffer */
|
||||
buffer = (uInt8 *)malloc(buflen + 1);
|
||||
// Allocate buffer
|
||||
buffer = (uInt8*)malloc(buflen + 1);
|
||||
if(buffer == nullptr)
|
||||
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,
|
||||
buflen, read_length);
|
||||
if(!success || read_length != buflen)
|
||||
|
@ -489,24 +491,24 @@ ZipHandler::zip_error ZipHandler::read_ecd(zip_file *zip)
|
|||
return ZIPERR_FILE_ERROR;
|
||||
}
|
||||
|
||||
/* find the ECD signature */
|
||||
// Find the ECD signature
|
||||
for(offset = buflen - 22; offset >= 0; offset--)
|
||||
if(buffer[offset + 0] == 'P' && buffer[offset + 1] == 'K' &&
|
||||
buffer[offset + 2] == 0x05 && buffer[offset + 3] == 0x06)
|
||||
break;
|
||||
|
||||
/* if we found it, fill out the data */
|
||||
// If we found it, fill out the data
|
||||
if(offset >= 0)
|
||||
{
|
||||
/* reuse the buffer as our ECD buffer */
|
||||
// Reuse the buffer as our ECD buffer
|
||||
zip->ecd.raw = buffer;
|
||||
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);
|
||||
zip->ecd.raw[zip->ecd.rawlength] = 0;
|
||||
|
||||
/* extract ecd info */
|
||||
// Extract ecd info
|
||||
zip->ecd.signature = read_dword(zip->ecd.raw + ZIPESIG);
|
||||
zip->ecd.disk_number = read_word (zip->ecd.raw + ZIPEDSK);
|
||||
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;
|
||||
}
|
||||
|
||||
/* didn't find it; free this buffer and expand our search */
|
||||
// Didn't find it; free this buffer and expand our search
|
||||
free(buffer);
|
||||
if(buflen < zip->length)
|
||||
buflen *= 2;
|
||||
|
@ -534,24 +536,24 @@ ZipHandler::zip_error ZipHandler::read_ecd(zip_file *zip)
|
|||
offset of the compressed data
|
||||
-------------------------------------------------*/
|
||||
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;
|
||||
|
||||
/* 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))
|
||||
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,
|
||||
ZIPNAME, read_length);
|
||||
if(!success || read_length != ZIPNAME)
|
||||
return success ? ZIPERR_FILE_TRUNCATED : ZIPERR_FILE_ERROR;
|
||||
|
||||
/* compute the final offset */
|
||||
*offset = zip->header.local_header_offset + ZIPNAME;
|
||||
*offset += read_word(zip->buffer + ZIPFNLN);
|
||||
*offset += read_word(zip->buffer + ZIPXTRALN);
|
||||
// Compute the final offset
|
||||
offset = zip->header.local_header_offset + ZIPNAME;
|
||||
offset += read_word(zip->buffer + ZIPFNLN);
|
||||
offset += read_word(zip->buffer + ZIPXTRALN);
|
||||
|
||||
return ZIPERR_NONE;
|
||||
}
|
||||
|
@ -565,14 +567,14 @@ ZipHandler::zip_error
|
|||
type 0 data (which is uncompressed)
|
||||
-------------------------------------------------*/
|
||||
ZipHandler::zip_error
|
||||
ZipHandler::decompress_data_type_0(zip_file *zip, uInt64 offset,
|
||||
void *buffer, uInt32 length)
|
||||
ZipHandler::decompress_data_type_0(zip_file* zip, uInt64 offset,
|
||||
void* buffer, uInt32 length)
|
||||
{
|
||||
uInt32 read_length;
|
||||
|
||||
/* the data is uncompressed; just read it */
|
||||
bool success = stream_read(zip->file, buffer, offset, zip->header.compressed_length,
|
||||
read_length);
|
||||
// The data is uncompressed; just read it
|
||||
bool success = stream_read(zip->file, buffer, offset,
|
||||
zip->header.compressed_length, read_length);
|
||||
if(!success)
|
||||
return ZIPERR_FILE_ERROR;
|
||||
else if(read_length != zip->header.compressed_length)
|
||||
|
@ -586,8 +588,8 @@ ZipHandler::zip_error
|
|||
type 8 data (which is deflated)
|
||||
-------------------------------------------------*/
|
||||
ZipHandler::zip_error
|
||||
ZipHandler::decompress_data_type_8(zip_file *zip, uInt64 offset,
|
||||
void *buffer, uInt32 length)
|
||||
ZipHandler::decompress_data_type_8(zip_file* zip, uInt64 offset,
|
||||
void* buffer, uInt32 length)
|
||||
{
|
||||
uInt32 input_remaining = zip->header.compressed_length;
|
||||
uInt32 read_length;
|
||||
|
@ -597,25 +599,25 @@ ZipHandler::zip_error
|
|||
#if 0
|
||||
// TODO - check newer versions of ZIP, and determine why this specific
|
||||
// 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)
|
||||
return ZIPERR_UNSUPPORTED;
|
||||
#endif
|
||||
|
||||
/* reset the stream */
|
||||
// Reset the stream
|
||||
memset(&stream, 0, sizeof(stream));
|
||||
stream.next_out = (Bytef *)buffer;
|
||||
stream.avail_out = length;
|
||||
|
||||
/* initialize the decompressor */
|
||||
// Initialize the decompressor
|
||||
zerr = inflateInit2(&stream, -MAX_WBITS);
|
||||
if(zerr != Z_OK)
|
||||
return ZIPERR_DECOMPRESS_ERROR;
|
||||
|
||||
/* loop until we're done */
|
||||
while(1)
|
||||
// Loop until we're done
|
||||
for(;;)
|
||||
{
|
||||
/* read in the next chunk of data */
|
||||
// Read in the next chunk of data
|
||||
bool success = stream_read(zip->file, zip->buffer, offset,
|
||||
BSPF_min(input_remaining, (uInt32)sizeof(zip->buffer)),
|
||||
read_length);
|
||||
|
@ -626,23 +628,23 @@ ZipHandler::zip_error
|
|||
}
|
||||
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)
|
||||
{
|
||||
inflateEnd(&stream);
|
||||
return ZIPERR_FILE_TRUNCATED;
|
||||
}
|
||||
|
||||
/* fill out the input data */
|
||||
// Fill out the input data
|
||||
stream.next_in = zip->buffer;
|
||||
stream.avail_in = 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)
|
||||
stream.avail_in++;
|
||||
|
||||
/* now inflate */
|
||||
// Now inflate
|
||||
zerr = inflate(&stream, Z_NO_FLUSH);
|
||||
if(zerr == Z_STREAM_END)
|
||||
break;
|
||||
|
@ -653,12 +655,12 @@ ZipHandler::zip_error
|
|||
}
|
||||
}
|
||||
|
||||
/* finish decompression */
|
||||
// Finish decompression
|
||||
zerr = inflateEnd(&stream);
|
||||
if(zerr != Z_OK)
|
||||
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)
|
||||
return ZIPERR_DECOMPRESS_ERROR;
|
||||
|
||||
|
|
|
@ -225,22 +225,22 @@ class ZipHandler
|
|||
/* ----- ZIP file access ----- */
|
||||
|
||||
/* 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) */
|
||||
void zip_file_close(zip_file *zip);
|
||||
void zip_file_close(zip_file* zip);
|
||||
|
||||
/* clear out all open ZIP files from the cache */
|
||||
void zip_file_cache_clear(void);
|
||||
void zip_file_cache_clear();
|
||||
|
||||
|
||||
/* ----- contained file access ----- */
|
||||
|
||||
/* 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 */
|
||||
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)
|
||||
{
|
||||
|
@ -253,17 +253,17 @@ class ZipHandler
|
|||
}
|
||||
|
||||
/* cache management */
|
||||
static void free_zip_file(zip_file *zip);
|
||||
static void free_zip_file(zip_file* zip);
|
||||
|
||||
/* ZIP file parsing */
|
||||
static zip_error read_ecd(zip_file *zip);
|
||||
static zip_error get_compressed_data_offset(zip_file *zip, uInt64 *offset);
|
||||
static zip_error read_ecd(zip_file* zip);
|
||||
static zip_error get_compressed_data_offset(zip_file* zip, uInt64& offset);
|
||||
|
||||
/* decompression interfaces */
|
||||
static zip_error decompress_data_type_0(zip_file *zip, uInt64 offset,
|
||||
void *buffer, uInt32 length);
|
||||
static zip_error decompress_data_type_8(zip_file *zip, uInt64 offset,
|
||||
void *buffer, uInt32 length);
|
||||
static zip_error decompress_data_type_0(zip_file* zip, uInt64 offset,
|
||||
void* buffer, uInt32 length);
|
||||
static zip_error decompress_data_type_8(zip_file* zip, uInt64 offset,
|
||||
void* buffer, uInt32 length);
|
||||
|
||||
private:
|
||||
zip_file* myZip;
|
||||
|
|
|
@ -19,31 +19,6 @@
|
|||
|
||||
#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()
|
||||
{
|
||||
|
|
|
@ -91,6 +91,30 @@ class FilesystemNodePOSIX : public AbstractFSNode
|
|||
* using the stat() function.
|
||||
*/
|
||||
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
|
||||
|
|
|
@ -101,7 +101,7 @@ rm -rf $RPM_BUILD_DIR/%{name}-%{version}
|
|||
%_datadir/icons/large/%{name}.png
|
||||
|
||||
%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
|
||||
|
||||
* Tue Oct 28 2014 Stephen Anthony <stephena@users.sf.net> 4.2-1
|
||||
|
|
Loading…
Reference in New Issue