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
|
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.
|
||||||
|
|
|
@ -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>
|
||||||
|
|
||||||
|
|
|
@ -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));
|
||||||
}
|
}
|
||||||
|
|
||||||
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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;
|
||||||
|
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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()
|
||||||
{
|
{
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
Loading…
Reference in New Issue