1 /****************************************************************************
2 **
3 ** Copyright (C) 2016 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 
42 #include "qsettings_p.h"
43 #include "qvector.h"
44 #include "qmap.h"
45 #include "qdebug.h"
46 #include "qfunctions_winrt.h"
47 
48 #include <wrl.h>
49 #include <wrl/event.h>
50 #include <Windows.ApplicationModel.h>
51 #include <windows.storage.h>
52 
53 using namespace ABI::Windows::ApplicationModel;
54 using namespace ABI::Windows::Storage;
55 using namespace ABI::Windows::Foundation;
56 using namespace ABI::Windows::Foundation::Collections;
57 using namespace Microsoft::WRL;
58 using namespace Microsoft::WRL::Wrappers;
59 
60 typedef ITypedEventHandler<ApplicationData*, IInspectable*> DataHandler;
61 typedef Collections::IKeyValuePair<HSTRING, ApplicationDataContainer*> ContainerItem;
62 typedef Collections::IIterable<ContainerItem*> ContainerIterable;
63 typedef Collections::IIterator<ContainerItem*> ContainerIterator;
64 
65 typedef Collections::IKeyValuePair<HSTRING, IInspectable*> ValueItem;
66 typedef Collections::IIterable<ValueItem*> ValueIterable;
67 typedef Collections::IIterator<ValueItem*> ValueIterator;
68 
69 QT_BEGIN_NAMESPACE
70 
subContainer(IApplicationDataContainer * parent,const QString & name)71 static IApplicationDataContainer *subContainer(IApplicationDataContainer *parent, const QString &name)
72 {
73     ComPtr<IMapView<HSTRING, ApplicationDataContainer*>> childrenContainer;
74     HRESULT hr = parent->get_Containers(&childrenContainer);
75     if (FAILED(hr))
76         return 0;
77 
78     ComPtr< ContainerIterable > iterable;
79     ComPtr< ContainerIterator > iterator;
80 
81     hr = childrenContainer.As(&iterable);
82     if (FAILED(hr))
83         return 0;
84 
85     hr = iterable->First(&iterator);
86     if (FAILED(hr))
87         return 0;
88     boolean current;
89     hr = iterator->get_HasCurrent(&current);
90     if (FAILED(hr))
91         return 0;
92 
93     while (SUCCEEDED(hr) && current) {
94         ComPtr<ContainerItem> item;
95         hr = iterator->get_Current(&item);
96         if (FAILED(hr))
97             return 0;
98 
99         HString key;
100         hr = item->get_Key(key.GetAddressOf());
101         if (FAILED(hr))
102             continue;
103         QString subName = QString::fromWCharArray(key.GetRawBuffer(nullptr));
104         if (name == subName) {
105             IApplicationDataContainer *container;
106             hr = item->get_Value(&container);
107             return SUCCEEDED(hr) ? container : 0;
108         }
109         hr = iterator->MoveNext(&current);
110     }
111 
112     return 0;
113 }
114 
subContainerNames(IApplicationDataContainer * container,bool recursive=false)115 static QStringList subContainerNames(IApplicationDataContainer *container, bool recursive = false)
116 {
117     QStringList result;
118     ComPtr<IMapView<HSTRING, ApplicationDataContainer*>> childrenContainer;
119     HRESULT hr = container->get_Containers(&childrenContainer);
120     if (FAILED(hr))
121         return result;
122 
123     ComPtr< ContainerIterable > iterable;
124     ComPtr< ContainerIterator > iterator;
125 
126     hr = childrenContainer.As(&iterable);
127     if (FAILED(hr))
128         return result;
129 
130     hr = iterable->First(&iterator);
131     if (FAILED(hr))
132         return result;
133     boolean current;
134     hr = iterator->get_HasCurrent(&current);
135     if (FAILED(hr))
136         return result;
137 
138     while (SUCCEEDED(hr) && current) {
139         ComPtr<ContainerItem> item;
140         hr = iterator->get_Current(&item);
141         if (FAILED(hr))
142             return result;
143 
144         HString key;
145         hr = item->get_Key(key.GetAddressOf());
146         if (SUCCEEDED(hr)) {
147             QString subName = QString::fromWCharArray(key.GetRawBuffer(nullptr));
148             result.append(subName);
149             if (recursive) {
150                 ComPtr<IApplicationDataContainer> sub = subContainer(container, subName);
151                 QStringList subSubNames = subContainerNames(sub.Get(), recursive);
152                 for (int i = 0; i < subSubNames.size(); ++i)
153                     subSubNames[i] = subName + QLatin1Char('/') + subSubNames[i];
154                 result.append(subSubNames);
155             }
156             hr = iterator->MoveNext(&current);
157         }
158     }
159     return result;
160 }
161 
keyNames(IApplicationDataContainer * container)162 static QStringList keyNames(IApplicationDataContainer *container) {
163     HRESULT hr;
164     QStringList result;
165     ComPtr<IPropertySet> values;
166     hr = container->get_Values(&values);
167     if (FAILED(hr))
168         return result;
169 
170     ComPtr<IMap<HSTRING, IInspectable*>> settingsMap;
171 
172     hr = values.As(&settingsMap);
173     if (FAILED(hr))
174         return result;
175 
176     ComPtr<IMapView<HSTRING, IInspectable*>> mapView;
177     hr = settingsMap->GetView(&mapView);
178     if (FAILED(hr))
179         return result;
180 
181     ComPtr< ValueIterable > iterable;
182     ComPtr< ValueIterator > iterator;
183 
184     hr = mapView.As(&iterable);
185     if (FAILED(hr))
186         return result;
187 
188     boolean current = false;
189     hr = iterable->First(&iterator);
190     if (FAILED(hr))
191         return result;
192     hr = iterator->get_HasCurrent(&current);
193     if (FAILED(hr))
194         return result;
195 
196     while (SUCCEEDED(hr) && current){
197         ComPtr<ValueItem> item;
198         hr = iterator->get_Current(&item);
199         if (FAILED(hr))
200             return result;
201 
202         HString key;
203         hr = item->get_Key(key.GetAddressOf());
204         if (SUCCEEDED(hr)) {
205             result += QString::fromWCharArray(key.GetRawBuffer(nullptr));
206             hr = iterator->MoveNext(&current);
207         }
208     }
209     return result;
210 }
211 
createSubContainer(IApplicationDataContainer * parent,const QString & name)212 static IApplicationDataContainer *createSubContainer(IApplicationDataContainer *parent, const QString &name)
213 {
214     HStringReference childGroupNativeName((const wchar_t*)name.utf16(), name.size());
215 
216     IApplicationDataContainer *result = subContainer(parent, name);
217     if (!result)
218         parent->CreateContainer(childGroupNativeName.Get(), ApplicationDataCreateDisposition_Always, &result);
219     return result;
220 }
221 
222 #define PROP_CASE_TO_VARIANT(TYPE, VARTYPE, QTYPE) \
223     case PropertyType_##TYPE: { \
224         VARTYPE v; \
225         value->Get##TYPE(&v); \
226         result.setValue( QTYPE(v) ); \
227         break; \
228     }
229 
propertyValueToQVariant(IPropertyValue * value)230 static QVariant propertyValueToQVariant(IPropertyValue *value)
231 {
232     QVariant result;
233     PropertyType type;
234     value->get_Type(&type);
235     switch (type) {
236     PROP_CASE_TO_VARIANT(Boolean, boolean, bool)
237     PROP_CASE_TO_VARIANT(UInt8, UINT8, quint8)
238     PROP_CASE_TO_VARIANT(Int16, INT16, qint16)
239     PROP_CASE_TO_VARIANT(UInt16, UINT16, quint16)
240     PROP_CASE_TO_VARIANT(Int32, INT32, qint32)
241     PROP_CASE_TO_VARIANT(UInt32, UINT32, quint32)
242     PROP_CASE_TO_VARIANT(Int64, INT64, qint64)
243     PROP_CASE_TO_VARIANT(UInt64, UINT64, quint64)
244     PROP_CASE_TO_VARIANT(Single, FLOAT, float)
245     PROP_CASE_TO_VARIANT(Double, DOUBLE, double)
246     case PropertyType_StringArray: {
247         UINT32 size;
248         HSTRING *content;
249         value->GetStringArray(&size, &content);
250         QStringList list;
251         // The last item is assumed to be added by us
252         for (UINT32 i = 0; i < size - 1; ++i) {
253             QString s = QString::fromWCharArray(WindowsGetStringRawBuffer(content[i], nullptr));
254             list.append(s);
255         }
256         result = QSettingsPrivate::stringListToVariantList(list);
257         break;
258     }
259     case PropertyType_String: {
260         HString v;
261         value->GetString(v.GetAddressOf());
262         result = QSettingsPrivate::stringToVariant(QString::fromWCharArray(v.GetRawBuffer(nullptr)));
263         break;
264     }
265     default: {
266         UINT32 size;
267         BYTE *arr;
268         value->GetUInt8Array(&size, &arr);
269         QByteArray data = QByteArray::fromRawData((const char*)arr, size);
270         QString s;
271         if (size) {
272             // We assume this is our qt stored data like on other platforms
273             // as well. QList and others are converted to byte arrays
274             s = QString::fromWCharArray((const wchar_t *)data.constData(), data.size() / 2);
275             result = QSettingsPrivate::stringToVariant(s);
276         }
277         break;
278     }
279     }
280     return result;
281 }
282 
283 class QWinRTSettingsPrivate : public QSettingsPrivate
284 {
285 public:
286     QWinRTSettingsPrivate(QSettings::Scope scope, const QString &organization,
287                           const QString &application);
288     QWinRTSettingsPrivate(const QString &rKey);
289     ~QWinRTSettingsPrivate();
290 
291     void remove(const QString &uKey) override;
292     void set(const QString &uKey, const QVariant &value) override;
293     bool get(const QString &uKey, QVariant *value) const override;
294     QStringList children(const QString &uKey, ChildSpec spec) const override;
295     void clear() override;
296     void sync() override;
297     void flush() override;
298     bool isWritable() const override;
299     QString fileName() const override;
300 
301 private:
302     void init(QSettings::Scope scope);
303     IApplicationDataContainer *getContainer(IApplicationDataContainer *parent, const QString &group, bool create = false) const;
304     void clearContainerMaps();
305 
306     HRESULT onDataChanged(IApplicationData*, IInspectable*);
307 
308     ComPtr<IApplicationData> applicationData;
309     QVector<ComPtr<IApplicationDataContainer>> readContainers;
310     ComPtr<IApplicationDataContainer> writeContainer;
311     EventRegistrationToken dataChangedToken;
312 };
313 
QWinRTSettingsPrivate(QSettings::Scope scope,const QString & organization,const QString & application)314 QWinRTSettingsPrivate::QWinRTSettingsPrivate(QSettings::Scope scope, const QString &organization,
315                                              const QString &application)
316     : QSettingsPrivate(QSettings::NativeFormat, scope, organization, application)
317     , writeContainer(0)
318 {
319     init(scope);
320 }
321 
QWinRTSettingsPrivate(const QString & rPath)322 QWinRTSettingsPrivate::QWinRTSettingsPrivate(const QString &rPath)
323     : QSettingsPrivate(QSettings::NativeFormat, QSettings::UserScope, rPath, QString())
324     , writeContainer(0)
325 {
326     init(QSettings::UserScope);
327 }
328 
~QWinRTSettingsPrivate()329 QWinRTSettingsPrivate::~QWinRTSettingsPrivate()
330 {
331     clearContainerMaps();
332 }
333 
remove(const QString & uKey)334 void QWinRTSettingsPrivate::remove(const QString &uKey)
335 {
336     int lastIndex = uKey.lastIndexOf(QLatin1Char('/'));
337     QString groupName = (lastIndex > 0) ? uKey.left(lastIndex) : QString();
338     QString groupKey = uKey.mid(lastIndex + 1);
339 
340     ComPtr<IApplicationDataContainer> container = getContainer(writeContainer.Get(), groupName, false);
341     if (!container)
342         return;
343 
344     HRESULT hr;
345     ComPtr<IPropertySet> values;
346     hr = container->get_Values(&values);
347     if (FAILED(hr))
348         return;
349 
350     ComPtr<IMap<HSTRING, IInspectable*>> settingsMap;
351 
352     hr = values.As(&settingsMap);
353     if (FAILED(hr))
354         return;
355 
356     HStringReference ref((const wchar_t*)groupKey.utf16(), groupKey.size());
357     hr = settingsMap->Remove(ref.Get());
358 
359     // groupKey can be a container as well
360     hr = container->DeleteContainer(ref.Get());
361     init(scope);
362 }
363 
set(const QString & uKey,const QVariant & value)364 void QWinRTSettingsPrivate::set(const QString &uKey, const QVariant &value)
365 {
366     int lastIndex = uKey.lastIndexOf(QLatin1Char('/'));
367     QString groupName = (lastIndex > 0) ? uKey.left(lastIndex) : QString();
368     QString groupKey = uKey.mid(lastIndex + 1);
369 
370     ComPtr<IApplicationDataContainer> container = getContainer(writeContainer.Get(), groupName, true);
371 
372     ComPtr<IPropertySet> values;
373     HRESULT hr = container->get_Values(&values);
374     if (FAILED(hr)) {
375         qErrnoWarning(hr, "Could not access Windows container values");
376         setStatus(QSettings::AccessError);
377         return;
378     }
379 
380     ComPtr<IMap<HSTRING, IInspectable*>> settingsMap;
381     hr = values.As(&settingsMap);
382     if (FAILED(hr)) {
383         setStatus(QSettings::AccessError);
384         return;
385     }
386 
387     ComPtr<IPropertyValueStatics> valueStatics;
388     hr = GetActivationFactory(HString::MakeReference(RuntimeClass_Windows_Foundation_PropertyValue).Get(), &valueStatics);
389     if (FAILED(hr)) {
390         setStatus(QSettings::AccessError);
391         return;
392     }
393 
394     ComPtr<IInspectable> val;
395 
396     switch (value.type()) {
397     case QVariant::List:
398     case QVariant::StringList: {
399         QStringList l = variantListToStringList(value.toList());
400         QStringList::const_iterator it = l.constBegin();
401         bool containsNull = false;
402         for (; it != l.constEnd(); ++it) {
403             if ((*it).length() == 0 || it->contains(QChar::Null)) {
404                 // We can only store as binary
405                 containsNull = true;
406                 break;
407             }
408         }
409 
410         if (containsNull) {
411             // Store binary
412             const QString s = variantToString(value);
413             hr = valueStatics->CreateUInt8Array(s.length() * 2, (BYTE*) s.utf16(), &val);
414         } else {
415             // Store as native string list
416             int size = l.size();
417             HSTRING *nativeHandleList = new HSTRING[size+1];
418             for (int i = 0; i < size; ++i)
419                 hr = WindowsCreateString((const wchar_t*)l[i].utf16(), l[i].size(), &nativeHandleList[i]);
420             // Add end marker
421             hr = WindowsCreateString((const wchar_t*)L"\0\0@", 3, &nativeHandleList[size]);
422             hr = valueStatics->CreateStringArray(size + 1 , nativeHandleList, &val);
423             for (int i = 0; i < size; ++i)
424                 hr = WindowsDeleteString(nativeHandleList[i]);
425             delete [] nativeHandleList;
426         }
427         break;
428     }
429     case QVariant::Bool:
430         hr = valueStatics->CreateBoolean(boolean(value.toBool()), &val);
431         break;
432     case QVariant::Int:
433         hr = valueStatics->CreateInt32(INT32(value.toInt()), &val);
434         break;
435     case QVariant::UInt:
436         hr = valueStatics->CreateUInt32(UINT32(value.toUInt()), &val);
437         break;
438     case QVariant::LongLong:
439         hr = valueStatics->CreateInt64(INT64(value.toLongLong()), &val);
440         break;
441     case QVariant::ULongLong:
442         hr = valueStatics->CreateUInt64(UINT64(value.toULongLong()), &val);
443         break;
444     default: {
445         const QString s = variantToString(value);
446         if (s.contains(QChar::Null)) {
447             hr = valueStatics->CreateUInt8Array(s.length() * 2, (BYTE*) s.utf16(), &val);
448         } else {
449             HStringReference ref((const wchar_t*)s.utf16(), s.size());
450             hr = valueStatics->CreateString(ref.Get(), &val);
451         }
452 
453         break;
454     }
455     }
456 
457     RETURN_VOID_IF_FAILED("QSettings: Could not save QVariant value into IInspectable");
458 
459     HStringReference key((const wchar_t*)groupKey.utf16(), groupKey.size());
460     boolean rep;
461 
462     hr = settingsMap->Insert(key.Get(), val.Get(), &rep);
463     RETURN_VOID_IF_FAILED("QSettings: Could not store value");
464 }
465 
get(const QString & uKey,QVariant * value) const466 bool QWinRTSettingsPrivate::get(const QString &uKey, QVariant *value) const
467 {
468     int lastIndex = uKey.lastIndexOf(QLatin1Char('/'));
469     QString groupName = (lastIndex > 0) ? uKey.left(lastIndex) : QString();
470     QString groupKey = uKey.mid(lastIndex + 1);
471 
472     HRESULT hr;
473 
474     for (int i = 0; i < readContainers.size(); ++i) {
475         ComPtr<IApplicationDataContainer> container = const_cast<QWinRTSettingsPrivate*>(this)->getContainer(readContainers.at(i).Get(), groupName);
476 
477         if (!container)
478             continue;
479 
480         ComPtr<IPropertySet> values;
481         hr = container->get_Values(&values);
482         if (FAILED(hr))
483             continue;
484 
485         ComPtr<IMap<HSTRING, IInspectable*>> settingsMap;
486         hr = values.As(&settingsMap);
487         if (FAILED(hr))
488             continue;
489 
490         HStringReference key((const wchar_t*)groupKey.utf16(), groupKey.size());
491         boolean exists;
492 
493         hr = settingsMap.Get()->HasKey(key.Get(), &exists);
494         if (FAILED(hr))
495             continue;
496 
497         if (!exists) {
498             if (!fallbacks)
499                 break;
500             else
501                 continue;
502         }
503 
504         if (value) {
505             ComPtr<IInspectable> val;
506             hr = settingsMap->Lookup(key.Get(), &val);
507             if (FAILED(hr))
508                 return false;
509 
510             ComPtr<IPropertyValue> pVal;
511             hr = val.As(&pVal);
512             if (FAILED(hr))
513                 return false;
514 
515             *value = propertyValueToQVariant(pVal.Get());
516         }
517         return true;
518     }
519     setStatus(QSettings::AccessError);
520     return false;
521 }
522 
children(const QString & uKey,ChildSpec spec) const523 QStringList QWinRTSettingsPrivate::children(const QString &uKey, ChildSpec spec) const
524 {
525     QStringList result;
526     for (int i = 0; i < readContainers.size(); ++i) {
527         ComPtr<IApplicationDataContainer> container = getContainer(readContainers.at(i).Get(), uKey, false);
528         if (!container.Get())
529             continue;
530 
531         // Get Keys in this container
532         if (spec == AllKeys || spec == ChildKeys)
533             result += keyNames(container.Get());
534 
535         // Get Subcontainer(s)
536         if (spec == AllKeys || spec == ChildGroups) {
537             const QStringList subContainerList = subContainerNames(container.Get(), spec == AllKeys);
538 
539             if (spec == AllKeys) {
540                 for (const QString &item : subContainerList) {
541                     const QString subChildren = uKey.isEmpty() ? item : (uKey + QLatin1Char('/') + item);
542                     const QStringList subResult = children(subChildren, ChildKeys);
543                     for (const QString &subItem : subResult)
544                         result += item + QLatin1Char('/') + subItem;
545                 }
546             }
547 
548             if (spec == ChildGroups)
549                 result += subContainerList;
550         }
551 
552     }
553     result.removeDuplicates();
554     return result;
555 }
556 
clear()557 void QWinRTSettingsPrivate::clear()
558 {
559     ComPtr<IApplicationDataContainer> container;
560     HRESULT hr;
561     if (scope == QSettings::UserScope)
562         hr = applicationData->get_LocalSettings(&container);
563     else
564         hr = applicationData->get_RoamingSettings(&container);
565 
566     RETURN_VOID_IF_FAILED("Could not access settings container");
567 
568     QString containerName = applicationName.isEmpty() ? organizationName : applicationName;
569     HStringReference containerNativeName((const wchar_t*)containerName.utf16(), containerName.size());
570 
571     hr = container->DeleteContainer(containerNativeName.Get());
572     RETURN_VOID_IF_FAILED("Could not delete Container");
573 
574     init(scope);
575 }
576 
sync()577 void QWinRTSettingsPrivate::sync()
578 {
579     // No native sync available
580 }
581 
flush()582 void QWinRTSettingsPrivate::flush()
583 {
584     // No native flush available
585 }
586 
fileName() const587 QString QWinRTSettingsPrivate::fileName() const
588 {
589     Q_UNIMPLEMENTED();
590     return QString();
591 }
592 
onDataChanged(IApplicationData *,IInspectable *)593 HRESULT QWinRTSettingsPrivate::onDataChanged(IApplicationData *, IInspectable *)
594 {
595     // This only happens, if roaming data is changed by the OS.
596     // To ensure sanity we clean up the map and start from scratch
597     init(scope);
598     return S_OK;
599 }
600 
init(QSettings::Scope scope)601 void QWinRTSettingsPrivate::init(QSettings::Scope scope)
602 {
603     clearContainerMaps();
604 
605     ComPtr<IApplicationDataStatics> applicationDataStatics;
606     HRESULT hr = GetActivationFactory(HString::MakeReference(RuntimeClass_Windows_Storage_ApplicationData).Get(), &applicationDataStatics);
607     if (FAILED(hr)) {
608         qErrnoWarning(hr, "Could not access Storage Factory");
609         setStatus(QSettings::AccessError);
610         return;
611     }
612 
613     hr = applicationDataStatics->get_Current(&applicationData);
614     if (FAILED(hr)) {
615         qErrnoWarning(hr, "Could not access application data statics");
616         setStatus(QSettings::AccessError);
617         return;
618     }
619 
620     const QString organizationString = organizationName.isEmpty() ? QLatin1String("OrganizationDefaults") : organizationName;
621     ComPtr<IApplicationDataContainer> localContainer;
622     if (scope == QSettings::UserScope && SUCCEEDED(applicationData->get_LocalSettings(&localContainer))) {
623         if (!applicationName.isEmpty())
624             readContainers.append(createSubContainer(localContainer.Get(), applicationName));
625         readContainers.append(createSubContainer(localContainer.Get(), organizationString));
626     }
627 
628     ComPtr<IApplicationDataContainer> roamingContainer;
629     if (SUCCEEDED(applicationData->get_RoamingSettings(&roamingContainer))) {
630         if (!applicationName.isEmpty())
631             readContainers.append(createSubContainer(roamingContainer.Get(), applicationName));
632         readContainers.append(createSubContainer(roamingContainer.Get(), organizationString));
633     }
634 
635     ComPtr<IApplicationDataContainer> writeRootContainer = (scope == QSettings::UserScope) ? localContainer : roamingContainer;
636     if (!applicationName.isEmpty())
637         writeContainer = createSubContainer(writeRootContainer.Get(), applicationName);
638     else
639         writeContainer = createSubContainer(writeRootContainer.Get(), organizationString);
640 
641     hr = applicationData->add_DataChanged(Callback<DataHandler>(this, &QWinRTSettingsPrivate::onDataChanged).Get(), &dataChangedToken);
642 }
643 
getContainer(IApplicationDataContainer * parent,const QString & group,bool create) const644 IApplicationDataContainer *QWinRTSettingsPrivate::getContainer(IApplicationDataContainer *parent, const QString &group, bool create) const
645 {
646     IApplicationDataContainer *current = parent;
647     if (group.isEmpty())
648         return current;
649     const QStringList groupPath = group.split(QLatin1Char('/'), Qt::SkipEmptyParts);
650 
651     for (const QString &subGroup : groupPath) {
652         ComPtr<IApplicationDataContainer> sub = subContainer(current, subGroup);
653         if (!sub && create)
654             sub = createSubContainer(current, subGroup);
655         if (!sub)
656             return 0; // Something seriously went wrong
657         current = sub.Detach();
658     }
659     return current;
660 }
661 
clearContainerMaps()662 void QWinRTSettingsPrivate::clearContainerMaps()
663 {
664     readContainers.clear();
665     writeContainer.Reset();
666 }
667 
isWritable() const668 bool QWinRTSettingsPrivate::isWritable() const
669 {
670     return true;
671 }
672 
create(QSettings::Format format,QSettings::Scope scope,const QString & organization,const QString & application)673 QSettingsPrivate *QSettingsPrivate::create(QSettings::Format format, QSettings::Scope scope,
674                                            const QString &organization, const QString &application)
675 {
676     if (format == QSettings::NativeFormat)
677         return new QWinRTSettingsPrivate(scope, organization, application);
678     else
679         return new QConfFileSettingsPrivate(format, scope, organization, application);
680 }
681 
create(const QString & fileName,QSettings::Format format)682 QSettingsPrivate *QSettingsPrivate::create(const QString &fileName, QSettings::Format format)
683 {
684     if (format == QSettings::NativeFormat)
685         return new QWinRTSettingsPrivate(fileName);
686     else
687         return new QConfFileSettingsPrivate(fileName, format);
688 }
689 
690 QT_END_NAMESPACE
691