9#include <QtCore/qiodevice.h>
15#include <QOpenGLTexture>
22#define KTX_IDENTIFIER_LENGTH 12
23static const char ktxIdentifier[
KTX_IDENTIFIER_LENGTH] = {
'\xAB',
'K',
'T',
'X',
' ',
'1',
'1',
'\xBB',
'\r',
'\n',
'\x1A',
'\n' };
108 if (
static_cast<size_t>(
buf.size()) > std::numeric_limits<quint32>::max()) {
109 qWarning(lcQtGuiTextureIO,
"Too big KTX file %s",
logName().constData());
114 qWarning(lcQtGuiTextureIO,
"Invalid KTX file %s",
logName().constData());
119 qWarning(lcQtGuiTextureIO,
"Invalid KTX header size in %s",
logName().constData());
125 if (!checkHeader(
header)) {
126 qWarning(lcQtGuiTextureIO,
"Unsupported KTX file format in %s",
logName().constData());
135 texData.setGLInternalFormat(
decode(
header.glInternalFormat));
136 texData.setGLBaseInternalFormat(
decode(
header.glBaseInternalFormat));
138 texData.setNumLevels(
decode(
header.numberOfMipmapLevels));
144 qWarning(lcQtGuiTextureIO,
"Overflow in size of key value data in header of KTX file %s",
149 if (headerKeyValueSize >=
quint32(
buf.size())) {
150 qWarning(lcQtGuiTextureIO,
"OOB request in KTX file %s",
logName().constData());
155 if (bytesOfKeyValueData > 0) {
157 if (keyValueDataView.isEmpty()) {
158 qWarning(lcQtGuiTextureIO,
"Invalid view in KTX file %s",
logName().constData());
162 auto keyValues = decodeKeyValues(keyValueDataView);
164 qWarning(lcQtGuiTextureIO,
"Could not parse key values in KTX file %s",
169 texData.setKeyValueMetadata(*keyValues);
175 const int maxLevels = (
sizeof(
quint32) * 8)
179 if (texData.numLevels() > maxLevels) {
180 qWarning(lcQtGuiTextureIO,
"Too many levels in KTX file %s",
logName().constData());
184 if (texData.numFaces() != 1 && texData.numFaces() != 6) {
185 qWarning(lcQtGuiTextureIO,
"Invalid number of faces in KTX file %s",
logName().constData());
192 if (imageSizeView.isEmpty()) {
193 qWarning(lcQtGuiTextureIO,
"OOB request in KTX file %s",
logName().constData());
207 qWarning(lcQtGuiTextureIO,
"Overflow in KTX file %s",
logName().constData());
213 qWarning(lcQtGuiTextureIO,
"OOB request in KTX file %s",
logName().constData());
221 if (!texData.isValid()) {
222 qWarning(lcQtGuiTextureIO,
"Invalid values in header of KTX file %s",
230 qDebug() <<
"KTX file handler read" << texData;
242 QMetaEnum tfme = QMetaEnum::fromType<QOpenGLTexture::TextureFormat>();
243 QMetaEnum ptme = QMetaEnum::fromType<QOpenGLTexture::PixelType>();
266 return is2D && (
isCubeMap || isCompressedImage);
269std::optional<QMap<QByteArray, QByteArray>> QKtxHandler::decodeKeyValues(
QByteArrayView view)
const
271 QMap<QByteArray, QByteArray>
output;
275 if (keyAndValueByteSizeView.isEmpty()) {
276 qWarning(lcQtGuiTextureIO,
"Invalid view in KTX key-value");
280 const quint32 keyAndValueByteSize =
281 decode(qFromUnaligned<quint32>(keyAndValueByteSizeView.data()));
283 quint32 offsetKeyAndValueStart;
285 qWarning(lcQtGuiTextureIO,
"Overflow in KTX key-value");
290 if (
qAddOverflow(offsetKeyAndValueStart, keyAndValueByteSize, &offsetKeyAndValueEnd)) {
291 qWarning(lcQtGuiTextureIO,
"Overflow in KTX key-value");
295 const auto keyValueView =
safeView(
view, offsetKeyAndValueStart, keyAndValueByteSize);
296 if (keyValueView.isEmpty()) {
297 qWarning(lcQtGuiTextureIO,
"Invalid view in KTX key-value");
305 const int idx = keyValueView.indexOf(
'\0');
307 qWarning(lcQtGuiTextureIO,
"Invalid key in KTX key-value");
312 if (keyView.isEmpty()) {
313 qWarning(lcQtGuiTextureIO,
"Overflow in KTX key-value");
317 const quint32 keySize = idx + 1;
320 if (
qAddOverflow(offsetKeyAndValueStart, keySize, &offsetValueStart)) {
321 qWarning(lcQtGuiTextureIO,
"Overflow in KTX key-value");
326 if (
qSubOverflow(keyAndValueByteSize, keySize, &valueSize)) {
327 qWarning(lcQtGuiTextureIO,
"Underflow in KTX key-value");
332 if (valueView.isEmpty()) {
333 qWarning(lcQtGuiTextureIO,
"Invalid view in KTX key-value");
337 output.insert(keyView.toByteArray(), valueView.toByteArray());
341 qWarning(lcQtGuiTextureIO,
"Overflow in KTX key-value");
353 return inverseEndian ? qbswap<quint32>(
val) :
val;
bool startsWith(QByteArrayView bv) const
QByteArray readAll()
Reads all remaining data from the device, and returns it as a byte array.
static bool canRead(const QByteArray &suffix, const QByteArray &block)
QTextureFileData read() override
void setData(const QByteArray &data)
QIODevice * device() const
QByteArray logName() const
Combined button and popup list for selecting options.
QT_POPCOUNT_RELAXED_CONSTEXPR uint qCountLeadingZeroBits(quint32 v) noexcept
static QString header(const QString &name)
static bool isCubeMap(const DDSHeader &dds)
typedef QByteArray(EGLAPIENTRYP PFNQGSGETDISPLAYSPROC)()
EGLOutputLayerEXT EGLint EGLAttrib value
[5]
static const quint32 platformEndianIdentifier
static const std::optional< quint32 > nearestMultipleOf4(quint32 value)
static QByteArrayView safeView(QByteArrayView view, quint32 start, quint32 length)
#define KTX_IDENTIFIER_LENGTH
static constexpr quint32 qktxh_headerSize
static const char ktxIdentifier[KTX_IDENTIFIER_LENGTH]
static const quint32 inversePlatformEndianIdentifier
std::enable_if_t< std::is_unsigned_v< T >, bool > qAddOverflow(T v1, T v2, T *r)
std::enable_if_t< std::is_unsigned_v< T >, bool > qSubOverflow(T v1, T v2, T *r)
GLenum GLuint GLint level
GLenum GLuint GLenum GLsizei length
GLenum GLuint GLenum GLsizei const GLchar * buf
GLenum GLuint GLintptr offset
GLint GLenum GLsizei GLsizei GLsizei GLint GLsizei imageSize
QT_BEGIN_NAMESPACE typedef uchar * output
quint32 keyAndValueByteSize