Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
77 changes: 6 additions & 71 deletions include/util/dutil.h
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// SPDX-FileCopyrightText: 2016 - 2023 UnionTech Software Technology Co., Ltd.
// SPDX-FileCopyrightText: 2016 - 2026 UnionTech Software Technology Co., Ltd.
//
// SPDX-License-Identifier: LGPL-3.0-or-later

Expand Down Expand Up @@ -54,78 +54,13 @@ void SecureErase(T &obj)
}
}

inline QString escapeToObjectPath(const QString &str)
{
if (str.isEmpty()) {
return "_";
}
QString escapeToObjectPath(const QByteArray &str) noexcept;

auto ret = str;
QRegularExpression re{R"([^a-zA-Z0-9])"};
auto matcher = re.globalMatch(ret);
while (matcher.hasNext()) {
auto replaceList = matcher.next().capturedTexts();
replaceList.removeDuplicates();
for (const auto &c : replaceList) {
auto hexStr = QString::number(static_cast<uint>(c.front().toLatin1()), 16);
ret.replace(c, QString{R"(_%1)"}.arg(hexStr));
}
}
return ret;
}
QString escapeToObjectPath(const QString &str) noexcept;

inline QString unescapeFromObjectPath(const QString &str)
{
auto ret = str;
for (int i = 0; i < str.size(); ++i) {
if (str[i] == '_' && i + 2 < str.size()) {
auto hexStr = str.mid(i + 1, 2);
ret.replace(QString{"_%1"}.arg(hexStr), QChar::fromLatin1(hexStr.toUInt(nullptr, 16)));
i += 2;
}
}
return ret;
}
QString unescapeFromObjectPath(const QString &str) noexcept;

inline QString getAppIdFromAbsolutePath(const QString &path)
{
static QString desktopSuffix{u8".desktop"};
const auto &appDirs = QStandardPaths::standardLocations(QStandardPaths::ApplicationsLocation);
if (!path.endsWith(desktopSuffix) ||
!std::any_of(appDirs.cbegin(), appDirs.constEnd(), [&path](const QString &dir) { return path.startsWith(dir); })) {
return {};
}
QString getAppIdFromAbsolutePath(const QString &path) noexcept;

auto tmp = path.chopped(desktopSuffix.size());
auto components = tmp.split(QDir::separator(), Qt::SkipEmptyParts);
auto location = std::find(components.cbegin(), components.cend(), "applications");
if (location == components.cend()) {
return {};
}

auto appId = QStringList{location + 1, components.cend()}.join('-');
return appId;
}

inline QStringList getAbsolutePathFromAppId(const QString &appId)
{
auto components = appId.split('-', Qt::SkipEmptyParts);
auto appDirs = QStandardPaths::standardLocations(QStandardPaths::ApplicationsLocation);

QStringList ret;
for (const auto &dirPath : appDirs) {
auto currentDir = dirPath;
for (auto it = components.cbegin(); it != components.cend(); ++it) {
auto currentName = QStringList{it, components.cend()}.join('-') + QString{".desktop"};
QDir dir{currentDir};
if (dir.exists(currentName)) {
ret.append(dir.filePath(currentName));
}

currentDir.append(QDir::separator() + *it);
}
}

return ret;
}
QStringList getAbsolutePathFromAppId(const QString &appId) noexcept;
}
105 changes: 105 additions & 0 deletions src/util/dutil.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
// SPDX-FileCopyrightText: 2026 UnionTech Software Technology Co., Ltd.
//
// SPDX-License-Identifier: LGPL-3.0-or-later

#include "dutil.h"

Check warning on line 5 in src/util/dutil.cpp

View workflow job for this annotation

GitHub Actions / cppcheck

Include file: "dutil.h" not found.

namespace DUtil {

QString escapeToObjectPath(const QByteArray &str) noexcept
{
if (str.isEmpty()) {
return QStringLiteral("_");
}

QString ret;
ret.reserve(str.size() * 3);

for (qsizetype i = 0; i < str.size(); ++i) {
auto byte = static_cast<unsigned char>(str.at(i));
if (std::isalnum(byte) != 0 || byte == '/') {
ret.append(QChar::fromLatin1(byte));
} else {
// TODO: a valid dbus object path component only allows "[A-Z][a-z][0-9]_"
// for compatibility with existing applications, we escape all unicode to avoid breakage
// but we should consider to drop this compatibility hack in the future.
ret.append(u'_');
ret.append(QString::number(byte, 16).rightJustified(2, u'0').toLower());
}
}

ret.shrink_to_fit();
return ret;
}

QString escapeToObjectPath(const QString &str) noexcept
{
return escapeToObjectPath(str.toUtf8());
}

QString unescapeFromObjectPath(const QString &str) noexcept

Check warning on line 40 in src/util/dutil.cpp

View workflow job for this annotation

GitHub Actions / cppcheck

The function 'unescapeFromObjectPath' is never used.
{
QByteArray ret;
ret.reserve(str.length());

for (qsizetype i = 0; i < str.length();) {
if (i <= str.length() - 3 && str.at(i) == u'_') {
bool ok{false};
auto byte = static_cast<unsigned char>(str.mid(i + 1, 2).toUShort(&ok, 16));
if (ok) {
ret.append(static_cast<char>(byte));
i += 3;
continue;
}
}

ret.append(str.at(i).toLatin1());
++i;
}

return QString::fromUtf8(ret);
}

QString getAppIdFromAbsolutePath(const QString &path) noexcept

Check warning on line 63 in src/util/dutil.cpp

View workflow job for this annotation

GitHub Actions / cppcheck

The function 'getAppIdFromAbsolutePath' is never used.
{
static QString desktopSuffix{u8".desktop"};
const auto &appDirs = QStandardPaths::standardLocations(QStandardPaths::ApplicationsLocation);
if (!path.endsWith(desktopSuffix) ||
!std::any_of(appDirs.cbegin(), appDirs.constEnd(), [&path](const QString &dir) { return path.startsWith(dir); })) {
return {};
}

auto tmp = path.chopped(desktopSuffix.size());
auto components = tmp.split(QDir::separator(), Qt::SkipEmptyParts);
auto location = std::find(components.cbegin(), components.cend(), "applications");
if (location == components.cend()) {
return {};
}

auto appId = QStringList{location + 1, components.cend()}.join('-');
return appId;
}

QStringList getAbsolutePathFromAppId(const QString &appId) noexcept

Check warning on line 83 in src/util/dutil.cpp

View workflow job for this annotation

GitHub Actions / cppcheck

The function 'getAbsolutePathFromAppId' is never used.
{
auto components = appId.split('-', Qt::SkipEmptyParts);
auto appDirs = QStandardPaths::standardLocations(QStandardPaths::ApplicationsLocation);

QStringList ret;
for (const auto &dirPath : appDirs) {
auto currentDir = dirPath;
for (auto it = components.cbegin(); it != components.cend(); ++it) {
auto currentName = QStringList{it, components.cend()}.join('-') + QString{".desktop"};
QDir dir{currentDir};
if (dir.exists(currentName)) {
ret.append(dir.filePath(currentName));
}

currentDir.append(QDir::separator() + *it);
}
}

return ret;
}

}
2 changes: 2 additions & 0 deletions src/util/util.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ if(LINUX)
${CMAKE_CURRENT_LIST_DIR}/ddbusextendedabstractinterface.cpp
${CMAKE_CURRENT_LIST_DIR}/ddbusextendedpendingcallwatcher.cpp
${CMAKE_CURRENT_LIST_DIR}/dtextencoding.cpp
${CMAKE_CURRENT_LIST_DIR}/dutil.cpp
)
else()
set(UTILS_SOURCES
Expand All @@ -37,6 +38,7 @@ else()
${CMAKE_CURRENT_LIST_DIR}/ddbusextendedabstractinterface.cpp
${CMAKE_CURRENT_LIST_DIR}/ddbusextendedpendingcallwatcher.cpp
${CMAKE_CURRENT_LIST_DIR}/dtextencoding.cpp
${CMAKE_CURRENT_LIST_DIR}/dutil.cpp
)
endif()
file(GLOB UTILS_HEADERS
Expand Down
Loading