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
===========================================================================
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.

View File

@ -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>

View File

@ -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));
}
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

View File

@ -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

View File

@ -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;

View File

@ -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;

View File

@ -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()
{

View File

@ -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

View File

@ -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