Qt
Internal/Contributor docs for the Qt SDK. Note: These are NOT official API docs; those are found at https://doc.qt.io/
Toggle main menu visibility
Loading...
Searching...
No Matches
qssggltfresourceresolver.cpp
Go to the documentation of this file.
1
// Copyright (C) 2026 The Qt Company Ltd.
2
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
3
// Qt-Security score:critical reason:data-parser
4
5
#
include
"qssggltfresourceresolver_p.h"
6
7
#
include
<
QtCore
/
qdir
.
h
>
8
#
include
<
QtCore
/
qfile
.
h
>
9
#
include
<
QtCore
/
qurl
.
h
>
10
11
QT_BEGIN_NAMESPACE
12
13
/*!
14
\namespace QSSGGltfResourceResolver
15
\internal
16
17
Resolves glTF URIs: data: URIs (base64 or percent-encoded), and relative
18
or absolute file paths, including Qt resource (":/...") paths.
19
*/
20
namespace
QSSGGltfResourceResolver {
21
22
/*!
23
\internal
24
25
Returns whether \a uri is a data: URI.
26
*/
27
bool
isDataUri
(QStringView uri)
28
{
29
return
uri.startsWith(QLatin1String(
"data:"
), Qt::CaseInsensitive);
30
}
31
32
/*!
33
\internal
34
35
Decodes the payload of the data: URI \a uri. Returns an empty array and
36
sets \a errorMessage on failure.
37
*/
38
QByteArray
decodeDataUri
(QStringView uri, QString *errorMessage)
39
{
40
// data:[<mediatype>][;base64],<payload>
41
const
qsizetype comma = uri.indexOf(u',');
42
if
(!isDataUri(uri) || comma < 0) {
43
if
(errorMessage)
44
*errorMessage = QStringLiteral(
"Malformed data URI"
);
45
return
{};
46
}
47
48
const
QStringView header = uri.mid(0, comma);
49
const
QStringView payload = uri.mid(comma + 1);
50
51
if
(header.endsWith(QLatin1String(
";base64"
), Qt::CaseInsensitive)) {
52
auto
result = QByteArray::fromBase64Encoding(payload.toLatin1());
53
if
(!result) {
54
if
(errorMessage)
55
*errorMessage = QStringLiteral(
"Invalid base64 payload in data URI"
);
56
return
{};
57
}
58
return
result.decoded;
59
}
60
61
// Non-base64 data URIs carry percent-encoded octets. Decoding has to stay
62
// in QByteArray: going through QString would replace every octet sequence
63
// that is not valid UTF-8 with U+FFFD, changing both the contents and the
64
// length of what is meant to be arbitrary binary data.
65
return
QByteArray::fromPercentEncoding(payload.toLatin1());
66
}
67
68
/*!
69
\internal
70
71
Resolves the relative file URI \a uri against \a baseDir to a local or qrc
72
path. The URI is percent-decoded as required by the glTF specification.
73
74
A URI that would reach outside \a baseDir is rejected, which returns an
75
empty string. The specification only allows relative references here, so
76
an absolute path or one climbing out with ".." is malformed rather than
77
merely unusual, and refusing it keeps a hostile asset from naming an
78
arbitrary file for the application to load and read back.
79
*/
80
QString
resolveFilePath
(QStringView uri,
const
QString &baseDir)
81
{
82
// glTF URIs are percent-encoded relative URI references
83
const
QString decoded = QUrl::fromPercentEncoding(uri.toUtf8());
84
if
(decoded.isEmpty())
85
return
{};
86
if
(QDir::isAbsolutePath(decoded) || decoded.startsWith(QLatin1String(
":/"
)))
87
return
{};
88
if
(baseDir.isEmpty())
89
return
QDir::cleanPath(decoded).startsWith(QLatin1String(
".."
)) ? QString() : decoded;
90
91
const
QString base = QDir::cleanPath(baseDir);
92
const
QString resolved = QDir::cleanPath(base + QLatin1Char(
'/'
) + decoded);
93
if
(resolved != base && !resolved.startsWith(base + QLatin1Char(
'/'
)))
94
return
{};
95
return
resolved;
96
}
97
98
/*!
99
\internal
100
101
Loads the contents referenced by the glTF URI \a uri: data: URIs are
102
decoded, anything else is treated as a file path relative to \a baseDir.
103
Sets \a errorMessage on failure.
104
*/
105
QByteArray
loadUri
(QStringView uri,
const
QString &baseDir, QString *errorMessage)
106
{
107
if
(isDataUri(uri))
108
return
decodeDataUri(uri, errorMessage);
109
110
const
QString path = resolveFilePath(uri, baseDir);
111
if
(path.isEmpty()) {
112
if
(errorMessage)
113
*errorMessage = QStringLiteral(
"Refusing to resolve '%1' outside the asset directory"
).arg(uri);
114
return
{};
115
}
116
117
QFile file(path);
118
if
(!file.open(QIODevice::ReadOnly)) {
119
if
(errorMessage)
120
*errorMessage = QStringLiteral(
"Failed to open '%1': %2"
).arg(path, file.errorString());
121
return
{};
122
}
123
return
file.readAll();
124
}
125
126
}
// namespace QSSGGltfResourceResolver
127
128
QT_END_NAMESPACE
QSSGGltfResourceResolver::decodeDataUri
QByteArray decodeDataUri(QStringView uri, QString *errorMessage)
Definition
qssggltfresourceresolver.cpp:38
QSSGGltfResourceResolver::isDataUri
bool isDataUri(QStringView uri)
Definition
qssggltfresourceresolver.cpp:27
QSSGGltfResourceResolver::loadUri
QByteArray loadUri(QStringView uri, const QString &baseDir, QString *errorMessage)
Definition
qssggltfresourceresolver.cpp:105
QSSGGltfResourceResolver::resolveFilePath
QString resolveFilePath(QStringView uri, const QString &baseDir)
Definition
qssggltfresourceresolver.cpp:80
QT_BEGIN_NAMESPACE
Combined button and popup list for selecting options.
Definition
qsequentialanimationgroup.cpp:47
qtquick3d
src
gltf
qssggltfresourceresolver.cpp
Generated on
for Qt by
1.18.0