Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Initial changes required for ZIP64 support #2

Merged
merged 1 commit into from
Sep 16, 2015
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
79 changes: 76 additions & 3 deletions src/compress/qzip.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@

// Zip standard version for archives handled by this API
// (actually, the only basic support of this version is implemented but it is enough for now)
#define ZIP_VERSION 20
#define ZIP_VERSION 45

#if defined(Q_OS_WIN)
# undef S_IFREG
Expand Down Expand Up @@ -103,6 +103,15 @@

QT_BEGIN_NAMESPACE

static inline quint64 readUInt64(const uchar *data)
{
return (data[0]) + (data[1]<<8) + (data[2]<<16) + (data[3]<<24) +
((quint64)data[4]<<32) +
((quint64)data[5]<<40) +
((quint64)data[6]<<48) +
((quint64)data[7]<<56);
}

static inline uint readUInt(const uchar *data)
{
return (data[0]) + (data[1]<<8) + (data[2]<<16) + (data[3]<<24);
Expand All @@ -127,6 +136,18 @@ static inline void writeUShort(uchar *data, ushort i)
data[1] = (i>>8) & 0xff;
}

static inline void copyUInt64(uchar *dest, const uchar *src)
{
dest[0] = src[0];
dest[1] = src[1];
dest[2] = src[2];
dest[3] = src[3];
dest[4] = src[4];
dest[5] = src[5];
dest[6] = src[6];
dest[7] = src[7];
}

static inline void copyUInt(uchar *dest, const uchar *src)
{
dest[0] = src[0];
Expand Down Expand Up @@ -382,6 +403,12 @@ struct LocalFileHeader
uchar extra_field_length[2];
};

struct ExtensibleDataField
{
uchar header[2];
uchar data_size[2];
};

struct DataDescriptor
{
uchar crc_32[4];
Expand Down Expand Up @@ -976,7 +1003,7 @@ QByteArray QZipReader::fileData(const QString &fileName) const

ushort version_needed = readUShort(header.h.version_needed);
if (version_needed > ZIP_VERSION) {
qWarning("QZip: .ZIP specification version %d implementationis needed to extract the data.", version_needed);
qWarning("QZip: .ZIP specification version %d implementation is needed to extract the data.", version_needed);
return QByteArray();
}

Expand All @@ -989,9 +1016,55 @@ QByteArray QZipReader::fileData(const QString &fileName) const
d->device->seek(start);
LocalFileHeader lh;
d->device->read((char *)&lh, sizeof(LocalFileHeader));
uint skip = readUShort(lh.file_name_length) + readUShort(lh.extra_field_length);
uint skip = readUShort(lh.file_name_length);
d->device->seek(d->device->pos() + skip);

// read extra fields
ushort extra_field_length = readUShort(lh.extra_field_length);
while (extra_field_length > sizeof(ExtensibleDataField)) {
ExtensibleDataField df;

d->device->read((char *)&df, sizeof(ExtensibleDataField));
extra_field_length -= sizeof(ExtensibleDataField);

ushort header = readUShort(df.header);
ushort data_size = readUShort(df.data_size);

if (extra_field_length < data_size) {
qWarning("QZip: Invalid extra field length");
return QByteArray();
}

extra_field_length -= data_size;

if (header == 0x0001) { // ZIP64
const QByteArray ba = d->device->read(data_size);
if (ba.length() != data_size) {
qWarning() << "QZip: Failed to read extra field in zip file, file may be incomplete";
return QByteArray();
}

const uchar *data = (const uchar *) ba.constData();

if (uncompressed_size == -1) {
uncompressed_size = readUInt64(data);
data += 8;
}
if (compressed_size == -1) {
compressed_size = readUInt64(data);
data += 8;
}
if (start == -1) {
start = readUInt64(data);
data += 8;
}
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since you just merged this I was reading this code again, and noticed that the above three reads may go beyond the actual size of the data for invalid ZIP archives. Small issue but may be worth adding a check for.


break;
} else {
d->device->seek(d->device->pos() + data_size);
}
}

int compression_method = readUShort(lh.compression_method);
//qDebug("file=%s: compressed_size=%d, uncompressed_size=%d", fileName.toLocal8Bit().data(), compressed_size, uncompressed_size);

Expand Down