fix for GH #1416: use seekg() instead of multiple putback() operations, which may not work in all cases. Note that this requires the stream passed to Poco::Zip::Decompress to be seekable.

This commit is contained in:
Günter Obiltschnig
2016-09-29 11:25:03 +02:00
parent 4c7562c497
commit ed0284c7c6
6 changed files with 19 additions and 24 deletions

View File

@@ -69,6 +69,7 @@ int AutoDetectStreamBuf::readFromDevice(char* buffer, std::streamsize length)
{ {
_pIstr->seekg(_start, std::ios_base::beg); _pIstr->seekg(_start, std::ios_base::beg);
_reposition = false; _reposition = false;
if (!_pIstr->good()) return -1;
} }
if (!_prefix.empty()) if (!_prefix.empty())
@@ -145,11 +146,9 @@ int AutoDetectStreamBuf::readFromDevice(char* buffer, std::streamsize length)
{ {
if (c-1 == byte3) if (c-1 == byte3)
{ {
// a match, pushback // a match, seek back first, try pushback as fallback
_pIstr->putback(c); _pIstr->seekg(-4, std::ios::cur);
_pIstr->putback(byte3); if (!_pIstr->good()) throw Poco::IOException("Failed to seek on input stream");
_pIstr->putback(ZipLocalFileHeader::HEADER[1]);
_pIstr->putback(ZipLocalFileHeader::HEADER[0]);
_eofDetected = true; _eofDetected = true;
return tempPos; return tempPos;
} }

View File

@@ -93,6 +93,7 @@ void Compress::addFileRaw(std::istream& in, const ZipLocalFileHeader& h, const P
std::string fn = ZipUtil::validZipEntryFileName(fileName); std::string fn = ZipUtil::validZipEntryFileName(fileName);
//bypass the header of the input stream and point to the first byte of the data payload //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); in.seekg(h.getDataStartPos(), std::ios_base::beg);
if (!in.good()) throw Poco::IOException("Failed to seek on input stream");
if (_files.size() >= 65535) if (_files.size() >= 65535)
throw ZipException("Maximum number of entries for a ZIP file reached: 65535"); throw ZipException("Maximum number of entries for a ZIP file reached: 65535");

View File

@@ -69,7 +69,7 @@ int PartialStreamBuf::readFromDevice(char* buffer, std::streamsize length)
_pIstr->clear(); _pIstr->clear();
_pIstr->seekg(_start, std::ios_base::beg); _pIstr->seekg(_start, std::ios_base::beg);
if (_pIstr->fail()) if (_pIstr->fail())
throw Poco::IOException("Failed to reposition in stream"); throw Poco::IOException("Failed to seek on input stream");
} }
if (!_prefix.empty()) if (!_prefix.empty())
{ {

View File

@@ -17,6 +17,7 @@
#include "Poco/Zip/SkipCallback.h" #include "Poco/Zip/SkipCallback.h"
#include "Poco/Zip/ZipLocalFileHeader.h" #include "Poco/Zip/ZipLocalFileHeader.h"
#include "Poco/Zip/ZipUtil.h" #include "Poco/Zip/ZipUtil.h"
#include "Poco/Exception.h"
namespace Poco { namespace Poco {
@@ -39,6 +40,7 @@ bool SkipCallback::handleZipEntry(std::istream& zipStream, const ZipLocalFileHea
zipStream.seekg(hdr.getCompressedSize(), std::ios_base::cur); zipStream.seekg(hdr.getCompressedSize(), std::ios_base::cur);
else else
ZipUtil::sync(zipStream); ZipUtil::sync(zipStream);
if (!zipStream.good()) throw Poco::IOException("Failed to seek on input stream");
return true; return true;
} }

View File

@@ -175,8 +175,8 @@ int ZipStreamBuf::readFromDevice(char* buffer, std::streamsize length)
Poco::Int32 size = static_cast<Poco::Int32>(nfo.getFullHeaderSize()); Poco::Int32 size = static_cast<Poco::Int32>(nfo.getFullHeaderSize());
_expectedCrc32 = nfo.getCRC32(); _expectedCrc32 = nfo.getCRC32();
const char* rawHeader = nfo.getRawHeader(); const char* rawHeader = nfo.getRawHeader();
for (Poco::Int32 i = size-1; i >= 0; --i) _pIstr->seekg(-size, std::ios::cur);
_pIstr->putback(rawHeader[i]); if (!_pIstr->good()) throw Poco::IOException("Failed to seek on input stream");
if (!crcValid()) if (!crcValid())
throw ZipException("CRC failure"); throw ZipException("CRC failure");
} }

View File

@@ -117,31 +117,23 @@ void ZipUtil::sync(std::istream& in)
{ {
if (std::memcmp(ZipLocalFileHeader::HEADER+PREFIX, &temp[tempPos - PREFIX], PREFIX) == 0) if (std::memcmp(ZipLocalFileHeader::HEADER+PREFIX, &temp[tempPos - PREFIX], PREFIX) == 0)
{ {
in.putback(ZipLocalFileHeader::HEADER[3]); in.seekg(-4, std::ios::cur);
in.putback(ZipLocalFileHeader::HEADER[2]); if (!in.good()) throw Poco::IOException("Failed to seek on input stream");
in.putback(ZipLocalFileHeader::HEADER[1]);
in.putback(ZipLocalFileHeader::HEADER[0]);
} }
else if (std::memcmp(ZipArchiveInfo::HEADER+PREFIX, &temp[tempPos - PREFIX], PREFIX) == 0) else if (std::memcmp(ZipArchiveInfo::HEADER+PREFIX, &temp[tempPos - PREFIX], PREFIX) == 0)
{ {
in.putback(ZipArchiveInfo::HEADER[3]); in.seekg(-4, std::ios::cur);
in.putback(ZipArchiveInfo::HEADER[2]); if (!in.good()) throw Poco::IOException("Failed to seek on input stream");
in.putback(ZipArchiveInfo::HEADER[1]);
in.putback(ZipArchiveInfo::HEADER[0]);
} }
else if (std::memcmp(ZipFileInfo::HEADER+PREFIX, &temp[tempPos - PREFIX], PREFIX) == 0) else if (std::memcmp(ZipFileInfo::HEADER+PREFIX, &temp[tempPos - PREFIX], PREFIX) == 0)
{ {
in.putback(ZipFileInfo::HEADER[3]); in.seekg(-4, std::ios::cur);
in.putback(ZipFileInfo::HEADER[2]); if (!in.good()) throw Poco::IOException("Failed to seek on input stream");
in.putback(ZipFileInfo::HEADER[1]);
in.putback(ZipFileInfo::HEADER[0]);
} }
else else
{ {
in.putback(ZipDataInfo::HEADER[3]); in.seekg(-4, std::ios::cur);
in.putback(ZipDataInfo::HEADER[2]); if (!in.good()) throw Poco::IOException("Failed to seek on input stream");
in.putback(ZipDataInfo::HEADER[1]);
in.putback(ZipDataInfo::HEADER[0]);
} }
return; return;
} }
@@ -149,6 +141,7 @@ void ZipUtil::sync(std::istream& in)
{ {
// we have read 2 bytes, should only be one: putback the last char // we have read 2 bytes, should only be one: putback the last char
in.putback(temp[tempPos - 1]); in.putback(temp[tempPos - 1]);
if (!in.good()) throw Poco::IOException("Failed to putback on input stream");
--tempPos; --tempPos;
} }
} }