1
0
mirror of https://github.com/VCMP-SqMod/SqMod.git synced 2025-02-07 13:27:13 +01:00
SqMod/vendor/POCO/Zip/src/ZipUtil.cpp
Sandu Liviu Catalin 4a6bfc086c Major plugin refactor and cleanup.
Switched to POCO library for unified platform/library interface.
Deprecated the external module API. It was creating more problems than solving.
Removed most built-in libraries in favor of system libraries for easier maintenance.
Cleaned and secured code with help from static analyzers.
2021-01-30 08:51:39 +02:00

250 lines
7.1 KiB
C++

//
// ZipUtil.cpp
//
// Library: Zip
// Package: Zip
// Module: ZipUtil
//
// Copyright (c) 2007, Applied Informatics Software Engineering GmbH.
// and Contributors.
//
// SPDX-License-Identifier: BSL-1.0
//
#include "Poco/Zip/ZipUtil.h"
#include "Poco/Zip/ZipException.h"
#include "Poco/Zip/ZipLocalFileHeader.h"
#include "Poco/Zip/ZipFileInfo.h"
#include "Poco/Zip/ZipDataInfo.h"
#include "Poco/Zip/ZipArchiveInfo.h"
#include <cstring>
namespace Poco {
namespace Zip {
Poco::DateTime ZipUtil::parseDateTime(const char* pVal, const Poco::UInt32 timePos, const Poco::UInt32 datePos)
{
Poco::UInt16 time = ZipUtil::get16BitValue(pVal, timePos);
Poco::UInt16 date = ZipUtil::get16BitValue(pVal, datePos);
// TIME: second 0-4, minute 5-10, hour 11-15, second resolution is 2!
int sec = 2*(time & 0x001fu); // 0000 0000 0001 1111
int min = ((time & 0x07e0u) >> 5); // 0000 0111 1110 0000
int hour = ((time & 0xf800u) >> 11); // 1111 1000 0000 0000
// DATE: day 0-4, month 5-8, year (starting with 1980): 9-16
int day = (date & 0x001fu); // 0000 0000 0001 1111
int mon = ((date & 0x01e0u) >> 5); // 0000 0001 1110 0000
int year = 1980+((date & 0xfe00u) >> 9); // 1111 1110 0000 0000
if (Poco::DateTime::isValid(year, mon, day, hour, min, sec))
return Poco::DateTime(year, mon, day, hour, min, sec);
else
return Poco::DateTime(1970, 01, 01);
}
void ZipUtil::setDateTime(const Poco::DateTime& dt, char* pVal, const Poco::UInt32 timePos, const Poco::UInt32 datePos)
{
// TIME: second 0-4, minute 5-10, hour 11-15
Poco::UInt16 time = static_cast<Poco::UInt16>((dt.second()/2) + (dt.minute()<<5) + (dt.hour()<<11));
// DATE: day 0-4, month 5-8, year (starting with 1980): 9-16
int year = dt.year() - 1980;
if (year < 0) year = 0;
Poco::UInt16 date = static_cast<Poco::UInt16>(dt.day() + (dt.month()<<5) + (year<<9));
ZipUtil::set16BitValue(time, pVal, timePos);
ZipUtil::set16BitValue(date, pVal, datePos);
}
std::string ZipUtil::fakeZLibInitString(ZipCommon::CompressionLevel cl)
{
std::string init(2, ' ');
// compression info:
// deflate is used, bit 0-3: 0x08
// dictionary size is always 32k: calc ld2(32k)-8 = ld2(2^15) - 8 = 15 - 8 = 7 --> bit 4-7: 0x70
init[0] = '\x78';
// now fake flags
// bits 0-4 check bits: set them so that init[0]*256+init[1] % 31 == 0
// bit 5: preset dictionary? always no for us, set to 0
// bits 6-7: compression level: 00 very fast, 01 fast, 10 normal, 11 best
if (cl == ZipCommon::CL_SUPERFAST)
init[1] = '\x00';
else if (cl == ZipCommon::CL_FAST)
init[1] = '\x40';
else if (cl == ZipCommon::CL_NORMAL)
init[1] = '\x80';
else
init[1] = '\xc0';
// now set the last 5 bits
Poco::UInt16 tmpVal = ((Poco::UInt16)init[0])*256+((unsigned char)init[1]);
char checkBits = (31 - (char)(tmpVal%31));
init[1] |= checkBits; // set the lower 5 bits
tmpVal = ((Poco::UInt16)init[0])*256+((unsigned char)init[1]);
poco_assert_dbg ((tmpVal % 31) == 0);
return init;
}
void ZipUtil::sync(std::istream& in)
{
enum
{
PREFIX = 2,
BUFFER_SIZE = 1024
};
char temp[BUFFER_SIZE];
in.read(temp, PREFIX);
std::size_t tempPos = PREFIX;
while (in.good() && !in.eof())
{
// all zip headers start withe same 2byte prefix
if (std::memcmp(ZipLocalFileHeader::HEADER, &temp[tempPos - PREFIX], PREFIX) == 0)
{
// we have a possible header!
// read the next 2 bytes
in.read(temp+tempPos, PREFIX);
tempPos += PREFIX;
if (std::memcmp(ZipLocalFileHeader::HEADER+PREFIX, &temp[tempPos - PREFIX], PREFIX) == 0 ||
std::memcmp(ZipArchiveInfo::HEADER+PREFIX, &temp[tempPos - PREFIX], PREFIX) == 0 ||
std::memcmp(ZipFileInfo::HEADER+PREFIX, &temp[tempPos - PREFIX], PREFIX) == 0 ||
std::memcmp(ZipDataInfo::HEADER+PREFIX, &temp[tempPos - PREFIX], PREFIX) == 0)
{
if (std::memcmp(ZipLocalFileHeader::HEADER+PREFIX, &temp[tempPos - PREFIX], PREFIX) == 0)
{
in.seekg(-4, std::ios::cur);
if (!in.good()) throw Poco::IOException("Failed to seek on input stream");
}
else if (std::memcmp(ZipArchiveInfo::HEADER+PREFIX, &temp[tempPos - PREFIX], PREFIX) == 0)
{
in.seekg(-4, std::ios::cur);
if (!in.good()) throw Poco::IOException("Failed to seek on input stream");
}
else if (std::memcmp(ZipFileInfo::HEADER+PREFIX, &temp[tempPos - PREFIX], PREFIX) == 0)
{
in.seekg(-4, std::ios::cur);
if (!in.good()) throw Poco::IOException("Failed to seek on input stream");
}
else
{
in.seekg(-4, std::ios::cur);
if (!in.good()) throw Poco::IOException("Failed to seek on input stream");
}
return;
}
else
{
// we have read 2 bytes, should only be one: putback the last char
in.putback(temp[tempPos - 1]);
if (!in.good()) throw Poco::IOException("Failed to putback on input stream");
--tempPos;
}
}
else
{
// read one byte
in.read(temp + tempPos, 1);
++tempPos;
}
if (tempPos > (BUFFER_SIZE - ZipCommon::HEADER_SIZE))
{
std::memcpy(temp, &temp[tempPos - ZipCommon::HEADER_SIZE], ZipCommon::HEADER_SIZE);
tempPos = ZipCommon::HEADER_SIZE;
}
}
}
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)
{
if (fn.find("\\") != std::string::npos)
throw ZipException("Illegal entry name " + fn + " containing \\");
if (fn == "/")
throw ZipException("Illegal entry name /");
if (fn.empty())
throw ZipException("Illegal empty entry name");
if (!ZipCommon::isValidPath(fn))
throw ZipException("Illegal entry name " + fn + " containing parent directory reference");
}
std::string ZipUtil::validZipEntryFileName(const Poco::Path& entry)
{
std::string fn = entry.toString(Poco::Path::PATH_UNIX);
verifyZipEntryFileName(fn);
return fn;
}
} } // namespace Poco::Zip