// Ryzom - MMORPG Framework // Copyright (C) 2010 Winch Gate Property Limited // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU Affero General Public License as // published by the Free Software Foundation, either version 3 of the // License, or (at your option) any later version. // // This program 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 Affero General Public License for more details. // // You should have received a copy of the GNU Affero General Public License // along with this program. If not, see . #include "stdpch.h" #include "utils.h" #include "nel/misc/path.h" #ifdef DEBUG_NEW #define new DEBUG_NEW #endif QString qBytesToHumanReadable(qint64 bytes) { static std::vector units; if (units.empty()) { units.push_back(QObject::tr("B").toUtf8().constData()); units.push_back(QObject::tr("KiB").toUtf8().constData()); units.push_back(QObject::tr("MiB").toUtf8().constData()); units.push_back(QObject::tr("GiB").toUtf8().constData()); units.push_back(QObject::tr("TiB").toUtf8().constData()); units.push_back(QObject::tr("PiB").toUtf8().constData()); } return QString::fromUtf8(NLMISC::bytesToHumanReadableUnits(bytes, units).c_str()); } bool isDirectoryEmpty(const QString &directory, bool recursize) { bool res = true; if (!directory.isEmpty()) { QDir dir(directory); if (dir.exists()) { QFileInfoList list = dir.entryInfoList(QDir::Files | QDir::Dirs | QDir::Hidden | QDir::NoSymLinks | QDir::NoDotAndDotDot); for (int i = 0; i < list.size(); ++i) { QFileInfo fileInfo = list.at(i); if (fileInfo.isDir()) { if (recursize) if (!isDirectoryEmpty(fileInfo.absoluteFilePath(), true)) return false; } else { return false; } } } } return res; } qint64 getDirectorySize(const QString &directory, bool recursize) { qint64 size = 0; if (!directory.isEmpty()) { QDir dir(directory); if (dir.exists()) { QFileInfoList list = dir.entryInfoList(QDir::Files | QDir::Dirs | QDir::Hidden | QDir::NoSymLinks | QDir::NoDotAndDotDot); for (int i = 0; i < list.size(); ++i) { QFileInfo fileInfo = list.at(i); if (fileInfo.isDir()) { if (recursize) size += getDirectorySize(fileInfo.absoluteFilePath(), true); } else { size += fileInfo.size(); } } } } return size; } QString qFromUtf8(const std::string &str) { return QString::fromUtf8(str.c_str()); } std::string qToUtf8(const QString &str) { return str.toUtf8().constData(); } QString qFromUtf16(const ucstring &str) { return QString::fromUtf16(str.c_str()); } ucstring qToUtf16(const QString &str) { return ucstring::makeFromUtf8(qToUtf8(str)); } QString qFromWide(const wchar_t *str) { return QString::fromUtf16((ushort*)str); } wchar_t* qToWide(const QString &str) { return (wchar_t*)str.utf16(); } bool shortcutExists(const QString &shortcut) { return !shortcut.isEmpty() && NLMISC::CFile::isExists(qToUtf8(appendShortcutExtension(shortcut))); } #ifdef Q_OS_WIN32 bool createShortcut(const QString &shortcut, const QString &name, const QString &executable, const QString &arguments, const QString &icon, const QString &workingDir) { CCOMHelper comHelper; IShellLinkW* psl; // Get a pointer to the IShellLink interface. It is assumed that CoInitialize // has already been called. HRESULT hres = CoCreateInstance(CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER, IID_IShellLinkW, (LPVOID*)&psl); if (SUCCEEDED(hres)) { IPersistFile* ppf = NULL; // Set the path to the shortcut target and add the description. psl->SetPath(qToWide(QDir::toNativeSeparators(executable))); psl->SetIconLocation(qToWide(QDir::toNativeSeparators(icon)), 0); psl->SetDescription(qToWide(name)); psl->SetArguments(qToWide(arguments)); psl->SetWorkingDirectory(qToWide(QDir::toNativeSeparators(workingDir))); // Query IShellLink for the IPersistFile interface, used for saving the shortcut in persistent storage. hres = psl->QueryInterface(IID_IPersistFile, (LPVOID*)&ppf); if (SUCCEEDED(hres)) { QString path(shortcut + ".lnk"); // Save the link by calling IPersistFile::Save. hres = ppf->Save(qToWide(QDir::toNativeSeparators(path)), TRUE); ppf->Release(); } psl->Release(); } return SUCCEEDED(hres); } bool resolveShortcut(const QWidget &window, const QString &shortcut, QString &path) { CCOMHelper comHelper; IShellLinkW* psl; WIN32_FIND_DATAW wfd; path.clear(); // Assume failure // Get a pointer to the IShellLink interface. It is assumed that CoInitialize // has already been called. HRESULT hres = CoCreateInstance(CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER, IID_IShellLink, (LPVOID*)&psl); if (SUCCEEDED(hres)) { IPersistFile* ppf; // Get a pointer to the IPersistFile interface. hres = psl->QueryInterface(IID_IPersistFile, (void**)&ppf); if (SUCCEEDED(hres)) { // Add code here to check return value from MultiByteWideChar // for success. // Load the shortcut. hres = ppf->Load(qToWide(QDir::toNativeSeparators(shortcut)), STGM_READ); if (SUCCEEDED(hres)) { // Resolve the link. hres = psl->Resolve((HWND)window.winId(), 0); if (SUCCEEDED(hres)) { WCHAR szGotPath[MAX_PATH]; // Get the path to the link target. hres = psl->GetPath(szGotPath, MAX_PATH, (WIN32_FIND_DATAW*)&wfd, SLGP_SHORTPATH); if (SUCCEEDED(hres)) { WCHAR szDescription[MAX_PATH]; // Get the description of the target. hres = psl->GetDescription(szDescription, MAX_PATH); if (SUCCEEDED(hres)) { // Handle success path = QDir::fromNativeSeparators(qFromWide(szGotPath)); } } } } // Release the pointer to the IPersistFile interface. ppf->Release(); } // Release the pointer to the IShellLink interface. psl->Release(); } return SUCCEEDED(hres); } #else bool createShortcut(const QString &shortcut, const QString &name, const QString &executable, const QString &arguments, const QString &icon, const QString &workingDir) { // open template QFile file(":/templates/template.desktop"); if (!file.open(QFile::ReadOnly)) return false; QString data = QString::fromUtf8(file.readAll()); file.close(); // build command QString command = executable; if (!arguments.isEmpty()) command += " " + arguments; // replace strings data.replace("$NAME", name); data.replace("$COMMAND", command); data.replace("$ICON", icon); QString path(shortcut + ".desktop"); // write file file.setFileName(path); if (!file.open(QFile::WriteOnly)) return false; file.write(data.toUtf8()); file.close(); // set executable flags to .desktop QFile::setPermissions(path, QFile::permissions(path) | QFile::ExeGroup | QFile::ExeUser | QFile::ExeOther); return true; } bool resolveShortcut(const QWidget &window, const QString &pathLink, QString &pathObj) { return false; } #endif bool removeShortcut(const QString &shortcut) { // empty links are invalid if (shortcut.isEmpty()) return false; // append extension if missing QString fullPath = appendShortcutExtension(shortcut); // link doesn't exist if (!NLMISC::CFile::isExists(qToUtf8(fullPath))) return false; // remove it return QFile::remove(fullPath); } QString appendShortcutExtension(const QString &shortcut) { QString extension; #if defined(Q_OS_WIN32) extension = ".lnk"; #elif defined(Q_OS_MAC) // TODO #else extension = ".desktop"; #endif // already the good extension if (shortcut.indexOf(extension) > -1) return shortcut; return shortcut + extension; } QString getVersionFromExecutable(const QString &path) { // launch executable with --version argument QProcess process; process.setProcessChannelMode(QProcess::MergedChannels); process.start(path, QStringList() << "--version", QIODevice::ReadWrite); if (!process.waitForStarted()) return ""; QByteArray data; // read all output while (process.waitForReadyRead(1000)) data.append(process.readAll()); if (!data.isEmpty()) { QString versionString = QString::fromUtf8(data); // parse version from output (client) QRegExp reg("([A-Za-z0-1_.]+) ((DEV|FV) ([0-9.]+))"); if (reg.indexIn(versionString) > -1) return reg.cap(2); // parse version from output (other tools) reg.setPattern("([A-Za-z_ ]+) ([0-9.]+)"); if (reg.indexIn(versionString) > -1) return reg.cap(2); } #ifdef Q_OS_WIN // try to parse version of executable in resources DWORD verHandle = NULL; uint size = 0; VS_FIXEDFILEINFO *verInfo = NULL; // get size to be allocated uint32_t verSize = GetFileVersionInfoSizeW(qToWide(path), &verHandle); if (!verSize) return ""; // allocate buffer QScopedArrayPointer verData(new char[verSize]); // get pointer on version structure if (!GetFileVersionInfoW(qToWide(path), verHandle, verSize, &verData[0])) return ""; // get pointer on version if (!VerQueryValueA(&verData[0], "\\", (void**)&verInfo, &size)) return ""; // check if version is right if (size && verInfo && verInfo->dwSignature == 0xfeef04bd) { // Doesn't matter if you are on 32 bit or 64 bit, // DWORD is always 32 bits, so first two revision numbers // come from dwFileVersionMS, last two come from dwFileVersionLS return QString("%1.%2.%3.%4") .arg((verInfo->dwFileVersionMS >> 16) & 0xffff) .arg((verInfo->dwFileVersionMS >> 0) & 0xffff) .arg((verInfo->dwFileVersionLS >> 16) & 0xffff) .arg((verInfo->dwFileVersionLS >> 0) & 0xffff); } #endif return ""; } CCOMHelper::CCOMHelper() { #ifdef Q_OS_WIN // to fix the bug with QFileDialog::getExistingDirectory hanging under Windows m_mustUninit = SUCCEEDED(CoInitialize(NULL)); #else m_mustUninit = false; #endif } CCOMHelper::~CCOMHelper() { #ifdef Q_OS_WIN // only call CoUninitialize if CoInitialize succeeded if (m_mustUninit) CoUninitialize(); #endif }