Qt
Internal/Contributor docs for the Qt SDK. Note: These are NOT official API docs; those are found at https://doc.qt.io/
Loading...
Searching...
No Matches
qlocalfileapi.cpp
Go to the documentation of this file.
1// Copyright (C) 2022 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
3// Qt-Security score:significant reason:default
4
6#include <private/qstdweb_p.h>
7#include <QtCore/QRegularExpression>
8
10namespace LocalFileApi {
11namespace {
12std::string qtFilterListToFileInputAccept(const QStringList &filterList)
13{
14 QStringList transformed;
15 for (const auto &filter : filterList) {
16 const auto type = Type::fromQt(filter);
17 if (type && type->accept()) {
18 const auto &extensions = type->accept()->mimeType().extensions();
19 std::transform(extensions.begin(), extensions.end(), std::back_inserter(transformed),
20 [](const Type::Accept::MimeType::Extension &extension) {
21 return extension.value().toString();
22 });
23 }
24 }
25 return transformed.join(QStringLiteral(",")).toStdString();
26}
27
28std::optional<emscripten::val> qtFilterListToTypes(const QStringList &filterList)
29{
30 using namespace qstdweb;
31 using namespace emscripten;
32 auto types = emscripten::val::array();
33
34 for (const auto &fileFilter : filterList) {
35 auto type = Type::fromQt(fileFilter);
36 if (type) {
37 auto jsType = emscripten::val::object();
38 jsType.set("description", type->description().toString().toStdString());
39 if (type->accept()) {
40 jsType.set("accept", ([&mimeType = type->accept()->mimeType()]() {
41 val acceptDict = val::object();
42
43 QList<emscripten::val> extensions;
44 extensions.reserve(mimeType.extensions().size());
45 std::transform(
46 mimeType.extensions().begin(), mimeType.extensions().end(),
47 std::back_inserter(extensions),
48 [](const Type::Accept::MimeType::Extension &extension) {
49 return val(extension.value().toString().toStdString());
50 });
51 acceptDict.set("application/octet-stream",
52 emscripten::val::array(extensions.begin(),
53 extensions.end()));
54 return acceptDict;
55 })());
56 }
57 types.call<void>("push", std::move(jsType));
58 }
59 }
60
61 return types["length"].as<int>() == 0 ? std::optional<emscripten::val>() : types;
62}
63} // namespace
64
69
70Type::~Type() = default;
71
73{
74 using namespace emscripten;
75
76 // Accepts either a string in format:
77 // GROUP3
78 // or in this format:
79 // GROUP1 (GROUP2)
80 // Group 1 is treated as the description, whereas group 2 or 3 are treated as the filter list.
82 QString(QStringLiteral("(?:(?:([^(]*)\\‍(([^()]+)\\‍)[^)]*)|([^()]+))")));
83 const auto match = regex.matchView(type);
84
85 if (!match.hasMatch())
86 return std::nullopt;
87
88 constexpr size_t DescriptionIndex = 1;
90 constexpr size_t PlainFilterListIndex = 3;
91
94 : QStringView();
98
100 if (!accept)
101 return std::nullopt;
102
103 return Type(description, std::move(*accept));
104}
105
106Type::Accept::Accept() = default;
107
108Type::Accept::~Accept() = default;
109
111{
113
114 // Used for accepting multiple extension specifications on a filter list.
115 // The next group of non-empty characters.
116 static QRegularExpression internalRegex(QString(QStringLiteral("([^\\s]+)\\s*")));
117 int offset = 0;
120
121 while (internalMatch.hasMatch()) {
123
124 if (!webExtension)
125 return std::nullopt;
126
128
130 }
131
133 return accept;
134}
135
140
141Type::Accept::MimeType::MimeType() = default;
142
143Type::Accept::MimeType::~MimeType() = default;
144
149
151
152Type::Accept::MimeType::Extension::~Extension() = default;
153
156{
157 // Checks for a filter that matches everything:
158 // Any number of asterisks or any number of asterisks with a '.' between them.
159 // The web filter does not support wildcards.
163 return std::nullopt;
164
165 // Checks for correctness. The web filter only allows filename extensions and does not filter
166 // the actual filenames, therefore we check whether the filter provided only filters for the
167 // extension.
170
174
175 // Mapping impossible.
176 return std::nullopt;
177}
178
179emscripten::val makeOpenFileOptions(const QStringList &filterList, bool acceptMultiple)
180{
181 auto options = emscripten::val::object();
182 if (auto typeList = qtFilterListToTypes(filterList); typeList) {
183 options.set("types", std::move(*typeList));
184 options.set("excludeAcceptAllOption", true);
185 }
186
187 options.set("multiple", acceptMultiple);
188
189 return options;
190}
191
192emscripten::val makeSaveFileOptions(const QStringList &filterList, const std::string& suggestedName)
193{
194 auto options = emscripten::val::object();
195
196 if (!suggestedName.empty())
197 options.set("suggestedName", emscripten::val(suggestedName));
198
199 if (auto typeList = qtFilterListToTypes(filterList))
200 options.set("types", emscripten::val(std::move(*typeList)));
201
202 return options;
203}
204
205std::string makeFileInputAccept(const QStringList &filterList)
206{
207 return qtFilterListToFileInputAccept(filterList);
208}
209
210} // namespace LocalFileApi
211
212QT_END_NAMESPACE
std::string makeFileInputAccept(const QStringList &filterList)
emscripten::val makeOpenFileOptions(const QStringList &filterList, bool acceptMultiple)
emscripten::val makeSaveFileOptions(const QStringList &filterList, const std::string &suggestedName)
Combined button and popup list for selecting options.