Skip to content

Commit

Permalink
QTextureFileData: support key value metadata
Browse files Browse the repository at this point in the history
Task-Id: QTBUG-76970
Pick-to: 6.1
Change-Id: I9dba1b373250cea4d0c806997290a7afcdc900d7
Reviewed-by: Eirik Aavitsland <[email protected]>
  • Loading branch information
karjonas committed Feb 9, 2021
1 parent d66cb66 commit 2861cfb
Show file tree
Hide file tree
Showing 8 changed files with 75 additions and 3 deletions.
41 changes: 39 additions & 2 deletions src/gui/util/qktxhandler.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -146,7 +146,12 @@ QTextureFileData QKtxHandler::read()

texData.setNumLevels(decode(header->numberOfMipmapLevels));
texData.setNumFaces(decode(header->numberOfFaces));
quint32 offset = headerSize + decode(header->bytesOfKeyValueData);

const quint32 bytesOfKeyValueData = decode(header->bytesOfKeyValueData);
if (headerSize + bytesOfKeyValueData < buf.length()) // oob check
texData.setKeyValueMetadata(
decodeKeyValues(QByteArrayView(buf.data() + headerSize, bytesOfKeyValueData)));
quint32 offset = headerSize + bytesOfKeyValueData;

constexpr int MAX_ITERATIONS = 32; // cap iterations in case of corrupt data

Expand Down Expand Up @@ -213,7 +218,39 @@ bool QKtxHandler::checkHeader(const KTXHeader &header)
return is2D && (isCubeMap || isCompressedImage);
}

quint32 QKtxHandler::decode(quint32 val)
QMap<QByteArray, QByteArray> QKtxHandler::decodeKeyValues(QByteArrayView view) const
{
QMap<QByteArray, QByteArray> output;
quint32 offset = 0;
while (offset < view.size() + sizeof(quint32)) {
const quint32 keyAndValueByteSize =
decode(qFromUnaligned<quint32>(view.constData() + offset));
offset += sizeof(quint32);

if (offset + keyAndValueByteSize > view.size())
break; // oob read

// 'key' is a UTF-8 string ending with a null terminator, 'value' is the rest.
// To separate the key and value we convert the complete data to utf-8 and find the first
// null terminator from the left, here we split the data into two.
const auto str = QString::fromUtf8(view.constData() + offset, keyAndValueByteSize);
const int idx = str.indexOf(QLatin1Char('\0'));
if (idx == -1)
continue;

const QByteArray key = str.left(idx).toUtf8();
const size_t keySize = key.size() + 1; // Actual data size
const QByteArray value = QByteArray::fromRawData(view.constData() + offset + keySize,
keyAndValueByteSize - keySize);

offset = withPadding(offset + keyAndValueByteSize, 4);
output.insert(key, value);
}

return output;
}

quint32 QKtxHandler::decode(quint32 val) const
{
return inverseEndian ? qbswap<quint32>(val) : val;
}
Expand Down
3 changes: 2 additions & 1 deletion src/gui/util/qktxhandler_p.h
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,8 @@ class QKtxHandler : public QTextureFileHandler

private:
bool checkHeader(const KTXHeader &header);
quint32 decode(quint32 val);
QMap<QByteArray, QByteArray> decodeKeyValues(QByteArrayView view) const;
quint32 decode(quint32 val) const;

bool inverseEndian = false;
};
Expand Down
12 changes: 12 additions & 0 deletions src/gui/util/qtexturefiledata.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,7 @@ class QTextureFileDataPrivate : public QSharedData
quint32 baseInternalFormat = 0;
int numFaces = 0;
int numLevels = 0;
QMap<QByteArray, QByteArray> keyValues;
};

QTextureFileData::QTextureFileData()
Expand Down Expand Up @@ -292,6 +293,17 @@ void QTextureFileData::setLogName(const QByteArray &name)
d->logName = name;
}

QMap<QByteArray, QByteArray> QTextureFileData::keyValueMetadata() const
{
return d ? d->keyValues : QMap<QByteArray, QByteArray>();
}

void QTextureFileData::setKeyValueMetadata(const QMap<QByteArray, QByteArray> &keyValues)
{
if (d)
d->keyValues = keyValues;
}

static QByteArray glFormatName(quint32 fmt)
{
return QByteArray("0x" + QByteArray::number(fmt, 16).rightJustified(4, '0'));
Expand Down
3 changes: 3 additions & 0 deletions src/gui/util/qtexturefiledata_p.h
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,9 @@ class Q_GUI_EXPORT QTextureFileData
QByteArray logName() const;
void setLogName(const QByteArray &name);

QMap<QByteArray, QByteArray> keyValueMetadata() const;
void setKeyValueMetadata(const QMap<QByteArray, QByteArray> &keyValues);

private:
QSharedDataPointer<QTextureFileDataPrivate> d;
};
Expand Down
1 change: 1 addition & 0 deletions tests/auto/gui/util/qtexturefilereader/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ set(qtexturefilereader_resource_files
"texturefiles/car.ktx"
"texturefiles/car_mips.ktx"
"texturefiles/cubemap_float32_rgba.ktx"
"texturefiles/cubemap_metadata.ktx"
"texturefiles/newlogo.astc"
"texturefiles/newlogo_srgb.astc"
"texturefiles/pattern.pkm"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
<qresource prefix="/">
<file>texturefiles/car.ktx</file>
<file>texturefiles/cubemap_float32_rgba.ktx</file>
<file>texturefiles/cubemap_metadata.ktx</file>
<file>texturefiles/pattern.pkm</file>
<file>texturefiles/car_mips.ktx</file>
<file>texturefiles/newlogo_srgb.astc</file>
Expand Down
Binary file not shown.
17 changes: 17 additions & 0 deletions tests/auto/gui/util/qtexturefilereader/tst_qtexturefilereader.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ class tst_qtexturefilereader : public QObject
private slots:
void checkHandlers_data();
void checkHandlers();
void checkMetadata();
};

void tst_qtexturefilereader::checkHandlers_data()
Expand Down Expand Up @@ -148,6 +149,22 @@ void tst_qtexturefilereader::checkHandlers()
}
}

void tst_qtexturefilereader::checkMetadata()
{
QFile f(":/texturefiles/cubemap_metadata.ktx");
QVERIFY(f.open(QIODevice::ReadOnly));
QTextureFileReader r(&f);
QTextureFileData d = r.read();
auto kvs = d.keyValueMetadata();

QVERIFY(kvs.contains("test A"));
QVERIFY(kvs.contains("test B"));
QVERIFY(kvs.contains("test C"));
QCOMPARE(kvs.value("test A"), QByteArrayLiteral("1\x0000"));
QCOMPARE(kvs.value("test B"), QByteArrayLiteral("2\x0000"));
QCOMPARE(kvs.value("test C"), QByteArrayLiteral("3\x0000"));
}

QTEST_MAIN(tst_qtexturefilereader)

#include "tst_qtexturefilereader.moc"

0 comments on commit 2861cfb

Please sign in to comment.