1// Copyright (C) 2018 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 "QtGui/qimage.h"
6#include "qtexturefiledata_p.h"
7#include <QtCore/qsize.h>
8#include <QtCore/qvarlengtharray.h>
9#include <QtCore/qmap.h>
10
11QT_BEGIN_NAMESPACE
12
13Q_LOGGING_CATEGORY(lcQtGuiTextureIO, "qt.gui.textureio");
14
15constexpr size_t MAX_FACES = 6;
16
17class QTextureFileDataPrivate : public QSharedData
18{
19public:
20 QTextureFileDataPrivate()
21 {
22 }
23
24 QTextureFileDataPrivate(const QTextureFileDataPrivate &other)
25 : QSharedData(other),
26 mode(other.mode),
27 logName(other.logName),
28 data(other.data),
29 offsets(other.offsets),
30 lengths(other.lengths),
31 images(other.images),
32 size(other.size),
33 format(other.format),
34 numFaces(other.numFaces),
35 numLevels(other.numLevels),
36 keyValues(other.keyValues)
37 {
38 }
39
40 ~QTextureFileDataPrivate()
41 {
42 }
43
44 void ensureSize(int levels, int faces, bool force = false)
45 {
46 numLevels = force ? levels : qMax(a: numLevels, b: levels);
47 numFaces = force ? faces : qMax(a: numFaces, b: faces);
48 if (mode == QTextureFileData::ByteArrayMode) {
49 offsets.resize(sz: numFaces);
50 lengths.resize(sz: numFaces);
51
52 for (auto faceList : { &offsets, &lengths })
53 for (auto &levelList : *faceList)
54 levelList.resize(size: numLevels);
55 } else {
56 images.resize(sz: numFaces);
57 for (auto &levelList : images)
58 levelList.resize(size: numLevels);
59 }
60 }
61
62 bool isValid(int level, int face) const { return level < numLevels && face < numFaces; }
63
64 int getOffset(int level, int face) const { return offsets[face][level]; }
65 void setOffset(int value, int level, int face) { offsets[face][level] = value; }
66 int getLength(int level, int face) const { return lengths[face][level]; }
67 void setLength(int value, int level, int face) { lengths[face][level] = value; }
68
69 QTextureFileData::Mode mode = QTextureFileData::ByteArrayMode;
70 QByteArray logName;
71 QByteArray data;
72 QVarLengthArray<QList<int>, MAX_FACES> offsets; // [Face][Level] = offset
73 QVarLengthArray<QList<int>, MAX_FACES> lengths; // [Face][Level] = length
74 QVarLengthArray<QList<QImage>, MAX_FACES> images; // [Face][Level] = length
75 QSize size;
76 quint32 format = 0;
77 quint32 internalFormat = 0;
78 quint32 baseInternalFormat = 0;
79 int numFaces = 0;
80 int numLevels = 0;
81 QMap<QByteArray, QByteArray> keyValues;
82};
83
84QTextureFileData::QTextureFileData(Mode mode)
85{
86 d = new QTextureFileDataPrivate;
87 d->mode = mode;
88}
89
90QTextureFileData::QTextureFileData(const QTextureFileData &other)
91 : d(other.d)
92{
93}
94
95QTextureFileData &QTextureFileData::operator=(const QTextureFileData &other)
96{
97 d = other.d;
98 return *this;
99}
100
101QTextureFileData::~QTextureFileData()
102{
103}
104
105bool QTextureFileData::isNull() const
106{
107 return !d;
108}
109
110bool QTextureFileData::isValid() const
111{
112 if (!d)
113 return false;
114
115 if (d->mode == ImageMode)
116 return true; // Manually populated: the caller needs to do verification at that time.
117
118 if (d->data.isEmpty() || d->size.isEmpty() || (!d->format && !d->internalFormat))
119 return false;
120
121 const int numFacesOffset = d->offsets.size();
122 const int numFacesLength = d->lengths.size();
123 if (numFacesOffset == 0 || numFacesLength == 0 || d->numFaces != numFacesOffset
124 || d->numFaces != numFacesLength)
125 return false;
126
127 const qint64 dataSize = d->data.size();
128
129 // Go through all faces and levels and check that the range is inside the data size.
130 for (int face = 0; face < d->numFaces; face++) {
131 const int numLevelsOffset = d->offsets.at(idx: face).size();
132 const int numLevelsLength = d->lengths.at(idx: face).size();
133 if (numLevelsOffset == 0 || numLevelsLength == 0 || d->numLevels != numLevelsOffset
134 || d->numLevels != numLevelsLength)
135 return false;
136
137 for (int level = 0; level < d->numLevels; level++) {
138 const qint64 offset = d->getOffset(level, face);
139 const qint64 length = d->getLength(level, face);
140 if (offset < 0 || offset >= dataSize || length <= 0 || (offset + length > dataSize))
141 return false;
142 }
143 }
144 return true;
145}
146
147void QTextureFileData::clear()
148{
149 d = nullptr;
150}
151
152QByteArray QTextureFileData::data() const
153{
154 return d ? d->data : QByteArray();
155}
156
157void QTextureFileData::setData(const QByteArray &data)
158{
159 Q_ASSERT(d->mode == ByteArrayMode);
160 d->data = data;
161}
162
163void QTextureFileData::setData(const QImage &image, int level, int face)
164{
165 Q_ASSERT(d->mode == ImageMode);
166 d->ensureSize(levels: level + 1, faces: face + 1);
167 d->images[face][level] = image;
168}
169
170int QTextureFileData::dataOffset(int level, int face) const
171{
172 Q_ASSERT(d->mode == ByteArrayMode);
173 return (d && d->isValid(level, face)) ? d->getOffset(level, face) : 0;
174}
175
176void QTextureFileData::setDataOffset(int offset, int level, int face)
177{
178 Q_ASSERT(d->mode == ByteArrayMode);
179 if (d.constData() && level >= 0) {
180 d->ensureSize(levels: level + 1, faces: face + 1);
181 d->setOffset(value: offset, level, face);
182 }
183}
184
185int QTextureFileData::dataLength(int level, int face) const
186{
187 Q_ASSERT(d->mode == ByteArrayMode);
188 return (d && d->isValid(level, face)) ? d->getLength(level, face) : 0;
189}
190
191QByteArrayView QTextureFileData::getDataView(int level, int face) const
192{
193 if (d->mode == ByteArrayMode) {
194 const int dataLength = this->dataLength(level, face);
195 const int dataOffset = this->dataOffset(level, face);
196
197 if (d == nullptr || dataLength == 0)
198 return QByteArrayView();
199
200 return QByteArrayView(d->data.constData() + dataOffset, dataLength);
201 } else {
202 if (!d->isValid(level, face))
203 return QByteArrayView();
204 const QImage &img = d->images[face][level];
205 return img.isNull() ? QByteArrayView() : QByteArrayView(img.constBits(), img.sizeInBytes());
206 }
207}
208
209void QTextureFileData::setDataLength(int length, int level, int face)
210{
211 Q_ASSERT(d->mode == ByteArrayMode);
212 if (d.constData() && level >= 0) {
213 d->ensureSize(levels: level + 1, faces: face + 1);
214 d->setLength(value: length, level, face);
215 }
216}
217
218int QTextureFileData::numLevels() const
219{
220 return d ? d->numLevels : 0;
221}
222
223void QTextureFileData::setNumLevels(int numLevels)
224{
225 if (d && numLevels >= 0)
226 d->ensureSize(levels: numLevels, faces: d->numFaces, force: true);
227}
228
229int QTextureFileData::numFaces() const
230{
231 return d ? d->numFaces : 0;
232}
233
234void QTextureFileData::setNumFaces(int numFaces)
235{
236 if (d && numFaces >= 0)
237 d->ensureSize(levels: d->numLevels, faces: numFaces, force: true);
238}
239
240QSize QTextureFileData::size() const
241{
242 return d ? d->size : QSize();
243}
244
245void QTextureFileData::setSize(const QSize &size)
246{
247 if (d.constData())
248 d->size = size;
249}
250
251quint32 QTextureFileData::glFormat() const
252{
253 return d ? d->format : 0;
254}
255
256void QTextureFileData::setGLFormat(quint32 format)
257{
258 if (d.constData())
259 d->format = format;
260}
261
262quint32 QTextureFileData::glInternalFormat() const
263{
264 return d ? d->internalFormat : 0;
265}
266
267void QTextureFileData::setGLInternalFormat(quint32 format)
268{
269 if (d.constData())
270 d->internalFormat = format;
271}
272
273quint32 QTextureFileData::glBaseInternalFormat() const
274{
275 return d ? d->baseInternalFormat : 0;
276}
277
278void QTextureFileData::setGLBaseInternalFormat(quint32 format)
279{
280 if (d.constData())
281 d->baseInternalFormat = format;
282}
283
284QByteArray QTextureFileData::logName() const
285{
286 return d ? d->logName : QByteArray();
287}
288
289void QTextureFileData::setLogName(const QByteArray &name)
290{
291 if (d.constData())
292 d->logName = name;
293}
294
295QMap<QByteArray, QByteArray> QTextureFileData::keyValueMetadata() const
296{
297 return d ? d->keyValues : QMap<QByteArray, QByteArray>();
298}
299
300void QTextureFileData::setKeyValueMetadata(const QMap<QByteArray, QByteArray> &keyValues)
301{
302 if (d)
303 d->keyValues = keyValues;
304}
305
306static QByteArray glFormatName(quint32 fmt)
307{
308 return QByteArray("0x" + QByteArray::number(fmt, base: 16).rightJustified(width: 4, fill: '0'));
309}
310
311QDebug operator<<(QDebug dbg, const QTextureFileData &d)
312{
313 QDebugStateSaver saver(dbg);
314
315 dbg.nospace() << "QTextureFileData(";
316 if (!d.isNull()) {
317 dbg.space() << d.logName() << d.size();
318 dbg << "glFormat:" << glFormatName(fmt: d.glFormat());
319 dbg << "glInternalFormat:" << glFormatName(fmt: d.glInternalFormat());
320 dbg << "glBaseInternalFormat:" << glFormatName(fmt: d.glBaseInternalFormat());
321 dbg.nospace() << "Levels: " << d.numLevels();
322 dbg.nospace() << "Faces: " << d.numFaces();
323 if (!d.isValid())
324 dbg << " {Invalid}";
325 dbg << ")";
326 dbg << (d.d->mode ? "[bytearray-based]" : "[image-based]");
327 } else {
328 dbg << "null)";
329 }
330
331 return dbg;
332}
333
334QT_END_NAMESPACE
335

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