mirror of
https://github.com/VCMP-SqMod/SqMod.git
synced 2024-11-14 19:57:17 +01:00
4a6bfc086c
Switched to POCO library for unified platform/library interface. Deprecated the external module API. It was creating more problems than solving. Removed most built-in libraries in favor of system libraries for easier maintenance. Cleaned and secured code with help from static analyzers.
163 lines
7.4 KiB
Plaintext
163 lines
7.4 KiB
Plaintext
POCO Zip User Guide
|
|
POCO Zip Library
|
|
|
|
!!!Introduction
|
|
POCO Zip adds support for parsing and creating Zip files. It offers the following features:
|
|
* decompress from local files
|
|
* decompress from network files while they are downloaded
|
|
* compress to local files
|
|
* compress directly to a network destination
|
|
|
|
!!Restrictions
|
|
* POCO Zip does not support the DEFLATE64 algorithm.
|
|
* encrypted files are not supported
|
|
|
|
!!!Main Classes
|
|
Most users will work with two common classes: <*Compress*> and <*Decompress*>
|
|
|
|
!!Compress
|
|
Compress is a helper class that simplifies creation of Zip files.
|
|
Creating a Zip file is a basically a three-step process:
|
|
* Create the Compress object: Specify the output stream and define if it is seekable (set to true for local files, to false for network files)
|
|
|
|
Compress(std::ostream& out, bool seekableOut);
|
|
----
|
|
* Add entries: either add single files or directory entries
|
|
|
|
void addFile(std::istream& input,
|
|
const Poco::DateTime& lastModifiedAt,
|
|
const Poco::Path& fileName,
|
|
ZipCommon::CompressionMethod cm = ZipCommon::CM_DEFLATE,
|
|
ZipCommon::CompressionLevel cl = ZipCommon::CL_MAXIMUM);
|
|
/// Adds a single file to the Zip File. fileName must not be a directory name.
|
|
|
|
void addFile(const Poco::Path& file,
|
|
const Poco::Path& fileName,
|
|
ZipCommon::CompressionMethod cm = ZipCommon::CM_DEFLATE,
|
|
ZipCommon::CompressionLevel cl = ZipCommon::CL_MAXIMUM);
|
|
/// Adds a single file to the Zip File. fileName must not be a directory name. The file must exist physically!
|
|
|
|
void addDirectory(const Poco::Path& entryName, const Poco::DateTime& lastModifiedAt);
|
|
/// Adds a directory entry excluding all children to the Zip file, entryName must not be empty.
|
|
|
|
void addRecursive(const Poco::Path& entry,
|
|
ZipCommon::CompressionLevel cl = ZipCommon::CL_MAXIMUM,
|
|
bool excludeRoot = true,
|
|
const Poco::Path& name = Poco::Path());
|
|
/// Adds a directory entry recursively to the zip file, set excludeRoot to false to exclude the parent directory.
|
|
/// The name specifies under which path the entries are added in the Zip file.
|
|
----
|
|
Note that one must always define a name when adding a file entry, otherwise the compresser can not decide if the file should be added with an absolute or a relative path.
|
|
Assume you are adding the file <*c:\\data\\hello.txt*> twice to a Zip:
|
|
|
|
// MUST use binary!
|
|
std::ofstream out("test.zip", std::ios::binary);
|
|
Compress c(out, true);
|
|
Poco::Path aFile("c:\\data\\hello.txt");
|
|
c.addFile(theFile, "hello.txt");
|
|
c.addFile(theFile, theFile);
|
|
c.close(); // MUST be done to finalize the Zip file
|
|
----
|
|
A Zip file stores entries internally in UNIX path style. The Zip file created above will contain the following entries:
|
|
|
|
hello.txt
|
|
data/
|
|
data/hello.txt
|
|
----
|
|
The directory entry <*data/*> was automatically added.
|
|
|
|
When adding directories recursively, the same principle applies. You specify the root directory that should be added and an optional path name where entries are added in the Zip file.
|
|
Assume you have the following directory structure:
|
|
|
|
data/
|
|
run1/
|
|
result1.txt
|
|
run2/
|
|
result2.txt
|
|
----
|
|
The following call will add all subdirectories and all files of data to the Zip but not the root entry <*data*>:
|
|
|
|
Poco::Path data("data");
|
|
data.makeDirectory();
|
|
c.addRecursive(data);
|
|
----
|
|
Or if you want the files to be added under the directory name <*20070401*> (you basically <*rename*> data to 20070401):
|
|
|
|
Poco::Path data("data");
|
|
Poco::Path name("20070401);
|
|
data.makeDirectory();
|
|
name.makeDirectory();
|
|
c.addRecursive(data, ZipCommon::CL_NORMAL, false, name);
|
|
----
|
|
Note that <*makeDirectory*> does not create a directory, it simply assures that the Path is treated as a directory not as a file.
|
|
Also using NORMAL compression instead of MAXIMUM (which is the default) has the benefit of improved performance.
|
|
To get notified about the entries that are added during <*addRecursive*> register to the <!EDone!> event of the Compress object:
|
|
|
|
Poco::FIFOEvent<const ZipLocalFileHeader> EDone;
|
|
----
|
|
* Closing the Zip file: It is mandatory to manually close Compress objects. This guarantees that the Zip directory is written, thus creating a valid Zip file. It is safe to call <*close*> multiple times, only the first call takes effect.
|
|
|
|
ZipArchive close();
|
|
----
|
|
<*close*> returns a ZipArchive which describes all entries inside a Zip file.
|
|
|
|
!!Decompress
|
|
Decompress can be used to decompress all files from a Zip file or to decompress single files only.
|
|
|
|
!Decompress All
|
|
The following sample code shows how all entries can be extracted from a Zip file:
|
|
|
|
std::ifstream inp("test.zip", std::ios::binary);
|
|
poco_assert (inp);
|
|
// decompress to current working dir
|
|
Decompress dec(inp, Poco::Path());
|
|
// if an error happens invoke the ZipTest::onDecompressError method
|
|
dec.EError += Poco::Delegate<ZipTest, std::pair<const Poco::Zip::ZipLocalFileHeader, const std::string> >(this, &ZipTest::onDecompressError);
|
|
dec.decompressAllFiles();
|
|
dec.EError -= Poco::Delegate<ZipTest, std::pair<const Poco::Zip::ZipLocalFileHeader, const std::string> >(this, &ZipTest::onDecompressError);
|
|
----
|
|
The onDecompressError method:
|
|
|
|
void ZipTest::onDecompressError(const void* pSender, std::pair<const Poco::Zip::ZipLocalFileHeader, const std::string>& info)
|
|
{
|
|
// inform user about error
|
|
[...]
|
|
}
|
|
----
|
|
Decompressing directly from the net works similar:
|
|
|
|
Poco::URI uri("http://www.appinf.com/test.zip");
|
|
HTTPClientSession session(uri.getHost(), uri.getPort());
|
|
HTTPRequest req(HTTPRequest::HTTP_GET, path, HTTPMessage::HTTP_1_1);
|
|
session.sendRequest(req);
|
|
HTTPResponse res;
|
|
std::istream& rs = session.receiveResponse(res);
|
|
Decompress dec(rs, Poco::Path());
|
|
// if an error happens invoke the ZipTest::onDecompressError method
|
|
dec.EError += Poco::Delegate<ZipTest, std::pair<const Poco::Zip::ZipLocalFileHeader, const std::string> >(this, &ZipTest::onDecompressError);
|
|
dec.decompressAllFiles();
|
|
dec.EError -= Poco::Delegate<ZipTest, std::pair<const Poco::Zip::ZipLocalFileHeader, const std::string> >(this, &ZipTest::onDecompressError);
|
|
----
|
|
Furthermore, Decompress supports additional parameters:
|
|
|
|
Decompress(std::istream& in, const Poco::Path& outputDir, bool flattenDirs = false, bool keepIncompleteFiles = false);
|
|
----
|
|
If <*flattenDirs*> is set to true no subdirs are extracted, if <*keepIncompleteFiles*> is set to true, corrupt files (i.e. wrong CRC, wrong size on disk) will not be deleted.
|
|
|
|
!Decompress Single Files
|
|
To decompress single files you must first parse a Zip file, and then decompress the file which happens transparently inside the <*ZipInputStream*>:
|
|
|
|
std::ifstream inp("test.zip", std::ios::binary);
|
|
poco_assert (inp);
|
|
ZipArchive arch(inp);
|
|
ZipArchive::FileHeaders::const_iterator it = arch.findHeader("data/hello.txt");
|
|
poco_assert (it != arch.headerEnd());
|
|
inp.clear();
|
|
ZipInputStream zipin(inp, it->second);
|
|
std::ostringstream out(std::ios::binary);
|
|
Poco::StreamCopier::copyStream(zipin, out);
|
|
----
|
|
Note that this will only work with local files which allow us to seek inside the file.
|
|
Directly extracting single entries from a network file is currently not possible via the Decompress class.
|
|
|