1 /****************************************************************************
2 **
3 ** Copyright (C) 2019 The Qt Company Ltd.
4 ** Contact: https://www.qt.io/licensing/
5 **
6 ** This file is part of the QtCore module of the Qt Toolkit.
7 **
8 ** $QT_BEGIN_LICENSE:LGPL$
9 ** Commercial License Usage
10 ** Licensees holding valid commercial Qt licenses may use this file in
11 ** accordance with the commercial license agreement provided with the
12 ** Software or, alternatively, in accordance with the terms contained in
13 ** a written agreement between you and The Qt Company. For licensing terms
14 ** and conditions see https://www.qt.io/terms-conditions. For further
15 ** information use the contact form at https://www.qt.io/contact-us.
16 **
17 ** GNU Lesser General Public License Usage
18 ** Alternatively, this file may be used under the terms of the GNU Lesser
19 ** General Public License version 3 as published by the Free Software
20 ** Foundation and appearing in the file LICENSE.LGPL3 included in the
21 ** packaging of this file. Please review the following information to
22 ** ensure the GNU Lesser General Public License version 3 requirements
23 ** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
24 **
25 ** GNU General Public License Usage
26 ** Alternatively, this file may be used under the terms of the GNU
27 ** General Public License version 2.0 or (at your option) the GNU General
28 ** Public license version 3 or any later version approved by the KDE Free
29 ** Qt Foundation. The licenses are as published by the Free Software
30 ** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
31 ** included in the packaging of this file. Please review the following
32 ** information to ensure the GNU General Public License requirements will
33 ** be met: https://www.gnu.org/licenses/gpl-2.0.html and
34 ** https://www.gnu.org/licenses/gpl-3.0.html.
35 **
36 ** $QT_END_LICENSE$
37 **
38 ****************************************************************************/
39
40 #include "qsettings.h"
41 #ifndef QT_NO_SETTINGS
42
43 #include "qsettings_p.h"
44 #ifndef QT_NO_QOBJECT
45 #include "qcoreapplication.h"
46 #include <QFile>
47 #endif // QT_NO_QOBJECT
48 #include <QDebug>
49
50 #include <QFileInfo>
51 #include <QDir>
52 #include <emscripten.h>
53
54 QT_BEGIN_NAMESPACE
55
56 static bool isReadReady = false;
57
58 class QWasmSettingsPrivate : public QConfFileSettingsPrivate
59 {
60 public:
61 QWasmSettingsPrivate(QSettings::Scope scope, const QString &organization,
62 const QString &application);
63 ~QWasmSettingsPrivate();
64
65 bool get(const QString &key, QVariant *value) const override;
66 QStringList children(const QString &prefix, ChildSpec spec) const override;
67 void clear() override;
68 void sync() override;
69 void flush() override;
70 bool isWritable() const override;
71
72 void syncToLocal(const char *data, int size);
73 void loadLocal(const QByteArray &filename);
74 void setReady();
75 void initAccess() override;
76
77 private:
78 QString databaseName;
79 QString id;
80 };
81
QWasmSettingsPrivate_onLoad(void * userData,void * dataPtr,int size)82 static void QWasmSettingsPrivate_onLoad(void *userData, void *dataPtr, int size)
83 {
84 QWasmSettingsPrivate *wasm = reinterpret_cast<QWasmSettingsPrivate *>(userData);
85
86 QFile file(wasm->fileName());
87 QFileInfo fileInfo(wasm->fileName());
88 QDir dir(fileInfo.path());
89 if (!dir.exists())
90 dir.mkpath(fileInfo.path());
91
92 if (file.open(QFile::WriteOnly)) {
93 file.write(reinterpret_cast<char *>(dataPtr), size);
94 file.close();
95 wasm->setReady();
96 }
97 }
98
QWasmSettingsPrivate_onError(void * userData)99 static void QWasmSettingsPrivate_onError(void *userData)
100 {
101 QWasmSettingsPrivate *wasm = reinterpret_cast<QWasmSettingsPrivate *>(userData);
102 if (wasm)
103 wasm->setStatus(QSettings::AccessError);
104 }
105
QWasmSettingsPrivate_onStore(void * userData)106 static void QWasmSettingsPrivate_onStore(void *userData)
107 {
108 QWasmSettingsPrivate *wasm = reinterpret_cast<QWasmSettingsPrivate *>(userData);
109 if (wasm)
110 wasm->setStatus(QSettings::NoError);
111 }
112
QWasmSettingsPrivate_onCheck(void * userData,int exists)113 static void QWasmSettingsPrivate_onCheck(void *userData, int exists)
114 {
115 QWasmSettingsPrivate *wasm = reinterpret_cast<QWasmSettingsPrivate *>(userData);
116 if (wasm) {
117 if (exists)
118 wasm->loadLocal(wasm->fileName().toLocal8Bit());
119 else
120 wasm->setReady();
121 }
122 }
123
create(QSettings::Format format,QSettings::Scope scope,const QString & organization,const QString & application)124 QSettingsPrivate *QSettingsPrivate::create(QSettings::Format format,
125 QSettings::Scope scope,
126 const QString &organization,
127 const QString &application)
128 {
129 Q_UNUSED(format)
130 if (organization == QLatin1String("Qt"))
131 {
132 QString organizationDomain = QCoreApplication::organizationDomain();
133 QString applicationName = QCoreApplication::applicationName();
134
135 QSettingsPrivate *newSettings;
136 newSettings = new QWasmSettingsPrivate(scope, organizationDomain, applicationName);
137
138 newSettings->beginGroupOrArray(QSettingsGroup(normalizedKey(organization)));
139 if (!application.isEmpty())
140 newSettings->beginGroupOrArray(QSettingsGroup(normalizedKey(application)));
141
142 return newSettings;
143 }
144 return new QWasmSettingsPrivate(scope, organization, application);
145 }
146
QWasmSettingsPrivate(QSettings::Scope scope,const QString & organization,const QString & application)147 QWasmSettingsPrivate::QWasmSettingsPrivate(QSettings::Scope scope, const QString &organization,
148 const QString &application)
149 : QConfFileSettingsPrivate(QSettings::NativeFormat, scope, organization, application)
150 {
151 setStatus(QSettings::AccessError); // access error until sandbox gets loaded
152 databaseName = organization;
153 id = application;
154
155 emscripten_idb_async_exists("/home/web_user",
156 fileName().toLocal8Bit(),
157 reinterpret_cast<void*>(this),
158 QWasmSettingsPrivate_onCheck,
159 QWasmSettingsPrivate_onError);
160 }
161
~QWasmSettingsPrivate()162 QWasmSettingsPrivate::~QWasmSettingsPrivate()
163 {
164 }
165
initAccess()166 void QWasmSettingsPrivate::initAccess()
167 {
168 if (isReadReady)
169 QConfFileSettingsPrivate::initAccess();
170 }
171
get(const QString & key,QVariant * value) const172 bool QWasmSettingsPrivate::get(const QString &key, QVariant *value) const
173 {
174 if (isReadReady)
175 return QConfFileSettingsPrivate::get(key, value);
176
177 return false;
178 }
179
children(const QString & prefix,ChildSpec spec) const180 QStringList QWasmSettingsPrivate::children(const QString &prefix, ChildSpec spec) const
181 {
182 return QConfFileSettingsPrivate::children(prefix, spec);
183 }
184
clear()185 void QWasmSettingsPrivate::clear()
186 {
187 QConfFileSettingsPrivate::clear();
188 emscripten_idb_async_delete("/home/web_user",
189 fileName().toLocal8Bit(),
190 reinterpret_cast<void*>(this),
191 QWasmSettingsPrivate_onStore,
192 QWasmSettingsPrivate_onError);
193 }
194
sync()195 void QWasmSettingsPrivate::sync()
196 {
197 QConfFileSettingsPrivate::sync();
198
199 QFile file(fileName());
200 if (file.open(QFile::ReadOnly)) {
201 QByteArray dataPointer = file.readAll();
202
203 emscripten_idb_async_store("/home/web_user",
204 fileName().toLocal8Bit(),
205 reinterpret_cast<void *>(dataPointer.data()),
206 dataPointer.length(),
207 reinterpret_cast<void*>(this),
208 QWasmSettingsPrivate_onStore,
209 QWasmSettingsPrivate_onError);
210 }
211 }
212
flush()213 void QWasmSettingsPrivate::flush()
214 {
215 sync();
216 }
217
isWritable() const218 bool QWasmSettingsPrivate::isWritable() const
219 {
220 return isReadReady && QConfFileSettingsPrivate::isWritable();
221 }
222
syncToLocal(const char * data,int size)223 void QWasmSettingsPrivate::syncToLocal(const char *data, int size)
224 {
225 QFile file(fileName());
226
227 if (file.open(QFile::WriteOnly)) {
228 file.write(data, size + 1);
229 QByteArray data = file.readAll();
230
231 emscripten_idb_async_store("/home/web_user",
232 fileName().toLocal8Bit(),
233 reinterpret_cast<void *>(data.data()),
234 data.length(),
235 reinterpret_cast<void*>(this),
236 QWasmSettingsPrivate_onStore,
237 QWasmSettingsPrivate_onError);
238 setReady();
239 }
240 }
241
loadLocal(const QByteArray & filename)242 void QWasmSettingsPrivate::loadLocal(const QByteArray &filename)
243 {
244 emscripten_idb_async_load("/home/web_user",
245 filename.data(),
246 reinterpret_cast<void*>(this),
247 QWasmSettingsPrivate_onLoad,
248 QWasmSettingsPrivate_onError);
249 }
250
setReady()251 void QWasmSettingsPrivate::setReady()
252 {
253 isReadReady = true;
254 setStatus(QSettings::NoError);
255 QConfFileSettingsPrivate::initAccess();
256 }
257
258 QT_END_NAMESPACE
259 #endif // QT_NO_SETTINGS
260