fixed SF# 2583934: Zip: No Unix permissions set

This commit is contained in:
Guenter Obiltschnig
2009-02-18 16:04:14 +00:00
parent 717dd9cf45
commit 12c1ae5823
4 changed files with 1284 additions and 1252 deletions

View File

@@ -1,322 +1,322 @@
//
// Compress.cpp
//
// $Id: //poco/1.3/Zip/src/Compress.cpp#4 $
//
// 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 <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

View File

@@ -1,143 +1,159 @@
//
// ZipFileInfo.cpp
//
// $Id: //poco/1.3/Zip/src/ZipFileInfo.cpp#4 $
//
// Library: Zip
// Package: Zip
// Module: ZipFileInfo
//
// 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/ZipFileInfo.h"
#include "Poco/Zip/ZipLocalFileHeader.h"
#include "Poco/Buffer.h"
#include <istream>
#include <cstring>
namespace Poco {
namespace Zip {
const char ZipFileInfo::HEADER[ZipCommon::HEADER_SIZE] = {'\x50', '\x4b', '\x01', '\x02'};
ZipFileInfo::ZipFileInfo(const ZipLocalFileHeader& header):
_rawInfo(),
_crc32(0),
_compressedSize(0),
_uncompressedSize(0),
_fileName(),
_lastModifiedAt(),
_extraField()
{
std::memset(_rawInfo, 0, FULLHEADER_SIZE);
std::memcpy(_rawInfo, HEADER, ZipCommon::HEADER_SIZE);
setCompressedSize(header.getCompressedSize());
setUncompressedSize(header.getUncompressedSize());
setCRC(header.getCRC());
setCompressionMethod(header.getCompressionMethod());
setCompressionLevel(header.getCompressionLevel());
setRequiredVersion(header.getMajorVersionNumber(), header.getMinorVersionNumber());
setHostSystem(header.getHostSystem());
setLastModifiedAt(header.lastModifiedAt());
setEncryption(false);
setFileName(header.getFileName());
}
ZipFileInfo::ZipFileInfo(std::istream& in, bool assumeHeaderRead):
_rawInfo(),
_crc32(0),
_compressedSize(0),
_uncompressedSize(0),
_fileName(),
_lastModifiedAt(),
_extraField()
{
// sanity check
poco_assert_dbg (RELATIVEOFFSETLOCALHEADER_POS + RELATIVEOFFSETLOCALHEADER_SIZE == FULLHEADER_SIZE);
parse(in, assumeHeaderRead);
}
ZipFileInfo::~ZipFileInfo()
{
}
void ZipFileInfo::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);
_crc32 = getCRCFromHeader();
_compressedSize = getCompressedSizeFromHeader();
_uncompressedSize = getUncompressedSizeFromHeader();
parseDateTime();
Poco::UInt16 len = getFileNameLength();
Poco::Buffer<char> buf(len);
inp.read(buf.begin(), len);
_fileName = std::string(buf.begin(), len);
if (hasExtraField())
{
len = getExtraFieldLength();
Poco::Buffer<char> xtra(len);
inp.read(xtra.begin(), len);
_extraField = std::string(xtra.begin(), len);
}
len = getFileCommentLength();
if (len > 0)
{
Poco::Buffer<char> buf2(len);
inp.read(buf2.begin(), len);
_fileComment = std::string(buf2.begin(), len);
}
}
std::string ZipFileInfo::createHeader() const
{
std::string result(_rawInfo, FULLHEADER_SIZE);
result.append(_fileName);
result.append(_extraField);
result.append(_fileComment);
return result;
}
} } // namespace Poco::Zip
//
// ZipFileInfo.cpp
//
// $Id: //poco/Main/Zip/src/ZipFileInfo.cpp#9 $
//
// Library: Zip
// Package: Zip
// Module: ZipFileInfo
//
// 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/ZipFileInfo.h"
#include "Poco/Zip/ZipLocalFileHeader.h"
#include "Poco/Buffer.h"
#include <istream>
#include <cstring>
namespace Poco {
namespace Zip {
const char ZipFileInfo::HEADER[ZipCommon::HEADER_SIZE] = {'\x50', '\x4b', '\x01', '\x02'};
ZipFileInfo::ZipFileInfo(const ZipLocalFileHeader& header):
_rawInfo(),
_crc32(0),
_compressedSize(0),
_uncompressedSize(0),
_fileName(),
_lastModifiedAt(),
_extraField()
{
std::memset(_rawInfo, 0, FULLHEADER_SIZE);
std::memcpy(_rawInfo, HEADER, ZipCommon::HEADER_SIZE);
setCompressedSize(header.getCompressedSize());
setUncompressedSize(header.getUncompressedSize());
setCRC(header.getCRC());
setCompressionMethod(header.getCompressionMethod());
setCompressionLevel(header.getCompressionLevel());
setRequiredVersion(header.getMajorVersionNumber(), header.getMinorVersionNumber());
setHostSystem(header.getHostSystem());
setLastModifiedAt(header.lastModifiedAt());
setEncryption(false);
setFileName(header.getFileName());
if (getHostSystem() == ZipCommon::HS_UNIX)
setUnixAttributes();
}
ZipFileInfo::ZipFileInfo(std::istream& in, bool assumeHeaderRead):
_rawInfo(),
_crc32(0),
_compressedSize(0),
_uncompressedSize(0),
_fileName(),
_lastModifiedAt(),
_extraField()
{
// sanity check
poco_assert_dbg (RELATIVEOFFSETLOCALHEADER_POS + RELATIVEOFFSETLOCALHEADER_SIZE == FULLHEADER_SIZE);
parse(in, assumeHeaderRead);
}
ZipFileInfo::~ZipFileInfo()
{
}
void ZipFileInfo::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);
_crc32 = getCRCFromHeader();
_compressedSize = getCompressedSizeFromHeader();
_uncompressedSize = getUncompressedSizeFromHeader();
parseDateTime();
Poco::UInt16 len = getFileNameLength();
Poco::Buffer<char> buf(len);
inp.read(buf.begin(), len);
_fileName = std::string(buf.begin(), len);
if (hasExtraField())
{
len = getExtraFieldLength();
Poco::Buffer<char> xtra(len);
inp.read(xtra.begin(), len);
_extraField = std::string(xtra.begin(), len);
}
len = getFileCommentLength();
if (len > 0)
{
Poco::Buffer<char> buf2(len);
inp.read(buf2.begin(), len);
_fileComment = std::string(buf2.begin(), len);
}
}
std::string ZipFileInfo::createHeader() const
{
std::string result(_rawInfo, FULLHEADER_SIZE);
result.append(_fileName);
result.append(_extraField);
result.append(_fileComment);
return result;
}
void ZipFileInfo::setUnixAttributes()
{
bool isDir = isDirectory();
int mode;
if (isDir)
mode = DEFAULT_UNIX_DIR_MODE;
else
mode = DEFAULT_UNIX_FILE_MODE;
Poco::UInt32 attrs = (mode << 16) | (isDir ? 0x10 : 0);
setExternalFileAttributes(attrs);
}
} } // namespace Poco::Zip

View File

@@ -1,319 +1,319 @@
//
// ZipStream.cpp
//
// $Id: //poco/1.3/Zip/src/ZipStream.cpp#4 $
//
// Library: Zip
// Package: Zip
// Module: ZipStream
//
// 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/ZipStream.h"
#include "Poco/zlib.h"
#include "Poco/Zip/ZipArchive.h"
#include "Poco/Zip/AutoDetectStream.h"
#include "Poco/Zip/PartialStream.h"
#include "Poco/Zip/ZipDataInfo.h"
#include "Poco/Zip/ZipException.h"
#include "Poco/Exception.h"
#include "Poco/InflatingStream.h"
#include "Poco/DeflatingStream.h"
namespace Poco {
namespace Zip {
ZipStreamBuf::ZipStreamBuf(std::istream& istr, const ZipLocalFileHeader& fileEntry, bool reposition):
Poco::BufferedStreamBuf(STREAM_BUFFER_SIZE, std::ios::in),
_pIstr(&istr),
_pOstr(0),
_ptrBuf(),
_ptrOBuf(),
_ptrHelper(),
_ptrOHelper(),
_crc32(Poco::Checksum::TYPE_CRC32),
_expectedCrc32(0),
_checkCRC(true),
_bytesWritten(0),
_pHeader(0)
{
if (fileEntry.isDirectory())
return;
_expectedCrc32 = fileEntry.getCRC();
std::streamoff start = fileEntry.getDataStartPos();
std::streamoff end = fileEntry.getDataEndPos();
_checkCRC = !fileEntry.searchCRCAndSizesAfterData();
if (fileEntry.getCompressionMethod() == ZipCommon::CM_DEFLATE)
{
// Fake init bytes at beginning of stream
std::string init = ZipUtil::fakeZLibInitString(fileEntry.getCompressionLevel());
// Fake adler at end of stream: just some dummy value, not checked anway
std::string crc(4, ' ');
if (fileEntry.searchCRCAndSizesAfterData())
{
_ptrHelper = new AutoDetectInputStream(istr, init, crc, reposition, start);
}
else
_ptrHelper = new PartialInputStream(istr, start, end, reposition, init, crc);
_ptrBuf = new Poco::InflatingInputStream(*_ptrHelper, Poco::InflatingStreamBuf::STREAM_ZIP);
}
else if (fileEntry.getCompressionMethod() == ZipCommon::CM_STORE)
{
if (fileEntry.searchCRCAndSizesAfterData())
{
_ptrBuf = new AutoDetectInputStream(istr, "", "", reposition, start);
}
else
_ptrBuf = new PartialInputStream(istr, start, end, reposition);
}
else
{
throw Poco::NotImplementedException("Unsupported compression method");
}
}
ZipStreamBuf::ZipStreamBuf(std::ostream& ostr, ZipLocalFileHeader& fileEntry, bool reposition):
Poco::BufferedStreamBuf(STREAM_BUFFER_SIZE, std::ios::out),
_pIstr(0),
_pOstr(&ostr),
_ptrBuf(),
_ptrOBuf(),
_ptrHelper(),
_ptrOHelper(),
_crc32(Poco::Checksum::TYPE_CRC32),
_expectedCrc32(0),
_checkCRC(false),
_bytesWritten(0),
_pHeader(&fileEntry)
{
if (fileEntry.isEncrypted())
throw Poco::NotImplementedException("Encryption not supported");
if (fileEntry.isDirectory())
{
// only header, no payload, zero crc
fileEntry.setSearchCRCAndSizesAfterData(false);
fileEntry.setCompressedSize(0);
fileEntry.setUncompressedSize(0);
fileEntry.setCRC(0);
std::string header = fileEntry.createHeader();
ostr.write(header.c_str(), static_cast<std::streamsize>(header.size()));
}
else
{
fileEntry.setSearchCRCAndSizesAfterData(!reposition);
if (fileEntry.getCompressionMethod() == ZipCommon::CM_DEFLATE)
{
int level = Z_DEFAULT_COMPRESSION;
if (fileEntry.getCompressionLevel() == ZipCommon::CL_FAST || fileEntry.getCompressionLevel() == ZipCommon::CL_SUPERFAST)
level = Z_BEST_SPEED;
else if (fileEntry.getCompressionLevel() == ZipCommon::CL_MAXIMUM)
level = Z_BEST_COMPRESSION;
// ignore the zlib init string which is of size 2 and also ignore the 4 byte adler32 value at the end of the stream!
_ptrOHelper = new PartialOutputStream(*_pOstr, 2, 4, false);
_ptrOBuf = new Poco::DeflatingOutputStream(*_ptrOHelper, DeflatingStreamBuf::STREAM_ZLIB, level);
}
else if (fileEntry.getCompressionMethod() == ZipCommon::CM_STORE)
{
_ptrOHelper = new PartialOutputStream(*_pOstr, 0, 0, false);
_ptrOBuf = _ptrOHelper;
}
else
{
throw Poco::NotImplementedException("Unsupported compression method");
}
// now write the header to the ostr!
std::string header = fileEntry.createHeader();
ostr.write(header.c_str(), static_cast<std::streamsize>(header.size()));
}
}
ZipStreamBuf::~ZipStreamBuf()
{
}
int ZipStreamBuf::readFromDevice(char* buffer, std::streamsize length)
{
if (!_ptrBuf) return 0; // directory entry
_ptrBuf->read(buffer, length);
int cnt = _ptrBuf->gcount();
if (cnt > 0)
{
_crc32.update(buffer, cnt);
}
else
{
if (_crc32.checksum() != _expectedCrc32)
{
if (_checkCRC)
throw ZipException("CRC failure");
else
{
// the CRC value is written directly after the data block
// parse it directly from the input stream
ZipDataInfo nfo(*_pIstr, false);
// now push back the header to the stream, so that the ZipLocalFileHeader can read it
Poco::Int32 size = static_cast<Poco::Int32>(nfo.getFullHeaderSize());
_expectedCrc32 = nfo.getCRC32();
const char* rawHeader = nfo.getRawHeader();
for (Poco::Int32 i = size-1; i >= 0; --i)
_pIstr->putback(rawHeader[i]);
if (!crcValid())
throw ZipException("CRC failure");
}
}
}
return cnt;
}
int ZipStreamBuf::writeToDevice(const char* buffer, std::streamsize length)
{
if (!_ptrOBuf) return 0; // directory entry
if (length == 0)
return 0;
_bytesWritten += length;
_ptrOBuf->write(buffer, length);
_crc32.update(buffer, length);
return length;
}
void ZipStreamBuf::close()
{
if (_ptrOBuf && _pHeader)
{
_ptrOBuf->flush();
DeflatingOutputStream* pDO = dynamic_cast<DeflatingOutputStream*>(_ptrOBuf.get());
if (pDO)
pDO->close();
if (_ptrOHelper)
{
_ptrOHelper->flush();
_ptrOHelper->close();
}
_ptrOBuf = 0;
poco_assert (*_pOstr);
// write an extra datablock if required
// or fix the crc entries
if (_pHeader->searchCRCAndSizesAfterData())
{
ZipDataInfo info;
info.setCRC32(_crc32.checksum());
info.setUncompressedSize(_bytesWritten);
info.setCompressedSize(static_cast<Poco::UInt32>(_ptrOHelper->bytesWritten()));
_pOstr->write(info.getRawHeader(), static_cast<std::streamsize>(info.getFullHeaderSize()));
}
else
{
poco_check_ptr (_pHeader);
_pHeader->setCRC(_crc32.checksum());
_pHeader->setUncompressedSize(_bytesWritten);
_pHeader->setCompressedSize(static_cast<Poco::UInt32>(_ptrOHelper->bytesWritten()));
_pOstr->seekp(_pHeader->getStartPos(), std::ios_base::beg);
poco_assert (*_pOstr);
std::string header = _pHeader->createHeader();
_pOstr->write(header.c_str(), static_cast<std::streamsize>(header.size()));
_pOstr->seekp(0, std::ios_base::end);
poco_assert (*_pOstr);
}
_pHeader = 0;
}
}
bool ZipStreamBuf::crcValid() const
{
if (!_ptrBuf) return true; // directory entry
return _crc32.checksum() == _expectedCrc32;
}
ZipIOS::ZipIOS(std::istream& istr, const ZipLocalFileHeader& fileEntry, bool reposition): _buf(istr, fileEntry, reposition)
{
poco_ios_init(&_buf);
}
ZipIOS::ZipIOS(std::ostream& ostr, ZipLocalFileHeader& fileEntry, bool reposition): _buf(ostr, fileEntry, reposition)
{
poco_ios_init(&_buf);
}
ZipIOS::~ZipIOS()
{
}
ZipStreamBuf* ZipIOS::rdbuf()
{
return &_buf;
}
ZipInputStream::ZipInputStream(std::istream& istr, const ZipLocalFileHeader& fileEntry, bool reposition): ZipIOS(istr, fileEntry, reposition), std::istream(&_buf)
{
}
ZipInputStream::~ZipInputStream()
{
}
bool ZipInputStream::crcValid() const
{
return _buf.crcValid();
}
ZipOutputStream::ZipOutputStream(std::ostream& ostr, ZipLocalFileHeader& fileEntry, bool seekableOutput): ZipIOS(ostr, fileEntry, seekableOutput), std::ostream(&_buf)
{
}
ZipOutputStream::~ZipOutputStream()
{
}
void ZipOutputStream::close()
{
flush();
_buf.close();
}
} } // namespace Poco::Zip
//
// ZipStream.cpp
//
// $Id: //poco/Main/Zip/src/ZipStream.cpp#14 $
//
// Library: Zip
// Package: Zip
// Module: ZipStream
//
// 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/ZipStream.h"
#include "Poco/zlib.h"
#include "Poco/Zip/ZipArchive.h"
#include "Poco/Zip/AutoDetectStream.h"
#include "Poco/Zip/PartialStream.h"
#include "Poco/Zip/ZipDataInfo.h"
#include "Poco/Zip/ZipException.h"
#include "Poco/Exception.h"
#include "Poco/InflatingStream.h"
#include "Poco/DeflatingStream.h"
namespace Poco {
namespace Zip {
ZipStreamBuf::ZipStreamBuf(std::istream& istr, const ZipLocalFileHeader& fileEntry, bool reposition):
Poco::BufferedStreamBuf(STREAM_BUFFER_SIZE, std::ios::in),
_pIstr(&istr),
_pOstr(0),
_ptrBuf(),
_ptrOBuf(),
_ptrHelper(),
_ptrOHelper(),
_crc32(Poco::Checksum::TYPE_CRC32),
_expectedCrc32(0),
_checkCRC(true),
_bytesWritten(0),
_pHeader(0)
{
if (fileEntry.isDirectory())
return;
_expectedCrc32 = fileEntry.getCRC();
std::streamoff start = fileEntry.getDataStartPos();
std::streamoff end = fileEntry.getDataEndPos();
_checkCRC = !fileEntry.searchCRCAndSizesAfterData();
if (fileEntry.getCompressionMethod() == ZipCommon::CM_DEFLATE)
{
// Fake init bytes at beginning of stream
std::string init = ZipUtil::fakeZLibInitString(fileEntry.getCompressionLevel());
// Fake adler at end of stream: just some dummy value, not checked anway
std::string crc(4, ' ');
if (fileEntry.searchCRCAndSizesAfterData())
{
_ptrHelper = new AutoDetectInputStream(istr, init, crc, reposition, start);
}
else
_ptrHelper = new PartialInputStream(istr, start, end, reposition, init, crc);
_ptrBuf = new Poco::InflatingInputStream(*_ptrHelper, Poco::InflatingStreamBuf::STREAM_ZIP);
}
else if (fileEntry.getCompressionMethod() == ZipCommon::CM_STORE)
{
if (fileEntry.searchCRCAndSizesAfterData())
{
_ptrBuf = new AutoDetectInputStream(istr, "", "", reposition, start);
}
else
_ptrBuf = new PartialInputStream(istr, start, end, reposition);
}
else
{
throw Poco::NotImplementedException("Unsupported compression method");
}
}
ZipStreamBuf::ZipStreamBuf(std::ostream& ostr, ZipLocalFileHeader& fileEntry, bool reposition):
Poco::BufferedStreamBuf(STREAM_BUFFER_SIZE, std::ios::out),
_pIstr(0),
_pOstr(&ostr),
_ptrBuf(),
_ptrOBuf(),
_ptrHelper(),
_ptrOHelper(),
_crc32(Poco::Checksum::TYPE_CRC32),
_expectedCrc32(0),
_checkCRC(false),
_bytesWritten(0),
_pHeader(&fileEntry)
{
if (fileEntry.isEncrypted())
throw Poco::NotImplementedException("Encryption not supported");
if (fileEntry.isDirectory())
{
// only header, no payload, zero crc
fileEntry.setSearchCRCAndSizesAfterData(false);
fileEntry.setCompressedSize(0);
fileEntry.setUncompressedSize(0);
fileEntry.setCRC(0);
std::string header = fileEntry.createHeader();
ostr.write(header.c_str(), static_cast<std::streamsize>(header.size()));
}
else
{
fileEntry.setSearchCRCAndSizesAfterData(!reposition);
if (fileEntry.getCompressionMethod() == ZipCommon::CM_DEFLATE)
{
int level = Z_DEFAULT_COMPRESSION;
if (fileEntry.getCompressionLevel() == ZipCommon::CL_FAST || fileEntry.getCompressionLevel() == ZipCommon::CL_SUPERFAST)
level = Z_BEST_SPEED;
else if (fileEntry.getCompressionLevel() == ZipCommon::CL_MAXIMUM)
level = Z_BEST_COMPRESSION;
// ignore the zlib init string which is of size 2 and also ignore the 4 byte adler32 value at the end of the stream!
_ptrOHelper = new PartialOutputStream(*_pOstr, 2, 4, false);
_ptrOBuf = new Poco::DeflatingOutputStream(*_ptrOHelper, DeflatingStreamBuf::STREAM_ZLIB, level);
}
else if (fileEntry.getCompressionMethod() == ZipCommon::CM_STORE)
{
_ptrOHelper = new PartialOutputStream(*_pOstr, 0, 0, false);
_ptrOBuf = _ptrOHelper;
}
else
{
throw Poco::NotImplementedException("Unsupported compression method");
}
// now write the header to the ostr!
std::string header = fileEntry.createHeader();
ostr.write(header.c_str(), static_cast<std::streamsize>(header.size()));
}
}
ZipStreamBuf::~ZipStreamBuf()
{
}
int ZipStreamBuf::readFromDevice(char* buffer, std::streamsize length)
{
if (!_ptrBuf) return 0; // directory entry
_ptrBuf->read(buffer, length);
int cnt = _ptrBuf->gcount();
if (cnt > 0)
{
_crc32.update(buffer, cnt);
}
else
{
if (_crc32.checksum() != _expectedCrc32)
{
if (_checkCRC)
throw ZipException("CRC failure");
else
{
// the CRC value is written directly after the data block
// parse it directly from the input stream
ZipDataInfo nfo(*_pIstr, false);
// now push back the header to the stream, so that the ZipLocalFileHeader can read it
Poco::Int32 size = static_cast<Poco::Int32>(nfo.getFullHeaderSize());
_expectedCrc32 = nfo.getCRC32();
const char* rawHeader = nfo.getRawHeader();
for (Poco::Int32 i = size-1; i >= 0; --i)
_pIstr->putback(rawHeader[i]);
if (!crcValid())
throw ZipException("CRC failure");
}
}
}
return cnt;
}
int ZipStreamBuf::writeToDevice(const char* buffer, std::streamsize length)
{
if (!_ptrOBuf) return 0; // directory entry
if (length == 0)
return 0;
_bytesWritten += length;
_ptrOBuf->write(buffer, length);
_crc32.update(buffer, length);
return length;
}
void ZipStreamBuf::close()
{
if (_ptrOBuf && _pHeader)
{
_ptrOBuf->flush();
DeflatingOutputStream* pDO = dynamic_cast<DeflatingOutputStream*>(_ptrOBuf.get());
if (pDO)
pDO->close();
if (_ptrOHelper)
{
_ptrOHelper->flush();
_ptrOHelper->close();
}
_ptrOBuf = 0;
poco_assert (*_pOstr);
// write an extra datablock if required
// or fix the crc entries
if (_pHeader->searchCRCAndSizesAfterData())
{
ZipDataInfo info;
info.setCRC32(_crc32.checksum());
info.setUncompressedSize(_bytesWritten);
info.setCompressedSize(static_cast<Poco::UInt32>(_ptrOHelper->bytesWritten()));
_pOstr->write(info.getRawHeader(), static_cast<std::streamsize>(info.getFullHeaderSize()));
}
else
{
poco_check_ptr (_pHeader);
_pHeader->setCRC(_crc32.checksum());
_pHeader->setUncompressedSize(_bytesWritten);
_pHeader->setCompressedSize(static_cast<Poco::UInt32>(_ptrOHelper->bytesWritten()));
_pOstr->seekp(_pHeader->getStartPos(), std::ios_base::beg);
poco_assert (*_pOstr);
std::string header = _pHeader->createHeader();
_pOstr->write(header.c_str(), static_cast<std::streamsize>(header.size()));
_pOstr->seekp(0, std::ios_base::end);
poco_assert (*_pOstr);
}
_pHeader = 0;
}
}
bool ZipStreamBuf::crcValid() const
{
if (!_ptrBuf) return true; // directory entry
return _crc32.checksum() == _expectedCrc32;
}
ZipIOS::ZipIOS(std::istream& istr, const ZipLocalFileHeader& fileEntry, bool reposition): _buf(istr, fileEntry, reposition)
{
poco_ios_init(&_buf);
}
ZipIOS::ZipIOS(std::ostream& ostr, ZipLocalFileHeader& fileEntry, bool reposition): _buf(ostr, fileEntry, reposition)
{
poco_ios_init(&_buf);
}
ZipIOS::~ZipIOS()
{
}
ZipStreamBuf* ZipIOS::rdbuf()
{
return &_buf;
}
ZipInputStream::ZipInputStream(std::istream& istr, const ZipLocalFileHeader& fileEntry, bool reposition): ZipIOS(istr, fileEntry, reposition), std::istream(&_buf)
{
}
ZipInputStream::~ZipInputStream()
{
}
bool ZipInputStream::crcValid() const
{
return _buf.crcValid();
}
ZipOutputStream::ZipOutputStream(std::ostream& ostr, ZipLocalFileHeader& fileEntry, bool seekableOutput): ZipIOS(ostr, fileEntry, seekableOutput), std::ostream(&_buf)
{
}
ZipOutputStream::~ZipOutputStream()
{
}
void ZipOutputStream::close()
{
flush();
_buf.close();
}
} } // namespace Poco::Zip