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
qqmlpreviewfileengine.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:significant
4
5
#
include
"qqmlpreviewfileengine.h"
6
#
include
"qqmlpreviewservice.h"
7
8
#
include
<
QtCore
/
qlibraryinfo
.
h
>
9
#
include
<
QtCore
/
qthread
.
h
>
10
#
include
<
QtCore
/
qwaitcondition
.
h
>
11
12
#
include
<
cstring
>
13
14
QT_BEGIN_NAMESPACE
15
16
static
bool
isRelative
(
const
QString &path)
17
{
18
if
(path.isEmpty())
19
return
true
;
20
if
(path.at(0) ==
'/'
)
21
return
false
;
22
if
(path.at(0) ==
':'
&& path.size() >= 2 && path.at(1) ==
'/'
)
23
return
false
;
24
#
ifdef
Q_OS_WIN
25
if
(path.length() >= 2 && path.at(1) ==
':'
)
26
return
false
;
27
#
endif
28
return
true
;
29
}
30
31
static
QString
absolutePath
(
const
QString &path)
32
{
33
return
QDir::cleanPath(isRelative(path) ? (QDir::currentPath() +
'/'
+ path) : path);
34
}
35
36
bool
isRootPath
(
const
QString &path)
37
{
38
return
QFileSystemEntry::isRootPath(path);
39
}
40
41
class
QQmlPreviewFileEngineIterator
:
public
QAbstractFileEngineIterator
42
{
43
public
:
44
QQmlPreviewFileEngineIterator
(
const
QString &path, QDirListing::IteratorFlags filters,
45
const
QStringList &filterNames,
const
QStringList &m_entries);
46
~
QQmlPreviewFileEngineIterator
();
47
48
bool
advance
()
override
;
49
QString
currentFileName
()
const
override
;
50
51
private
:
52
const
QStringList m_entries;
53
int
m_index;
54
};
55
56
QQmlPreviewFileEngineIterator
::
QQmlPreviewFileEngineIterator
(
const
QString &path,
57
QDirListing::IteratorFlags filters,
58
const
QStringList &filterNames,
59
const
QStringList &entries)
60
:
QAbstractFileEngineIterator
(
path
,
filters
,
filterNames
),
m_entries
(
entries
), m_index(0)
61
{
62
}
63
64
QQmlPreviewFileEngineIterator
::~
QQmlPreviewFileEngineIterator
()
65
{
66
}
67
68
bool
QQmlPreviewFileEngineIterator
::
advance
()
69
{
70
if
(m_index >= m_entries.size())
71
return
false
;
72
73
++m_index;
74
return
true
;
75
}
76
77
QString
QQmlPreviewFileEngineIterator
::
currentFileName
()
const
78
{
79
if
(m_index == 0 || m_index > m_entries.size())
80
return
QString();
81
return
m_entries.at(m_index - 1);
82
}
83
84
QQmlPreviewFileEngine::QQmlPreviewFileEngine(
const
QString &file,
const
QString &absolute,
85
QQmlPreviewFileLoader
*loader) :
86
m_name(file), m_absolute(absolute), m_loader(loader)
87
{
88
load();
89
}
90
91
void
QQmlPreviewFileEngine::setFileName(
const
QString &file)
92
{
93
m_name = file;
94
m_absolute = absolutePath(file);
95
m_fallback.reset();
96
m_contents.close();
97
m_contents.setData(QByteArray());
98
m_entries.clear();
99
load();
100
}
101
102
bool
QQmlPreviewFileEngine::open(QIODevice::OpenMode flags,
103
std::optional<QFile::Permissions> permissions)
104
{
105
switch
(m_result) {
106
case
QQmlPreviewFileLoader::File:
107
return
m_contents.open(flags);
108
case
QQmlPreviewFileLoader::Directory:
109
return
false
;
110
case
QQmlPreviewFileLoader::Fallback:
111
return
m_fallback->open(flags, permissions);
112
default
:
113
Q_UNREACHABLE_RETURN(
false
);
114
}
115
}
116
117
bool
QQmlPreviewFileEngine::close()
118
{
119
switch
(m_result) {
120
case
QQmlPreviewFileLoader::Fallback:
121
return
m_fallback->close();
122
case
QQmlPreviewFileLoader::File:
123
m_contents.close();
124
return
true
;
125
case
QQmlPreviewFileLoader::Directory:
126
return
false
;
127
default
:
128
Q_UNREACHABLE_RETURN(
false
);
129
}
130
}
131
132
qint64 QQmlPreviewFileEngine::size()
const
133
{
134
return
m_fallback ? m_fallback->size() : m_contents.size();
135
}
136
137
qint64 QQmlPreviewFileEngine::pos()
const
138
{
139
return
m_fallback ? m_fallback->pos() : m_contents.pos();
140
}
141
142
bool
QQmlPreviewFileEngine::seek(qint64 newPos)
143
{
144
return
m_fallback? m_fallback->seek(newPos) : m_contents.seek(newPos);
145
}
146
147
qint64 QQmlPreviewFileEngine::read(
char
*data, qint64 maxlen)
148
{
149
return
m_fallback ? m_fallback->read(data, maxlen) : m_contents.read(data, maxlen);
150
}
151
152
QAbstractFileEngine::FileFlags QQmlPreviewFileEngine::fileFlags(
153
QAbstractFileEngine::FileFlags type)
const
154
{
155
if
(m_fallback)
156
return
m_fallback->fileFlags(type);
157
158
QAbstractFileEngine::FileFlags ret;
159
160
if
(type & PermsMask) {
161
ret |= QAbstractFileEngine::FileFlags(
162
ReadOwnerPerm | ReadUserPerm | ReadGroupPerm | ReadOtherPerm);
163
}
164
165
if
(type & TypesMask) {
166
if
(m_result == QQmlPreviewFileLoader::Directory)
167
ret |= DirectoryType;
168
else
169
ret |= FileType;
170
}
171
172
if
(type & FlagsMask) {
173
ret |= ExistsFlag;
174
if
(isRootPath(m_name))
175
ret |= RootFlag;
176
}
177
178
return
ret;
179
}
180
181
QString QQmlPreviewFileEngine::fileName(QAbstractFileEngine::FileName file)
const
182
{
183
if
(m_fallback)
184
return
m_fallback->fileName(file);
185
186
if
(file == BaseName) {
187
int
slashPos = m_name.lastIndexOf(
'/'
);
188
if
(slashPos == -1)
189
return
m_name;
190
return
m_name.mid(slashPos + 1);
191
}
else
if
(file == PathName || file == AbsolutePathName) {
192
const
QString path = (file == AbsolutePathName) ? m_absolute : m_name;
193
const
int
slashPos = path.lastIndexOf(
'/'
);
194
if
(slashPos == -1)
195
return
QString();
196
else
if
(slashPos == 0)
197
return
"/"
;
198
return
path.left(slashPos);
199
}
else
if
(file == CanonicalName || file == CanonicalPathName) {
200
if
(file == CanonicalPathName) {
201
const
int
slashPos = m_absolute.lastIndexOf(
'/'
);
202
if
(slashPos != -1)
203
return
m_absolute.left(slashPos);
204
}
205
return
m_absolute;
206
}
207
return
m_name;
208
}
209
210
uint QQmlPreviewFileEngine::ownerId(QAbstractFileEngine::FileOwner owner)
const
211
{
212
return
m_fallback ? m_fallback->ownerId(owner) :
static_cast
<uint>(-2);
213
}
214
215
QAbstractFileEngine::IteratorUniquePtr QQmlPreviewFileEngine::beginEntryList(
216
const
QString &path, QDirListing::IteratorFlags filters,
const
QStringList &filterNames)
217
{
218
return
m_fallback ? m_fallback->beginEntryList(path, filters, filterNames)
219
: std::make_unique<QQmlPreviewFileEngineIterator>(
220
path, filters, filterNames, m_entries);
221
}
222
223
QAbstractFileEngine::IteratorUniquePtr QQmlPreviewFileEngine::endEntryList()
224
{
225
return
m_fallback ? m_fallback->endEntryList() :
nullptr
;
226
}
227
228
bool
QQmlPreviewFileEngine::flush()
229
{
230
return
m_fallback ? m_fallback->flush() :
true
;
231
}
232
233
bool
QQmlPreviewFileEngine::syncToDisk()
234
{
235
return
m_fallback ? m_fallback->syncToDisk() :
false
;
236
}
237
238
bool
QQmlPreviewFileEngine::isSequential()
const
239
{
240
return
m_fallback ? m_fallback->isSequential() : m_contents.isSequential();
241
}
242
243
bool
QQmlPreviewFileEngine::remove()
244
{
245
return
m_fallback ? m_fallback->remove() :
false
;
246
}
247
248
bool
QQmlPreviewFileEngine::copy(
const
QString &newName)
249
{
250
return
m_fallback ? m_fallback->copy(newName) :
false
;
251
}
252
253
bool
QQmlPreviewFileEngine::rename(
const
QString &newName)
254
{
255
return
m_fallback ? m_fallback->rename(newName) :
false
;
256
}
257
258
bool
QQmlPreviewFileEngine::renameOverwrite(
const
QString &newName)
259
{
260
return
m_fallback ? m_fallback->renameOverwrite(newName) :
false
;
261
}
262
263
bool
QQmlPreviewFileEngine::link(
const
QString &newName)
264
{
265
return
m_fallback ? m_fallback->link(newName) :
false
;
266
}
267
268
bool
QQmlPreviewFileEngine::mkdir(
const
QString &dirName,
bool
createParentDirectories,
269
std::optional<QFile::Permissions> permissions)
const
270
{
271
if
(m_fallback)
272
return
m_fallback->mkdir(dirName, createParentDirectories, permissions);
273
274
if
(isRelative(dirName))
275
return
false
;
276
277
// If we're creating a directory from an absolute path, it can be anywhere.
278
// The result is unrelated to the currently running preview.
279
return
QAbstractFileEngine::create(QDir::rootPath())
280
->mkdir(dirName, createParentDirectories, permissions);
281
}
282
283
bool
QQmlPreviewFileEngine::rmdir(
const
QString &dirName,
bool
recurseParentDirectories)
const
284
{
285
if
(m_fallback)
286
m_fallback->rmdir(dirName, recurseParentDirectories);
287
288
if
(isRelative(dirName))
289
return
false
;
290
291
// If we're removing a directory at an absolute path, it can be anywhere.
292
// The result is unrelated to the currently running preview.
293
return
QAbstractFileEngine::create(QDir::rootPath())
294
->rmdir(dirName, recurseParentDirectories);
295
}
296
297
bool
QQmlPreviewFileEngine::setSize(qint64 size)
298
{
299
switch
(m_result) {
300
case
QQmlPreviewFileLoader::Fallback:
301
return
m_fallback->setSize(size);
302
case
QQmlPreviewFileLoader::File:
303
if
(size < 0 || size > std::numeric_limits<
int
>::max())
304
return
false
;
305
m_contents.buffer().resize(
static_cast
<
int
>(size));
306
return
true
;
307
case
QQmlPreviewFileLoader::Directory:
308
return
false
;
309
default
:
310
Q_UNREACHABLE_RETURN(
false
);
311
}
312
}
313
314
bool
QQmlPreviewFileEngine::caseSensitive()
const
315
{
316
return
m_fallback ? m_fallback->caseSensitive() :
true
;
317
}
318
319
bool
QQmlPreviewFileEngine::isRelativePath()
const
320
{
321
return
m_fallback ? m_fallback->isRelativePath() : isRelative(m_name);
322
}
323
324
bool
QQmlPreviewFileEngine::setPermissions(uint perms)
325
{
326
return
m_fallback ? m_fallback->setPermissions(perms) :
false
;
327
}
328
329
QByteArray QQmlPreviewFileEngine::id()
const
330
{
331
return
m_fallback ? m_fallback->id() : QByteArray();
332
}
333
334
QString QQmlPreviewFileEngine::owner(FileOwner owner)
const
335
{
336
return
m_fallback ? m_fallback->owner(owner) : QString();
337
}
338
339
QDateTime QQmlPreviewFileEngine::fileTime(QFile::FileTime time)
const
340
{
341
// Files we replace are always newer than the ones we had before. This makes the QML engine
342
// actually recompile them, rather than pick them from the cache.
343
return
m_fallback ? m_fallback->fileTime(time) : QDateTime::currentDateTime();
344
}
345
346
int
QQmlPreviewFileEngine::handle()
const
347
{
348
return
m_fallback ? m_fallback->handle() : -1;
349
}
350
351
qint64 QQmlPreviewFileEngine::readLine(
char
*data, qint64 maxlen)
352
{
353
return
m_fallback ? m_fallback->readLine(data, maxlen) : m_contents.readLine(data, maxlen);
354
}
355
356
qint64 QQmlPreviewFileEngine::write(
const
char
*data, qint64 len)
357
{
358
return
m_fallback ? m_fallback->write(data, len) : m_contents.write(data, len);
359
}
360
361
bool
QQmlPreviewFileEngine::extension(Extension extension,
const
ExtensionOption *option, ExtensionReturn *output)
362
{
363
return
m_fallback ? m_fallback->extension(extension, option, output) :
false
;
364
}
365
366
bool
QQmlPreviewFileEngine::supportsExtension(Extension extension)
const
367
{
368
return
m_fallback ? m_fallback->supportsExtension(extension) :
false
;
369
}
370
371
void
QQmlPreviewFileEngine::load()
const
372
{
373
// We can get here from different threads on different instances of QQmlPreviewFileEngine.
374
// However, there is only one loader per QQmlPreviewFileEngineHandler and it is not thread-safe.
375
// Its content mutex doesn't help us here because we explicitly wait on it in load(), which
376
// causes it to be released. Therefore, lock the load mutex first.
377
// This doesn't cause any deadlocks because the only thread that wakes the loader on the content
378
// mutex never calls load(). It's the QML debug server thread that handles the debug protocol.
379
QMutexLocker loadLocker(m_loader->loadMutex());
380
381
m_result = m_loader->load(m_absolute);
382
switch
(m_result) {
383
case
QQmlPreviewFileLoader::File:
384
m_contents.setData(m_loader->contents());
385
break
;
386
case
QQmlPreviewFileLoader::Directory:
387
m_entries = m_loader->entries();
388
break
;
389
case
QQmlPreviewFileLoader::Fallback:
390
m_fallback = QAbstractFileEngine::create(m_name);
391
break
;
392
case
QQmlPreviewFileLoader::Unknown:
393
Q_UNREACHABLE();
394
break
;
395
}
396
}
397
398
QQmlPreviewFileEngineHandler
::QQmlPreviewFileEngineHandler(
QQmlPreviewFileLoader
*loader)
399
: m_loader(loader)
400
{
401
}
402
403
std
::
unique_ptr
<
QAbstractFileEngine
>
QQmlPreviewFileEngineHandler
::
create
(
404
const
QString &fileName)
const
405
{
406
using
namespace
Qt::StringLiterals;
407
static
QList<QLatin1StringView> prohibitedSuffixes {
408
// Don't load compiled QML/JS over the network
409
".qmlc"_L1
,
".jsc"_L1
,
".mjsc"_L1
,
410
411
// Don't load plugins over the network
412
".dll"_L1
,
".so"_L1
,
".dylib"_L1
413
};
414
415
for
(QLatin1StringView suffix : prohibitedSuffixes) {
416
if
(fileName.endsWith(suffix))
417
return
nullptr
;
418
}
419
420
if
(isRootPath(fileName))
421
return
nullptr
;
422
423
QString relative = fileName;
424
while
(relative.endsWith(
'/'
))
425
relative.chop(1);
426
427
if
(relative.isEmpty() || relative ==
":"
)
428
return
nullptr
;
429
430
const
QString absolute = relative.startsWith(
':'
) ? relative : absolutePath(relative);
431
432
if
(m_loader->isBlacklisted(absolute))
433
return
{};
434
435
return
std
::make_unique<QQmlPreviewFileEngine>(relative, absolute, m_loader.data());
436
}
437
438
QT_END_NAMESPACE
QQmlPreviewFileEngineHandler
Definition
qqmlpreviewfileengine.h:92
QQmlPreviewFileEngineHandler::create
std::unique_ptr< QAbstractFileEngine > create(const QString &fileName) const override
If this file handler can handle fileName, this method creates a file engine and returns it wrapped in...
Definition
qqmlpreviewfileengine.cpp:403
QQmlPreviewFileEngineIterator
Definition
qqmlpreviewfileengine.cpp:42
QQmlPreviewFileEngineIterator::currentFileName
QString currentFileName() const override
This pure virtual function returns the name of the current directory entry, excluding the path.
Definition
qqmlpreviewfileengine.cpp:77
QQmlPreviewFileEngineIterator::QQmlPreviewFileEngineIterator
QQmlPreviewFileEngineIterator(const QString &path, QDirListing::IteratorFlags filters, const QStringList &filterNames, const QStringList &m_entries)
Definition
qqmlpreviewfileengine.cpp:56
QQmlPreviewFileEngineIterator::~QQmlPreviewFileEngineIterator
~QQmlPreviewFileEngineIterator()
Definition
qqmlpreviewfileengine.cpp:64
QQmlPreviewFileEngineIterator::advance
bool advance() override
This pure virtual function advances the iterator to the next directory entry; if the operation was su...
Definition
qqmlpreviewfileengine.cpp:68
QQmlPreviewFileLoader
Definition
qqmlpreviewfileloader.h:34
std
[33]
Definition
src_corelib_tools_qhash.cpp:421
isRelative
static QT_BEGIN_NAMESPACE bool isRelative(const QString &path)
Definition
qqmlpreviewfileengine.cpp:16
absolutePath
static QString absolutePath(const QString &path)
Definition
qqmlpreviewfileengine.cpp:31
isRootPath
bool isRootPath(const QString &path)
Definition
qqmlpreviewfileengine.cpp:36
qtdeclarative
src
plugins
qmltooling
qmldbg_preview
qqmlpreviewfileengine.cpp
Generated on
for Qt by
1.18.0