Repository navigation
Expand file tree
/
Copy pathutil.cpp
More file actions
209 lines (183 loc) · 6.73 KB
/
Copy pathutil.cpp
File metadata and controls
209 lines (183 loc) · 6.73 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
#include "util.h"
#include <QApplication>
#include <QSettings>
#include <QDir>
#include <QMimeData>
#include <QDebug>
#include <QImage>
#include <QBuffer>
#include <QClipboard>
#include <QUuid>
#include <QRegularExpression>
#include <QTemporaryFile>
#include <QUrl>
#include <QNetworkRequest>
#include <QNetworkReply>
#include <QStandardPaths>
#include <QSaveFile>
#include <QElapsedTimer>
#include <Windows.h>
#include <QDesktopServices>
#include "webIconFetcher.h"
const QString Util::REG_AUTORUN = "HKEY_CURRENT_USER\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Run"; //HKEY_CURRENT_USER仅仅对当前用户有效,但不需要管理员权限
QString Util::printDataSize(int bytes)
{
if (bytes < 1024) {
return QString::number(bytes) + " B";
} else if (bytes < 1024 * 1024) {
return QString::number(bytes / 1024) + " KB";
} else if (bytes < 1024 * 1024 * 1024) {
return QString::number(bytes / 1024 / 1024) + " MB";
} else {
return QString::number(bytes / 1024 / 1024 / 1024) + " GB";
}
}
QString Util::genSHA256(const QString& str)
{
return QString(QCryptographicHash::hash(str.toUtf8(), QCryptographicHash::Sha256).toHex());
}
QString Util::appPath()
{
return QDir::toNativeSeparators(QApplication::applicationFilePath());
}
void Util::setAutoRun(const QString& appName, bool autoRun)
{
QSettings reg(REG_AUTORUN, QSettings::NativeFormat);
if (autoRun)
reg.setValue(appName, appPath());
else
reg.remove(appName);
}
bool Util::isAutoRun(const QString& appName)
{
QSettings reg(REG_AUTORUN, QSettings::NativeFormat);
return reg.value(appName).toString() == appPath();
}
QByteArray Util::clipboardData(bool* isText)
{
QByteArray data;
const QMimeData* clipData = qApp->clipboard()->mimeData();
if (clipData->formats().isEmpty()) { //复制 then [粘贴文件]的时候,剪贴板会变化,并且formats为空,WTF?
qWarning() << "WARN: No formats";
return data;
}
if (isText != nullptr) {
*isText = !clipData->hasImage(); //有可能同时hasText,所以以image为准
}
if (clipData->hasImage()) {
static auto extractFilePath = [](const QString& str) {
static QRegularExpression re("filepath=\"([^\"]*)\"");
QRegularExpressionMatch match = re.match(str);
if (match.hasMatch()) {
return match.captured(1);
} else {
return QString();
}
};
// 貌似不同软件的mime格式不一样,这里只处理QQ
// "<QQRichEditFormat><Info version=\"1001\"></Info><EditElement type=\"1\" imagebiztype=\"7\" textsummary=\"[崇拜]\"
// filepath=\"E:\\xxx\\Tencent Files\\xxx\\Image\\C2C\\Image8\\a611951b0d...681d24c21a94c.gif\" shortcut=\"\">
// </EditElement></QQRichEditFormat>"
auto qqRichData = QString::fromUtf8(clipData->data("application/x-qt-windows-mime;value=\"QQ_Unicode_RichEdit_Format\""));
auto imagePath = extractFilePath(qqRichData); // 正则提取路径
// .gif 特殊处理,因为QImage不支持gif的Write,如果直接转换为jpg只会保留一帧
if (imagePath.endsWith(".gif")) {
QFile file(imagePath);
if (file.open(QIODevice::ReadOnly)) {
data = file.readAll();
file.close();
return data;
} else {
qCritical() << "Unable to open the file:" << imagePath;
}
}
//format: application/x-qt-image
QImage image = qvariant_cast<QImage>(clipData->imageData()); //不能直接toByteArray,需要先转换为QImage,否则为空
if (!image.isNull()) {
QBuffer buffer(&data);
buffer.open(QIODevice::WriteOnly);
image.save(&buffer, "jpg"); // 将 QImage 保存为 jpg 格式
buffer.close();
// data = data.toBase64(); // 转换为 Base64 编码,防止老式设备进行隐式编解码导致信息丢失
} else
qWarning() << "WARN: QImage is null";
} else if (clipData->hasText()) {
data = clipData->text().toUtf8();
} else {
qWarning() << "WARN: This Type is not supported NOW." << clipData->formats();
}
return data;
}
QString Util::genUUID()
{
return QUuid::createUuid().toString(QUuid::WithoutBraces);
}
void Util::openExplorerAndSelectFile(const QString& filePath)
{
ShellExecuteW(NULL, L"open", L"explorer", QString("/select, \"%1\"").arg(QDir::toNativeSeparators(filePath)).toStdWString().c_str(), NULL, SW_SHOW);
}
QString Util::saveImageToTemp(const QImage& image, const char *format)
{
QTemporaryFile tmp;
tmp.setAutoRemove(false); // 关键:否则对象析构就删了,Toast 还没读到
if (!tmp.open()) return {};
image.save(&tmp, format);
tmp.close();
return QDir::toNativeSeparators(tmp.fileName());
}
bool Util::isHttpUrl(const QString& s)
{
return WebIconFetcher::isHttpUrl(s.trimmed());
}
// 从文本中提取第一个Http(s)链接
QString Util::extractFirstHttpUrl(const QString& text)
{
static const QRegularExpression urlRegex(R"((https?://[^\s"'<>()]+))",
QRegularExpression::CaseInsensitiveOption);
QRegularExpressionMatch match = urlRegex.match(text);
if (match.hasMatch()) {
QString urlStr = match.captured(1);
if (isHttpUrl(urlStr))
return urlStr;
}
return {};
}
void Util::downloadFaviconIcoToTemp(
QNetworkAccessManager* nam,
const QString& pageUrlStr,
std::function<void(QString localPath)> cb,
int timeoutMs)
{
static WebIconFetcher fetcher(nam, nullptr, timeoutMs);
fetcher.fetch(pageUrlStr, cb);
}
bool Util::isTencentMeetingInstalled()
{
// 检查 HKEY_CLASSES_ROOT\wemeet
QSettings reg("HKEY_CLASSES_ROOT\\wemeet", QSettings::NativeFormat);
if (reg.allKeys().isEmpty()) {
// 注册表没有 wemeet 协议
return false;
}
return true;
}
QString Util::parseTencentMeetingCode(const QString &link)
{
QUrl url(link.trimmed());
if (!url.isValid() || url.host().toLower() != "meeting.tencent.com")
return {};
QStringList segments = url.path().split('/', Qt::SkipEmptyParts);
if (segments.isEmpty())
return {};
// 会议号通常是数字(这里做个合理长度范围,避免误判)
static const QRegularExpression reDigits("^\\d{6,15}$");
auto code = segments.last();
if (!reDigits.match(code).hasMatch())
return {};
return code; // 最后一段就是会议号
}
bool Util::openTencentMeetingClient(const QString& meetingCode)
{
QString protocol = QString("wemeet://page/inmeeting?meeting_code=%1").arg(meetingCode);
return QDesktopServices::openUrl(QUrl(protocol));
}