diff options
Diffstat (limited to 'src/gui/platform/wasm/qwasmlocalfileaccess.cpp')
-rw-r--r-- | src/gui/platform/wasm/qwasmlocalfileaccess.cpp | 77 |
1 files changed, 65 insertions, 12 deletions
diff --git a/src/gui/platform/wasm/qwasmlocalfileaccess.cpp b/src/gui/platform/wasm/qwasmlocalfileaccess.cpp index 1b797be9fe..a946cda043 100644 --- a/src/gui/platform/wasm/qwasmlocalfileaccess.cpp +++ b/src/gui/platform/wasm/qwasmlocalfileaccess.cpp @@ -9,6 +9,8 @@ #include <emscripten/html5.h> #include <emscripten/val.h> +#include <QtCore/qregularexpression.h> + QT_BEGIN_NAMESPACE namespace QWasmLocalFileAccess { @@ -29,7 +31,7 @@ void showOpenViaHTMLPolyfill(const QStringList &accept, FileSelectMode fileSelec emscripten::val input = document.call<emscripten::val>("createElement", std::string("input")); input.set("type", "file"); input.set("style", "display:none"); - // input.set("accept", emscripten::val(accept)); + input.set("accept", LocalFileApi::makeFileInputAccept(accept)); Q_UNUSED(accept); input.set("multiple", emscripten::val(fileSelectMode == FileSelectMode::MultipleFiles)); @@ -124,7 +126,7 @@ void readFiles(const qstdweb::FileList &fileList, } // Read file data into caller-provided buffer - file.stream(buffer, [=]() { + file.stream(buffer, [readFile = readFile.get(), fileIndex, fileDataReady]() { fileDataReady(); (*readFile)(fileIndex + 1); }); @@ -132,15 +134,28 @@ void readFiles(const qstdweb::FileList &fileList, (*readFile)(0); } + +QStringList makeFilterList(const std::string &qtAcceptList) +{ + // copy of qt_make_filter_list() from qfiledialog.cpp + auto filter = QString::fromStdString(qtAcceptList); + if (filter.isEmpty()) + return QStringList(); + QString sep(";;"); + if (!filter.contains(sep) && filter.contains(u'\n')) + sep = u'\n'; + + return filter.split(sep); +} } -void downloadDataAsFile(const QByteArray &data, const std::string &fileNameHint) +void downloadDataAsFile(const char *content, size_t size, const std::string &fileNameHint) { // Save a file by creating programmatically clicking a download // link to an object url to a Blob containing a copy of the file // content. The copy is made so that the passed in content buffer // can be released as soon as this function returns. - qstdweb::Blob contentBlob = qstdweb::Blob::copyFrom(data.constData(), data.size()); + qstdweb::Blob contentBlob = qstdweb::Blob::copyFrom(content, size); emscripten::val document = emscripten::val::global("document"); emscripten::val window = qstdweb::window(); emscripten::val contentUrl = window["URL"].call<emscripten::val>("createObjectURL", contentBlob.val()); @@ -157,12 +172,12 @@ void downloadDataAsFile(const QByteArray &data, const std::string &fileNameHint) window["URL"].call<emscripten::val>("revokeObjectURL", contentUrl); } -void openFiles(const QStringList &accept, FileSelectMode fileSelectMode, +void openFiles(const std::string &accept, FileSelectMode fileSelectMode, const std::function<void (int fileCount)> &fileDialogClosed, const std::function<char *(uint64_t size, const std::string& name)> &acceptFile, const std::function<void()> &fileDataReady) { - FileDialog::showOpen(accept, fileSelectMode, { + FileDialog::showOpen(makeFilterList(accept), fileSelectMode, { .thenFunc = [=](emscripten::val result) { auto files = qstdweb::FileList(result); fileDialogClosed(files.length()); @@ -174,7 +189,7 @@ void openFiles(const QStringList &accept, FileSelectMode fileSelectMode, }); } -void openFile(const QStringList &accept, +void openFile(const std::string &accept, const std::function<void (bool fileSelected)> &fileDialogClosed, const std::function<char *(uint64_t size, const std::string& name)> &acceptFile, const std::function<void()> &fileDataReady) @@ -195,6 +210,11 @@ void saveDataToFileInChunks(emscripten::val fileHandle, const QByteArray &data) std::function<void(val result)> continuation; }; + static constexpr size_t desiredChunkSize = 1024u; +#if defined(__EMSCRIPTEN_SHARED_MEMORY__) + qstdweb::Uint8Array chunkArray(desiredChunkSize); +#endif + auto state = std::make_shared<State>(); state->written = 0u; state->continuation = [=](val) mutable { @@ -204,11 +224,30 @@ void saveDataToFileInChunks(emscripten::val fileHandle, const QByteArray &data) state.reset(); return; } - static constexpr size_t desiredChunkSize = 1024u; + const auto currentChunkSize = std::min(remaining, desiredChunkSize); - Promise::make(writable, QStringLiteral("write"), { - .thenFunc = state->continuation, - }, val(typed_memory_view(currentChunkSize, data.constData() + state->written))); + +#if defined(__EMSCRIPTEN_SHARED_MEMORY__) + // If shared memory is used, WebAssembly.Memory is instantiated with the 'shared' + // option on. Passing a typed_memory_view to SharedArrayBuffer to + // FileSystemWritableFileStream.write is disallowed by security policies, so we + // need to make a copy of the data to a chunk array buffer. + Promise::make( + writable, QStringLiteral("write"), + { + .thenFunc = state->continuation, + }, + chunkArray.copyFrom(data.constData() + state->written, currentChunkSize) + .val() + .call<emscripten::val>("subarray", emscripten::val(0), + emscripten::val(currentChunkSize))); +#else + Promise::make(writable, QStringLiteral("write"), + { + .thenFunc = state->continuation, + }, + val(typed_memory_view(currentChunkSize, data.constData() + state->written))); +#endif state->written += currentChunkSize; }; @@ -220,7 +259,7 @@ void saveDataToFileInChunks(emscripten::val fileHandle, const QByteArray &data) void saveFile(const QByteArray &data, const std::string &fileNameHint) { if (!FileDialog::canShowSave()) { - downloadDataAsFile(data, fileNameHint); + downloadDataAsFile(data.constData(), data.size(), fileNameHint); return; } @@ -231,6 +270,20 @@ void saveFile(const QByteArray &data, const std::string &fileNameHint) }); } +void saveFile(const char *content, size_t size, const std::string &fileNameHint) +{ + if (!FileDialog::canShowSave()) { + downloadDataAsFile(content, size, fileNameHint); + return; + } + + FileDialog::showSave(fileNameHint, { + .thenFunc = [=](emscripten::val result) { + saveDataToFileInChunks(result, QByteArray(content, size)); + }, + }); +} + } // namespace QWasmLocalFileAccess QT_END_NAMESPACE |