Zip: complete merge to 1.4.2

This commit is contained in:
Marian Krivos
2011-09-14 15:41:51 +00:00
parent 7e5c3a13d6
commit 9b3117e6c5
41 changed files with 5172 additions and 1845 deletions

View File

@@ -1,322 +1,323 @@
//
// Compress.cpp
//
// $Id: //poco/Main/Zip/src/Compress.cpp#8 $
//
// Library: Zip
// Package: Zip
// Module: Compress
//
// Copyright (c) 2007, Applied Informatics Software Engineering GmbH.
// and Contributors.
//
// Permission is hereby granted, free of charge, to any person or organization
// obtaining a copy of the software and accompanying documentation covered by
// this license (the "Software") to use, reproduce, display, distribute,
// execute, and transmit the Software, and to prepare derivative works of the
// Software, and to permit third-parties to whom the Software is furnished to
// do so, all subject to the following:
//
// The copyright notices in the Software and this entire statement, including
// the above license grant, this restriction and the following disclaimer,
// must be included in all copies of the Software, in whole or in part, and
// all derivative works of the Software, unless such copies or derivative
// works are solely in the form of machine-executable object code generated by
// a source language processor.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
// SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
// FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
// ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
//
#include "Poco/Zip/Compress.h"
#include "Poco/Zip/ZipLocalFileHeader.h"
#include "Poco/Zip/ZipStream.h"
#include "Poco/Zip/ZipArchiveInfo.h"
#include "Poco/Zip/ZipDataInfo.h"
#include "Poco/Zip/ZipException.h"
#include "Poco/StreamCopier.h"
#include "Poco/File.h"
#include <fstream>
namespace Poco {
namespace Zip {
Compress::Compress(std::ostream& out, bool seekableOut):
_out(out),
_seekableOut(seekableOut),
_files(),
_infos(),
_dirs(),
_offset(0)
{
}
Compress::~Compress()
{
}
void Compress::addEntry(std::istream& in, const Poco::DateTime& lastModifiedAt, const Poco::Path& fileName, ZipCommon::CompressionMethod cm, ZipCommon::CompressionLevel cl)
{
std::string fn = ZipUtil::validZipEntryFileName(fileName);
if (_files.size() >= 65535)
throw ZipException("Maximum number of entries for a ZIP file reached: 65535");
if (!in.good())
throw ZipException("Invalid input stream");
std::streamoff localHeaderOffset = _offset;
ZipLocalFileHeader hdr(fileName, lastModifiedAt, cm, cl);
hdr.setStartPos(localHeaderOffset);
ZipOutputStream zipOut(_out, hdr, _seekableOut);
Poco::StreamCopier::copyStream(in, zipOut);
zipOut.close();
hdr.setStartPos(localHeaderOffset); // reset again now that compressed Size is known
_offset = hdr.getEndPos();
if (hdr.searchCRCAndSizesAfterData())
_offset += ZipDataInfo::getFullHeaderSize();
_files.insert(std::make_pair(fileName.toString(Poco::Path::PATH_UNIX), hdr));
poco_assert (_out);
ZipFileInfo nfo(hdr);
nfo.setOffset(localHeaderOffset);
_infos.insert(std::make_pair(fileName.toString(Poco::Path::PATH_UNIX), nfo));
EDone.notify(this, hdr);
}
void Compress::addFileRaw(std::istream& in, const ZipLocalFileHeader& h, const Poco::Path& fileName)
{
std::string fn = ZipUtil::validZipEntryFileName(fileName);
//bypass the header of the input stream and point to the first byte of the data payload
in.seekg(h.getDataStartPos(), std::ios_base::beg);
if (_files.size() >= 65535)
throw ZipException("Maximum number of entries for a ZIP file reached: 65535");
if (!in.good())
throw ZipException("Invalid input stream");
std::streamoff localHeaderOffset = _offset;
ZipLocalFileHeader hdr(h);
hdr.setFileName(fn, h.isDirectory());
hdr.setStartPos(localHeaderOffset);
//bypass zipoutputstream
//write the header directly
std::string header = hdr.createHeader();
_out.write(header.c_str(), static_cast<std::streamsize>(header.size()));
// now fwd the payload to _out in chunks of size CHUNKSIZE
Poco::UInt32 totalSize = hdr.getCompressedSize();
if (totalSize > 0)
{
Poco::Buffer<char> buffer(COMPRESS_CHUNK_SIZE);
Poco::UInt32 remaining = totalSize;
while(remaining > 0)
{
if (remaining > COMPRESS_CHUNK_SIZE)
{
in.read(buffer.begin(), COMPRESS_CHUNK_SIZE);
std::streamsize n = in.gcount();
poco_assert_dbg (n == COMPRESS_CHUNK_SIZE);
_out.write(buffer.begin(), n);
remaining -= COMPRESS_CHUNK_SIZE;
}
else
{
in.read(buffer.begin(), remaining);
std::streamsize n = in.gcount();
poco_assert_dbg (n == remaining);
_out.write(buffer.begin(), n);
remaining = 0;
}
}
}
//write optional block afterwards
if (hdr.searchCRCAndSizesAfterData())
{
ZipDataInfo info(in, false);
_out.write(info.getRawHeader(), static_cast<std::streamsize>(info.getFullHeaderSize()));
}
hdr.setStartPos(localHeaderOffset); // reset again now that compressed Size is known
_offset = hdr.getEndPos();
if (hdr.searchCRCAndSizesAfterData())
_offset += ZipDataInfo::getFullHeaderSize();
_files.insert(std::make_pair(fileName.toString(Poco::Path::PATH_UNIX), hdr));
poco_assert (_out);
ZipFileInfo nfo(hdr);
nfo.setOffset(localHeaderOffset);
_infos.insert(std::make_pair(fileName.toString(Poco::Path::PATH_UNIX), nfo));
EDone.notify(this, hdr);
}
void Compress::addFile(std::istream& in, const Poco::DateTime& lastModifiedAt, const Poco::Path& fileName, ZipCommon::CompressionMethod cm, ZipCommon::CompressionLevel cl)
{
if (!fileName.isFile())
throw ZipException("Not a file: "+ fileName.toString());
if (fileName.depth() > 1)
{
addDirectory(fileName.parent(), lastModifiedAt);
}
addEntry(in, lastModifiedAt, fileName, cm, cl);
}
void Compress::addFile(const Poco::Path& file, const Poco::Path& fileName, ZipCommon::CompressionMethod cm, ZipCommon::CompressionLevel cl)
{
Poco::File aFile(file);
Poco::File::FileSize size = aFile.getSize();
if (size < 16)
{
cm = ZipCommon::CM_STORE;
cl = ZipCommon::CL_NORMAL;
}
std::ifstream in(file.toString().c_str(), std::ios::binary);
if (!in.good())
throw ZipException("Invalid input stream for " + aFile.path());
if (fileName.depth() > 1)
{
Poco::File aParent(file.parent());
addDirectory(fileName.parent(), aParent.getLastModified());
}
addFile(in, aFile.getLastModified(), fileName, cm, cl);
}
void Compress::addDirectory(const Poco::Path& entryName, const Poco::DateTime& lastModifiedAt)
{
if (!entryName.isDirectory())
throw ZipException("Not a directory: "+ entryName.toString());
std::string fileStr = entryName.toString(Poco::Path::PATH_UNIX);
if (_files.find(fileStr) != _files.end())
return; // ignore duplicate add
if (_files.size() >= 65535)
throw ZipException("Maximum number of entries for a ZIP file reached: 65535");
if (fileStr == "/")
throw ZipException("Illegal entry name /");
if (fileStr.empty())
throw ZipException("Illegal empty entry name");
if (fileStr.find(ZipCommon::ILLEGAL_PATH) != std::string::npos)
throw ZipException("Illegal entry name " + fileStr + " containing " + ZipCommon::ILLEGAL_PATH);
if (entryName.depth() > 1)
{
addDirectory(entryName.parent(), lastModifiedAt);
}
std::streamoff localHeaderOffset = _offset;
ZipCommon::CompressionMethod cm = ZipCommon::CM_STORE;
ZipCommon::CompressionLevel cl = ZipCommon::CL_NORMAL;
ZipLocalFileHeader hdr(entryName, lastModifiedAt, cm, cl);
hdr.setStartPos(localHeaderOffset);
ZipOutputStream zipOut(_out, hdr, _seekableOut);
zipOut.close();
hdr.setStartPos(localHeaderOffset); // reset again now that compressed Size is known
_offset = hdr.getEndPos();
if (hdr.searchCRCAndSizesAfterData())
_offset += ZipDataInfo::getFullHeaderSize();
_files.insert(std::make_pair(entryName.toString(Poco::Path::PATH_UNIX), hdr));
poco_assert (_out);
ZipFileInfo nfo(hdr);
nfo.setOffset(localHeaderOffset);
_infos.insert(std::make_pair(entryName.toString(Poco::Path::PATH_UNIX), nfo));
EDone.notify(this, hdr);
}
void Compress::addRecursive(const Poco::Path& entry, ZipCommon::CompressionLevel cl, bool excludeRoot, const Poco::Path& name)
{
Poco::File aFile(entry);
if (!aFile.isDirectory())
throw ZipException("Not a directory: "+ entry.toString());
Poco::Path aName(name);
aName.makeDirectory();
if (!excludeRoot)
{
if (aName.depth() == 0)
{
Poco::Path tmp(entry);
tmp.makeAbsolute(); // eliminate ../
aName = Poco::Path(tmp[tmp.depth()-1]);
aName.makeDirectory();
}
addDirectory(aName, aFile.getLastModified());
}
// iterate over children
std::vector<std::string> children;
aFile.list(children);
std::vector<std::string>::const_iterator it = children.begin();
std::vector<std::string>::const_iterator itEnd = children.end();
for (; it != itEnd; ++it)
{
Poco::Path realFile(entry, *it);
Poco::Path renamedFile(aName, *it);
Poco::File aFile(realFile);
if (aFile.isDirectory())
{
realFile.makeDirectory();
renamedFile.makeDirectory();
addRecursive(realFile, cl, false, renamedFile);
}
else
{
realFile.makeFile();
renamedFile.makeFile();
addFile(realFile, renamedFile, ZipCommon::CM_DEFLATE, cl);
}
}
}
ZipArchive Compress::close()
{
if (!_dirs.empty())
return ZipArchive(_files, _infos, _dirs);
poco_assert (_infos.size() == _files.size());
poco_assert (_files.size() < 65536);
Poco::UInt32 centralDirStart = _offset;
Poco::UInt32 centralDirSize = 0;
// write all infos
ZipArchive::FileInfos::const_iterator it = _infos.begin();
ZipArchive::FileInfos::const_iterator itEnd = _infos.end();
for (; it != itEnd; ++it)
{
const ZipFileInfo& nfo = it->second;
std::string info(nfo.createHeader());
_out.write(info.c_str(), static_cast<std::streamsize>(info.size()));
Poco::UInt32 entrySize = static_cast<Poco::UInt32>(info.size());
centralDirSize += entrySize;
_offset += entrySize;
}
poco_assert (_out);
Poco::UInt16 numEntries = static_cast<Poco::UInt16>(_infos.size());
ZipArchiveInfo central;
central.setCentralDirectorySize(centralDirSize);
central.setNumberOfEntries(numEntries);
central.setTotalNumberOfEntries(numEntries);
central.setHeaderOffset(centralDirStart);
std::string centr(central.createHeader());
_out.write(centr.c_str(), static_cast<std::streamsize>(centr.size()));
_out.flush();
_dirs.insert(std::make_pair(0, central));
return ZipArchive(_files, _infos, _dirs);
}
} } // namespace Poco::Zip
//
// Compress.cpp
//
// $Id: //poco/Main/Zip/src/Compress.cpp#8 $
//
// Library: Zip
// Package: Zip
// Module: Compress
//
// Copyright (c) 2007, Applied Informatics Software Engineering GmbH.
// and Contributors.
//
// Permission is hereby granted, free of charge, to any person or organization
// obtaining a copy of the software and accompanying documentation covered by
// this license (the "Software") to use, reproduce, display, distribute,
// execute, and transmit the Software, and to prepare derivative works of the
// Software, and to permit third-parties to whom the Software is furnished to
// do so, all subject to the following:
//
// The copyright notices in the Software and this entire statement, including
// the above license grant, this restriction and the following disclaimer,
// must be included in all copies of the Software, in whole or in part, and
// all derivative works of the Software, unless such copies or derivative
// works are solely in the form of machine-executable object code generated by
// a source language processor.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
// SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
// FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
// ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
//
#include "Poco/Zip/Compress.h"
#include "Poco/Zip/ZipLocalFileHeader.h"
#include "Poco/Zip/ZipStream.h"
#include "Poco/Zip/ZipArchiveInfo.h"
#include "Poco/Zip/ZipDataInfo.h"
#include "Poco/Zip/ZipException.h"
#include "Poco/StreamCopier.h"
#include "Poco/File.h"
#include "Poco/FileStream.h"
namespace Poco {
namespace Zip {
Compress::Compress(std::ostream& out, bool seekableOut):
_out(out),
_seekableOut(seekableOut),
_files(),
_infos(),
_dirs(),
_offset(0)
{
}
Compress::~Compress()
{
}
void Compress::addEntry(std::istream& in, const Poco::DateTime& lastModifiedAt, const Poco::Path& fileName, ZipCommon::CompressionMethod cm, ZipCommon::CompressionLevel cl)
{
std::string fn = ZipUtil::validZipEntryFileName(fileName);
if (_files.size() >= 65535)
throw ZipException("Maximum number of entries for a ZIP file reached: 65535");
if (!in.good())
throw ZipException("Invalid input stream");
std::streamoff localHeaderOffset = _offset;
ZipLocalFileHeader hdr(fileName, lastModifiedAt, cm, cl);
hdr.setStartPos(localHeaderOffset);
ZipOutputStream zipOut(_out, hdr, _seekableOut);
Poco::StreamCopier::copyStream(in, zipOut);
zipOut.close();
hdr.setStartPos(localHeaderOffset); // reset again now that compressed Size is known
_offset = hdr.getEndPos();
if (hdr.searchCRCAndSizesAfterData())
_offset += ZipDataInfo::getFullHeaderSize();
_files.insert(std::make_pair(fileName.toString(Poco::Path::PATH_UNIX), hdr));
poco_assert (_out);
ZipFileInfo nfo(hdr);
nfo.setOffset(localHeaderOffset);
_infos.insert(std::make_pair(fileName.toString(Poco::Path::PATH_UNIX), nfo));
EDone.notify(this, hdr);
}
void Compress::addFileRaw(std::istream& in, const ZipLocalFileHeader& h, const Poco::Path& fileName)
{
std::string fn = ZipUtil::validZipEntryFileName(fileName);
//bypass the header of the input stream and point to the first byte of the data payload
in.seekg(h.getDataStartPos(), std::ios_base::beg);
if (_files.size() >= 65535)
throw ZipException("Maximum number of entries for a ZIP file reached: 65535");
if (!in.good())
throw ZipException("Invalid input stream");
std::streamoff localHeaderOffset = _offset;
ZipLocalFileHeader hdr(h);
hdr.setFileName(fn, h.isDirectory());
hdr.setStartPos(localHeaderOffset);
//bypass zipoutputstream
//write the header directly
std::string header = hdr.createHeader();
_out.write(header.c_str(), static_cast<std::streamsize>(header.size()));
// now fwd the payload to _out in chunks of size CHUNKSIZE
Poco::UInt32 totalSize = hdr.getCompressedSize();
if (totalSize > 0)
{
Poco::Buffer<char> buffer(COMPRESS_CHUNK_SIZE);
Poco::UInt32 remaining = totalSize;
while(remaining > 0)
{
if (remaining > COMPRESS_CHUNK_SIZE)
{
in.read(buffer.begin(), COMPRESS_CHUNK_SIZE);
std::streamsize n = in.gcount();
poco_assert_dbg (n == COMPRESS_CHUNK_SIZE);
_out.write(buffer.begin(), n);
remaining -= COMPRESS_CHUNK_SIZE;
}
else
{
in.read(buffer.begin(), remaining);
std::streamsize n = in.gcount();
poco_assert_dbg (n == remaining);
_out.write(buffer.begin(), n);
remaining = 0;
}
}
}
//write optional block afterwards
if (hdr.searchCRCAndSizesAfterData())
{
ZipDataInfo info(in, false);
_out.write(info.getRawHeader(), static_cast<std::streamsize>(info.getFullHeaderSize()));
}
hdr.setStartPos(localHeaderOffset); // reset again now that compressed Size is known
_offset = hdr.getEndPos();
if (hdr.searchCRCAndSizesAfterData())
_offset += ZipDataInfo::getFullHeaderSize();
_files.insert(std::make_pair(fileName.toString(Poco::Path::PATH_UNIX), hdr));
poco_assert (_out);
ZipFileInfo nfo(hdr);
nfo.setOffset(localHeaderOffset);
_infos.insert(std::make_pair(fileName.toString(Poco::Path::PATH_UNIX), nfo));
EDone.notify(this, hdr);
}
void Compress::addFile(std::istream& in, const Poco::DateTime& lastModifiedAt, const Poco::Path& fileName, ZipCommon::CompressionMethod cm, ZipCommon::CompressionLevel cl)
{
if (!fileName.isFile())
throw ZipException("Not a file: "+ fileName.toString());
if (fileName.depth() > 1)
{
addDirectory(fileName.parent(), lastModifiedAt);
}
addEntry(in, lastModifiedAt, fileName, cm, cl);
}
void Compress::addFile(const Poco::Path& file, const Poco::Path& fileName, ZipCommon::CompressionMethod cm, ZipCommon::CompressionLevel cl)
{
Poco::File aFile(file);
Poco::File::FileSize size = aFile.getSize();
if (size < 16)
{
cm = ZipCommon::CM_STORE;
cl = ZipCommon::CL_NORMAL;
}
Poco::FileInputStream in(file.toString());
if (fileName.depth() > 1)
{
Poco::File aParent(file.parent());
addDirectory(fileName.parent(), aParent.getLastModified());
}
addFile(in, aFile.getLastModified(), fileName, cm, cl);
}
void Compress::addDirectory(const Poco::Path& entryName, const Poco::DateTime& lastModifiedAt)
{
if (!entryName.isDirectory())
throw ZipException("Not a directory: "+ entryName.toString());
std::string fileStr = entryName.toString(Poco::Path::PATH_UNIX);
if (_files.find(fileStr) != _files.end())
return; // ignore duplicate add
if (_files.size() >= 65535)
throw ZipException("Maximum number of entries for a ZIP file reached: 65535");
if (fileStr == "/")
throw ZipException("Illegal entry name /");
if (fileStr.empty())
throw ZipException("Illegal empty entry name");
if (fileStr.find(ZipCommon::ILLEGAL_PATH) != std::string::npos)
throw ZipException("Illegal entry name " + fileStr + " containing " + ZipCommon::ILLEGAL_PATH);
if (entryName.depth() > 1)
{
addDirectory(entryName.parent(), lastModifiedAt);
}
std::streamoff localHeaderOffset = _offset;
ZipCommon::CompressionMethod cm = ZipCommon::CM_STORE;
ZipCommon::CompressionLevel cl = ZipCommon::CL_NORMAL;
ZipLocalFileHeader hdr(entryName, lastModifiedAt, cm, cl);
hdr.setStartPos(localHeaderOffset);
ZipOutputStream zipOut(_out, hdr, _seekableOut);
zipOut.close();
hdr.setStartPos(localHeaderOffset); // reset again now that compressed Size is known
_offset = hdr.getEndPos();
if (hdr.searchCRCAndSizesAfterData())
_offset += ZipDataInfo::getFullHeaderSize();
_files.insert(std::make_pair(entryName.toString(Poco::Path::PATH_UNIX), hdr));
poco_assert (_out);
ZipFileInfo nfo(hdr);
nfo.setOffset(localHeaderOffset);
_infos.insert(std::make_pair(entryName.toString(Poco::Path::PATH_UNIX), nfo));
EDone.notify(this, hdr);
}
void Compress::addRecursive(const Poco::Path& entry, ZipCommon::CompressionLevel cl, bool excludeRoot, const Poco::Path& name)
{
Poco::File aFile(entry);
if (!aFile.isDirectory())
throw ZipException("Not a directory: "+ entry.toString());
Poco::Path aName(name);
aName.makeDirectory();
if (!excludeRoot)
{
if (aName.depth() == 0)
{
Poco::Path tmp(entry);
tmp.makeAbsolute(); // eliminate ../
aName = Poco::Path(tmp[tmp.depth()-1]);
aName.makeDirectory();
}
addDirectory(aName, aFile.getLastModified());
}
// iterate over children
std::vector<std::string> children;
aFile.list(children);
std::vector<std::string>::const_iterator it = children.begin();
std::vector<std::string>::const_iterator itEnd = children.end();
for (; it != itEnd; ++it)
{
Poco::Path realFile(entry, *it);
Poco::Path renamedFile(aName, *it);
Poco::File aFile(realFile);
if (aFile.isDirectory())
{
realFile.makeDirectory();
renamedFile.makeDirectory();
addRecursive(realFile, cl, false, renamedFile);
}
else
{
realFile.makeFile();
renamedFile.makeFile();
addFile(realFile, renamedFile, ZipCommon::CM_DEFLATE, cl);
}
}
}
ZipArchive Compress::close()
{
if (!_dirs.empty())
return ZipArchive(_files, _infos, _dirs);
poco_assert (_infos.size() == _files.size());
poco_assert (_files.size() < 65536);
Poco::UInt32 centralDirStart = _offset;
Poco::UInt32 centralDirSize = 0;
// write all infos
ZipArchive::FileInfos::const_iterator it = _infos.begin();
ZipArchive::FileInfos::const_iterator itEnd = _infos.end();
for (; it != itEnd; ++it)
{
const ZipFileInfo& nfo = it->second;
std::string info(nfo.createHeader());
_out.write(info.c_str(), static_cast<std::streamsize>(info.size()));
Poco::UInt32 entrySize = static_cast<Poco::UInt32>(info.size());
centralDirSize += entrySize;
_offset += entrySize;
}
poco_assert (_out);
Poco::UInt16 numEntries = static_cast<Poco::UInt16>(_infos.size());
ZipArchiveInfo central;
central.setCentralDirectorySize(centralDirSize);
central.setNumberOfEntries(numEntries);
central.setTotalNumberOfEntries(numEntries);
central.setHeaderOffset(centralDirStart);
if (!_comment.empty() && _comment.size() <= 65535)
{
central.setZipComment(_comment);
}
std::string centr(central.createHeader());
_out.write(centr.c_str(), static_cast<std::streamsize>(centr.size()));
_out.flush();
_dirs.insert(std::make_pair(0, central));
return ZipArchive(_files, _infos, _dirs);
}
} } // namespace Poco::Zip

View File

@@ -1,193 +1,187 @@
//
// Decompress.cpp
//
//
// Decompress.cpp
//
// $Id: //poco/Main/Zip/src/Decompress.cpp#6 $
//
// Library: Zip
// Package: Zip
// Module: Decompress
//
// Copyright (c) 2007, Applied Informatics Software Engineering GmbH.
// and Contributors.
//
// Permission is hereby granted, free of charge, to any person or organization
// obtaining a copy of the software and accompanying documentation covered by
// this license (the "Software") to use, reproduce, display, distribute,
// execute, and transmit the Software, and to prepare derivative works of the
// Software, and to permit third-parties to whom the Software is furnished to
// do so, all subject to the following:
//
// The copyright notices in the Software and this entire statement, including
// the above license grant, this restriction and the following disclaimer,
// must be included in all copies of the Software, in whole or in part, and
// all derivative works of the Software, unless such copies or derivative
// works are solely in the form of machine-executable object code generated by
// a source language processor.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
// SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
// FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
// ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
//
#include "Poco/Zip/Decompress.h"
#include "Poco/Zip/ZipLocalFileHeader.h"
#include "Poco/Zip/ZipArchive.h"
#include "Poco/Zip/ZipStream.h"
#include "Poco/Zip/ZipException.h"
#include "Poco/File.h"
#include "Poco/Exception.h"
#include "Poco/StreamCopier.h"
#include "Poco/Delegate.h"
#include <fstream>
namespace Poco {
namespace Zip {
Decompress::Decompress(std::istream& in, const Poco::Path& outputDir, bool flattenDirs, bool keepIncompleteFiles):
_in(in),
_outDir(outputDir),
_flattenDirs(flattenDirs),
_keepIncompleteFiles(keepIncompleteFiles),
_mapping()
{
_outDir.makeAbsolute();
_outDir.makeDirectory();
poco_assert (_in.good());
Poco::File tmp(_outDir);
if (!tmp.exists())
{
tmp.createDirectories();
}
if (!tmp.isDirectory())
throw Poco::IOException("Failed to create/open directory: " + _outDir.toString());
EOk += Poco::Delegate<Decompress, std::pair<const ZipLocalFileHeader, const Poco::Path> >(this, &Decompress::onOk);
}
Decompress::~Decompress()
{
EOk -= Poco::Delegate<Decompress, std::pair<const ZipLocalFileHeader, const Poco::Path> >(this, &Decompress::onOk);
}
ZipArchive Decompress::decompressAllFiles()
{
poco_assert (_mapping.empty());
ZipArchive arch(_in, *this);
return arch;
}
bool Decompress::handleZipEntry(std::istream& zipStream, const ZipLocalFileHeader& hdr)
{
if (hdr.isDirectory())
{
// directory have 0 size, nth to read
if (!_flattenDirs)
{
std::string dirName = hdr.getFileName();
if (dirName.find(ZipCommon::ILLEGAL_PATH) != std::string::npos)
throw ZipException("Illegal entry name " + dirName + " containing " + ZipCommon::ILLEGAL_PATH);
Poco::Path dir(_outDir, dirName);
dir.makeDirectory();
Poco::File aFile(dir);
aFile.createDirectories();
}
return true;
}
try
{
std::string fileName = hdr.getFileName();
if (_flattenDirs)
{
// remove path info
Poco::Path p(fileName);
p.makeFile();
fileName = p.getFileName();
}
if (fileName.find(ZipCommon::ILLEGAL_PATH) != std::string::npos)
throw ZipException("Illegal entry name " + fileName + " containing " + ZipCommon::ILLEGAL_PATH);
Poco::Path file(fileName);
file.makeFile();
Poco::Path dest(_outDir, file);
dest.makeFile();
if (dest.depth() > 0)
{
Poco::File aFile(dest.parent());
aFile.createDirectories();
}
std::ofstream out(dest.toString().c_str(), std::ios::binary);
if (!out)
{
std::pair<const ZipLocalFileHeader, const std::string> tmp = std::make_pair(hdr, "Failed to open output stream " + dest.toString());
EError.notify(this, tmp);
return false;
}
ZipInputStream inp(zipStream, hdr, false);
Poco::StreamCopier::copyStream(inp, out);
out.close();
Poco::File aFile(file);
if (!aFile.exists() || !aFile.isFile())
{
std::pair<const ZipLocalFileHeader, const std::string> tmp = std::make_pair(hdr, "Failed to create output stream " + dest.toString());
EError.notify(this, tmp);
return false;
}
if (!inp.crcValid())
{
if (!_keepIncompleteFiles)
aFile.remove();
std::pair<const ZipLocalFileHeader, const std::string> tmp = std::make_pair(hdr, "CRC mismatch. Corrupt file: " + dest.toString());
EError.notify(this, tmp);
return false;
}
// cannot check against hdr.getUnCompressedSize if CRC and size are not set in hdr but in a ZipDataInfo
// crc is typically enough to detect errors
if (aFile.getSize() != hdr.getUncompressedSize() && !hdr.searchCRCAndSizesAfterData())
{
if (!_keepIncompleteFiles)
aFile.remove();
std::pair<const ZipLocalFileHeader, const std::string> tmp = std::make_pair(hdr, "Filesizes do not match. Corrupt file: " + dest.toString());
EError.notify(this, tmp);
return false;
}
std::pair<const ZipLocalFileHeader, const Poco::Path> tmp = std::make_pair(hdr, file);
EOk.notify(this, tmp);
}
catch (Poco::Exception& e)
{
std::pair<const ZipLocalFileHeader, const std::string> tmp = std::make_pair(hdr, std::string("Exception: " + e.displayText()));
EError.notify(this, tmp);
return false;
}
catch (...)
{
std::pair<const ZipLocalFileHeader, const std::string> tmp = std::make_pair(hdr, std::string("Unknown Exception"));
EError.notify(this, tmp);
return false;
}
return true;
}
void Decompress::onOk(const void*, std::pair<const ZipLocalFileHeader, const Poco::Path>& val)
{
_mapping.insert(std::make_pair(val.first.getFileName(), val.second));
}
} } // namespace Poco::Zip
//
// Library: Zip
// Package: Zip
// Module: Decompress
//
// Copyright (c) 2007, Applied Informatics Software Engineering GmbH.
// and Contributors.
//
// Permission is hereby granted, free of charge, to any person or organization
// obtaining a copy of the software and accompanying documentation covered by
// this license (the "Software") to use, reproduce, display, distribute,
// execute, and transmit the Software, and to prepare derivative works of the
// Software, and to permit third-parties to whom the Software is furnished to
// do so, all subject to the following:
//
// The copyright notices in the Software and this entire statement, including
// the above license grant, this restriction and the following disclaimer,
// must be included in all copies of the Software, in whole or in part, and
// all derivative works of the Software, unless such copies or derivative
// works are solely in the form of machine-executable object code generated by
// a source language processor.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
// SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
// FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
// ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
//
#include "Poco/Zip/Decompress.h"
#include "Poco/Zip/ZipLocalFileHeader.h"
#include "Poco/Zip/ZipArchive.h"
#include "Poco/Zip/ZipStream.h"
#include "Poco/Zip/ZipException.h"
#include "Poco/File.h"
#include "Poco/Exception.h"
#include "Poco/StreamCopier.h"
#include "Poco/Delegate.h"
#include "Poco/FileStream.h"
namespace Poco {
namespace Zip {
Decompress::Decompress(std::istream& in, const Poco::Path& outputDir, bool flattenDirs, bool keepIncompleteFiles):
_in(in),
_outDir(outputDir),
_flattenDirs(flattenDirs),
_keepIncompleteFiles(keepIncompleteFiles),
_mapping()
{
_outDir.makeAbsolute();
_outDir.makeDirectory();
poco_assert (_in.good());
Poco::File tmp(_outDir);
if (!tmp.exists())
{
tmp.createDirectories();
}
if (!tmp.isDirectory())
throw Poco::IOException("Failed to create/open directory: " + _outDir.toString());
EOk += Poco::Delegate<Decompress, std::pair<const ZipLocalFileHeader, const Poco::Path> >(this, &Decompress::onOk);
}
Decompress::~Decompress()
{
EOk -= Poco::Delegate<Decompress, std::pair<const ZipLocalFileHeader, const Poco::Path> >(this, &Decompress::onOk);
}
ZipArchive Decompress::decompressAllFiles()
{
poco_assert (_mapping.empty());
ZipArchive arch(_in, *this);
return arch;
}
bool Decompress::handleZipEntry(std::istream& zipStream, const ZipLocalFileHeader& hdr)
{
if (hdr.isDirectory())
{
// directory have 0 size, nth to read
if (!_flattenDirs)
{
std::string dirName = hdr.getFileName();
if (dirName.find(ZipCommon::ILLEGAL_PATH) != std::string::npos)
throw ZipException("Illegal entry name " + dirName + " containing " + ZipCommon::ILLEGAL_PATH);
Poco::Path dir(_outDir, dirName);
dir.makeDirectory();
Poco::File aFile(dir);
aFile.createDirectories();
}
return true;
}
try
{
std::string fileName = hdr.getFileName();
if (_flattenDirs)
{
// remove path info
Poco::Path p(fileName);
p.makeFile();
fileName = p.getFileName();
}
if (fileName.find(ZipCommon::ILLEGAL_PATH) != std::string::npos)
throw ZipException("Illegal entry name " + fileName + " containing " + ZipCommon::ILLEGAL_PATH);
Poco::Path file(fileName);
file.makeFile();
Poco::Path dest(_outDir, file);
dest.makeFile();
if (dest.depth() > 0)
{
Poco::File aFile(dest.parent());
aFile.createDirectories();
}
Poco::FileOutputStream out(dest.toString());
ZipInputStream inp(zipStream, hdr, false);
Poco::StreamCopier::copyStream(inp, out);
out.close();
Poco::File aFile(dest.toString());
if (!aFile.exists() || !aFile.isFile())
{
std::pair<const ZipLocalFileHeader, const std::string> tmp = std::make_pair(hdr, "Failed to create output stream " + dest.toString());
EError.notify(this, tmp);
return false;
}
if (!inp.crcValid())
{
if (!_keepIncompleteFiles)
aFile.remove();
std::pair<const ZipLocalFileHeader, const std::string> tmp = std::make_pair(hdr, "CRC mismatch. Corrupt file: " + dest.toString());
EError.notify(this, tmp);
return false;
}
// cannot check against hdr.getUnCompressedSize if CRC and size are not set in hdr but in a ZipDataInfo
// crc is typically enough to detect errors
if (aFile.getSize() != hdr.getUncompressedSize() && !hdr.searchCRCAndSizesAfterData())
{
if (!_keepIncompleteFiles)
aFile.remove();
std::pair<const ZipLocalFileHeader, const std::string> tmp = std::make_pair(hdr, "Filesizes do not match. Corrupt file: " + dest.toString());
EError.notify(this, tmp);
return false;
}
std::pair<const ZipLocalFileHeader, const Poco::Path> tmp = std::make_pair(hdr, file);
EOk.notify(this, tmp);
}
catch (Poco::Exception& e)
{
std::pair<const ZipLocalFileHeader, const std::string> tmp = std::make_pair(hdr, std::string("Exception: " + e.displayText()));
EError.notify(this, tmp);
return false;
}
catch (...)
{
std::pair<const ZipLocalFileHeader, const std::string> tmp = std::make_pair(hdr, std::string("Unknown Exception"));
EError.notify(this, tmp);
return false;
}
return true;
}
void Decompress::onOk(const void*, std::pair<const ZipLocalFileHeader, const Poco::Path>& val)
{
_mapping.insert(std::make_pair(val.first.getFileName(), val.second));
}
} } // namespace Poco::Zip

View File

@@ -1,121 +1,129 @@
//
// ZipArchive.cpp
//
//
// ZipArchive.cpp
//
// $Id: //poco/Main/Zip/src/ZipArchive.cpp#8 $
//
// Library: Zip
// Package: Zip
// Module: ZipArchive
//
// Copyright (c) 2007, Applied Informatics Software Engineering GmbH.
// and Contributors.
//
// Permission is hereby granted, free of charge, to any person or organization
// obtaining a copy of the software and accompanying documentation covered by
// this license (the "Software") to use, reproduce, display, distribute,
// execute, and transmit the Software, and to prepare derivative works of the
// Software, and to permit third-parties to whom the Software is furnished to
// do so, all subject to the following:
//
// The copyright notices in the Software and this entire statement, including
// the above license grant, this restriction and the following disclaimer,
// must be included in all copies of the Software, in whole or in part, and
// all derivative works of the Software, unless such copies or derivative
// works are solely in the form of machine-executable object code generated by
// a source language processor.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
// SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
// FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
// ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
//
#include "Poco/Zip/ZipArchive.h"
#include "Poco/Zip/SkipCallback.h"
#include "Poco/Exception.h"
#include <cstring>
namespace Poco {
namespace Zip {
ZipArchive::ZipArchive(std::istream& in):
_entries(),
_infos(),
_disks()
{
poco_assert_dbg (in);
SkipCallback skip;
parse(in, skip);
}
ZipArchive::ZipArchive(const FileHeaders& entries, const FileInfos& infos, const DirectoryInfos& dirs):
_entries(entries),
_infos(infos),
_disks(dirs)
{
}
ZipArchive::ZipArchive(std::istream& in, ParseCallback& pc):
_entries(),
_infos(),
_disks()
{
poco_assert_dbg (in);
parse(in, pc);
}
ZipArchive::~ZipArchive()
{
}
void ZipArchive::parse(std::istream& in, ParseCallback& pc)
{
// read 4 bytes
while (in.good() && !in.eof())
{
char header[ZipCommon::HEADER_SIZE]={'\x00', '\x00', '\x00', '\x00'};
in.read(header, ZipCommon::HEADER_SIZE);
if (in.eof())
return;
if (std::memcmp(header, ZipLocalFileHeader::HEADER, ZipCommon::HEADER_SIZE) == 0)
{
ZipLocalFileHeader entry(in, true, pc);
poco_assert (_entries.insert(std::make_pair(entry.getFileName(), entry)).second);
}
else if (std::memcmp(header, ZipFileInfo::HEADER, ZipCommon::HEADER_SIZE) == 0)
{
ZipFileInfo info(in, true);
FileHeaders::iterator it = _entries.find(info.getFileName());
if (it != _entries.end())
{
it->second.setStartPos(info.getRelativeOffsetOfLocalHeader());
}
poco_assert (_infos.insert(std::make_pair(info.getFileName(), info)).second);
}
else if (std::memcmp(header, ZipArchiveInfo::HEADER, ZipCommon::HEADER_SIZE) == 0)
{
ZipArchiveInfo nfo(in, true);
poco_assert (_disks.insert(std::make_pair(nfo.getDiskNumber(), nfo)).second);
}
else
{
if (_disks.empty())
throw Poco::IllegalStateException("Illegal header in zip file");
else
throw Poco::IllegalStateException("Garbage after directory header");
}
}
}
} } // namespace Poco::Zip
//
// Library: Zip
// Package: Zip
// Module: ZipArchive
//
// Copyright (c) 2007, Applied Informatics Software Engineering GmbH.
// and Contributors.
//
// Permission is hereby granted, free of charge, to any person or organization
// obtaining a copy of the software and accompanying documentation covered by
// this license (the "Software") to use, reproduce, display, distribute,
// execute, and transmit the Software, and to prepare derivative works of the
// Software, and to permit third-parties to whom the Software is furnished to
// do so, all subject to the following:
//
// The copyright notices in the Software and this entire statement, including
// the above license grant, this restriction and the following disclaimer,
// must be included in all copies of the Software, in whole or in part, and
// all derivative works of the Software, unless such copies or derivative
// works are solely in the form of machine-executable object code generated by
// a source language processor.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
// SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
// FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
// ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
//
#include "Poco/Zip/ZipArchive.h"
#include "Poco/Zip/SkipCallback.h"
#include "Poco/Exception.h"
#include <cstring>
namespace Poco {
namespace Zip {
ZipArchive::ZipArchive(std::istream& in):
_entries(),
_infos(),
_disks()
{
poco_assert_dbg (in);
SkipCallback skip;
parse(in, skip);
}
ZipArchive::ZipArchive(const FileHeaders& entries, const FileInfos& infos, const DirectoryInfos& dirs):
_entries(entries),
_infos(infos),
_disks(dirs)
{
}
ZipArchive::ZipArchive(std::istream& in, ParseCallback& pc):
_entries(),
_infos(),
_disks()
{
poco_assert_dbg (in);
parse(in, pc);
}
ZipArchive::~ZipArchive()
{
}
void ZipArchive::parse(std::istream& in, ParseCallback& pc)
{
// read 4 bytes
while (in.good() && !in.eof())
{
char header[ZipCommon::HEADER_SIZE]={'\x00', '\x00', '\x00', '\x00'};
in.read(header, ZipCommon::HEADER_SIZE);
if (in.eof())
return;
if (std::memcmp(header, ZipLocalFileHeader::HEADER, ZipCommon::HEADER_SIZE) == 0)
{
ZipLocalFileHeader entry(in, true, pc);
poco_assert (_entries.insert(std::make_pair(entry.getFileName(), entry)).second);
}
else if (std::memcmp(header, ZipFileInfo::HEADER, ZipCommon::HEADER_SIZE) == 0)
{
ZipFileInfo info(in, true);
FileHeaders::iterator it = _entries.find(info.getFileName());
if (it != _entries.end())
{
it->second.setStartPos(info.getRelativeOffsetOfLocalHeader());
}
poco_assert (_infos.insert(std::make_pair(info.getFileName(), info)).second);
}
else if (std::memcmp(header, ZipArchiveInfo::HEADER, ZipCommon::HEADER_SIZE) == 0)
{
ZipArchiveInfo nfo(in, true);
poco_assert (_disks.insert(std::make_pair(nfo.getDiskNumber(), nfo)).second);
}
else
{
if (_disks.empty())
throw Poco::IllegalStateException("Illegal header in zip file");
else
throw Poco::IllegalStateException("Garbage after directory header");
}
}
}
const std::string& ZipArchive::getZipComment() const
{
// It seems that only the "first" disk is populated (look at Compress::close()), so getting the first ZipArchiveInfo
DirectoryInfos::const_iterator it = _disks.begin();
return it->second.getZipComment();
}
} } // namespace Poco::Zip

View File

@@ -1,106 +1,121 @@
//
// ZipArchiveInfo.cpp
//
//
// ZipArchiveInfo.cpp
//
// $Id: //poco/Main/Zip/src/ZipArchiveInfo.cpp#7 $
//
// Library: Zip
// Package: Zip
// Module: ZipArchiveInfo
//
// Copyright (c) 2007, Applied Informatics Software Engineering GmbH.
// and Contributors.
//
// Permission is hereby granted, free of charge, to any person or organization
// obtaining a copy of the software and accompanying documentation covered by
// this license (the "Software") to use, reproduce, display, distribute,
// execute, and transmit the Software, and to prepare derivative works of the
// Software, and to permit third-parties to whom the Software is furnished to
// do so, all subject to the following:
//
// The copyright notices in the Software and this entire statement, including
// the above license grant, this restriction and the following disclaimer,
// must be included in all copies of the Software, in whole or in part, and
// all derivative works of the Software, unless such copies or derivative
// works are solely in the form of machine-executable object code generated by
// a source language processor.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
// SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
// FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
// ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
//
#include "Poco/Zip/ZipArchiveInfo.h"
#include "Poco/Buffer.h"
#include <istream>
#include <cstring>
namespace Poco {
namespace Zip {
const char ZipArchiveInfo::HEADER[ZipCommon::HEADER_SIZE] = {'\x50', '\x4b', '\x05', '\x06'};
ZipArchiveInfo::ZipArchiveInfo(std::istream& in, bool assumeHeaderRead):
_rawInfo(),
_startPos(in.tellg()),
_comment()
{
if (assumeHeaderRead)
_startPos -= ZipCommon::HEADER_SIZE;
parse(in, assumeHeaderRead);
}
ZipArchiveInfo::ZipArchiveInfo():
_rawInfo(),
_startPos(0),
_comment()
{
std::memset(_rawInfo, 0, FULLHEADER_SIZE);
std::memcpy(_rawInfo, HEADER, ZipCommon::HEADER_SIZE);
}
ZipArchiveInfo::~ZipArchiveInfo()
{
}
void ZipArchiveInfo::parse(std::istream& inp, bool assumeHeaderRead)
{
if (!assumeHeaderRead)
{
inp.read(_rawInfo, ZipCommon::HEADER_SIZE);
}
else
{
std::memcpy(_rawInfo, HEADER, ZipCommon::HEADER_SIZE);
}
poco_assert (std::memcmp(_rawInfo, HEADER, ZipCommon::HEADER_SIZE) == 0);
// read the rest of the header
inp.read(_rawInfo + ZipCommon::HEADER_SIZE, FULLHEADER_SIZE - ZipCommon::HEADER_SIZE);
Poco::UInt16 len = getZipCommentSize();
if (len > 0)
{
Poco::Buffer<char> buf(len);
inp.read(buf.begin(), len);
_comment = std::string(buf.begin(), len);
}
}
std::string ZipArchiveInfo::createHeader() const
{
std::string result(_rawInfo, FULLHEADER_SIZE);
result.append(_comment);
return result;
}
} } // namespace Poco::Zip
//
// Library: Zip
// Package: Zip
// Module: ZipArchiveInfo
//
// Copyright (c) 2007, Applied Informatics Software Engineering GmbH.
// and Contributors.
//
// Permission is hereby granted, free of charge, to any person or organization
// obtaining a copy of the software and accompanying documentation covered by
// this license (the "Software") to use, reproduce, display, distribute,
// execute, and transmit the Software, and to prepare derivative works of the
// Software, and to permit third-parties to whom the Software is furnished to
// do so, all subject to the following:
//
// The copyright notices in the Software and this entire statement, including
// the above license grant, this restriction and the following disclaimer,
// must be included in all copies of the Software, in whole or in part, and
// all derivative works of the Software, unless such copies or derivative
// works are solely in the form of machine-executable object code generated by
// a source language processor.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
// SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
// FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
// ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
//
#include "Poco/Zip/ZipArchiveInfo.h"
#include "Poco/Zip/ZipException.h"
#include "Poco/Buffer.h"
#include <istream>
#include <cstring>
namespace Poco {
namespace Zip {
const char ZipArchiveInfo::HEADER[ZipCommon::HEADER_SIZE] = {'\x50', '\x4b', '\x05', '\x06'};
ZipArchiveInfo::ZipArchiveInfo(std::istream& in, bool assumeHeaderRead):
_rawInfo(),
_startPos(in.tellg()),
_comment()
{
if (assumeHeaderRead)
_startPos -= ZipCommon::HEADER_SIZE;
parse(in, assumeHeaderRead);
}
ZipArchiveInfo::ZipArchiveInfo():
_rawInfo(),
_startPos(0),
_comment()
{
std::memset(_rawInfo, 0, FULLHEADER_SIZE);
std::memcpy(_rawInfo, HEADER, ZipCommon::HEADER_SIZE);
}
ZipArchiveInfo::~ZipArchiveInfo()
{
}
void ZipArchiveInfo::parse(std::istream& inp, bool assumeHeaderRead)
{
if (!assumeHeaderRead)
{
inp.read(_rawInfo, ZipCommon::HEADER_SIZE);
}
else
{
std::memcpy(_rawInfo, HEADER, ZipCommon::HEADER_SIZE);
}
poco_assert (std::memcmp(_rawInfo, HEADER, ZipCommon::HEADER_SIZE) == 0);
// read the rest of the header
inp.read(_rawInfo + ZipCommon::HEADER_SIZE, FULLHEADER_SIZE - ZipCommon::HEADER_SIZE);
Poco::UInt16 len = getZipCommentSize();
if (len > 0)
{
Poco::Buffer<char> buf(len);
inp.read(buf.begin(), len);
_comment = std::string(buf.begin(), len);
}
}
std::string ZipArchiveInfo::createHeader() const
{
std::string result(_rawInfo, FULLHEADER_SIZE);
result.append(_comment);
return result;
}
void ZipArchiveInfo::setZipComment(const std::string& comment)
{
// Confirm string is of valid size
if (comment.size() > 65535)
throw ZipException("Maximum number of entries for a ZIP file reached: 65535");
// Change the value of the ZIP Comment Size to reflect new comment size
ZipUtil::set16BitValue(static_cast<Poco::UInt16>(comment.size()), _rawInfo, ZIPCOMMENT_LENGTH_POS);
// Now change our internal comment
_comment = comment;
}
} } // namespace Poco::Zip

View File

@@ -1,194 +1,193 @@
//
// ZipManipulator.cpp
//
//
// ZipManipulator.cpp
//
// $Id: //poco/Main/Zip/src/ZipManipulator.cpp#4 $
//
// Library: Zip
// Package: Manipulation
// Module: ZipManipulator
//
// Copyright (c) 2007, Applied Informatics Software Engineering GmbH.
// and Contributors.
//
// Permission is hereby granted, free of charge, to any person or organization
// obtaining a copy of the software and accompanying documentation covered by
// this license (the "Software") to use, reproduce, display, distribute,
// execute, and transmit the Software, and to prepare derivative works of the
// Software, and to permit third-parties to whom the Software is furnished to
// do so, all subject to the following:
//
// The copyright notices in the Software and this entire statement, including
// the above license grant, this restriction and the following disclaimer,
// must be included in all copies of the Software, in whole or in part, and
// all derivative works of the Software, unless such copies or derivative
// works are solely in the form of machine-executable object code generated by
// a source language processor.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
// SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
// FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
// ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
//
#include "Poco/Zip/ZipManipulator.h"
#include "Poco/Zip/ZipException.h"
#include "Poco/Zip/ZipUtil.h"
#include "Poco/Zip/Add.h"
#include "Poco/Zip/Delete.h"
#include "Poco/Zip/Keep.h"
#include "Poco/Zip/Rename.h"
#include "Poco/Zip/Replace.h"
#include "Poco/Zip/Compress.h"
#include "Poco/Delegate.h"
#include "Poco/File.h"
#include "Poco/FileStream.h"
#include <fstream>
namespace Poco {
namespace Zip {
ZipManipulator::ZipManipulator(const std::string& zipFile, bool backupOriginalFile):
_zipFile(zipFile),
_backupOriginalFile(backupOriginalFile),
_changes(),
_in(0)
{
std::ifstream in(zipFile.c_str(), std::ios::binary);
_in = new ZipArchive(in);
}
ZipManipulator::~ZipManipulator()
{
}
void ZipManipulator::deleteFile(const std::string& zipPath)
{
const ZipLocalFileHeader& entry = getForChange(zipPath);
addOperation(zipPath, new Delete(entry));
}
void ZipManipulator::replaceFile(const std::string& zipPath, const std::string& localPath)
{
const ZipLocalFileHeader& entry = getForChange(zipPath);
addOperation(zipPath, new Replace(entry, localPath));
}
void ZipManipulator::renameFile(const std::string& zipPath, const std::string& newZipPath)
{
const ZipLocalFileHeader& entry = getForChange(zipPath);
// checked later in Compress too but the earlier one gets the error the better
std::string fn = ZipUtil::validZipEntryFileName(newZipPath);
addOperation(zipPath, new Rename(entry, fn));
}
void ZipManipulator::addFile(const std::string& zipPath, const std::string& localPath, ZipCommon::CompressionMethod cm, ZipCommon::CompressionLevel cl)
{
addOperation(zipPath, new Add(zipPath, localPath, cm, cl));
}
ZipArchive ZipManipulator::commit()
{
// write to a tmp file
std::string outFile(_zipFile + ".tmp");
ZipArchive retVal(compress(outFile));
//renaming
{
Poco::File aFile(_zipFile);
if (_backupOriginalFile)
{
Poco::File tmp(_zipFile+".bak");
if (tmp.exists())
tmp.remove();
aFile.renameTo(_zipFile+".bak");
}
else
aFile.remove();
}
{
Poco::File resFile(outFile);
Poco::File zipFile(_zipFile);
if (zipFile.exists())
zipFile.remove();
resFile.renameTo(_zipFile);
}
return retVal;
}
const ZipLocalFileHeader& ZipManipulator::getForChange(const std::string& zipPath) const
{
ZipArchive::FileHeaders::const_iterator it = _in->findHeader(zipPath);
if (it == _in->headerEnd())
throw ZipManipulationException("entry not found: " + zipPath);
if (_changes.find(zipPath) != _changes.end())
throw ZipManipulationException("A change request exists already for entry " + zipPath);
return it->second;
}
void ZipManipulator::addOperation(const std::string& zipPath, ZipOperation::Ptr ptrOp)
{
std::pair<Changes::iterator, bool> result = _changes.insert(std::make_pair(zipPath, ptrOp));
if (!result.second)
throw ZipManipulationException("A change request exists already for entry " + zipPath);
}
void ZipManipulator::onEDone(const void*, const ZipLocalFileHeader& hdr)
{
EDone(this, hdr);
}
ZipArchive ZipManipulator::compress(const std::string& outFile)
{
// write to a tmp file
Poco::FileInputStream in(_zipFile);
Poco::FileOutputStream out(outFile);
Compress c(out, true);
c.EDone += Poco::Delegate<ZipManipulator, const ZipLocalFileHeader>(this, &ZipManipulator::onEDone);
ZipArchive::FileHeaders::const_iterator it = _in->headerBegin();
for (; it != _in->headerEnd(); ++it)
{
Changes::iterator itC = _changes.find(it->first);
if (itC != _changes.end())
{
itC->second->execute(c, in);
_changes.erase(itC);
}
else
{
Keep k(it->second);
k.execute(c, in);
}
}
//Remaining files are add operations!
Changes::iterator itC = _changes.begin();
for (; itC != _changes.end(); ++itC)
{
itC->second->execute(c, in);
}
_changes.clear();
c.EDone -= Poco::Delegate<ZipManipulator, const ZipLocalFileHeader>(this, &ZipManipulator::onEDone);
in.close();
return c.close();
}
} } // namespace Poco::Zip
//
// Library: Zip
// Package: Manipulation
// Module: ZipManipulator
//
// Copyright (c) 2007, Applied Informatics Software Engineering GmbH.
// and Contributors.
//
// Permission is hereby granted, free of charge, to any person or organization
// obtaining a copy of the software and accompanying documentation covered by
// this license (the "Software") to use, reproduce, display, distribute,
// execute, and transmit the Software, and to prepare derivative works of the
// Software, and to permit third-parties to whom the Software is furnished to
// do so, all subject to the following:
//
// The copyright notices in the Software and this entire statement, including
// the above license grant, this restriction and the following disclaimer,
// must be included in all copies of the Software, in whole or in part, and
// all derivative works of the Software, unless such copies or derivative
// works are solely in the form of machine-executable object code generated by
// a source language processor.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
// SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
// FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
// ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
//
#include "Poco/Zip/ZipManipulator.h"
#include "Poco/Zip/ZipException.h"
#include "Poco/Zip/ZipUtil.h"
#include "Poco/Zip/Add.h"
#include "Poco/Zip/Delete.h"
#include "Poco/Zip/Keep.h"
#include "Poco/Zip/Rename.h"
#include "Poco/Zip/Replace.h"
#include "Poco/Zip/Compress.h"
#include "Poco/Delegate.h"
#include "Poco/File.h"
#include "Poco/FileStream.h"
namespace Poco {
namespace Zip {
ZipManipulator::ZipManipulator(const std::string& zipFile, bool backupOriginalFile):
_zipFile(zipFile),
_backupOriginalFile(backupOriginalFile),
_changes(),
_in(0)
{
Poco::FileInputStream in(zipFile);
_in = new ZipArchive(in);
}
ZipManipulator::~ZipManipulator()
{
}
void ZipManipulator::deleteFile(const std::string& zipPath)
{
const ZipLocalFileHeader& entry = getForChange(zipPath);
addOperation(zipPath, new Delete(entry));
}
void ZipManipulator::replaceFile(const std::string& zipPath, const std::string& localPath)
{
const ZipLocalFileHeader& entry = getForChange(zipPath);
addOperation(zipPath, new Replace(entry, localPath));
}
void ZipManipulator::renameFile(const std::string& zipPath, const std::string& newZipPath)
{
const ZipLocalFileHeader& entry = getForChange(zipPath);
// checked later in Compress too but the earlier one gets the error the better
std::string fn = ZipUtil::validZipEntryFileName(newZipPath);
addOperation(zipPath, new Rename(entry, fn));
}
void ZipManipulator::addFile(const std::string& zipPath, const std::string& localPath, ZipCommon::CompressionMethod cm, ZipCommon::CompressionLevel cl)
{
addOperation(zipPath, new Add(zipPath, localPath, cm, cl));
}
ZipArchive ZipManipulator::commit()
{
// write to a tmp file
std::string outFile(_zipFile + ".tmp");
ZipArchive retVal(compress(outFile));
//renaming
{
Poco::File aFile(_zipFile);
if (_backupOriginalFile)
{
Poco::File tmp(_zipFile+".bak");
if (tmp.exists())
tmp.remove();
aFile.renameTo(_zipFile+".bak");
}
else
aFile.remove();
}
{
Poco::File resFile(outFile);
Poco::File zipFile(_zipFile);
if (zipFile.exists())
zipFile.remove();
resFile.renameTo(_zipFile);
}
return retVal;
}
const ZipLocalFileHeader& ZipManipulator::getForChange(const std::string& zipPath) const
{
ZipArchive::FileHeaders::const_iterator it = _in->findHeader(zipPath);
if (it == _in->headerEnd())
throw ZipManipulationException("entry not found: " + zipPath);
if (_changes.find(zipPath) != _changes.end())
throw ZipManipulationException("A change request exists already for entry " + zipPath);
return it->second;
}
void ZipManipulator::addOperation(const std::string& zipPath, ZipOperation::Ptr ptrOp)
{
std::pair<Changes::iterator, bool> result = _changes.insert(std::make_pair(zipPath, ptrOp));
if (!result.second)
throw ZipManipulationException("A change request exists already for entry " + zipPath);
}
void ZipManipulator::onEDone(const void*, const ZipLocalFileHeader& hdr)
{
EDone(this, hdr);
}
ZipArchive ZipManipulator::compress(const std::string& outFile)
{
// write to a tmp file
Poco::FileInputStream in(_zipFile);
Poco::FileOutputStream out(outFile);
Compress c(out, true);
c.EDone += Poco::Delegate<ZipManipulator, const ZipLocalFileHeader>(this, &ZipManipulator::onEDone);
ZipArchive::FileHeaders::const_iterator it = _in->headerBegin();
for (; it != _in->headerEnd(); ++it)
{
Changes::iterator itC = _changes.find(it->first);
if (itC != _changes.end())
{
itC->second->execute(c, in);
_changes.erase(itC);
}
else
{
Keep k(it->second);
k.execute(c, in);
}
}
//Remaining files are add operations!
Changes::iterator itC = _changes.begin();
for (; itC != _changes.end(); ++itC)
{
itC->second->execute(c, in);
}
_changes.clear();
c.EDone -= Poco::Delegate<ZipManipulator, const ZipLocalFileHeader>(this, &ZipManipulator::onEDone);
in.close();
return c.close();
}
} } // namespace Poco::Zip