mirror of
https://github.com/pocoproject/poco.git
synced 2025-11-24 14:20:10 +01:00
Zip: complete merge to 1.4.2
This commit is contained in:
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user