Only accept PBF gziped files in canRead()

This commit is contained in:
Martin Tůma 2020-04-15 09:47:43 +02:00
parent 402e1e3adc
commit a298cfc47d
3 changed files with 67 additions and 33 deletions

View File

@ -3,33 +3,57 @@
#include <zlib.h>
#include "gzip.h"
#define CHUNK 16384
QByteArray Gzip::uncompress(const QByteArray &data)
QByteArray Gzip::uncompress(QIODevice *device, qint64 limit)
{
int ret;
z_stream strm;
unsigned char in[CHUNK];
unsigned char out[CHUNK];
qint64 rs;
QByteArray uba;
z_stream stream;
quint32 *size = (quint32*)(data.constData() + data.size() - sizeof(quint32));
uba.resize(qFromLittleEndian(*size));
stream.zalloc = Z_NULL;
stream.zfree = Z_NULL;
stream.opaque = Z_NULL;
strm.zalloc = Z_NULL;
strm.zfree = Z_NULL;
strm.opaque = Z_NULL;
strm.avail_in = 0;
strm.next_in = Z_NULL;
if (inflateInit2(&strm, MAX_WBITS + 16) != Z_OK)
return QByteArray();
stream.next_in = (Bytef*)data.constData();
stream.avail_in = data.size();
stream.next_out = (Bytef*)uba.data();
stream.avail_out = uba.size();
do {
rs = device->read((char*)in, CHUNK);
if (rs < 0) {
(void)inflateEnd(&strm);
return QByteArray();
} else if (rs == 0)
break;
else
strm.avail_in = (uInt)rs;
strm.next_in = in;
if (inflateInit2(&stream, MAX_WBITS + 16) != Z_OK)
return uba;
do {
strm.avail_out = CHUNK;
strm.next_out = out;
ret = inflate(&strm, Z_NO_FLUSH);
Q_ASSERT(ret != Z_STREAM_ERROR);
switch (ret) {
case Z_NEED_DICT:
case Z_DATA_ERROR:
case Z_MEM_ERROR:
(void)inflateEnd(&strm);
return QByteArray();
}
uba.append((char*)out, CHUNK - strm.avail_out);
if (limit && uba.size() >= limit) {
(void)inflateEnd(&strm);
return uba;
}
} while (!strm.avail_out);
} while (ret != Z_STREAM_END);
if (inflate(&stream, Z_NO_FLUSH) != Z_STREAM_END) {
qCritical() << "Invalid gzip data";
uba = QByteArray();
}
inflateEnd(&stream);
return uba;
(void)inflateEnd(&strm);
return (ret == Z_STREAM_END) ? uba : QByteArray();
}

View File

@ -3,9 +3,11 @@
#include <QByteArray>
class QIODevice;
namespace Gzip
{
QByteArray uncompress(const QByteArray &data);
QByteArray uncompress(QIODevice *device, qint64 limit = 0);
}
#endif // GZIP_H

View File

@ -10,22 +10,22 @@
#define TILE_SIZE 512
#define GZIP_MAGIC 0x1F8B0800
#define GZIP_MAGIC_MASK 0xFFFFFF00
#define PBF_MAGIC 0x1A000000
#define PBF_MAGIC_MASK 0xFF000000
#define GZIP_MAGIC 0x1F8B
#define GZIP_MAGIC_MASK 0xFFFF
#define PBF_MAGIC 0x1A00
#define PBF_MAGIC_MASK 0xFF00
static bool isMagic(quint32 magic, quint32 mask, quint32 value)
static bool isMagic(quint16 magic, quint16 mask, quint16 value)
{
return ((qFromBigEndian(value) & mask) == magic);
}
static bool isGZIPPBF(quint32 magic)
static bool isGZIPPBF(quint16 magic)
{
return isMagic(GZIP_MAGIC, GZIP_MAGIC_MASK, magic);
}
static bool isPlainPBF(quint32 magic)
static bool isPlainPBF(quint16 magic)
{
return isMagic(PBF_MAGIC, PBF_MAGIC_MASK, magic);
}
@ -42,23 +42,31 @@ bool PBFHandler::canRead() const
bool PBFHandler::canRead(QIODevice *device)
{
quint32 magic;
quint16 magic;
qint64 size = device->peek((char*)&magic, sizeof(magic));
if (size != sizeof(magic))
return false;
return (isGZIPPBF(magic) || isPlainPBF(magic));
if (isPlainPBF(magic))
return true;
else if (isGZIPPBF(magic)) {
QByteArray ba(Gzip::uncompress(device, sizeof(magic)));
if (ba.size() < (int)sizeof(magic))
return false;
return isPlainPBF(*((quint16*)ba.constData()));
} else
return false;
}
bool PBFHandler::read(QImage *image)
{
quint32 magic;
quint16 magic;
if (device()->peek((char*)&magic, sizeof(magic)) != sizeof(magic))
return false;
QByteArray ba;
if (isGZIPPBF(magic))
ba = Gzip::uncompress(device()->readAll());
ba = Gzip::uncompress(device());
else if (isPlainPBF(magic))
ba = device()->readAll();
if (ba.isNull())