Merge branch 'release/2.4.2' into develop
This commit is contained in:
89
src/core/Alloc.cpp
Normal file
89
src/core/Alloc.cpp
Normal file
@@ -0,0 +1,89 @@
|
||||
/*
|
||||
* Copyright (C) 2019 KeePassXC Team <team@keepassxc.org>
|
||||
*
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 2 or (at your option)
|
||||
* version 3 of the License.
|
||||
*
|
||||
* 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 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 <QtGlobal>
|
||||
#include <cstdint>
|
||||
#include <sodium.h>
|
||||
#ifdef Q_OS_MACOS
|
||||
#include <malloc/malloc.h>
|
||||
#else
|
||||
#include <malloc.h>
|
||||
#endif
|
||||
|
||||
#if defined(NDEBUG) && !defined(__cpp_sized_deallocation)
|
||||
#warning "KeePassXC is being compiled without sized deallocation support. Deletes may be slow."
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Custom sized delete operator which securely zeroes out allocated
|
||||
* memory before freeing it (requires C++14 sized deallocation support).
|
||||
*/
|
||||
void operator delete(void* ptr, std::size_t size) noexcept
|
||||
{
|
||||
if (!ptr) {
|
||||
return;
|
||||
}
|
||||
|
||||
sodium_memzero(ptr, size);
|
||||
std::free(ptr);
|
||||
}
|
||||
|
||||
void operator delete[](void* ptr, std::size_t size) noexcept
|
||||
{
|
||||
::operator delete(ptr, size);
|
||||
}
|
||||
|
||||
/**
|
||||
* Custom delete operator which securely zeroes out
|
||||
* allocated memory before freeing it.
|
||||
*/
|
||||
void operator delete(void* ptr) noexcept
|
||||
{
|
||||
if (!ptr) {
|
||||
return;
|
||||
}
|
||||
|
||||
#if defined(Q_OS_WIN)
|
||||
::operator delete(ptr, _msize(ptr));
|
||||
#elif defined(Q_OS_MACOS)
|
||||
::operator delete(ptr, malloc_size(ptr));
|
||||
#elif defined(Q_OS_UNIX)
|
||||
::operator delete(ptr, malloc_usable_size(ptr));
|
||||
#else
|
||||
// whatever OS this is, give up and simply free stuff
|
||||
std::free(ptr);
|
||||
#endif
|
||||
}
|
||||
|
||||
void operator delete[](void* ptr) noexcept
|
||||
{
|
||||
::operator delete(ptr);
|
||||
}
|
||||
|
||||
/**
|
||||
* Custom insecure delete operator that does not zero out memory before
|
||||
* freeing a buffer. Can be used for better performance.
|
||||
*/
|
||||
void operator delete(void* ptr, bool) noexcept
|
||||
{
|
||||
std::free(ptr);
|
||||
}
|
||||
|
||||
void operator delete[](void* ptr, bool) noexcept
|
||||
{
|
||||
::operator delete(ptr, false);
|
||||
}
|
||||
@@ -85,6 +85,12 @@ namespace Bootstrap
|
||||
bootstrap();
|
||||
MessageBox::initializeButtonDefs();
|
||||
|
||||
#ifdef KEEPASSXC_DIST_SNAP
|
||||
// snap: force fallback theme to avoid using system theme (gtk integration)
|
||||
// with missing actions just like on Windows and macOS
|
||||
QIcon::setThemeSearchPaths(QStringList() << ":/icons");
|
||||
#endif
|
||||
|
||||
#ifdef Q_OS_MACOS
|
||||
// Don't show menu icons on OSX
|
||||
QApplication::setAttribute(Qt::AA_DontShowIconsInMenus);
|
||||
|
||||
@@ -16,9 +16,12 @@
|
||||
*/
|
||||
|
||||
#include "CustomData.h"
|
||||
#include "Clock.h"
|
||||
|
||||
#include "core/Global.h"
|
||||
|
||||
const QString CustomData::LastModified = "_LAST_MODIFIED";
|
||||
|
||||
CustomData::CustomData(QObject* parent)
|
||||
: QObject(parent)
|
||||
{
|
||||
@@ -60,6 +63,7 @@ void CustomData::set(const QString& key, const QString& value)
|
||||
|
||||
if (addAttribute || changeValue) {
|
||||
m_data.insert(key, value);
|
||||
updateLastModified();
|
||||
emit customDataModified();
|
||||
}
|
||||
|
||||
@@ -74,6 +78,7 @@ void CustomData::remove(const QString& key)
|
||||
|
||||
m_data.remove(key);
|
||||
|
||||
updateLastModified();
|
||||
emit removed(key);
|
||||
emit customDataModified();
|
||||
}
|
||||
@@ -94,6 +99,7 @@ void CustomData::rename(const QString& oldKey, const QString& newKey)
|
||||
m_data.remove(oldKey);
|
||||
m_data.insert(newKey, data);
|
||||
|
||||
updateLastModified();
|
||||
emit customDataModified();
|
||||
emit renamed(oldKey, newKey);
|
||||
}
|
||||
@@ -108,9 +114,19 @@ void CustomData::copyDataFrom(const CustomData* other)
|
||||
|
||||
m_data = other->m_data;
|
||||
|
||||
updateLastModified();
|
||||
emit reset();
|
||||
emit customDataModified();
|
||||
}
|
||||
|
||||
QDateTime CustomData::getLastModified() const
|
||||
{
|
||||
if (m_data.contains(LastModified)) {
|
||||
return Clock::parse(m_data.value(LastModified));
|
||||
}
|
||||
return {};
|
||||
}
|
||||
|
||||
bool CustomData::operator==(const CustomData& other) const
|
||||
{
|
||||
return (m_data == other.m_data);
|
||||
@@ -152,3 +168,13 @@ int CustomData::dataSize() const
|
||||
}
|
||||
return size;
|
||||
}
|
||||
|
||||
void CustomData::updateLastModified()
|
||||
{
|
||||
if (m_data.size() == 1 && m_data.contains(LastModified)) {
|
||||
m_data.remove(LastModified);
|
||||
return;
|
||||
}
|
||||
|
||||
m_data.insert(LastModified, Clock::currentDateTimeUtc().toString());
|
||||
}
|
||||
|
||||
@@ -42,9 +42,12 @@ public:
|
||||
int size() const;
|
||||
int dataSize() const;
|
||||
void copyDataFrom(const CustomData* other);
|
||||
QDateTime getLastModified() const;
|
||||
bool operator==(const CustomData& other) const;
|
||||
bool operator!=(const CustomData& other) const;
|
||||
|
||||
static const QString LastModified;
|
||||
|
||||
signals:
|
||||
void customDataModified();
|
||||
void aboutToBeAdded(const QString& key);
|
||||
@@ -55,6 +58,10 @@ signals:
|
||||
void renamed(const QString& oldKey, const QString& newKey);
|
||||
void aboutToBeReset();
|
||||
void reset();
|
||||
void lastModified();
|
||||
|
||||
private slots:
|
||||
void updateLastModified();
|
||||
|
||||
private:
|
||||
QHash<QString, QString> m_data;
|
||||
|
||||
@@ -609,9 +609,6 @@ Merger::ChangeList Merger::mergeMetadata(const MergeContext& context)
|
||||
// TODO HNH: missing handling of recycle bin, names, templates for groups and entries,
|
||||
// public data (entries of newer dict override keys of older dict - ignoring
|
||||
// their own age - it is enough if one entry of the whole dict is newer) => possible lost update
|
||||
// TODO HNH: CustomData is merged with entries of the new customData overwrite entries
|
||||
// of the older CustomData - the dict with the newest entry is considered
|
||||
// newer regardless of the age of the other entries => possible lost update
|
||||
ChangeList changes;
|
||||
auto* sourceMetadata = context.m_sourceDb->metadata();
|
||||
auto* targetMetadata = context.m_targetDb->metadata();
|
||||
@@ -624,5 +621,32 @@ Merger::ChangeList Merger::mergeMetadata(const MergeContext& context)
|
||||
changes << tr("Adding missing icon %1").arg(QString::fromLatin1(customIconId.toRfc4122().toHex()));
|
||||
}
|
||||
}
|
||||
|
||||
// Merge Custom Data if source is newer
|
||||
const auto targetCustomDataModificationTime = sourceMetadata->customData()->getLastModified();
|
||||
const auto sourceCustomDataModificationTime = targetMetadata->customData()->getLastModified();
|
||||
if (!targetMetadata->customData()->contains(CustomData::LastModified) ||
|
||||
(targetCustomDataModificationTime.isValid() && sourceCustomDataModificationTime.isValid() &&
|
||||
targetCustomDataModificationTime > sourceCustomDataModificationTime)) {
|
||||
const auto sourceCustomDataKeys = sourceMetadata->customData()->keys();
|
||||
const auto targetCustomDataKeys = targetMetadata->customData()->keys();
|
||||
|
||||
// Check missing keys from source. Remove those from target
|
||||
for (const auto& key : targetCustomDataKeys) {
|
||||
if (!sourceMetadata->customData()->contains(key)) {
|
||||
auto value = targetMetadata->customData()->value(key);
|
||||
targetMetadata->customData()->remove(key);
|
||||
changes << tr("Removed custom data %1 [%2]").arg(key, value);
|
||||
}
|
||||
}
|
||||
|
||||
// Transfer new/existing keys
|
||||
for (const auto& key : sourceCustomDataKeys) {
|
||||
auto value = sourceMetadata->customData()->value(key);
|
||||
targetMetadata->customData()->set(key, value);
|
||||
changes << tr("Adding custom data %1 [%2]").arg(key, value);
|
||||
}
|
||||
}
|
||||
|
||||
return changes;
|
||||
}
|
||||
|
||||
@@ -195,7 +195,7 @@ QPixmap Metadata::customIconScaledPixmap(const QUuid& uuid) const
|
||||
QPixmapCache::Key& cacheKey = m_customIconScaledCacheKeys[uuid];
|
||||
|
||||
if (!QPixmapCache::find(cacheKey, &pixmap)) {
|
||||
QImage image = m_customIcons.value(uuid).scaled(16, 16, Qt::KeepAspectRatio, Qt::SmoothTransformation);
|
||||
QImage image = m_customIcons.value(uuid).scaled(16, 16, Qt::IgnoreAspectRatio, Qt::SmoothTransformation);
|
||||
pixmap = QPixmap::fromImage(image);
|
||||
cacheKey = QPixmapCache::insert(pixmap);
|
||||
}
|
||||
|
||||
@@ -34,13 +34,14 @@
|
||||
*/
|
||||
void Translator::installTranslators()
|
||||
{
|
||||
QLocale locale;
|
||||
QString language = config()->get("GUI/Language").toString();
|
||||
if (language == "system" || language.isEmpty()) {
|
||||
language = QLocale::system().name();
|
||||
}
|
||||
if (language == "en") {
|
||||
if (!language.isEmpty() && language != "system") {
|
||||
// use actual English translation instead of the English locale source language
|
||||
language = "en_US";
|
||||
if (language == "en") {
|
||||
language = "en_US";
|
||||
}
|
||||
locale = QLocale(language);
|
||||
}
|
||||
|
||||
const QStringList paths = {
|
||||
@@ -51,11 +52,12 @@ void Translator::installTranslators()
|
||||
|
||||
bool translationsLoaded = false;
|
||||
for (const QString& path : paths) {
|
||||
translationsLoaded |= installTranslator(language, path) || installTranslator("en_US", path);
|
||||
translationsLoaded |= installTranslator(locale, path) || installTranslator(QLocale("en_US"), path);
|
||||
if (!installQtTranslator(language, path)) {
|
||||
installQtTranslator("en", path);
|
||||
installQtTranslator(QLocale("en"), path);
|
||||
}
|
||||
}
|
||||
|
||||
if (!translationsLoaded) {
|
||||
// couldn't load configured language or fallback
|
||||
qWarning("Couldn't load translations.");
|
||||
@@ -114,10 +116,10 @@ QList<QPair<QString, QString>> Translator::availableLanguages()
|
||||
* @param path local search path
|
||||
* @return true on success
|
||||
*/
|
||||
bool Translator::installTranslator(const QString& language, const QString& path)
|
||||
bool Translator::installTranslator(const QLocale& locale, const QString& path)
|
||||
{
|
||||
QScopedPointer<QTranslator> translator(new QTranslator(qApp));
|
||||
if (translator->load(QString("keepassx_%1").arg(language), path)) {
|
||||
if (translator->load(locale, "keepassx_", "", path)) {
|
||||
return QCoreApplication::installTranslator(translator.take());
|
||||
}
|
||||
return false;
|
||||
@@ -131,13 +133,12 @@ bool Translator::installTranslator(const QString& language, const QString& path)
|
||||
* @param path local search path
|
||||
* @return true on success
|
||||
*/
|
||||
bool Translator::installQtTranslator(const QString& language, const QString& path)
|
||||
bool Translator::installQtTranslator(const QLocale& locale, const QString& path)
|
||||
{
|
||||
QScopedPointer<QTranslator> qtTranslator(new QTranslator(qApp));
|
||||
if (qtTranslator->load(QString("qtbase_%1").arg(language), path)) {
|
||||
if (qtTranslator->load(locale, "qtbase_", "", path)) {
|
||||
return QCoreApplication::installTranslator(qtTranslator.take());
|
||||
} else if (qtTranslator->load(QString("qtbase_%1").arg(language),
|
||||
QLibraryInfo::location(QLibraryInfo::TranslationsPath))) {
|
||||
} else if (qtTranslator->load(locale, "qtbase_", "", QLibraryInfo::location(QLibraryInfo::TranslationsPath))) {
|
||||
return QCoreApplication::installTranslator(qtTranslator.take());
|
||||
}
|
||||
return false;
|
||||
|
||||
@@ -20,6 +20,7 @@
|
||||
|
||||
#include <QPair>
|
||||
#include <QString>
|
||||
#include <QLocale>
|
||||
|
||||
class Translator
|
||||
{
|
||||
@@ -28,8 +29,8 @@ public:
|
||||
static QList<QPair<QString, QString>> availableLanguages();
|
||||
|
||||
private:
|
||||
static bool installTranslator(const QString& language, const QString& path);
|
||||
static bool installQtTranslator(const QString& language, const QString& path);
|
||||
static bool installTranslator(const QLocale& locale, const QString& path);
|
||||
static bool installQtTranslator(const QLocale& locale, const QString& path);
|
||||
};
|
||||
|
||||
#endif // KEEPASSX_TRANSLATOR_H
|
||||
|
||||
Reference in New Issue
Block a user