mirror of
https://github.com/pocoproject/poco.git
synced 2025-11-02 14:03:41 +01:00
@@ -23,7 +23,6 @@
|
||||
#include "Poco/Zip/Zip.h"
|
||||
#include "Poco/BufferedStreamBuf.h"
|
||||
#include <istream>
|
||||
#include <ostream>
|
||||
|
||||
|
||||
namespace Poco {
|
||||
@@ -31,24 +30,18 @@ namespace Zip {
|
||||
|
||||
|
||||
class Zip_API AutoDetectStreamBuf: public Poco::BufferedStreamBuf
|
||||
/// A AutoDetectStreamBuf is a class that limits one view on an inputstream to a selected view range
|
||||
/// AutoDetectStreamBuf automatically detects the end of a stream using the
|
||||
/// Data Descriptor signature.
|
||||
{
|
||||
public:
|
||||
AutoDetectStreamBuf(std::istream& in, const std::string& prefix, const std::string& postfix, bool reposition, Poco::UInt32 start);
|
||||
AutoDetectStreamBuf(std::istream& in, const std::string& prefix, const std::string& postfix, bool reposition, Poco::UInt32 start, bool needsZip64);
|
||||
/// Creates the AutoDetectStream.
|
||||
|
||||
|
||||
AutoDetectStreamBuf(std::ostream& out);
|
||||
/// Creates the AutoDetectStream.
|
||||
/// If initStream is true the status of the stream will be cleared on the first access, and the stream will be repositioned
|
||||
/// to position start
|
||||
|
||||
~AutoDetectStreamBuf();
|
||||
/// Destroys the AutoDetectStream.
|
||||
|
||||
protected:
|
||||
int readFromDevice(char* buffer, std::streamsize length);
|
||||
|
||||
int writeToDevice(const char* buffer, std::streamsize length);
|
||||
|
||||
private:
|
||||
@@ -57,14 +50,15 @@ private:
|
||||
STREAM_BUFFER_SIZE = 1024
|
||||
};
|
||||
|
||||
std::istream* _pIstr;
|
||||
std::ostream* _pOstr;
|
||||
bool _eofDetected;
|
||||
int _matchCnt;
|
||||
std::string _prefix;
|
||||
std::string _postfix;
|
||||
bool _reposition;
|
||||
Poco::UInt32 _start;
|
||||
std::istream* _pIstr;
|
||||
bool _eofDetected;
|
||||
int _matchCnt;
|
||||
std::string _prefix;
|
||||
std::string _postfix;
|
||||
bool _reposition;
|
||||
Poco::UInt32 _start;
|
||||
bool _needsZip64;
|
||||
Poco::UInt64 _length;
|
||||
};
|
||||
|
||||
|
||||
@@ -75,14 +69,10 @@ class Zip_API AutoDetectIOS: public virtual std::ios
|
||||
/// order of the stream buffer and base classes.
|
||||
{
|
||||
public:
|
||||
AutoDetectIOS(std::istream& istr, const std::string& prefix, const std::string& postfix, bool reposition, Poco::UInt32 start);
|
||||
AutoDetectIOS(std::istream& istr, const std::string& prefix, const std::string& postfix, bool reposition, Poco::UInt32 start, bool needsZip64);
|
||||
/// Creates the basic stream and connects it
|
||||
/// to the given input stream.
|
||||
|
||||
AutoDetectIOS(std::ostream& ostr);
|
||||
/// Creates the basic stream and connects it
|
||||
/// to the given output stream.
|
||||
|
||||
~AutoDetectIOS();
|
||||
/// Destroys the stream.
|
||||
|
||||
@@ -95,37 +85,18 @@ protected:
|
||||
|
||||
|
||||
class Zip_API AutoDetectInputStream: public AutoDetectIOS, public std::istream
|
||||
/// This stream copies all characters read through it
|
||||
/// to one or multiple output streams.
|
||||
/// AutoDetectInputStream automatically detects the end of a stream using the
|
||||
/// Data Descriptor signature.
|
||||
{
|
||||
public:
|
||||
AutoDetectInputStream(std::istream& istr, const std::string& prefix = std::string(), const std::string& postfix = std::string(), bool reposition = false, Poco::UInt32 start = 0);
|
||||
/// Creates the AutoDetectInputStream and connects it
|
||||
/// to the given input stream. Bytes read are guaranteed to be in the range [start, end-1]
|
||||
/// If initStream is true the status of the stream will be cleared on the first access, and the stream will be repositioned
|
||||
/// to position start
|
||||
AutoDetectInputStream(std::istream& istr, const std::string& prefix = std::string(), const std::string& postfix = std::string(), bool reposition = false, Poco::UInt32 start = 0, bool needsZip64 = false);
|
||||
/// Creates the AutoDetectInputStream and connects it to the underlying stream.
|
||||
|
||||
~AutoDetectInputStream();
|
||||
/// Destroys the AutoDetectInputStream.
|
||||
};
|
||||
|
||||
|
||||
class Zip_API AutoDetectOutputStream: public AutoDetectIOS, public std::ostream
|
||||
/// This stream copies all characters written to it
|
||||
/// to one or multiple output streams.
|
||||
{
|
||||
public:
|
||||
AutoDetectOutputStream(std::ostream& ostr);
|
||||
/// Creates the AutoDetectOutputStream and connects it
|
||||
/// to the given input stream. Bytes written are guaranteed to be in the range [start, end-1]
|
||||
/// If initStream is true the status of the stream will be cleared on the first access, and the stream will be repositioned
|
||||
/// to position start
|
||||
|
||||
~AutoDetectOutputStream();
|
||||
/// Destroys the AutoDetectOutputStream.
|
||||
};
|
||||
|
||||
|
||||
} } // namespace Poco::Zip
|
||||
|
||||
|
||||
|
||||
@@ -280,6 +280,7 @@ inline void ZipLocalFileHeader::setRequiredVersion(int major, int minor)
|
||||
_rawHeader[VERSION_POS] = static_cast<char>(static_cast<unsigned char>(major)*10+static_cast<unsigned char>(minor));
|
||||
}
|
||||
|
||||
|
||||
inline Poco::UInt16 ZipLocalFileHeader::getFileNameLength() const
|
||||
{
|
||||
return ZipUtil::get16BitValue(_rawHeader, FILE_LENGTH_POS);
|
||||
|
||||
@@ -27,30 +27,17 @@ namespace Poco {
|
||||
namespace Zip {
|
||||
|
||||
|
||||
AutoDetectStreamBuf::AutoDetectStreamBuf(std::istream& in, const std::string& pre, const std::string& post, bool reposition, Poco::UInt32 start):
|
||||
AutoDetectStreamBuf::AutoDetectStreamBuf(std::istream& in, const std::string& pre, const std::string& post, bool reposition, Poco::UInt32 start, bool needsZip64):
|
||||
Poco::BufferedStreamBuf(STREAM_BUFFER_SIZE, std::ios::in),
|
||||
_pIstr(&in),
|
||||
_pOstr(0),
|
||||
_eofDetected(false),
|
||||
_matchCnt(0),
|
||||
_prefix(pre),
|
||||
_postfix(post),
|
||||
_reposition(reposition),
|
||||
_start(start)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
AutoDetectStreamBuf::AutoDetectStreamBuf(std::ostream& out):
|
||||
Poco::BufferedStreamBuf(STREAM_BUFFER_SIZE, std::ios::out),
|
||||
_pIstr(0),
|
||||
_pOstr(&out),
|
||||
_eofDetected(false),
|
||||
_matchCnt(0),
|
||||
_prefix(),
|
||||
_postfix(),
|
||||
_reposition(false),
|
||||
_start(0u)
|
||||
_start(start),
|
||||
_needsZip64(needsZip64),
|
||||
_length(0)
|
||||
{
|
||||
}
|
||||
|
||||
@@ -63,7 +50,7 @@ AutoDetectStreamBuf::~AutoDetectStreamBuf()
|
||||
int AutoDetectStreamBuf::readFromDevice(char* buffer, std::streamsize length)
|
||||
{
|
||||
poco_assert_dbg(length >= 8);
|
||||
if (_pIstr == 0 ||length == 0) return -1;
|
||||
if (_pIstr == 0 || length == 0) return -1;
|
||||
|
||||
if (_reposition)
|
||||
{
|
||||
@@ -74,120 +61,138 @@ int AutoDetectStreamBuf::readFromDevice(char* buffer, std::streamsize length)
|
||||
|
||||
if (!_prefix.empty())
|
||||
{
|
||||
std::streamsize tmp = (_prefix.size() > length)? length: static_cast<std::streamsize>(_prefix.size());
|
||||
std::memcpy(buffer, _prefix.c_str(), tmp);
|
||||
_prefix = _prefix.substr(tmp);
|
||||
return tmp;
|
||||
std::streamsize n = (_prefix.size() > length) ? length : static_cast<std::streamsize>(_prefix.size());
|
||||
std::memcpy(buffer, _prefix.data(), n);
|
||||
_prefix.erase(0, n);
|
||||
return n;
|
||||
}
|
||||
|
||||
if (_eofDetected)
|
||||
{
|
||||
if (!_postfix.empty())
|
||||
{
|
||||
std::streamsize tmp = (_postfix.size() > length)? length: static_cast<std::streamsize>(_postfix.size());
|
||||
std::memcpy(buffer, _postfix.c_str(), tmp);
|
||||
_postfix = _postfix.substr(tmp);
|
||||
return tmp;
|
||||
std::streamsize n = (_postfix.size() > length) ? length : static_cast<std::streamsize>(_postfix.size());
|
||||
std::memcpy(buffer, _postfix.data(), n);
|
||||
_postfix.erase(0, n);
|
||||
return n;
|
||||
}
|
||||
else
|
||||
return -1;
|
||||
else return -1;
|
||||
}
|
||||
|
||||
if (!_pIstr->good())
|
||||
return -1;
|
||||
if (!_pIstr->good()) return -1;
|
||||
|
||||
char byte3('\x00');
|
||||
std::streamsize tempPos = 0;
|
||||
std::streamsize offset = 0;
|
||||
static std::istream::int_type eof = std::istream::traits_type::eof();
|
||||
while (_pIstr->good() && !_pIstr->eof() && (tempPos+4) < length)
|
||||
while (_pIstr->good() && !_pIstr->eof() && (offset + 4) < length)
|
||||
{
|
||||
std::istream::int_type c = _pIstr->get();
|
||||
if (c != eof)
|
||||
{
|
||||
// all zip headers start with the same 2byte prefix
|
||||
if (_matchCnt<2)
|
||||
if (_matchCnt < 3)
|
||||
{
|
||||
if (c == ZipLocalFileHeader::HEADER[_matchCnt])
|
||||
if (c == ZipDataInfo::HEADER[_matchCnt])
|
||||
{
|
||||
++_matchCnt;
|
||||
}
|
||||
else
|
||||
{
|
||||
// matchcnt was either 0 or 1 the headers have all unique chars -> safe to set to 0
|
||||
if (_matchCnt == 1)
|
||||
for (int i = 0; i < _matchCnt; i++)
|
||||
{
|
||||
buffer[tempPos++] = ZipLocalFileHeader::HEADER[0];
|
||||
buffer[offset++] = ZipDataInfo::HEADER[i];
|
||||
}
|
||||
_matchCnt = 0;
|
||||
|
||||
buffer[tempPos++] = static_cast<char>(c);
|
||||
buffer[offset++] = static_cast<char>(c);
|
||||
}
|
||||
}
|
||||
else
|
||||
else if (_matchCnt == 3)
|
||||
{
|
||||
//the upper 2 bytes differ: the lower one must be in range 1,3,5,7, the upper must be one larger: 2,4,6,8
|
||||
if (_matchCnt == 2)
|
||||
if (ZipDataInfo::HEADER[3] == c)
|
||||
{
|
||||
if (ZipLocalFileHeader::HEADER[2] == c ||
|
||||
ZipArchiveInfo::HEADER[2] == c ||
|
||||
ZipFileInfo::HEADER[2] == c ||
|
||||
ZipDataInfo::HEADER[2] == c)
|
||||
std::streamsize dataInfoSize = 0;
|
||||
if (_needsZip64)
|
||||
{
|
||||
byte3 = static_cast<char>(c);;
|
||||
_matchCnt++;
|
||||
ZipDataInfo64 dataInfo(*_pIstr, true);
|
||||
if (!_pIstr->good()) throw Poco::IOException("Failed to read data descriptor");
|
||||
|
||||
dataInfoSize = dataInfo.getFullHeaderSize();
|
||||
if (dataInfo.getCompressedSize() == _length + offset)
|
||||
{
|
||||
_pIstr->seekg(-static_cast<int>(dataInfoSize), std::ios::cur);
|
||||
if (!_pIstr->good()) throw Poco::IOException("Failed to seek on input stream");
|
||||
|
||||
_eofDetected = true;
|
||||
_length += offset;
|
||||
|
||||
if (offset == 0 && !_postfix.empty())
|
||||
{
|
||||
offset = (_postfix.size() > length) ? length : static_cast<std::streamsize>(_postfix.size());
|
||||
std::memcpy(buffer, _postfix.data(), offset);
|
||||
_postfix.erase(0, offset);
|
||||
}
|
||||
|
||||
return offset;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
buffer[tempPos++] = ZipLocalFileHeader::HEADER[0];
|
||||
buffer[tempPos++] = ZipLocalFileHeader::HEADER[1];
|
||||
buffer[tempPos++] = static_cast<char>(c);
|
||||
_matchCnt = 0;
|
||||
ZipDataInfo dataInfo(*_pIstr, true);
|
||||
if (!_pIstr->good()) throw Poco::IOException("Failed to read data descriptor");
|
||||
|
||||
dataInfoSize = dataInfo.getFullHeaderSize();
|
||||
if (dataInfo.getCompressedSize() == _length + offset)
|
||||
{
|
||||
_pIstr->seekg(-static_cast<int>(dataInfoSize), std::ios::cur);
|
||||
if (!_pIstr->good()) throw Poco::IOException("Failed to seek on input stream");
|
||||
|
||||
_eofDetected = true;
|
||||
_length += offset;
|
||||
|
||||
if (offset == 0 && !_postfix.empty())
|
||||
{
|
||||
offset = (_postfix.size() > length) ? length : static_cast<std::streamsize>(_postfix.size());
|
||||
std::memcpy(buffer, _postfix.data(), offset);
|
||||
_postfix.erase(0, offset);
|
||||
}
|
||||
|
||||
return offset;
|
||||
}
|
||||
}
|
||||
|
||||
_pIstr->seekg(-static_cast<int>(dataInfoSize - 4), std::ios::cur);
|
||||
if (!_pIstr->good()) throw Poco::IOException("Failed to seek on input stream");
|
||||
|
||||
buffer[offset++] = ZipDataInfo::HEADER[0];
|
||||
buffer[offset++] = ZipDataInfo::HEADER[1];
|
||||
buffer[offset++] = ZipDataInfo::HEADER[2];
|
||||
buffer[offset++] = ZipDataInfo::HEADER[3];
|
||||
_matchCnt = 0;
|
||||
}
|
||||
else if (_matchCnt == 3)
|
||||
else
|
||||
{
|
||||
if (c-1 == byte3)
|
||||
{
|
||||
// a match, seek back
|
||||
_pIstr->seekg(-4, std::ios::cur);
|
||||
if (!_pIstr->good()) throw Poco::IOException("Failed to seek on input stream");
|
||||
_eofDetected = true;
|
||||
return tempPos;
|
||||
}
|
||||
else
|
||||
{
|
||||
buffer[tempPos++] = ZipLocalFileHeader::HEADER[0];
|
||||
buffer[tempPos++] = ZipLocalFileHeader::HEADER[1];
|
||||
buffer[tempPos++] = byte3;
|
||||
buffer[tempPos++] = c;
|
||||
_matchCnt = 0; //the headers have all unique chars -> safe to set to 0
|
||||
}
|
||||
buffer[offset++] = ZipDataInfo::HEADER[0];
|
||||
buffer[offset++] = ZipDataInfo::HEADER[1];
|
||||
buffer[offset++] = ZipDataInfo::HEADER[2];
|
||||
buffer[offset++] = c;
|
||||
_matchCnt = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return tempPos;
|
||||
_length += offset;
|
||||
return offset;
|
||||
|
||||
}
|
||||
|
||||
|
||||
int AutoDetectStreamBuf::writeToDevice(const char* buffer, std::streamsize length)
|
||||
{
|
||||
if (_pOstr == 0 || length == 0) return -1;
|
||||
_pOstr->write(buffer, length);
|
||||
if (_pOstr->good())
|
||||
return length;
|
||||
throw Poco::IOException("Failed to write to output stream");
|
||||
return -1; // not supported
|
||||
}
|
||||
|
||||
|
||||
AutoDetectIOS::AutoDetectIOS(std::istream& istr, const std::string& pre, const std::string& post, bool reposition, Poco::UInt32 start):
|
||||
_buf(istr, pre, post, reposition, start)
|
||||
{
|
||||
poco_ios_init(&_buf);
|
||||
}
|
||||
|
||||
|
||||
AutoDetectIOS::AutoDetectIOS(std::ostream& ostr): _buf(ostr)
|
||||
AutoDetectIOS::AutoDetectIOS(std::istream& istr, const std::string& pre, const std::string& post, bool reposition, Poco::UInt32 start, bool needsZip64):
|
||||
_buf(istr, pre, post, reposition, start, needsZip64)
|
||||
{
|
||||
poco_ios_init(&_buf);
|
||||
}
|
||||
@@ -204,8 +209,8 @@ AutoDetectStreamBuf* AutoDetectIOS::rdbuf()
|
||||
}
|
||||
|
||||
|
||||
AutoDetectInputStream::AutoDetectInputStream(std::istream& istr, const std::string& pre, const std::string& post, bool reposition, Poco::UInt32 start):
|
||||
AutoDetectIOS(istr, pre, post, reposition, start),
|
||||
AutoDetectInputStream::AutoDetectInputStream(std::istream& istr, const std::string& pre, const std::string& post, bool reposition, Poco::UInt32 start, bool needsZip64):
|
||||
AutoDetectIOS(istr, pre, post, reposition, start, needsZip64),
|
||||
std::istream(&_buf)
|
||||
{
|
||||
}
|
||||
@@ -216,16 +221,4 @@ AutoDetectInputStream::~AutoDetectInputStream()
|
||||
}
|
||||
|
||||
|
||||
AutoDetectOutputStream::AutoDetectOutputStream(std::ostream& ostr):
|
||||
AutoDetectIOS(ostr),
|
||||
std::ostream(&_buf)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
AutoDetectOutputStream::~AutoDetectOutputStream()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
} } // namespace Poco::Zip
|
||||
|
||||
@@ -64,7 +64,6 @@ ZipDataInfo::~ZipDataInfo()
|
||||
}
|
||||
|
||||
|
||||
|
||||
const char ZipDataInfo64::HEADER[ZipCommon::HEADER_SIZE] = {'\x50', '\x4b', '\x07', '\x08'};
|
||||
|
||||
|
||||
|
||||
@@ -83,7 +83,7 @@ ZipLocalFileHeader::ZipLocalFileHeader(std::istream& inp, bool assumeHeaderRead,
|
||||
{
|
||||
char header[ZipCommon::HEADER_SIZE]={'\x00', '\x00', '\x00', '\x00'};
|
||||
inp.read(header, ZipCommon::HEADER_SIZE);
|
||||
if (std::memcmp(header, ZipDataInfo64::HEADER, sizeof(header)) == 0)
|
||||
if (_forceZip64)
|
||||
{
|
||||
ZipDataInfo64 nfo(inp, true);
|
||||
setCRC(nfo.getCRC32());
|
||||
@@ -166,6 +166,7 @@ void ZipLocalFileHeader::parse(std::istream& inp, bool assumeHeaderRead)
|
||||
ptr += 2;
|
||||
if (id == ZipCommon::ZIP64_EXTRA_ID)
|
||||
{
|
||||
_forceZip64 = true;
|
||||
poco_assert(size >= 8);
|
||||
if (getUncompressedSizeFromHeader() == ZipCommon::ZIP64_MAGIC)
|
||||
{
|
||||
|
||||
@@ -63,7 +63,7 @@ ZipStreamBuf::ZipStreamBuf(std::istream& istr, const ZipLocalFileHeader& fileEnt
|
||||
std::string crc(4, ' ');
|
||||
if (fileEntry.searchCRCAndSizesAfterData())
|
||||
{
|
||||
_ptrHelper = new AutoDetectInputStream(istr, init, crc, reposition, start);
|
||||
_ptrHelper = new AutoDetectInputStream(istr, init, crc, reposition, start, fileEntry.needsZip64());
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -75,7 +75,7 @@ ZipStreamBuf::ZipStreamBuf(std::istream& istr, const ZipLocalFileHeader& fileEnt
|
||||
{
|
||||
if (fileEntry.searchCRCAndSizesAfterData())
|
||||
{
|
||||
_ptrBuf = new AutoDetectInputStream(istr, "", "", reposition, start);
|
||||
_ptrBuf = new AutoDetectInputStream(istr, "", "", reposition, start, fileEntry.needsZip64());
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user