mirror of
https://github.com/pocoproject/poco.git
synced 2025-10-27 02:53:10 +01:00
213 lines
7.0 KiB
C++
213 lines
7.0 KiB
C++
//
|
|
// ZipUtil.cpp
|
|
//
|
|
// $Id: //poco/1.3/Zip/src/ZipUtil.cpp#4 $
|
|
//
|
|
// Library: Zip
|
|
// Package: Zip
|
|
// Module: ZipUtil
|
|
//
|
|
// Copyright (c) 2007, Applied Informatics Software Engineering GmbH.
|
|
// and Contributors.
|
|
//
|
|
// Permission is hereby granted, free of charge, to any person or organization
|
|
// obtaining a copy of the software and accompanying documentation covered by
|
|
// this license (the "Software") to use, reproduce, display, distribute,
|
|
// execute, and transmit the Software, and to prepare derivative works of the
|
|
// Software, and to permit third-parties to whom the Software is furnished to
|
|
// do so, all subject to the following:
|
|
//
|
|
// The copyright notices in the Software and this entire statement, including
|
|
// the above license grant, this restriction and the following disclaimer,
|
|
// must be included in all copies of the Software, in whole or in part, and
|
|
// all derivative works of the Software, unless such copies or derivative
|
|
// works are solely in the form of machine-executable object code generated by
|
|
// a source language processor.
|
|
//
|
|
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
// FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
|
|
// SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
|
|
// FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
|
|
// ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
|
// DEALINGS IN THE SOFTWARE.
|
|
//
|
|
|
|
|
|
#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
|
|
return Poco::DateTime(year, mon, day, hour, min, sec);
|
|
}
|
|
|
|
|
|
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.putback(ZipLocalFileHeader::HEADER[3]);
|
|
in.putback(ZipLocalFileHeader::HEADER[2]);
|
|
in.putback(ZipLocalFileHeader::HEADER[1]);
|
|
in.putback(ZipLocalFileHeader::HEADER[0]);
|
|
}
|
|
else if (std::memcmp(ZipArchiveInfo::HEADER+PREFIX, &temp[tempPos - PREFIX], PREFIX) == 0)
|
|
{
|
|
in.putback(ZipArchiveInfo::HEADER[3]);
|
|
in.putback(ZipArchiveInfo::HEADER[2]);
|
|
in.putback(ZipArchiveInfo::HEADER[1]);
|
|
in.putback(ZipArchiveInfo::HEADER[0]);
|
|
}
|
|
else if (std::memcmp(ZipFileInfo::HEADER+PREFIX, &temp[tempPos - PREFIX], PREFIX) == 0)
|
|
{
|
|
in.putback(ZipFileInfo::HEADER[3]);
|
|
in.putback(ZipFileInfo::HEADER[2]);
|
|
in.putback(ZipFileInfo::HEADER[1]);
|
|
in.putback(ZipFileInfo::HEADER[0]);
|
|
}
|
|
else
|
|
{
|
|
in.putback(ZipDataInfo::HEADER[3]);
|
|
in.putback(ZipDataInfo::HEADER[2]);
|
|
in.putback(ZipDataInfo::HEADER[1]);
|
|
in.putback(ZipDataInfo::HEADER[0]);
|
|
}
|
|
return;
|
|
}
|
|
else
|
|
{
|
|
// we have read 2 bytes, should only be one: putback the last char
|
|
in.putback(temp[tempPos - 1]);
|
|
--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::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 (fn.find(ZipCommon::ILLEGAL_PATH) != std::string::npos)
|
|
throw ZipException("Illegal entry name " + fn + " containing " + ZipCommon::ILLEGAL_PATH);
|
|
}
|
|
|
|
|
|
std::string ZipUtil::validZipEntryFileName(const Poco::Path& entry)
|
|
{
|
|
std::string fn = entry.toString(Poco::Path::PATH_UNIX);
|
|
verifyZipEntryFileName(fn);
|
|
return fn;
|
|
}
|
|
|
|
|
|
} } // namespace Poco::Zip
|