Details
-
Task
-
Resolution: Done
-
P2: Important
-
None
-
None
Description
Categories of local access
Local file system access can be divided into two categories: persisting application state and accessing user files.
Persisting Application State
The application wants to save state, so that the user can continue where they left later on.
Emscripten has sandboxed file system access via FS
https://kripken.github.io/emscripten-site/docs/api_reference/Filesystem-API.html
Using IDBFS files can be synced to and from this sandbox. QSettings currently uses this.
Drawbacks are that it does this asynchronously and does take some amount of time to do (after app c'tor has completed)
Note that files synced like this are stored in a database private to the browser and are inaccessible outside of the web application.
Accessing user files.
The application wants to load and save user files, e.g. to enable interop with other applications and give users access to the files.
Html5 apps can read local files via a native file dialog:
https://developer.mozilla.org/en-US/docs/Web/API/File/Using_files_from_web_applications
On the Qt side file access would preferably happen through the existing QFile and QFileDialog API, but this does not seem to be a good match for the platform:
- We can’t block the GUI thread or re-enter the event loop; the static API won’t work
- The native API gives us file content directly; QFileDialog returns a path which can be opened using QFile.
- File save is not well supported (see below)
There are various ways around this:
- Provide OS_HTML5 specific API for working with files
void loadFile(QStringList acceptTypes, std::function<void(QByteArray &)> dataReady); void saveFile(QString fileName, QByteArray contents);
- Save the file to emscripten in-memory MEMFS, after which it can be opened with QFile. File save would still need an API, perhaps unless we can get write notifications on the file.
Implementation details
Qt Implementation with custom API: https://codereview.qt-project.org/#/c/228599/
Stage 1: to JavasScript memory
Prototype https://github.com/msorvig/qt-webassembly-examples/blob/master/html_localfiles/index.html
Load: HTML5 supports showing a native file dialog via <input type="file”>, which gives a FileList, whose File entries can be read by a FileReader (asyncly) to produce an ArrayBuffer.
FileList https://developer.mozilla.org/en-US/docs/Web/API/FileList
FileReader: https://developer.mozilla.org/en-US/docs/Web/API/FileReader
Save: There is no corresponding file save API. Instead. we can create a data download link (window.URL.createObjectURL), and then programmatically trigger it.
https://stackoverflow.com/questions/32326973/file-write-operation-in-javascript
This is not really “file save”, it's rather “file download”. The file save destination will be the standard download directory
Stage 2 a): To C++ memory
ArrayBuffer <-> QByteArray
emscripten prototype: https://github.com/msorvig/qt-webassembly-examples/tree/master/emscripten_localfiles
Stage 2 b): To the in-memory file system
FS.writeFile(“/tmp/foofile”, arrayBuffer)