diff options
-rw-r--r-- | src/gui/util/qktxhandler.cpp | 30 | ||||
-rw-r--r-- | tests/auto/gui/util/qtexturefilereader/qtexturefilereader.qrc | 1 | ||||
-rw-r--r-- | tests/auto/gui/util/qtexturefilereader/texturefiles/car_mips.ktx | bin | 0 -> 8088 bytes | |||
-rw-r--r-- | tests/auto/gui/util/qtexturefilereader/tst_qtexturefilereader.cpp | 36 |
4 files changed, 46 insertions, 21 deletions
diff --git a/src/gui/util/qktxhandler.cpp b/src/gui/util/qktxhandler.cpp index c7831f8143..7eda4c46fb 100644 --- a/src/gui/util/qktxhandler.cpp +++ b/src/gui/util/qktxhandler.cpp @@ -43,6 +43,11 @@ #include <QSize> //#define KTX_DEBUG +#ifdef KTX_DEBUG +#include <QDebug> +#include <QMetaEnum> +#include <QOpenGLTexture> +#endif QT_BEGIN_NAMESPACE @@ -68,7 +73,7 @@ struct KTXHeader { quint32 bytesOfKeyValueData; }; -static const int headerSize = sizeof(KTXHeader); +static const quint32 headerSize = sizeof(KTXHeader); // Currently unused, declared for future reference struct KTXKeyValuePairItem { @@ -111,7 +116,8 @@ QTextureFileData QKtxHandler::read() return QTextureFileData(); QByteArray buf = device()->readAll(); - if (buf.size() < headerSize || !canRead(QByteArray(), buf)) { + const quint32 dataSize = quint32(buf.size()); + if (dataSize < headerSize || !canRead(QByteArray(), buf)) { qCDebug(lcQtGuiTextureIO, "Invalid KTX file %s", logName().constData()); return QTextureFileData(); } @@ -130,13 +136,17 @@ QTextureFileData QKtxHandler::read() texData.setGLInternalFormat(decode(header->glInternalFormat)); texData.setGLBaseInternalFormat(decode(header->glBaseInternalFormat)); - //### For now, ignore any additional mipmap levels - texData.setNumLevels(1); - int preambleSize = headerSize + decode(header->bytesOfKeyValueData); - if (buf.size() >= preambleSize + int(sizeof(KTXMipmapLevel))) { - texData.setDataOffset(preambleSize + sizeof(quint32)); // for the imageSize - const KTXMipmapLevel *level = reinterpret_cast<const KTXMipmapLevel *>(buf.constData() + preambleSize); - texData.setDataLength(decode(level->imageSize)); + texData.setNumLevels(decode(header->numberOfMipmapLevels)); + quint32 offset = headerSize + decode(header->bytesOfKeyValueData); + const int maxLevels = qMin(texData.numLevels(), 32); // Cap iterations in case of corrupt file. + for (int i = 0; i < maxLevels; i++) { + if (offset + sizeof(KTXMipmapLevel) > dataSize) // Corrupt file; avoid oob read + break; + const KTXMipmapLevel *level = reinterpret_cast<const KTXMipmapLevel *>(buf.constData() + offset); + quint32 levelLen = decode(level->imageSize); + texData.setDataOffset(offset + sizeof(KTXMipmapLevel::imageSize), i); + texData.setDataLength(levelLen, i); + offset += sizeof(KTXMipmapLevel::imageSize) + levelLen + (3 - ((levelLen + 3) % 4)); } if (!texData.isValid()) { @@ -147,7 +157,7 @@ QTextureFileData QKtxHandler::read() texData.setLogName(logName()); #ifdef KTX_DEBUG - qDebug() << "KTX file handler read" << texData.data(); + qDebug() << "KTX file handler read" << texData; #endif return texData; diff --git a/tests/auto/gui/util/qtexturefilereader/qtexturefilereader.qrc b/tests/auto/gui/util/qtexturefilereader/qtexturefilereader.qrc index 74f33d57ad..ab882b5db2 100644 --- a/tests/auto/gui/util/qtexturefilereader/qtexturefilereader.qrc +++ b/tests/auto/gui/util/qtexturefilereader/qtexturefilereader.qrc @@ -2,5 +2,6 @@ <qresource prefix="/"> <file>texturefiles/car.ktx</file> <file>texturefiles/pattern.pkm</file> + <file>texturefiles/car_mips.ktx</file> </qresource> </RCC> diff --git a/tests/auto/gui/util/qtexturefilereader/texturefiles/car_mips.ktx b/tests/auto/gui/util/qtexturefilereader/texturefiles/car_mips.ktx Binary files differnew file mode 100644 index 0000000000..82822e6c0b --- /dev/null +++ b/tests/auto/gui/util/qtexturefilereader/texturefiles/car_mips.ktx diff --git a/tests/auto/gui/util/qtexturefilereader/tst_qtexturefilereader.cpp b/tests/auto/gui/util/qtexturefilereader/tst_qtexturefilereader.cpp index f480184067..9ff4f0ccf2 100644 --- a/tests/auto/gui/util/qtexturefilereader/tst_qtexturefilereader.cpp +++ b/tests/auto/gui/util/qtexturefilereader/tst_qtexturefilereader.cpp @@ -44,26 +44,38 @@ void tst_qtexturefilereader::checkHandlers_data() QTest::addColumn<QSize>("size"); QTest::addColumn<quint32>("glFormat"); QTest::addColumn<quint32>("glInternalFormat"); - // todo: glBaseInternalFormat + QTest::addColumn<quint32>("glBaseInternalFormat"); QTest::addColumn<int>("levels"); - QTest::addColumn<int>("dataOffset"); - QTest::addColumn<int>("dataLength"); + QTest::addColumn<QList<int>>("dataOffsets"); + QTest::addColumn<QList<int>>("dataLengths"); QTest::addRow("pattern.pkm") << QStringLiteral(":/texturefiles/pattern.pkm") << QSize(64, 64) << quint32(0x0) << quint32(0x8d64) + << quint32(0x0) << 1 - << 16 - << 2048; + << (QList<int>() << 16) + << (QList<int>() << 2048); QTest::addRow("car.ktx") << QStringLiteral(":/texturefiles/car.ktx") << QSize(146, 80) << quint32(0x0) << quint32(0x9278) + << quint32(0x1908) << 1 - << 68 - << 11840; + << (QList<int>() << 68) + << (QList<int>() << 11840); + + QTest::addRow("car_mips.ktx") << QStringLiteral(":/texturefiles/car_mips.ktx") + << QSize(146, 80) + << quint32(0x0) + << quint32(0x9274) + << quint32(0x1907) + << 8 + << (QList<int>() << 68 << 5992 << 7516 << 7880 << 8004 << 8056 << 8068 << 8080) + << (QList<int>() << 5920 << 1520 << 360 << 120 << 48 << 8 << 8 << 8); + } void tst_qtexturefilereader::checkHandlers() @@ -73,8 +85,8 @@ void tst_qtexturefilereader::checkHandlers() QFETCH(quint32, glFormat); QFETCH(quint32, glInternalFormat); QFETCH(int, levels); - QFETCH(int, dataOffset); - QFETCH(int, dataLength); + QFETCH(QList<int>, dataOffsets); + QFETCH(QList<int>, dataLengths); QFile f(fileName); QVERIFY(f.open(QIODevice::ReadOnly)); @@ -88,8 +100,10 @@ void tst_qtexturefilereader::checkHandlers() QCOMPARE(tex.glFormat(), glFormat); QCOMPARE(tex.glInternalFormat(), glInternalFormat); QCOMPARE(tex.numLevels(), levels); - QCOMPARE(tex.dataOffset(), dataOffset); - QCOMPARE(tex.dataLength(), dataLength); + for (int i = 0; i < tex.numLevels(); i++) { + QCOMPARE(tex.dataOffset(i), dataOffsets.at(i)); + QCOMPARE(tex.dataLength(i), dataLengths.at(i)); + } } QTEST_MAIN(tst_qtexturefilereader) |