1// Copyright (C) 2017 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
3// Qt-Security score:critical reason:data-parser
4
5#include "qpkmhandler_p.h"
6#include "qtexturefiledata_p.h"
7
8#include <QFile>
9#include <QDebug>
10#include <QSize>
11#include <qendian.h>
12
13//#define ETC_DEBUG
14
15QT_BEGIN_NAMESPACE
16
17static const int qpkmh_headerSize = 16;
18
19struct PkmType
20{
21 quint32 glFormat;
22 quint32 bytesPerBlock;
23};
24
25static constexpr PkmType typeMap[5] = {
26 { .glFormat: 0x8D64, .bytesPerBlock: 8 }, // GL_ETC1_RGB8_OES
27 { .glFormat: 0x9274, .bytesPerBlock: 8 }, // GL_COMPRESSED_RGB8_ETC2
28 { .glFormat: 0, .bytesPerBlock: 0 }, // unused (obsolete)
29 { .glFormat: 0x9278, .bytesPerBlock: 16}, // GL_COMPRESSED_RGBA8_ETC2_EAC
30 { .glFormat: 0x9276, .bytesPerBlock: 8 } // GL_COMPRESSED_RGB8_PUNCHTHROUGH_ALPHA1_ETC2
31};
32
33QPkmHandler::~QPkmHandler() = default;
34
35bool QPkmHandler::canRead(const QByteArray &suffix, const QByteArray &block)
36{
37 Q_UNUSED(suffix);
38
39 return block.startsWith(bv: "PKM ");
40}
41
42QTextureFileData QPkmHandler::read()
43{
44 QTextureFileData texData;
45
46 if (!device())
47 return texData;
48
49 QByteArray fileData = device()->readAll();
50 if (fileData.size() < qpkmh_headerSize || !canRead(suffix: QByteArray(), block: fileData)) {
51 qCDebug(lcQtGuiTextureIO, "Invalid PKM file %s", logName().constData());
52 return QTextureFileData();
53 }
54 texData.setData(fileData);
55
56 const char *rawData = fileData.constData();
57
58 // ignore version (rawData + 4 & 5)
59
60 // texture type
61 quint16 type = qFromBigEndian<quint16>(src: rawData + 6);
62 if (type >= sizeof(typeMap)/sizeof(typeMap[0])) {
63 qCDebug(lcQtGuiTextureIO, "Unknown compression format in PKM file %s", logName().constData());
64 return QTextureFileData();
65 }
66 texData.setGLFormat(0); // 0 for compressed textures
67 texData.setGLInternalFormat(typeMap[type].glFormat);
68 //### setBaseInternalFormat
69
70 // texture size
71 texData.setNumLevels(1);
72 texData.setNumFaces(1);
73 const int bpb = typeMap[type].bytesPerBlock;
74 QSize paddedSize(qFromBigEndian<quint16>(src: rawData + 8), qFromBigEndian<quint16>(src: rawData + 10));
75 texData.setDataLength(length: (paddedSize.width() / 4) * (paddedSize.height() / 4) * bpb);
76 QSize texSize(qFromBigEndian<quint16>(src: rawData + 12), qFromBigEndian<quint16>(src: rawData + 14));
77 texData.setSize(texSize);
78
79 texData.setDataOffset(offset: qpkmh_headerSize);
80
81 if (!texData.isValid()) {
82 qCDebug(lcQtGuiTextureIO, "Invalid values in header of PKM file %s", logName().constData());
83 return QTextureFileData();
84 }
85
86 texData.setLogName(logName());
87
88#ifdef ETC_DEBUG
89 qDebug() << "PKM file handler read" << texData;
90#endif
91 return texData;
92}
93
94QT_END_NAMESPACE
95

source code of qtbase/src/gui/util/qpkmhandler.cpp