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