Skip to content

Commit 12ebd23

Browse files
ComixHedeepin-bot[bot]
authored andcommitted
feat(util): support full Unicode with UTF-8 byte escaping
Desktop name and object path specs require ASCII-only. Now escapes all UTF-8 bytes to support Chinese, Japanese, Korean, etc. Bug: PMS-357251 Signed-off-by: ComixHe <heyuming@deepin.org>
1 parent c7005f4 commit 12ebd23

1 file changed

Lines changed: 41 additions & 20 deletions

File tree

include/util/dutil.h

Lines changed: 41 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
// SPDX-FileCopyrightText: 2016 - 2023 UnionTech Software Technology Co., Ltd.
1+
// SPDX-FileCopyrightText: 2016 - 2026 UnionTech Software Technology Co., Ltd.
22
//
33
// SPDX-License-Identifier: LGPL-3.0-or-later
44

@@ -54,37 +54,58 @@ void SecureErase(T &obj)
5454
}
5555
}
5656

57-
inline QString escapeToObjectPath(const QString &str)
57+
inline QString escapeToObjectPath(const QByteArray &str) noexcept
5858
{
5959
if (str.isEmpty()) {
60-
return "_";
60+
return QStringLiteral("_");
6161
}
6262

63-
auto ret = str;
64-
QRegularExpression re{R"([^a-zA-Z0-9])"};
65-
auto matcher = re.globalMatch(ret);
66-
while (matcher.hasNext()) {
67-
auto replaceList = matcher.next().capturedTexts();
68-
replaceList.removeDuplicates();
69-
for (const auto &c : replaceList) {
70-
auto hexStr = QString::number(static_cast<uint>(c.front().toLatin1()), 16);
71-
ret.replace(c, QString{R"(_%1)"}.arg(hexStr));
63+
QString ret;
64+
ret.reserve(str.size() * 3);
65+
66+
for (qsizetype i = 0; i < str.size(); ++i) {
67+
auto byte = static_cast<unsigned char>(str.at(i));
68+
if (std::isalnum(byte) != 0 || byte == '/') {
69+
ret.append(QChar::fromLatin1(byte));
70+
} else {
71+
// TODO: a valid dbus object path component only allows "[A-Z][a-z][0-9]_"
72+
// for compatibility with existing applications, we escape all unicode to avoid breakage
73+
// but we should consider to drop this compatibility hack in the future.
74+
ret.append(u'_');
75+
ret.append(QString::number(byte, 16).rightJustified(2, u'0').toLower());
7276
}
7377
}
78+
79+
ret.shrink_to_fit();
7480
return ret;
7581
}
7682

77-
inline QString unescapeFromObjectPath(const QString &str)
83+
inline QString escapeToObjectPath(const QString &str) noexcept
84+
{
85+
return escapeToObjectPath(str.toUtf8());
86+
}
87+
88+
inline QString unescapeFromObjectPath(const QString &str) noexcept
7889
{
79-
auto ret = str;
80-
for (int i = 0; i < str.size(); ++i) {
81-
if (str[i] == '_' && i + 2 < str.size()) {
82-
auto hexStr = str.mid(i + 1, 2);
83-
ret.replace(QString{"_%1"}.arg(hexStr), QChar::fromLatin1(hexStr.toUInt(nullptr, 16)));
84-
i += 2;
90+
QByteArray ret;
91+
ret.reserve(str.length());
92+
93+
for (qsizetype i = 0; i < str.length();) {
94+
if (i <= str.length() - 3 && str.at(i) == u'_') {
95+
bool ok{false};
96+
auto byte = static_cast<unsigned char>(str.mid(i + 1, 2).toUShort(&ok, 16));
97+
if (ok) {
98+
ret.append(static_cast<char>(byte));
99+
i += 3;
100+
continue;
101+
}
85102
}
103+
104+
ret.append(str.at(i).toLatin1());
105+
++i;
86106
}
87-
return ret;
107+
108+
return QString::fromUtf8(ret);
88109
}
89110

90111
inline QString getAppIdFromAbsolutePath(const QString &path)

0 commit comments

Comments
 (0)