Compare commits

..

4 Commits

Author SHA1 Message Date
21b3b890ec tga: Be less strict about palette
There's images in the wild that claim to not have a palette
but still have one.
2025-07-09 13:17:20 +02:00
aef4bd7e1c Fix unused param in MicroExif::toByteArray() 2025-07-07 08:17:36 +02:00
ea1983a7d1 IFF: Fix possible stack overflow 2025-07-05 09:59:06 +00:00
775b53f1f6 Update version to 6.17.0 2025-07-04 18:28:45 +02:00
5 changed files with 45 additions and 12 deletions

View File

@ -1,6 +1,6 @@
cmake_minimum_required(VERSION 3.16)
set(KF_VERSION "6.16.0") # handled by release scripts
set(KF_VERSION "6.17.0") # handled by release scripts
set(KF_DEP_VERSION "6.16.0") # handled by release scripts
project(KImageFormats VERSION ${KF_VERSION})

View File

@ -10,6 +10,8 @@
#include <QDebug>
#define RECURSION_PROTECTION 10
IFFChunk::~IFFChunk()
{
@ -20,6 +22,7 @@ IFFChunk::IFFChunk()
, _size{0}
, _align{2}
, _dataPos{0}
, _recursionCnt{0}
{
}
@ -49,12 +52,16 @@ qint32 IFFChunk::alignBytes() const
bool IFFChunk::readStructure(QIODevice *d)
{
auto ok = readInfo(d);
ok = ok && innerReadStructure(d);
if (recursionCounter() > RECURSION_PROTECTION - 1) {
ok = ok && IFFChunk::innerReadStructure(d); // force default implementation (no more recursion)
} else {
ok = ok && innerReadStructure(d);
}
if (ok) {
auto pos = _dataPos + _size;
if (auto align = pos % alignBytes())
pos += alignBytes() - align;
ok = d->seek(pos);
ok = pos < d->pos() ? false : d->seek(pos);
}
return ok;
}
@ -169,7 +176,17 @@ void IFFChunk::setChunks(const ChunkList &chunks)
_chunks = chunks;
}
IFFChunk::ChunkList IFFChunk::innerFromDevice(QIODevice *d, bool *ok, qint32 alignBytes)
qint32 IFFChunk::recursionCounter() const
{
return _recursionCnt;
}
void IFFChunk::setRecursionCounter(qint32 cnt)
{
_recursionCnt = cnt;
}
IFFChunk::ChunkList IFFChunk::innerFromDevice(QIODevice *d, bool *ok, qint32 alignBytes, qint32 recursionCnt)
{
auto tmp = false;
if (ok == nullptr) {
@ -181,6 +198,10 @@ IFFChunk::ChunkList IFFChunk::innerFromDevice(QIODevice *d, bool *ok, qint32 ali
return {};
}
if (recursionCnt > RECURSION_PROTECTION) {
return {};
}
IFFChunk::ChunkList list;
for (; !d->atEnd();) {
auto cid = d->peek(4);
@ -229,6 +250,7 @@ IFFChunk::ChunkList IFFChunk::innerFromDevice(QIODevice *d, bool *ok, qint32 ali
chunk->setAlignBytes(alignBytes);
}
chunk->setRecursionCounter(recursionCnt + 1);
if (!chunk->readStructure(d)) {
*ok = false;
return {};
@ -243,7 +265,7 @@ IFFChunk::ChunkList IFFChunk::innerFromDevice(QIODevice *d, bool *ok, qint32 ali
IFFChunk::ChunkList IFFChunk::fromDevice(QIODevice *d, bool *ok)
{
return innerFromDevice(d, ok, 2);
return innerFromDevice(d, ok, 2, 0);
}
@ -754,7 +776,7 @@ bool FORMChunk::innerReadStructure(QIODevice *d)
_type = d->read(4);
auto ok = true;
if (_type == QByteArray("ILBM")) {
setChunks(IFFChunk::innerFromDevice(d, &ok, alignBytes()));
setChunks(IFFChunk::innerFromDevice(d, &ok, alignBytes(), recursionCounter()));
}
return ok;
}
@ -857,9 +879,9 @@ bool FOR4Chunk::innerReadStructure(QIODevice *d)
_type = d->read(4);
auto ok = true;
if (_type == QByteArray("CIMG")) {
setChunks(IFFChunk::innerFromDevice(d, &ok, alignBytes()));
setChunks(IFFChunk::innerFromDevice(d, &ok, alignBytes(), recursionCounter()));
} else if (_type == QByteArray("TBMP")) {
setChunks(IFFChunk::innerFromDevice(d, &ok, alignBytes()));
setChunks(IFFChunk::innerFromDevice(d, &ok, alignBytes(), recursionCounter()));
}
return ok;
}

View File

@ -256,6 +256,14 @@ protected:
*/
void setChunks(const ChunkList &chunks);
/*!
* \brief recursionCounter
* Protection against stack overflow due to broken data.
* \return The current recursion counter.
*/
qint32 recursionCounter() const;
void setRecursionCounter(qint32 cnt);
inline quint16 ui16(quint8 c1, quint8 c2) const {
return (quint16(c2) << 8) | quint16(c1);
}
@ -272,7 +280,7 @@ protected:
return qint32(ui32(c1, c2, c3, c4));
}
static ChunkList innerFromDevice(QIODevice *d, bool *ok, qint32 alignBytes);
static ChunkList innerFromDevice(QIODevice *d, bool *ok, qint32 alignBytes, qint32 recursionCnt);
private:
char _chunkId[4];
@ -287,6 +295,8 @@ private:
ChunkList _chunks;
qint32 _recursionCnt;
};

View File

@ -1072,7 +1072,7 @@ QByteArray MicroExif::toByteArray(const QDataStream::ByteOrder &byteOrder, const
QByteArray ba;
{
QBuffer buf(&ba);
if (!write(&buf, byteOrder))
if (!write(&buf, byteOrder, version))
return {};
}
return ba;

View File

@ -119,10 +119,11 @@ static bool IsSupported(const TgaHeader &head)
if (head.pixel_size != 8 && head.pixel_size != 16 && head.pixel_size != 24 && head.pixel_size != 32) {
return false;
}
// If the colormap_type field is set to zero, indicating that no color map exists, then colormap_size, colormap_index and colormap_length should be set to zero.
if (head.colormap_type == 0 && (head.colormap_size != 0 || head.colormap_index != 0 || head.colormap_length != 0)) {
// If the colormap_type field is set to zero, indicating that no color map exists, then colormap_index and colormap_length should be set to zero.
if (head.colormap_type == 0 && (head.colormap_index != 0 || head.colormap_length != 0)) {
return false;
}
return true;
}