Qt 6.x
The Qt SDK
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
4#include "qlocalfileapi_p.h"
5#include <private/qstdweb_p.h>
6#include <QtCore/QRegularExpression>
7
9namespace LocalFileApi {
10namespace {
11std::string qtFilterListToFileInputAccept(const QStringList &filterList)
12{
13 QStringList transformed;
14 for (const auto &filter : filterList) {
15
16 emscripten::val::global("console").call<void>("log", filter.toStdString());
17
18 const auto type = Type::fromQt(filter);
19 if (type && type->accept()) {
20 const auto &extensions = type->accept()->mimeType().extensions();
21 for (const auto &ext : extensions) {
22 emscripten::val::global("console").call<void>("log",
23 ext.value().toString().toStdString());
24 }
25
26 std::transform(extensions.begin(), extensions.end(), std::back_inserter(transformed),
27 [](const Type::Accept::MimeType::Extension &extension) {
28 return extension.value().toString();
29 });
30 }
31 }
32 for (const QString &tran : transformed) {
33 emscripten::val::global("console").call<void>("log", tran.toStdString());
34 }
35 return transformed.join(QStringLiteral(",")).toStdString();
36}
37
38std::optional<emscripten::val> qtFilterListToTypes(const QStringList &filterList)
39{
40 using namespace qstdweb;
41 using namespace emscripten;
42
43 auto types = emscripten::val::array();
44
45 for (const auto &fileFilter : filterList) {
46 auto type = Type::fromQt(fileFilter);
47 if (type) {
48 auto jsType = val::object();
49 jsType.set("description", type->description().toString().toStdString());
50 if (type->accept()) {
51 jsType.set("accept", ([&mimeType = type->accept()->mimeType()]() {
52 val acceptDict = val::object();
53
54 QList<emscripten::val> extensions;
55 extensions.reserve(mimeType.extensions().size());
56 std::transform(
57 mimeType.extensions().begin(), mimeType.extensions().end(),
58 std::back_inserter(extensions),
59 [](const Type::Accept::MimeType::Extension &extension) {
60 return val(extension.value().toString().toStdString());
61 });
62 acceptDict.set("application/octet-stream",
63 emscripten::val::array(extensions.begin(),
64 extensions.end()));
65 return acceptDict;
66 })());
67 }
68 types.call<void>("push", std::move(jsType));
69 }
70 }
71
72 return types["length"].as<int>() == 0 ? std::optional<emscripten::val>() : types;
73}
74} // namespace
75
76Type::Type(QStringView description, std::optional<Accept> accept)
77 : m_description(description.trimmed()), m_accept(std::move(accept))
78{
79}
80
81Type::~Type() = default;
82
83std::optional<Type> Type::fromQt(QStringView type)
84{
85 using namespace emscripten;
86
87 // Accepts either a string in format:
88 // GROUP3
89 // or in this format:
90 // GROUP1 (GROUP2)
91 // Group 1 is treated as the description, whereas group 2 or 3 are treated as the filter list.
92 static QRegularExpression regex(
93 QString(QStringLiteral("(?:(?:([^(]*)\\(([^()]+)\\)[^)]*)|([^()]+))")));
94 const auto match = regex.matchView(type);
95
96 if (!match.hasMatch())
97 return std::nullopt;
98
99 constexpr size_t DescriptionIndex = 1;
100 constexpr size_t FilterListFromParensIndex = 2;
101 constexpr size_t PlainFilterListIndex = 3;
102
103 const auto description = match.hasCaptured(DescriptionIndex)
104 ? match.capturedView(DescriptionIndex)
105 : QStringView();
106 const auto filterList = match.capturedView(match.hasCaptured(FilterListFromParensIndex)
107 ? FilterListFromParensIndex
108 : PlainFilterListIndex);
109
110 auto accept = Type::Accept::fromQt(filterList);
111 if (!accept)
112 return std::nullopt;
113
114 return Type(description, std::move(*accept));
115}
116
117Type::Accept::Accept() = default;
118
119Type::Accept::~Accept() = default;
120
121std::optional<Type::Accept> Type::Accept::fromQt(QStringView qtRepresentation)
122{
123 Accept accept;
124
125 // Used for accepting multiple extension specifications on a filter list.
126 // The next group of non-empty characters.
127 static QRegularExpression internalRegex(QString(QStringLiteral("([^\\s]+)\\s*")));
128 int offset = 0;
129 auto internalMatch = internalRegex.matchView(qtRepresentation, offset);
131
132 while (internalMatch.hasMatch()) {
133 auto webExtension = MimeType::Extension::fromQt(internalMatch.capturedView(1));
134
135 if (!webExtension)
136 return std::nullopt;
137
138 mimeType.addExtension(*webExtension);
139
140 internalMatch = internalRegex.matchView(qtRepresentation, internalMatch.capturedEnd());
141 }
142
143 accept.setMimeType(mimeType);
144 return accept;
145}
146
147void Type::Accept::setMimeType(MimeType mimeType)
148{
149 m_mimeType = std::move(mimeType);
150}
151
152Type::Accept::MimeType::MimeType() = default;
153
154Type::Accept::MimeType::~MimeType() = default;
155
156void Type::Accept::MimeType::addExtension(Extension extension)
157{
158 m_extensions.push_back(std::move(extension));
159}
160
161Type::Accept::MimeType::Extension::Extension(QStringView extension) : m_value(extension) { }
162
163Type::Accept::MimeType::Extension::~Extension() = default;
164
165std::optional<Type::Accept::MimeType::Extension>
166Type::Accept::MimeType::Extension::fromQt(QStringView qtRepresentation)
167{
168 // Checks for a filter that matches everything:
169 // Any number of asterisks or any number of asterisks with a '.' between them.
170 // The web filter does not support wildcards.
171 static QRegularExpression qtAcceptAllRegex(
173 if (qtAcceptAllRegex.matchView(qtRepresentation).hasMatch())
174 return std::nullopt;
175
176 // Checks for correctness. The web filter only allows filename extensions and does not filter
177 // the actual filenames, therefore we check whether the filter provided only filters for the
178 // extension.
179 static QRegularExpression qtFilenameMatcherRegex(
181
182 auto extensionMatch = qtFilenameMatcherRegex.matchView(qtRepresentation);
183 if (extensionMatch.hasMatch())
184 return Extension(extensionMatch.capturedView(2));
185
186 // Mapping impossible.
187 return std::nullopt;
188}
189
190emscripten::val makeOpenFileOptions(const QStringList &filterList, bool acceptMultiple)
191{
192 auto options = emscripten::val::object();
193 if (auto typeList = qtFilterListToTypes(filterList)) {
194 options.set("types", std::move(*typeList));
195 options.set("excludeAcceptAllOption", true);
196 }
197
198 options.set("multiple", acceptMultiple);
199
200 return options;
201}
202
203emscripten::val makeSaveFileOptions(const QStringList &filterList, const std::string& suggestedName)
204{
205 auto options = emscripten::val::object();
206
207 if (!suggestedName.empty())
208 options.set("suggestedName", emscripten::val(suggestedName));
209
210 if (auto typeList = qtFilterListToTypes(filterList))
211 options.set("types", emscripten::val(std::move(*typeList)));
212
213 return options;
214}
215
216std::string makeFileInputAccept(const QStringList &filterList)
217{
218 return qtFilterListToFileInputAccept(filterList);
219}
220
221} // namespace LocalFileApi
222
NSString * m_mimeType
void setMimeType(MimeType mimeType)
const QStringView & description() const
const std::optional< Accept > & accept() const
bool hasMatch() const
Returns true if the regular expression matched against the subject string, or false otherwise.
\inmodule QtCore \reentrant
QRegularExpressionMatch matchView(QStringView subjectView, qsizetype offset=0, MatchType matchType=NormalMatch, MatchOptions matchOptions=NoMatchOption) const
static QString anchoredPattern(const QString &expression)
\inmodule QtCore
\inmodule QtCore
Definition qstringview.h:76
\macro QT_RESTRICTED_CAST_FROM_ASCII
Definition qstring.h:127
std::string toStdString() const
Returns a std::string object with the data contained in this QString.
Definition qstring.h:1319
void extension()
[6]
Definition dialogs.cpp:230
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.
const char * mimeType
GLsizei GLenum GLenum * types
GLenum type
GLint GLint GLint GLint GLint GLint GLint GLbitfield GLenum filter
GLenum GLuint GLintptr offset
static QT_BEGIN_NAMESPACE const char * typeList[]
#define QStringLiteral(str)
static bool match(const uchar *found, uint foundLen, const char *target, uint targetLen)