GrabBag/AppUtils/AppCommon/Src/PathManager.cpp

343 lines
11 KiB
C++
Raw Normal View History

#include "PathManager.h"
#include "ConfigEncryption.h"
#include <QtCore/QCoreApplication>
#include <QtCore/QFileInfo>
#include <QtCore/QDir>
#include <QtCore/QStandardPaths>
#include <QtCore/QFile>
#include <stdexcept>
#include "VrLog.h"
// 静态成员初始化
PathManager* PathManager::s_instance = nullptr;
std::mutex PathManager::s_mutex;
PathManager::PathManager(const QString& appName)
: m_appName(appName)
2025-12-10 00:01:32 +08:00
, m_encryptionEnabled(false) // 默认禁用加密(调试方便)
{
// 初始化时计算并缓存所有路径
m_configDirectory = GetConfigDirectory();
EnsureConfigDirectoryExists();
2025-12-10 00:01:32 +08:00
// 配置文件路径(根据加密开关决定)
if (m_encryptionEnabled)
{
m_configFilePath = m_configDirectory + "/config.encrypt";
// 设置固定密钥AppName + "VisionRobot"
m_encryptionPassword = appName + "VisionRobot";
}
else
{
m_configFilePath = m_configDirectory + "/config.xml";
}
2025-12-10 00:01:32 +08:00
m_calibrationFilePath = m_configDirectory + "/EyeHandCalibMatrixInfo.ini";
LOG_INFO("PathManager initialized for app: %s\n", appName.toStdString().c_str());
LOG_INFO("Config directory: %s\n", m_configDirectory.toStdString().c_str());
2025-12-10 00:01:32 +08:00
LOG_INFO("Config file: %s\n", m_configFilePath.toStdString().c_str());
LOG_INFO("Encryption: %s\n", m_encryptionEnabled ? "enabled" : "disabled");
2025-12-10 00:01:32 +08:00
// 仅在启用加密时才进行迁移
if (m_encryptionEnabled)
{
MigrateToEncryptedConfig();
}
}
PathManager& PathManager::GetInstance()
{
std::lock_guard<std::mutex> lock(s_mutex);
if (s_instance == nullptr) {
// 自动从应用程序路径获取应用名称
QString appFilePath = QCoreApplication::applicationFilePath();
QString appName = QFileInfo(appFilePath).baseName();
LOG_INFO("Auto-detected application name: %s\n", appName.toStdString().c_str());
s_instance = new PathManager(appName);
}
return *s_instance;
}
QString PathManager::GetConfigFilePath() const
{
return m_configFilePath;
}
QString PathManager::GetCalibrationFilePath() const
{
return m_calibrationFilePath;
}
QString PathManager::GetAppConfigDirectory() const
{
return m_configDirectory;
}
QString PathManager::GetConfigDirectory() const
{
QString baseDir;
#ifdef _WIN32
2025-12-20 16:18:12 +08:00
// Windows系统使用程序目录下的config子目录
baseDir = GetProgramDirectory();
2025-12-20 16:18:12 +08:00
return baseDir + "/Config";
#else
// Linux系统使用用户配置目录
baseDir = GetUserConfigDirectory();
return baseDir + "/../" + m_appName + "/Config";
2025-12-20 16:18:12 +08:00
#endif
}
bool PathManager::EnsureConfigDirectoryExists()
{
if (QDir().exists(m_configDirectory)) {
return true;
}
LOG_INFO("Creating configuration directory: %s\n", m_configDirectory.toStdString().c_str());
bool success = QDir().mkpath(m_configDirectory);
if (success) {
LOG_INFO("Configuration directory created successfully\n");
} else {
LOG_ERROR("Failed to create configuration directory: %s\n", m_configDirectory.toStdString().c_str());
}
return success;
}
QString PathManager::GetProgramDirectory() const
{
QString exePath = QCoreApplication::applicationFilePath();
return QFileInfo(exePath).absoluteDir().path();
}
QString PathManager::GetUserConfigDirectory() const
{
return QStandardPaths::writableLocation(QStandardPaths::ConfigLocation);
}
void PathManager::SetEncryptionPassword(const QString& password)
{
std::lock_guard<std::mutex> lock(s_mutex);
m_encryptionPassword = password;
LOG_INFO("配置加密密码已设置\n");
}
bool PathManager::EnableEncryptionProtection(bool enable)
{
std::lock_guard<std::mutex> lock(s_mutex);
if (enable && m_encryptionPassword.isEmpty()) {
LOG_ERROR("启用加密保护失败:未设置加密密码\n");
return false;
}
m_encryptionEnabled = enable;
2025-12-10 00:01:32 +08:00
// 更新配置文件路径
if (enable) {
2025-12-10 00:01:32 +08:00
m_configFilePath = m_configDirectory + "/config.encrypt";
LOG_INFO("配置加密保护已启用,配置文件: %s\n", m_configFilePath.toStdString().c_str());
} else {
2025-12-10 00:01:32 +08:00
m_configFilePath = m_configDirectory + "/config.xml";
LOG_INFO("配置加密保护已禁用,配置文件: %s\n", m_configFilePath.toStdString().c_str());
}
return true;
}
QByteArray PathManager::ReadEncryptedConfig(const QString& filePath) const
{
if (!m_encryptionEnabled) {
// 未启用加密,直接读取文件
QFile file(filePath);
if (!file.open(QIODevice::ReadOnly)) {
LOG_ERROR("无法打开配置文件: %s\n", filePath.toStdString().c_str());
return QByteArray();
}
return file.readAll();
}
// 启用了加密,读取并解密
QFile file(filePath);
if (!file.open(QIODevice::ReadOnly)) {
LOG_ERROR("无法打开配置文件: %s\n", filePath.toStdString().c_str());
return QByteArray();
}
QByteArray encryptedData = file.readAll();
file.close();
if (encryptedData.isEmpty()) {
LOG_ERROR("配置文件为空: %s\n", filePath.toStdString().c_str());
return QByteArray();
}
// 检查是否为加密文件
if (!IsConfigEncrypted(filePath)) {
// 文件未加密,直接返回
LOG_INFO("配置文件未加密,直接返回: %s\n", filePath.toStdString().c_str());
return encryptedData;
}
// 解密文件
QByteArray decryptedData = ConfigEncryption::DecryptConfig(encryptedData, m_encryptionPassword);
if (decryptedData.isEmpty()) {
LOG_ERROR("解密配置文件失败: %s可能是密码错误\n", filePath.toStdString().c_str());
}
return decryptedData;
}
bool PathManager::WriteEncryptedConfig(const QString& filePath, const QByteArray& data)
{
if (data.isEmpty()) {
LOG_ERROR("写入配置文件失败:数据为空\n");
return false;
}
if (!m_encryptionEnabled) {
// 未启用加密,直接写入文件
QFile file(filePath);
if (!file.open(QIODevice::WriteOnly | QIODevice::Truncate)) {
LOG_ERROR("无法打开配置文件进行写入: %s\n", filePath.toStdString().c_str());
return false;
}
qint64 written = file.write(data);
file.close();
if (written != data.size()) {
LOG_ERROR("写入配置文件失败: %s\n", filePath.toStdString().c_str());
return false;
}
LOG_INFO("配置文件写入成功(未加密): %s\n", filePath.toStdString().c_str());
return true;
}
// 启用了加密,加密后写入
QByteArray encryptedData = ConfigEncryption::EncryptConfig(data, m_encryptionPassword);
if (encryptedData.isEmpty()) {
LOG_ERROR("加密配置数据失败\n");
return false;
}
QFile file(filePath);
if (!file.open(QIODevice::WriteOnly | QIODevice::Truncate)) {
LOG_ERROR("无法打开配置文件进行写入: %s\n", filePath.toStdString().c_str());
return false;
}
qint64 written = file.write(encryptedData);
file.close();
if (written != encryptedData.size()) {
LOG_ERROR("写入加密配置文件失败: %s\n", filePath.toStdString().c_str());
return false;
}
LOG_INFO("加密配置文件写入成功: %s\n", filePath.toStdString().c_str());
return true;
}
bool PathManager::IsConfigEncrypted(const QString& filePath) const
{
QFile file(filePath);
if (!file.open(QIODevice::ReadOnly)) {
return false;
}
// 读取文件头部,检查是否有加密标记
QByteArray header = file.read(8);
file.close();
return header == QByteArray("VRENC1.0", 8);
}
QString PathManager::GetEncryptionKey() const
{
return m_encryptionPassword;
}
void PathManager::MigrateToEncryptedConfig()
{
QString oldConfigPath = m_configDirectory + "/config.xml";
QString newConfigPath = m_configFilePath; // config.encrypt
QFile oldFile(oldConfigPath);
QFile newFile(newConfigPath);
// 检查是否需要迁移config.xml 存在但 config.encrypt 不存在
if (oldFile.exists() && !newFile.exists()) {
LOG_INFO("发现旧的明文配置文件,开始迁移到加密格式...\n");
// 读取旧配置文件
if (!oldFile.open(QIODevice::ReadOnly)) {
LOG_ERROR("无法打开旧配置文件进行迁移: %s\n", oldConfigPath.toStdString().c_str());
return;
}
QByteArray plainData = oldFile.readAll();
oldFile.close();
if (plainData.isEmpty()) {
LOG_WARN("旧配置文件为空,跳过迁移\n");
return;
}
// 加密并保存到新文件
if (WriteEncryptedConfig(newConfigPath, plainData)) {
LOG_INFO("配置文件已成功加密并保存到: %s\n", newConfigPath.toStdString().c_str());
// 删除旧的明文文件
if (oldFile.remove()) {
LOG_INFO("已删除旧的明文配置文件: %s\n", oldConfigPath.toStdString().c_str());
} else {
LOG_WARN("删除旧配置文件失败: %s\n", oldConfigPath.toStdString().c_str());
}
} else {
LOG_ERROR("加密配置文件失败,保留旧文件\n");
}
}
else if (oldFile.exists() && newFile.exists()) {
// 两个文件都存在,说明用户可能刚解密过,准备重新加密
LOG_INFO("检测到 config.xml 和 config.encrypt 同时存在\n");
LOG_INFO("将使用 config.xml 更新 config.encrypt 并删除 config.xml\n");
// 读取 config.xml
if (!oldFile.open(QIODevice::ReadOnly)) {
LOG_ERROR("无法打开 config.xml: %s\n", oldConfigPath.toStdString().c_str());
return;
}
QByteArray plainData = oldFile.readAll();
oldFile.close();
if (!plainData.isEmpty()) {
// 更新加密文件
if (WriteEncryptedConfig(newConfigPath, plainData)) {
LOG_INFO("已使用 config.xml 更新 config.encrypt\n");
// 删除 config.xml
if (oldFile.remove()) {
LOG_INFO("已删除 config.xml\n");
} else {
LOG_WARN("删除 config.xml 失败: %s\n", oldConfigPath.toStdString().c_str());
}
} else {
LOG_ERROR("更新加密配置文件失败\n");
}
}
}
else {
LOG_INFO("配置文件已是加密格式,无需迁移\n");
}
}