mirror of
https://github.com/pocoproject/poco.git
synced 2024-12-13 10:32:57 +01:00
fix: Cannot open certain zip files, #2467
This commit is contained in:
parent
5d1c06fdcd
commit
9faebd9c52
@ -54,6 +54,9 @@ public:
|
||||
static void sync(std::istream& in);
|
||||
/// 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);
|
||||
/// Verifies that the name of the ZipEntry is a valid path
|
||||
|
||||
|
@ -37,7 +37,7 @@ bool SkipCallback::handleZipEntry(std::istream& zipStream, const ZipLocalFileHea
|
||||
if (!hdr.searchCRCAndSizesAfterData())
|
||||
zipStream.seekg(hdr.getCompressedSize(), std::ios_base::cur);
|
||||
else
|
||||
ZipUtil::sync(zipStream);
|
||||
ZipUtil::syncDataDescriptor(zipStream, hdr.needsZip64());
|
||||
if (!zipStream.good()) throw Poco::IOException("Failed to seek on input stream");
|
||||
return true;
|
||||
}
|
||||
|
@ -160,6 +160,69 @@ 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)
|
||||
{
|
||||
|
BIN
Zip/testsuite/data/encapsulated.zip
Normal file
BIN
Zip/testsuite/data/encapsulated.zip
Normal file
Binary file not shown.
@ -65,6 +65,34 @@ void ZipTest::testSkipSingleFile()
|
||||
const std::string& POCO_UNUSED fileName = hdr.getFileName();
|
||||
}
|
||||
|
||||
void ZipTest::testCrcAndSizeAfterDataEncapsulated()
|
||||
{
|
||||
// touch empty.txt
|
||||
// zip -fd foo.zip empty.txt
|
||||
// zip -fd encapsulated.zip foo.zip
|
||||
std::string testFile = getTestFile("data", "encapsulated.zip");
|
||||
Poco::FileInputStream inp(testFile);
|
||||
assertTrue(inp.good());
|
||||
|
||||
ZipArchive arch(inp);
|
||||
ZipArchive::FileHeaders::const_iterator it = arch.findHeader("foo.zip");
|
||||
assertTrue(it != arch.headerEnd());
|
||||
inp.clear(); // inp eof(), should clear
|
||||
|
||||
ZipInputStream zipin(inp, it->second);
|
||||
std::ostringstream out(std::ios::binary);
|
||||
Poco::StreamCopier::copyStream(zipin, out);
|
||||
|
||||
std::string result = out.str();
|
||||
// sub zip
|
||||
std::istringstream istr(result);
|
||||
ZipArchive subArch(istr);
|
||||
it = subArch.findHeader("empty.txt");
|
||||
assertTrue(it != subArch.headerEnd());
|
||||
assertTrue(it->second.getCompressedSize() == 0);
|
||||
assertTrue(it->second.getUncompressedSize() == 0);
|
||||
}
|
||||
|
||||
|
||||
void ZipTest::testDecompressSingleFile()
|
||||
{
|
||||
@ -325,6 +353,7 @@ CppUnit::Test* ZipTest::suite()
|
||||
CppUnit_addTest(pSuite, ZipTest, testDecompressFlatVuln);
|
||||
CppUnit_addTest(pSuite, ZipTest, testCrcAndSizeAfterData);
|
||||
CppUnit_addTest(pSuite, ZipTest, testCrcAndSizeAfterDataWithArchive);
|
||||
CppUnit_addTest(pSuite, ZipTest, testCrcAndSizeAfterDataEncapsulated);
|
||||
CppUnit_addTest(pSuite, ZipTest, testDecompressZip64);
|
||||
CppUnit_addTest(pSuite, ZipTest, testValidPath);
|
||||
|
||||
|
@ -34,6 +34,7 @@ public:
|
||||
void testDecompressFlatVuln();
|
||||
void testCrcAndSizeAfterData();
|
||||
void testCrcAndSizeAfterDataWithArchive();
|
||||
void testCrcAndSizeAfterDataEncapsulated();
|
||||
|
||||
static const Poco::UInt64 KB = 1024;
|
||||
static const Poco::UInt64 MB = 1024*KB;
|
||||
|
Loading…
Reference in New Issue
Block a user