/*
Copyright (C) 2005-2014 Sergey A. Tachenov
This file is part of QuaZIP.
QuaZIP is free software: you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
QuaZIP is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with QuaZIP. If not, see .
See COPYING file for the full LGPL text.
Original ZIP package is copyrighted by Gilles Vollant and contributors,
see quazip/(un)zip.h files for details. Basically it's the zlib license.
*/
#include
#include "quazipnewinfo.h"
#include
static void QuaZipNewInfo_setPermissions(QuaZipNewInfo *info,
QFile::Permissions perm, bool isDir)
{
quint32 uPerm = isDir ? 0040000 : 0100000;
if ((perm & QFile::ReadOwner) != 0)
uPerm |= 0400;
if ((perm & QFile::WriteOwner) != 0)
uPerm |= 0200;
if ((perm & QFile::ExeOwner) != 0)
uPerm |= 0100;
if ((perm & QFile::ReadGroup) != 0)
uPerm |= 0040;
if ((perm & QFile::WriteGroup) != 0)
uPerm |= 0020;
if ((perm & QFile::ExeGroup) != 0)
uPerm |= 0010;
if ((perm & QFile::ReadOther) != 0)
uPerm |= 0004;
if ((perm & QFile::WriteOther) != 0)
uPerm |= 0002;
if ((perm & QFile::ExeOther) != 0)
uPerm |= 0001;
info->externalAttr = (info->externalAttr & ~0xFFFF0000u) | (uPerm << 16);
}
template
void QuaZipNewInfo_init(QuaZipNewInfo &self, const FileInfo &existing)
{
self.name = existing.name;
self.dateTime = existing.dateTime;
self.internalAttr = existing.internalAttr;
self.externalAttr = existing.externalAttr;
self.comment = existing.comment;
self.extraLocal = existing.extra;
self.extraGlobal = existing.extra;
self.uncompressedSize = existing.uncompressedSize;
}
QuaZipNewInfo::QuaZipNewInfo(const QuaZipFileInfo &existing)
{
QuaZipNewInfo_init(*this, existing);
}
QuaZipNewInfo::QuaZipNewInfo(const QuaZipFileInfo64 &existing)
{
QuaZipNewInfo_init(*this, existing);
}
QuaZipNewInfo::QuaZipNewInfo(const QString& name):
name(name), dateTime(QDateTime::currentDateTime()), internalAttr(0), externalAttr(0),
uncompressedSize(0)
{
}
QuaZipNewInfo::QuaZipNewInfo(const QString& name, const QString& file):
name(name), internalAttr(0), externalAttr(0), uncompressedSize(0)
{
QFileInfo info(file);
QDateTime lm = info.lastModified();
if (!info.exists()) {
dateTime = QDateTime::currentDateTime();
} else {
dateTime = lm;
QuaZipNewInfo_setPermissions(this, info.permissions(), info.isDir());
}
}
void QuaZipNewInfo::setFileDateTime(const QString& file)
{
QFileInfo info(file);
QDateTime lm = info.lastModified();
if (info.exists())
dateTime = lm;
}
void QuaZipNewInfo::setFilePermissions(const QString &file)
{
QFileInfo info = QFileInfo(file);
QFile::Permissions perm = info.permissions();
QuaZipNewInfo_setPermissions(this, perm, info.isDir());
}
void QuaZipNewInfo::setPermissions(QFile::Permissions permissions)
{
QuaZipNewInfo_setPermissions(this, permissions, name.endsWith('/'));
}
void QuaZipNewInfo::setFileNTFSTimes(const QString &fileName)
{
QFileInfo fi(fileName);
if (!fi.exists()) {
qWarning("QuaZipNewInfo::setFileNTFSTimes(): '%s' doesn't exist",
fileName.toUtf8().constData());
return;
}
setFileNTFSmTime(fi.lastModified());
setFileNTFSaTime(fi.lastRead());
setFileNTFScTime(fi.created());
}
static void setNTFSTime(QByteArray &extra, const QDateTime &time, int position,
int fineTicks) {
int ntfsPos = -1, timesPos = -1;
unsigned ntfsLength = 0, ntfsTimesLength = 0;
for (int i = 0; i <= extra.size() - 4; ) {
unsigned type = static_cast(static_cast(
extra.at(i)))
| (static_cast(static_cast(
extra.at(i + 1))) << 8);
i += 2;
unsigned length = static_cast(static_cast(
extra.at(i)))
| (static_cast(static_cast(
extra.at(i + 1))) << 8);
i += 2;
if (type == QUAZIP_EXTRA_NTFS_MAGIC) {
ntfsPos = i - 4; // the beginning of the NTFS record
ntfsLength = length;
if (length <= 4) {
break; // no times in the NTFS record
}
i += 4; // reserved
while (i <= extra.size() - 4) {
unsigned tag = static_cast(
static_cast(extra.at(i)))
| (static_cast(
static_cast(extra.at(i + 1)))
<< 8);
i += 2;
unsigned tagsize = static_cast(
static_cast(extra.at(i)))
| (static_cast(
static_cast(extra.at(i + 1)))
<< 8);
i += 2;
if (tag == QUAZIP_EXTRA_NTFS_TIME_MAGIC) {
timesPos = i - 4; // the beginning of the NTFS times tag
ntfsTimesLength = tagsize;
break;
} else {
i += tagsize;
}
}
break; // I ain't going to search for yet another NTFS record!
} else {
i += length;
}
}
if (ntfsPos == -1) {
// No NTFS record, need to create one.
ntfsPos = extra.size();
ntfsLength = 32;
extra.resize(extra.size() + 4 + ntfsLength);
// the NTFS record header
extra[ntfsPos] = static_cast(QUAZIP_EXTRA_NTFS_MAGIC);
extra[ntfsPos + 1] = static_cast(QUAZIP_EXTRA_NTFS_MAGIC >> 8);
extra[ntfsPos + 2] = 32; // the 2-byte size in LittleEndian
extra[ntfsPos + 3] = 0;
// zero the record
memset(extra.data() + ntfsPos + 4, 0, 32);
timesPos = ntfsPos + 8;
// now set the tag data
extra[timesPos] = static_cast(QUAZIP_EXTRA_NTFS_TIME_MAGIC);
extra[timesPos + 1] = static_cast(QUAZIP_EXTRA_NTFS_TIME_MAGIC
>> 8);
// the size:
extra[timesPos + 2] = 24;
extra[timesPos + 3] = 0;
ntfsTimesLength = 24;
}
if (timesPos == -1) {
// No time tag in the NTFS record, need to add one.
timesPos = ntfsPos + 4 + ntfsLength;
extra.resize(extra.size() + 28);
// Now we need to move the rest of the field
// (possibly zero bytes, but memmove() is OK with that).
// 0 ......... ntfsPos .. ntfsPos + 4 ... timesPos
//
memmove(extra.data() + timesPos + 28, extra.data() + timesPos,
extra.size() - 28 - timesPos);
ntfsLength += 28;
// now set the tag data
extra[timesPos] = static_cast(QUAZIP_EXTRA_NTFS_TIME_MAGIC);
extra[timesPos + 1] = static_cast(QUAZIP_EXTRA_NTFS_TIME_MAGIC
>> 8);
// the size:
extra[timesPos + 2] = 24;
extra[timesPos + 3] = 0;
// zero the record
memset(extra.data() + timesPos + 4, 0, 24);
ntfsTimesLength = 24;
}
if (ntfsTimesLength < 24) {
// Broken times field. OK, this is really unlikely, but just in case...
size_t timesEnd = timesPos + 4 + ntfsTimesLength;
extra.resize(extra.size() + (24 - ntfsTimesLength));
// Move it!
// 0 ......... timesPos .... timesPos + 4 .. timesEnd
//