Use ansi codepage for internal multibyte strings on windows (fixes #976, fixes #974, fixes #444)

This commit is contained in:
albertony 2020-12-09 23:36:34 +01:00
parent e032d14a48
commit 402801e0a6
14 changed files with 151 additions and 86 deletions

View File

@ -30,34 +30,35 @@ CommandProcess::CommandProcess(QString cmd, QStringList arguments, QString input
QString CommandProcess::run() QString CommandProcess::run()
{ {
QProcess process; QProcess process;
QString standardOutput, standardError;
process.setReadChannel(QProcess::StandardOutput); process.setReadChannel(QProcess::StandardOutput);
process.start(m_Command, m_Arguments); process.start(m_Command, m_Arguments);
bool success = process.waitForStarted(); bool success = process.waitForStarted();
QString output, error;
if (success) if (success)
{ {
if (!m_Input.isEmpty()) { if (!m_Input.isEmpty()) {
process.write(m_Input.toStdString().c_str()); process.write(m_Input.toLocal8Bit());
} }
if (process.waitForFinished()) { if (process.waitForFinished()) {
output = process.readAllStandardOutput().trimmed(); standardOutput = QString::fromLocal8Bit(process.readAllStandardOutput().trimmed());
error = process.readAllStandardError().trimmed(); standardError = QString::fromLocal8Bit(process.readAllStandardError().trimmed());
} }
} }
int code = process.exitCode(); int code = process.exitCode();
if (!error.isEmpty() || !success || code != 0) if (!standardError.isEmpty() || !success || code != 0)
{ {
throw std::runtime_error( throw std::runtime_error(
std::string(
QString("Code: %1\nError: %2") QString("Code: %1\nError: %2")
.arg(process.exitCode()) .arg(process.exitCode())
.arg(error.isEmpty() ? "Unknown" : error) .arg(standardError.isEmpty() ? "Unknown" : standardError)
.toStdString()); .toLocal8Bit().constData()));
} }
emit finished(); emit finished();
return output; return standardOutput;
} }

View File

@ -16,8 +16,7 @@
*/ */
#include "Fingerprint.h" #include "Fingerprint.h"
#include "QUtility.h"
#include "common/DataDirectories.h"
#include <QDir> #include <QDir>
#include <QTextStream> #include <QTextStream>
@ -125,10 +124,8 @@ void Fingerprint::persistDirectory()
QString Fingerprint::directoryPath() QString Fingerprint::directoryPath()
{ {
auto profileDir = QString::fromStdString(DataDirectories::profile());
return QString("%1/%2") return QString("%1/%2")
.arg(profileDir) .arg(profilePath())
.arg(kDirName); .arg(kDirName);
} }

View File

@ -104,14 +104,12 @@ void IpcClient::sendCommand(const QString& command, ElevateMode const elevate)
stream.writeRawData(kIpcMsgCommand, 4); stream.writeRawData(kIpcMsgCommand, 4);
std::string stdStringCommand = command.toStdString(); QByteArray utf8Command = command.toUtf8();
const char* charCommand = stdStringCommand.c_str();
int length = (int)strlen(charCommand);
char lenBuf[4]; char lenBuf[4];
intToBytes(length, lenBuf, 4); intToBytes(utf8Command.size(), lenBuf, 4);
stream.writeRawData(lenBuf, 4); stream.writeRawData(lenBuf, 4);
stream.writeRawData(charCommand, length); stream.writeRawData(utf8Command.constData(), utf8Command.size());
char elevateBuf[1]; char elevateBuf[1];
// Refer to enum ElevateMode documentation for why this flag is mapped this way // Refer to enum ElevateMode documentation for why this flag is mapped this way

View File

@ -31,7 +31,6 @@
#include "ProcessorArch.h" #include "ProcessorArch.h"
#include "SslCertificate.h" #include "SslCertificate.h"
#include "ShutdownCh.h" #include "ShutdownCh.h"
#include "common/DataDirectories.h"
#include <QtCore> #include <QtCore>
#include <QtGui> #include <QtGui>
@ -526,7 +525,7 @@ void MainWindow::startBarrier()
// launched the process (e.g. when launched with elevation). setting the // launched the process (e.g. when launched with elevation). setting the
// profile dir on launch ensures it uses the same profile dir is used // profile dir on launch ensures it uses the same profile dir is used
// no matter how its relaunched. // no matter how its relaunched.
args << "--profile-dir" << QString::fromStdString("\"" + DataDirectories::profile() + "\""); args << "--profile-dir" << QString("\"%1\"").arg(profilePath());
#endif #endif
if ((barrierType() == barrierClient && !clientArgs(args, app)) if ((barrierType() == barrierClient && !clientArgs(args, app))

View File

@ -19,6 +19,7 @@
#include "ProcessorArch.h" #include "ProcessorArch.h"
#include "CommandProcess.h" #include "CommandProcess.h"
#include "common/DataDirectories.h"
#if defined(Q_OS_LINUX) #if defined(Q_OS_LINUX)
#include <QProcess> #include <QProcess>
@ -113,3 +114,11 @@ QString getOSInformation()
return result; return result;
} }
QString profilePath()
{
// Get path to current profile directory, properly converted
// from an OS locale std::string to Unicode QString.
auto localePath = DataDirectories::profile();
return QString::fromLocal8Bit(localePath.c_str(), localePath.size());
}

View File

@ -29,3 +29,4 @@ QString hash(const QString& string);
QString getFirstMacAddress(); QString getFirstMacAddress();
qProcessorArch getProcessorArch(); qProcessorArch getProcessorArch();
QString getOSInformation(); QString getOSInformation();
QString profilePath();

View File

@ -17,7 +17,7 @@
#include "SslCertificate.h" #include "SslCertificate.h"
#include "Fingerprint.h" #include "Fingerprint.h"
#include "common/DataDirectories.h" #include "QUtility.h"
#include <QProcess> #include <QProcess>
#include <QDir> #include <QDir>
@ -43,13 +43,13 @@ static const char kConfigFile[] = "barrier.conf";
SslCertificate::SslCertificate(QObject *parent) : SslCertificate::SslCertificate(QObject *parent) :
QObject(parent) QObject(parent)
{ {
m_ProfileDir = DataDirectories::profile(); m_ProfileDir = profilePath();
if (m_ProfileDir.empty()) { if (m_ProfileDir.isEmpty()) {
emit error(tr("Failed to get profile directory.")); emit error(tr("Failed to get profile directory."));
} }
} }
std::pair<bool, std::string> SslCertificate::runTool(const QStringList& args) std::pair<bool, QString> SslCertificate::runTool(const QStringList& args)
{ {
QString program; QString program;
#if defined(Q_OS_WIN) #if defined(Q_OS_WIN)
@ -68,17 +68,15 @@ std::pair<bool, std::string> SslCertificate::runTool(const QStringList& args)
#endif #endif
QProcess process; QProcess process;
QString standardOutput, standardError;
process.setEnvironment(environment); process.setEnvironment(environment);
process.start(program, args); process.start(program, args);
bool success = process.waitForStarted(); bool success = process.waitForStarted();
std::string output;
QString standardError;
if (success && process.waitForFinished()) if (success && process.waitForFinished())
{ {
output = process.readAllStandardOutput().trimmed().toStdString(); standardOutput = QString::fromLocal8Bit(process.readAllStandardOutput().trimmed());
standardError = process.readAllStandardError().trimmed(); standardError = QString::fromLocal8Bit(process.readAllStandardError().trimmed());
} }
int code = process.exitCode(); int code = process.exitCode();
@ -89,15 +87,15 @@ std::pair<bool, std::string> SslCertificate::runTool(const QStringList& args)
.arg(program) .arg(program)
.arg(process.exitCode()) .arg(process.exitCode())
.arg(standardError.isEmpty() ? "Unknown" : standardError)); .arg(standardError.isEmpty() ? "Unknown" : standardError));
return {false, output}; return {false, standardOutput};
} }
return {true, output}; return {true, standardOutput};
} }
void SslCertificate::generateCertificate() void SslCertificate::generateCertificate()
{ {
auto filename = QString::fromStdString(getCertificatePath()); auto filename = getCertificatePath();
QFile file(filename); QFile file(filename);
if (!file.exists() || !isCertificateValid(filename)) { if (!file.exists() || !isCertificateValid(filename)) {
@ -122,7 +120,7 @@ void SslCertificate::generateCertificate()
arguments.append("-newkey"); arguments.append("-newkey");
arguments.append("rsa:2048"); arguments.append("rsa:2048");
QDir sslDir(QString::fromStdString(getCertificateDirectory())); QDir sslDir(getCertificateDirectory());
if (!sslDir.exists()) { if (!sslDir.exists()) {
sslDir.mkpath("."); sslDir.mkpath(".");
} }
@ -159,20 +157,17 @@ void SslCertificate::generateFingerprint(const QString& certificateFilename)
auto ret = runTool(arguments); auto ret = runTool(arguments);
bool success = ret.first; bool success = ret.first;
std::string output = ret.second;
if (!success) { if (!success) {
return; return;
} }
// find the fingerprint from the tool output // find the fingerprint from the tool output
auto i = output.find_first_of('='); QString fingerprint = ret.second;
if (i != std::string::npos) { auto i = fingerprint.indexOf('=');
i++; if (i != -1) {
auto fingerprint = output.substr( fingerprint.remove(0, i+1);
i, output.size() - i);
Fingerprint::local().trust(QString::fromStdString(fingerprint), false); Fingerprint::local().trust(fingerprint, false);
emit info(tr("SSL fingerprint generated.")); emit info(tr("SSL fingerprint generated."));
} }
else { else {
@ -180,14 +175,14 @@ void SslCertificate::generateFingerprint(const QString& certificateFilename)
} }
} }
std::string SslCertificate::getCertificatePath() QString SslCertificate::getCertificatePath()
{ {
return getCertificateDirectory() + QDir::separator().toLatin1() + kCertificateFilename; return getCertificateDirectory() + QDir::separator() + kCertificateFilename;
} }
std::string SslCertificate::getCertificateDirectory() QString SslCertificate::getCertificateDirectory()
{ {
return m_ProfileDir + QDir::separator().toLatin1() + kSslDir; return m_ProfileDir + QDir::separator() + kSslDir;
} }
bool SslCertificate::isCertificateValid(const QString& path) bool SslCertificate::isCertificateValid(const QString& path)
@ -198,7 +193,7 @@ bool SslCertificate::isCertificateValid(const QString& path)
BIO* bio = BIO_new(BIO_s_file()); BIO* bio = BIO_new(BIO_s_file());
auto ret = BIO_read_filename(bio, path.toStdString().c_str()); auto ret = BIO_read_filename(bio, path.toLocal8Bit().constData());
if (!ret) { if (!ret) {
emit info(tr("Could not read from default certificate file.")); emit info(tr("Could not read from default certificate file."));
BIO_free_all(bio); BIO_free_all(bio);

View File

@ -36,13 +36,13 @@ signals:
void generateFinished(); void generateFinished();
private: private:
std::pair<bool, std::string> runTool(const QStringList& args); std::pair<bool, QString> runTool(const QStringList& args);
void generateFingerprint(const QString& certificateFilename); void generateFingerprint(const QString& certificateFilename);
std::string getCertificatePath(); QString getCertificatePath();
std::string getCertificateDirectory(); QString getCertificateDirectory();
bool isCertificateValid(const QString& path); bool isCertificateValid(const QString& path);
private: private:
std::string m_ProfileDir; QString m_ProfileDir;
}; };

View File

@ -34,6 +34,7 @@
#include "base/log_outputters.h" #include "base/log_outputters.h"
#include "base/Log.h" #include "base/Log.h"
#include "common/DataDirectories.h" #include "common/DataDirectories.h"
#include "base/Unicode.h"
#include "arch/win32/ArchMiscWindows.h" #include "arch/win32/ArchMiscWindows.h"
#include "arch/win32/XArchWindows.h" #include "arch/win32/XArchWindows.h"
@ -257,7 +258,7 @@ DaemonApp::handleIpcMessage(const Event& e, void*)
switch (m->type()) { switch (m->type()) {
case kIpcCommand: { case kIpcCommand: {
IpcCommandMessage* cm = static_cast<IpcCommandMessage*>(m); IpcCommandMessage* cm = static_cast<IpcCommandMessage*>(m);
String command = cm->command(); String command = Unicode::UTF8ToText(cm->command());
// if empty quotes, clear. // if empty quotes, clear.
if (command == "\"\"") { if (command == "\"\"") {

View File

@ -16,34 +16,12 @@
*/ */
#include "../DataDirectories.h" #include "../DataDirectories.h"
#include "KnownFolderPaths.h"
#include <Shlobj.h>
std::string unicode_to_mb(const WCHAR* utfStr)
{
int utfLength = lstrlenW(utfStr);
int mbLength = WideCharToMultiByte(CP_UTF8, 0, utfStr, utfLength, NULL, 0, NULL, NULL);
std::string mbStr(mbLength, 0);
WideCharToMultiByte(CP_UTF8, 0, utfStr, utfLength, &mbStr[0], mbLength, NULL, NULL);
return mbStr;
}
std::string known_folder_path(const KNOWNFOLDERID& id)
{
std::string path;
WCHAR* buffer;
HRESULT result = SHGetKnownFolderPath(id, 0, NULL, &buffer);
if (result == S_OK) {
path = unicode_to_mb(buffer);
CoTaskMemFree(buffer);
}
return path;
}
const std::string& DataDirectories::profile() const std::string& DataDirectories::profile()
{ {
if (_profile.empty()) if (_profile.empty())
_profile = known_folder_path(FOLDERID_LocalAppData) + "\\Barrier"; _profile = localAppDataPath() + "\\Barrier";
return _profile; return _profile;
} }
const std::string& DataDirectories::profile(const std::string& path) const std::string& DataDirectories::profile(const std::string& path)
@ -55,7 +33,7 @@ const std::string& DataDirectories::profile(const std::string& path)
const std::string& DataDirectories::global() const std::string& DataDirectories::global()
{ {
if (_global.empty()) if (_global.empty())
_global = known_folder_path(FOLDERID_ProgramData) + "\\Barrier"; _global = programDataPath() + "\\Barrier";
return _global; return _global;
} }
const std::string& DataDirectories::global(const std::string& path) const std::string& DataDirectories::global(const std::string& path)

View File

@ -0,0 +1,63 @@
/*
* barrier -- mouse and keyboard sharing utility
* Copyright (C) 2018 Debauchee Open Source Group
*
* This package is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* found in the file LICENSE that should have accompanied this file.
*
* This package is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "KnownFolderPaths.h"
#define WIN32_LEAN_AND_MEAN
#include <Windows.h>
#include <Shlobj.h>
static std::string wide_to_mb(const wchar_t* source, int length)
{
int ansiLength = WideCharToMultiByte(CP_ACP, 0, source, length, NULL, 0, NULL, NULL);
if (ansiLength > 0) {
std::string ansiString(ansiLength, 0);
ansiLength = WideCharToMultiByte(CP_ACP, 0, source, length, &ansiString[0], ansiLength, NULL, NULL);
if (ansiLength > 0) {
return ansiString;
}
}
return {};
}
static std::string known_folder_path(const KNOWNFOLDERID& id)
{
std::string path;
WCHAR* buffer;
HRESULT result = SHGetKnownFolderPath(id, 0, NULL, &buffer);
if (result == S_OK) {
auto length = lstrlenW(buffer);
path = wide_to_mb(buffer, length);
CoTaskMemFree(buffer);
}
return path;
}
std::string desktopPath()
{
return known_folder_path(FOLDERID_Desktop);
}
std::string localAppDataPath()
{
return known_folder_path(FOLDERID_LocalAppData);
}
std::string programDataPath()
{
return known_folder_path(FOLDERID_ProgramData);
}

View File

@ -0,0 +1,24 @@
/*
* barrier -- mouse and keyboard sharing utility
* Copyright (C) 2018 Debauchee Open Source Group
*
* This package is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* found in the file LICENSE that should have accompanied this file.
*
* This package is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#pragma once
#include <string>
std::string desktopPath();
std::string localAppDataPath();
std::string programDataPath();

View File

@ -29,6 +29,7 @@
#include "base/EventQueue.h" #include "base/EventQueue.h"
#include "base/TMethodEventJob.h" #include "base/TMethodEventJob.h"
#include "base/TMethodJob.h" #include "base/TMethodJob.h"
#include "base/Unicode.h"
enum EIpcLogOutputter { enum EIpcLogOutputter {
kBufferMaxSize = 1000, kBufferMaxSize = 1000,
@ -196,7 +197,7 @@ IpcLogOutputter::sendBuffer()
return; return;
} }
IpcLogLineMessage message(getChunk(kMaxSendLines)); IpcLogLineMessage message(Unicode::textToUTF8(getChunk(kMaxSendLines)));
m_sending = true; m_sending = true;
m_ipcServer.send(message, kIpcClientGui); m_ipcServer.send(message, kIpcClientGui);
m_sending = false; m_sending = false;

View File

@ -41,9 +41,9 @@
#include "base/IEventQueue.h" #include "base/IEventQueue.h"
#include "base/TMethodEventJob.h" #include "base/TMethodEventJob.h"
#include "base/TMethodJob.h" #include "base/TMethodJob.h"
#include "common/win32/KnownFolderPaths.h"
#include <string.h> #include <string.h>
#include <Shlobj.h>
#include <comutil.h> #include <comutil.h>
#include <algorithm> #include <algorithm>
@ -1916,14 +1916,12 @@ const std::string&
MSWindowsScreen::getDropTarget() const MSWindowsScreen::getDropTarget() const
{ {
if (m_dropTargetPath.empty()) { if (m_dropTargetPath.empty()) {
// SHGetFolderPath is deprecated in vista, but use it for xp support. m_dropTargetPath = desktopPath();
char desktopPath[MAX_PATH]; if (!m_dropTargetPath.empty()) {
if (SUCCEEDED(SHGetFolderPath(NULL, CSIDL_DESKTOP, NULL, 0, desktopPath))) { LOG((CLOG_DEBUG "using desktop for drop target: %s", m_dropTargetPath.c_str()));
m_dropTargetPath = std::string(desktopPath);
LOG((CLOG_INFO "using desktop for drop target: %s", m_dropTargetPath.c_str()));
} }
else { else {
LOG((CLOG_ERR "failed to get desktop path, no drop target available, error=%d", GetLastError())); LOG((CLOG_ERR "failed to get desktop path, no drop target available"));
} }
} }
return m_dropTargetPath; return m_dropTargetPath;