summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJonas Karlsson <jonas.karlsson@qt.io>2021-02-04 15:37:53 +0100
committerJonas Karlsson <jonas.karlsson@qt.io>2021-02-09 13:39:47 +0100
commit2861cfb6f851d7cee503b19f0e800a33374db66c (patch)
treee5c63255c61568bd327b3851fee2d1b90227c2a4
parentd66cb667efbc33b3a81ecc495e90a2e2f44616b2 (diff)
QTextureFileData: support key value metadata
Task-Id: QTBUG-76970 Pick-to: 6.1 Change-Id: I9dba1b373250cea4d0c806997290a7afcdc900d7 Reviewed-by: Eirik Aavitsland <eirik.aavitsland@qt.io>
-rw-r--r--src/gui/util/qktxhandler.cpp41
-rw-r--r--src/gui/util/qktxhandler_p.h3
-rw-r--r--src/gui/util/qtexturefiledata.cpp12
-rw-r--r--src/gui/util/qtexturefiledata_p.h3
-rw-r--r--tests/auto/gui/util/qtexturefilereader/CMakeLists.txt1
-rw-r--r--tests/auto/gui/util/qtexturefilereader/qtexturefilereader.qrc1
-rw-r--r--tests/auto/gui/util/qtexturefilereader/texturefiles/cubemap_metadata.ktxbin0 -> 4916 bytes
-rw-r--r--tests/auto/gui/util/qtexturefilereader/tst_qtexturefilereader.cpp17
8 files changed, 75 insertions, 3 deletions
diff --git a/src/gui/util/qktxhandler.cpp b/src/gui/util/qktxhandler.cpp
index 27fb69a348..cd8ca3635e 100644
--- a/src/gui/util/qktxhandler.cpp
+++ b/src/gui/util/qktxhandler.cpp
@@ -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
@@ -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;
}
diff --git a/src/gui/util/qktxhandler_p.h b/src/gui/util/qktxhandler_p.h
index 19f7b0e79a..4298433f36 100644
--- a/src/gui/util/qktxhandler_p.h
+++ b/src/gui/util/qktxhandler_p.h
@@ -68,7 +68,8 @@ public:
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;
};
diff --git a/src/gui/util/qtexturefiledata.cpp b/src/gui/util/qtexturefiledata.cpp
index 0a3958aaf2..6549206a26 100644
--- a/src/gui/util/qtexturefiledata.cpp
+++ b/src/gui/util/qtexturefiledata.cpp
@@ -100,6 +100,7 @@ public:
quint32 baseInternalFormat = 0;
int numFaces = 0;
int numLevels = 0;
+ QMap<QByteArray, QByteArray> keyValues;
};
QTextureFileData::QTextureFileData()
@@ -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'));
diff --git a/src/gui/util/qtexturefiledata_p.h b/src/gui/util/qtexturefiledata_p.h
index f6a03c0550..e553733d69 100644
--- a/src/gui/util/qtexturefiledata_p.h
+++ b/src/gui/util/qtexturefiledata_p.h
@@ -107,6 +107,9 @@ public:
QByteArray logName() const;
void setLogName(const QByteArray &name);
+ QMap<QByteArray, QByteArray> keyValueMetadata() const;
+ void setKeyValueMetadata(const QMap<QByteArray, QByteArray> &keyValues);
+
private:
QSharedDataPointer<QTextureFileDataPrivate> d;
};
diff --git a/tests/auto/gui/util/qtexturefilereader/CMakeLists.txt b/tests/auto/gui/util/qtexturefilereader/CMakeLists.txt
index e1731a45d5..de809f577d 100644
--- a/tests/auto/gui/util/qtexturefilereader/CMakeLists.txt
+++ b/tests/auto/gui/util/qtexturefilereader/CMakeLists.txt
@@ -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"
diff --git a/tests/auto/gui/util/qtexturefilereader/qtexturefilereader.qrc b/tests/auto/gui/util/qtexturefilereader/qtexturefilereader.qrc
index a014c0367a..c4cef6cc44 100644
--- a/tests/auto/gui/util/qtexturefilereader/qtexturefilereader.qrc
+++ b/tests/auto/gui/util/qtexturefilereader/qtexturefilereader.qrc
@@ -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>
diff --git a/tests/auto/gui/util/qtexturefilereader/texturefiles/cubemap_metadata.ktx b/tests/auto/gui/util/qtexturefilereader/texturefiles/cubemap_metadata.ktx
new file mode 100644
index 0000000000..a29f68a7c9
--- /dev/null
+++ b/tests/auto/gui/util/qtexturefilereader/texturefiles/cubemap_metadata.ktx
Binary files differ
diff --git a/tests/auto/gui/util/qtexturefilereader/tst_qtexturefilereader.cpp b/tests/auto/gui/util/qtexturefilereader/tst_qtexturefilereader.cpp
index cd90914bd9..89144eb245 100644
--- a/tests/auto/gui/util/qtexturefilereader/tst_qtexturefilereader.cpp
+++ b/tests/auto/gui/util/qtexturefilereader/tst_qtexturefilereader.cpp
@@ -36,6 +36,7 @@ class tst_qtexturefilereader : public QObject
private slots:
void checkHandlers_data();
void checkHandlers();
+ void checkMetadata();
};
void tst_qtexturefilereader::checkHandlers_data()
@@ -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"