fixed GH #2661: Poco::Zip::ZipArchive cannot load new tomcat.zip file

This commit is contained in:
Günter Obiltschnig
2019-06-22 18:24:49 +02:00
parent bb916b84d0
commit bad473f568
5 changed files with 87 additions and 20 deletions

View File

@@ -152,6 +152,7 @@ To decompress single files you must first parse a Zip file, and then decompress
ZipArchive arch(inp); ZipArchive arch(inp);
ZipArchive::FileHeaders::const_iterator it = arch.findHeader("data/hello.txt"); ZipArchive::FileHeaders::const_iterator it = arch.findHeader("data/hello.txt");
poco_assert (it != arch.headerEnd()); poco_assert (it != arch.headerEnd());
inp.clear();
ZipInputStream zipin(inp, it->second); ZipInputStream zipin(inp, it->second);
std::ostringstream out(std::ios::binary); std::ostringstream out(std::ios::binary);
Poco::StreamCopier::copyStream(zipin, out); Poco::StreamCopier::copyStream(zipin, out);

View File

@@ -54,6 +54,9 @@ public:
static void sync(std::istream& in); static void sync(std::istream& in);
/// Searches the next valid header in the input stream, stops right before it /// Searches the next valid header in the input stream, stops right before it
static void syncDataDescriptor(std::istream& in, bool force64);
/// Searches the next data descriptor
static void verifyZipEntryFileName(const std::string& zipPath); static void verifyZipEntryFileName(const std::string& zipPath);
/// Verifies that the name of the ZipEntry is a valid path /// Verifies that the name of the ZipEntry is a valid path

View File

@@ -37,7 +37,7 @@ bool SkipCallback::handleZipEntry(std::istream& zipStream, const ZipLocalFileHea
if (!hdr.searchCRCAndSizesAfterData()) if (!hdr.searchCRCAndSizesAfterData())
zipStream.seekg(hdr.getCompressedSize(), std::ios_base::cur); zipStream.seekg(hdr.getCompressedSize(), std::ios_base::cur);
else else
ZipUtil::sync(zipStream); ZipUtil::syncDataDescriptor(zipStream, hdr.needsZip64());
if (!zipStream.good()) throw Poco::IOException("Failed to seek on input stream"); if (!zipStream.good()) throw Poco::IOException("Failed to seek on input stream");
return true; return true;
} }

View File

@@ -126,8 +126,7 @@ void ZipFileInfo::parse(std::istream& inp, bool assumeHeaderRead)
ptr += 2; ptr += 2;
if (id == ZipCommon::ZIP64_EXTRA_ID) if (id == ZipCommon::ZIP64_EXTRA_ID)
{ {
poco_assert(size >= 8); if (size >= 8 && getUncompressedSizeFromHeader() == ZipCommon::ZIP64_MAGIC)
if (getUncompressedSizeFromHeader() == ZipCommon::ZIP64_MAGIC)
{ {
setUncompressedSize(ZipUtil::get64BitValue(ptr, 0)); setUncompressedSize(ZipUtil::get64BitValue(ptr, 0));
size -= 8; size -= 8;

View File

@@ -161,6 +161,70 @@ void ZipUtil::sync(std::istream& in)
} }
void ZipUtil::syncDataDescriptor(std::istream & in, bool force64)
{
std::streampos start = in.tellg();
const int eof = std::char_traits<char>::eof();
int c = in.get();
do
{
while (c != eof && c != ZipDataInfo::HEADER[0]) { c = in.get(); }
if (c == eof) return;
bool match = true;
for (int i = 1; i < 4 && match; i++)
{
c = in.get();
if (c != ZipDataInfo::HEADER[i]) match = false;
}
if (match)
{
std::streampos end = in.tellg();
if (force64)
{
ZipDataInfo64 nfo(in, true);
if (nfo.isValid())
{
if (end - start == nfo.getCompressedSize() + 4)
{
in.seekg(-static_cast<int>(ZipDataInfo64::getFullHeaderSize()), std::ios::cur);
if (!in.good()) throw Poco::IOException("Failed to seek on input stream");
break;
}
else
{
in.seekg(-static_cast<int>(ZipDataInfo64::getFullHeaderSize()) + 4, std::ios::cur);
if (!in.good()) throw Poco::IOException("Failed to seek on input stream");
}
}
}
else
{
ZipDataInfo nfo(in, true);
if (nfo.isValid())
{
if (end - start == nfo.getCompressedSize() + 4)
{
in.seekg(-static_cast<int>(ZipDataInfo::getFullHeaderSize()), std::ios::cur);
if (!in.good()) throw Poco::IOException("Failed to seek on input stream");
break;
}
else
{
in.seekg(-static_cast<int>(ZipDataInfo::getFullHeaderSize()) + 4, std::ios::cur);
if (!in.good()) throw Poco::IOException("Failed to seek on input stream");
}
}
}
}
} while (c != eof);
}
void ZipUtil::verifyZipEntryFileName(const std::string& fn) void ZipUtil::verifyZipEntryFileName(const std::string& fn)
{ {
if (fn.find("\\") != std::string::npos) if (fn.find("\\") != std::string::npos)