summaryrefslogtreecommitdiffstats
path: root/src/gui/platform/wasm/qwasmlocalfileaccess.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/gui/platform/wasm/qwasmlocalfileaccess.cpp')
-rw-r--r--src/gui/platform/wasm/qwasmlocalfileaccess.cpp77
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