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
qwasmlocalfileengine.cpp
Go to the documentation of this file.
1// Copyright (C) 2025 Qt Group
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 reason:default
5#include <QtCore/QDebug>
6#include <QtCore/QUrl>
7
9
10using namespace Qt::StringLiterals;
11
12// Custom URL scheme for files handled by this file engine. A complete file URL can
13// look like
14//
15// "weblocalfile:/n/file.ext"
16//
17// where n is a counter to ensure uniqueness, needed since web platform gives us the file name only
18// and does not provide the file path.
19//
20// The scheme may be visible to end users if the application displays it, so
21// we avoid using "wasm" and instead say "web", which should be more recognizable.
22static constexpr QLatin1StringView wasmlocalfileScheme = "weblocalfile"_L1;
23
24// Instantiate the engine, the system will pick it up automatically
25// Never destroy it to avoid problems with static destruction.
26// The OS will reclaim the memory anyway,
27// TODO: cleanup on QApplication destruction and re-init on QApplication re-creation.
29
30QWasmFileEngineHandler::QWasmFileEngineHandler()
31{
32}
33
37
39{
40 if (!QWasmFileEngineHandler::isWasmFileName(fileName))
41 return {};
42
43 // Check if it's a File or FileSystemFileHandle
44 if (singleton->m_files.contains(fileName)) {
45 qstdweb::File file = singleton->m_files.value(fileName);
46 return std::make_unique<QWasmFileEngine>(fileName, file);
47 } else if (singleton->m_fileSystemFiles.contains(fileName)) {
48 qstdweb::FileSystemFileHandle file = singleton->m_fileSystemFiles.value(fileName);
49 return std::make_unique<QWasmFileEngine>(fileName, file);
50 }
51
52 // Not an error, this function will be called with partial paths like "weblocalfile:/1/"
53 return {};
54}
55
56// Check if this is a wasm filename by checking the URL scheme.
57bool QWasmFileEngineHandler::isWasmFileName(const QString& fileName)
58{
59 return QUrl(fileName).scheme() == wasmlocalfileScheme;
60}
61
62// Creates a wasm filename using the custom URL scheme and a counter.
63QString QWasmFileEngineHandler::makeWasmFileName(const QString &nativeFileName)
64{
65 static std::atomic<uint64_t> sid = 0;
66 const uint64_t id = ++sid;
67 return wasmlocalfileScheme + QStringLiteral(":/%1/%2").arg(id).arg(nativeFileName);
68}
69
70// Extracts the native filename from the custom URL (removes scheme and counter).
71QString QWasmFileEngineHandler::nativeFileName(const QString &wasmFileName)
72{
73 QUrl url(wasmFileName);
74 if (url.scheme() == wasmlocalfileScheme) {
75 QString path = url.path();
76 // Path is "/n/filename", find the second '/' and extract the filename
77 const qsizetype idx = path.indexOf(u'/', 1);
78 if (idx != -1)
79 return path.mid(idx + 1);
80 }
81 return wasmFileName;
82}
83
84// Adds a File to the set of open files. Returns a prefixed wasm file name.
85QString QWasmFileEngineHandler::addFile(qstdweb::File file)
86{
87 QString nativeFileName = QString::fromStdString(file.name());
88 QString wasmFileName = makeWasmFileName(nativeFileName);
89 singleton->m_files.insert(wasmFileName, file);
90 return wasmFileName;
91}
92
93// Adds a FileSystemFileHandle to the set of open files. Returns a prefixed wasm file name.
94QString QWasmFileEngineHandler::addFile(qstdweb::FileSystemFileHandle file)
95{
96 QString nativeFileName = QString::fromStdString(file.name());
97 QString wasmFileName = makeWasmFileName(nativeFileName);
98 singleton->m_fileSystemFiles.insert(wasmFileName, file);
99 return wasmFileName;
100}
101
102// Removes a File or FileSystemFileHandle from the set of open file handlers
103void QWasmFileEngineHandler::removeFile(const QString fileName)
104{
105 singleton->m_files.remove(fileName);
106 singleton->m_fileSystemFiles.remove(fileName);
107}
108
110{
111 return singleton->m_files.value(fileName);
112}
113
115{
116 return singleton->m_fileSystemFiles.value(fileName);
117}
118
119/*!
120 \class QWasmFileEngine
121 \brief The QWasmFileEngine class provides a QAbstractFileEngine
122 for files that has the prefix ':weblocalfile/'.
123*/
124
125// Constructs a QWasmFileEngine with a File for read-only access
126QWasmFileEngine::QWasmFileEngine(const QString &fileName, qstdweb::File file)
129{
130 // TODO use m_blobDevice in unbuffered mode? if there is already a buffer higher up.
131}
132
133// Constructs a QWasmFileEngine with a FileSystemFileHandle for read-write access
134QWasmFileEngine::QWasmFileEngine(const QString &fileName, qstdweb::FileSystemFileHandle file)
137{
138
139}
140
145
146bool QWasmFileEngine::open(QIODevice::OpenMode openMode, std::optional<QFile::Permissions> permissions)
147{
148 Q_UNUSED(permissions);
149
150 // Warn on missing asyncify/JSPI and fail the open
151 if (!qstdweb::canBlockCallingThread()) {
152 const QString message =
153 QStringLiteral("Accessing local file contents on Qt for WebAssembly "
154 "requires JSPI or asyncify to be enabled.");
155 qWarning().noquote() << message;
156 setError(QFile::OpenError, message);
157 return false;
158 }
159
160 bool opened = false;
161 if (m_fileDevice)
162 opened = m_fileDevice->open(openMode);
163 else if (m_blobDevice)
164 opened = m_blobDevice->open(openMode);
165
166 if (opened)
167 m_openMode = openMode;
168 return opened;
169}
170
172{
173 if (m_openMode == QIODevice::NotOpen)
174 return false;
175
176 bool success = true;
177 if (m_fileDevice) {
178 m_fileDevice->close();
179 }
180 if (m_blobDevice) {
181 m_blobDevice->close();
182 }
183
184 m_openMode = QIODevice::NotOpen;
185 return success;
186}
187
189{
190 return true;
191}
192
194{
195 return true;
196}
197
199{
200 if (m_fileDevice)
201 return m_fileDevice->size();
202 if (m_blobDevice)
203 return m_blobDevice->size();
204 return 0;
205}
206
208{
209 if (m_fileDevice)
210 return m_fileDevice->pos();
211 if (m_blobDevice)
212 return m_blobDevice->pos();
213 return 0;
214}
215
216bool QWasmFileEngine::seek(qint64 pos)
217{
218 if (m_fileDevice)
219 return m_fileDevice->seek(pos);
220 if (m_blobDevice)
221 return m_blobDevice->seek(pos);
222 return false;
223}
224
226{
227 return false;
228}
229
231{
232 return false;
233}
234
235bool QWasmFileEngine::copy(const QString &newName)
236{
237 Q_UNUSED(newName);
238 return false;
239}
240
241bool QWasmFileEngine::rename(const QString &newName)
242{
243 Q_UNUSED(newName);
244 return false;
245}
246
247bool QWasmFileEngine::renameOverwrite(const QString &newName)
248{
249 Q_UNUSED(newName);
250 return false;
251}
252
253bool QWasmFileEngine::link(const QString &newName)
254{
255 Q_UNUSED(newName);
256 return false;
257}
258
259bool QWasmFileEngine::mkdir(const QString &dirName, bool createParentDirectories,
260 std::optional<QFile::Permissions> permissions) const
261{
262 Q_UNUSED(dirName);
263 Q_UNUSED(createParentDirectories);
264 Q_UNUSED(permissions);
265 return false;
266}
267
268bool QWasmFileEngine::rmdir(const QString &dirName, bool recurseParentDirectories) const
269{
270 Q_UNUSED(dirName);
271 Q_UNUSED(recurseParentDirectories);
272 return false;
273}
274
275bool QWasmFileEngine::setSize(qint64 size)
276{
277 Q_UNUSED(size);
278 return false;
279}
280
282{
283 return true;
284}
285
287{
288 return false;
289}
290
291
293{
294 return type & (QAbstractFileEngine::FileFlag::ExistsFlag |
295 QAbstractFileEngine::FileFlag::FileType |
296 QAbstractFileEngine::FileFlag::ReadOwnerPerm |
297 QAbstractFileEngine::FileFlag::WriteOwnerPerm |
298 QAbstractFileEngine::FileFlag::ReadUserPerm |
299 QAbstractFileEngine::FileFlag::WriteUserPerm);
300}
301
303{
304 Q_UNUSED(perms);
305 return false;
306}
307
309{
310 return {};
311}
312
313QString QWasmFileEngine::fileName(FileName file) const
314{
315 switch (file) {
316 case DefaultName:
317 case AbsoluteName:
318 case CanonicalName:
319 return m_fileName;
320 case BaseName: {
321 QString native = QWasmFileEngineHandler::nativeFileName(m_fileName);
322 QFileInfo info(native);
323 return info.fileName();
324 }
325 case PathName:
326 case AbsolutePathName:
327 case CanonicalPathName: {
328 QString native = QWasmFileEngineHandler::nativeFileName(m_fileName);
329 QFileInfo info(native);
330 QString path = info.path();
331 return path.isEmpty() ? "."_L1 : path;
332 }
333 default:
334 return QString();
335 }
336}
337
339{
340 return 0;
341}
342
344{
345 return {};
346}
347
348bool QWasmFileEngine::setFileTime(const QDateTime &newDate, QFile::FileTime time)
349{
350 Q_UNUSED(newDate);
351 Q_UNUSED(time);
352 return false;
353}
354
355QDateTime QWasmFileEngine::fileTime(QFile::FileTime time) const
356{
357 Q_UNUSED(time);
358 return {};
359}
360
361void QWasmFileEngine::setFileName(const QString &file)
362{
363 if (m_fileName == file)
364 return;
365 close();
366 m_fileName = file;
367}
368
370{
371 return -1;
372}
373
375{
376 Q_UNUSED(target);
377 return QAbstractFileEngine::TriStateResult::NotSupported;
378}
379
380QAbstractFileEngine::IteratorUniquePtr QWasmFileEngine::beginEntryList(const QString &path, QDirListing::IteratorFlags filters,
381 const QStringList &filterNames)
382{
383 Q_UNUSED(path);
384 Q_UNUSED(filters);
385 Q_UNUSED(filterNames);
386 return nullptr;
387}
388
389qint64 QWasmFileEngine::read(char *data, qint64 maxlen)
390{
391 if (!(m_openMode & QIODevice::ReadOnly))
392 return -1;
393
394 if (m_fileDevice)
395 return m_fileDevice->read(data, maxlen);
396 if (m_blobDevice)
397 return m_blobDevice->read(data, maxlen);
398 return -1;
399}
400
401qint64 QWasmFileEngine::readLine(char *data, qint64 maxlen)
402{
403 if (!(m_openMode & QIODevice::ReadOnly))
404 return -1;
405
406 if (m_fileDevice)
407 return m_fileDevice->readLine(data, maxlen);
408 if (m_blobDevice)
409 return m_blobDevice->readLine(data, maxlen);
410 return -1;
411}
412
413qint64 QWasmFileEngine::write(const char *data, qint64 len)
414{
415 if (!(m_openMode & QIODevice::WriteOnly))
416 return -1;
417
418 if (m_fileDevice)
419 return m_fileDevice->write(data, len);
420 return -1;
421}
422
423bool QWasmFileEngine::extension(Extension extension, const ExtensionOption *option, ExtensionReturn *output)
424{
425 Q_UNUSED(extension);
426 Q_UNUSED(option);
427 Q_UNUSED(output);
428 return false;
429}
430
431bool QWasmFileEngine::supportsExtension(Extension extension) const
432{
433 Q_UNUSED(extension);
434 return false;
435}
436
437QT_END_NAMESPACE
qstdweb::FileSystemFileHandle getFileSystemFile(const QString fileName)
virtual ~QWasmFileEngineHandler() override
virtual 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...
qstdweb::File getFile(const QString fileName)
The QWasmFileEngine class provides a QAbstractFileEngine for files that has the prefix ':weblocalfile...
virtual bool link(const QString &newName) override
Creates a link from the file currently specified by fileName() to newName.
virtual bool flush() override
Flushes the open file, returning true if successful; otherwise returns false.
virtual qint64 read(char *data, qint64 maxlen) override
Reads a number of characters from the file into data.
virtual void setFileName(const QString &file) override
Sets the file engine's file name to file.
virtual bool rmdir(const QString &dirName, bool recurseParentDirectories) const override
Requests that the directory dirName is deleted from the file system.
virtual bool setSize(qint64 size) override
Requests that the file be set to size size.
virtual bool copy(const QString &newName) override
Copies the contents of this file to a file with the name newName.
virtual uint ownerId(FileOwner) const override
If owner is OwnerUser return the ID of the user who owns the file.
virtual bool caseSensitive() const override
Should return true if the underlying file system is case-sensitive; otherwise return false.
virtual QString fileName(FileName file=DefaultName) const override
Return the file engine's current file name in the format specified by file.
virtual qint64 pos() const override
Returns the current file position.
virtual bool supportsExtension(Extension extension) const override
virtual bool extension(Extension extension, const ExtensionOption *option=nullptr, ExtensionReturn *output=nullptr) override
virtual bool close() override
Closes the file, returning true if successful; otherwise returns false.
virtual bool isSequential() const override
Returns true if the file is a sequential access device; returns false if the file is a direct access ...
virtual bool syncToDisk() override
virtual bool seek(qint64 pos) override
Sets the file position to the given offset.
virtual qint64 write(const char *data, qint64 len) override
Writes len bytes from data to the file.
virtual TriStateResult cloneTo(QAbstractFileEngine *target) override
virtual bool rename(const QString &newName) override
Requests that the file be renamed to newName in the file system.
virtual QByteArray id() const override
virtual QString owner(FileOwner) const override
If owner is OwnerUser return the name of the user who owns the file.
virtual qint64 readLine(char *data, qint64 maxlen) override
This function reads one line, terminated by a '\n' character, from the file info data.
virtual bool setPermissions(uint perms) override
Requests that the file's permissions be set to perms.
virtual int handle() const override
Returns the native file handle for this file engine.
virtual bool remove() override
Requests that the file is deleted from the file system.
virtual IteratorUniquePtr beginEntryList(const QString &path, QDirListing::IteratorFlags filters, const QStringList &filterNames) override
Returns a QAbstractFileEngine::IteratorUniquePtr, that can be used to iterate over the entries in pat...
virtual FileFlags fileFlags(FileFlags type=FileInfoAll) const override
This function should return the set of OR'd flags that are true for the file engine's file,...
virtual bool mkdir(const QString &dirName, bool createParentDirectories, std::optional< QFile::Permissions > permissions=std::nullopt) const override
Requests that the directory dirName be created with the specified permissions.
virtual qint64 size() const override
Returns the size of the file.
QWasmFileEngine(const QString &fileName, qstdweb::File file)
virtual bool renameOverwrite(const QString &newName) override
virtual bool isRelativePath() const override
Return true if the file referred to by this file engine has a relative path; otherwise return false.
virtual QDateTime fileTime(QFile::FileTime time) const override
If time is BirthTime, return when the file was born (created).
virtual bool setFileTime(const QDateTime &newDate, QFile::FileTime time) override
Combined button and popup list for selecting options.
static constexpr QLatin1StringView wasmlocalfileScheme