Compare commits

..

3 Commits

Author SHA1 Message Date
Felix Geyer
c8857ac2ba Finalize changelog. 2016-09-04 17:57:47 +02:00
Felix Geyer
367fbbba39 Update translations. 2016-09-04 17:14:15 +02:00
Felix Geyer
abf469f743 Prepare for 2.0.3 release. 2016-09-03 22:05:22 +02:00
216 changed files with 6227 additions and 4798 deletions

View File

@@ -1,32 +1,20 @@
language: cpp
sudo: required
dist: trusty
os:
- linux
# - osx
- osx
compiler:
- gcc
# - clang
git:
depth: 3
before_install:
- clang
language: cpp
install:
- if [ "$TRAVIS_OS_NAME" = "linux" ]; then sudo apt-get -qq update; fi
- if [ "$TRAVIS_OS_NAME" = "linux" ]; then sudo apt-get -qq install cmake libmicrohttpd10 libmicrohttpd-dev libxi-dev qtbase5-dev libqt5x11extras5-dev qttools5-dev qttools5-dev-tools libgcrypt20-dev zlib1g-dev libxtst-dev xvfb; fi
- if [ "$TRAVIS_OS_NAME" = "linux" ]; then sudo apt-get -qq install cmake libqt4-dev libgcrypt11-dev zlib1g-dev libxtst-dev; fi
- if [ "$TRAVIS_OS_NAME" = "osx" ]; then brew update; fi
- if [ "$TRAVIS_OS_NAME" = "osx" ]; then brew ls | grep -wq cmake || brew install cmake; fi
- if [ "$TRAVIS_OS_NAME" = "osx" ]; then brew ls | grep -wq qt5 || brew install qt5; fi
- if [ "$TRAVIS_OS_NAME" = "osx" ]; then brew ls | grep -wq qt || brew install qt; fi
- if [ "$TRAVIS_OS_NAME" = "osx" ]; then brew ls | grep -wq libgcrypt || brew install libgcrypt; fi
before_script:
- if [ "$TRAVIS_OS_NAME" = "osx" ]; then CMAKE_ARGS="-DCMAKE_PREFIX_PATH=/usr/local/opt/qt5"; fi
- mkdir build && pushd build
before_script: mkdir build && pushd build
script:
- cmake -DCMAKE_BUILD_TYPE=Release -DWITH_GUI_TESTS=ON $CMAKE_ARGS ..
- cmake -DCMAKE_BUILD_TYPE=Debug -DWITH_GUI_TESTS=ON ..
- make
- if [ "$TRAVIS_OS_NAME" = "linux" ]; then make test ARGS+="-E testgui --output-on-failure"; fi
- if [ "$TRAVIS_OS_NAME" = "linux" ]; then xvfb-run -a --server-args="-screen 0 800x600x24" make test ARGS+="-R testgui --output-on-failure"; fi

View File

@@ -21,7 +21,7 @@ endif()
project(KeePassX)
cmake_minimum_required(VERSION 2.8.12)
cmake_minimum_required(VERSION 2.6.4)
set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} ${CMAKE_CURRENT_SOURCE_DIR}/cmake)
@@ -31,7 +31,7 @@ include(CheckCXXSourceCompiles)
option(WITH_TESTS "Enable building of unit tests" ON)
option(WITH_GUI_TESTS "Enable building of GUI tests" OFF)
option(WITH_DEV_BUILD "Use only for development. Disables/warns about deprecated methods." OFF)
option(WITH_CXX11 "Build with the C++ 11 standard" ON)
set(KEEPASSX_VERSION "2.0.3")
set(KEEPASSX_VERSION_NUM "2.0.3")
@@ -61,7 +61,7 @@ macro(add_gcc_compiler_flags FLAGS)
add_gcc_compiler_cflags("${FLAGS}")
endmacro(add_gcc_compiler_flags)
add_definitions(-DQT_NO_KEYWORDS -DQT_NO_EXCEPTIONS -DQT_STRICT_ITERATORS -DQT_NO_CAST_TO_ASCII)
add_definitions(-DQT_NO_KEYWORDS -DQT_NO_EXCEPTIONS -DQT_NO_STL -DQT_STRICT_ITERATORS -DQT_NO_CAST_TO_ASCII)
add_gcc_compiler_flags("-fno-common -fstack-protector --param=ssp-buffer-size=4")
add_gcc_compiler_flags("-Wall -Wextra -Wundef -Wpointer-arith -Wno-long-long")
@@ -100,16 +100,14 @@ if(CMAKE_SYSTEM_NAME STREQUAL "Linux")
set(CMAKE_MODULE_LINKER_FLAGS "${CMAKE_MODULE_LINKER_FLAGS} -Wl,-z,relro")
endif()
add_gcc_compiler_cxxflags("-std=c++11")
if(APPLE)
add_gcc_compiler_cxxflags("-stdlib=libc++")
endif()
add_gcc_compiler_cflags("-ansi")
if(WITH_DEV_BUILD)
add_definitions(-DQT_DEPRECATED_WARNINGS -DGCRYPT_NO_DEPRECATED)
if (WITH_CXX11)
add_gcc_compiler_cxxflags("-std=c++0x")
add_gcc_compiler_cflags("-ansi")
if(APPLE)
add_gcc_compiler_cxxflags("-stdlib=libc++")
endif()
else()
add_gcc_compiler_flags("-ansi")
endif()
if(MINGW)
@@ -148,21 +146,19 @@ if(WITH_TESTS)
enable_testing()
endif(WITH_TESTS)
find_package(Qt5Core 5.2 REQUIRED)
find_package(Qt5Concurrent 5.2 REQUIRED)
find_package(Qt5Widgets 5.2 REQUIRED)
find_package(Qt5Test 5.2 REQUIRED)
find_package(Qt5LinguistTools 5.2 REQUIRED)
find_package(Qt5Network 5.2 REQUIRED)
set(CMAKE_AUTOMOC ON)
set(QT_REQUIRED_MODULES QtCore QtGui QtTest)
find_package(Qt4 4.6.0 REQUIRED ${QT_REQUIRED_MODULES})
include(${QT_USE_FILE})
# Debian sets the the build type to None for package builds.
# Make sure we don't enable asserts there.
set_property(DIRECTORY APPEND PROPERTY COMPILE_DEFINITIONS_NONE QT_NO_DEBUG)
find_package(Gcrypt 1.6.0 REQUIRED)
find_package(LibMicroHTTPD REQUIRED)
find_package(Gcrypt REQUIRED)
if(NOT (${GCRYPT_VERSION_STRING} VERSION_LESS "1.6.0"))
message(STATUS "Gcrypt ${GCRYPT_VERSION_STRING} supports the SALSA20 cipher")
set(GCRYPT_HAS_SALSA20 1)
endif()
find_package(ZLIB REQUIRED)
@@ -203,7 +199,10 @@ endif()
include_directories(SYSTEM ${GCRYPT_INCLUDE_DIR} ${ZLIB_INCLUDE_DIR})
include(FeatureSummary)
if(NOT (${CMAKE_VERSION} VERSION_LESS 2.8.3))
set(PRINT_SUMMARY ON)
include(FeatureSummary)
endif()
add_subdirectory(src)
add_subdirectory(share)

View File

@@ -1,35 +1,68 @@
# KeePassX v2.0.2 + keepasshttp
![alt text](https://travis-ci.org/keepassxreboot/keepassx.svg?branch=master "Travis-CI Badge")
# KeePassX
## About
Fork of [KeePassX](https://www.keepassx.org/) with keepasshttp support for use with [PassIFox](https://addons.mozilla.org/en-us/firefox/addon/passifox/) for Mozilla Firefox and [chromeIPass](https://chrome.google.com/webstore/detail/chromeipass/ompiailgknfdndiefoaoiligalphfdae) for Google Chrome.
KeePassX is an application for people with extremely high demands on secure personal data management.
It has a light interface, is cross platform and published under the terms of the GNU General Public License.
KeePassHttp implementation has been forked from jdachtera's repository, which in turn was based on code from code with Francois Ferrand's [keepassx-http](https://gitorious.org/keepassx/keepassx-http/source/master:) repository.
KeePassX saves many different information e.g. user names, passwords, urls, attachments and comments in one single database.
For a better management user-defined titles and icons can be specified for each single entry.
Furthermore the entries are sorted in groups, which are customizable as well. The integrated search function allows to search in a single group or the complete database.
KeePassX offers a little utility for secure password generation. The password generator is very customizable, fast and easy to use.
Especially someone who generates passwords frequently will appreciate this feature.
This is a rebuild from [denk-mal's keepasshttp](https://github.com/denk-mal/keepassx.git) that brings it forward to Qt5 and KeePassX v2.0.2.
The complete database is always encrypted with the AES (aka Rijndael) encryption algorithm using a 256 bit key.
Therefore the saved information can be considered as quite safe. KeePassX uses a database format that is compatible with [KeePass Password Safe](http://keepass.info/).
This makes the use of that application even more favorable.
## Install
KeePassX can be downloaded and installed using an assortment of installers available on the main [KeePassX website](http://www.keepassx.org).
KeePassX can also be installed from the official repositories of many Linux repositories.
If you wish to build KeePassX from source, rather than rely on the pre-compiled binaries, you may wish to read up on the _From Source_ section.
### Debian
To install KeePassX from the Debian repository:
```bash
sudo apt-get install keepassx
```
### Red Hat
Install KeePassX from the Red Hat (or CentOS) repository:
```bash
sudo yum install keepassx
```
### Windows / Mac OS X
Download the installer from the KeePassX [download](https://www.keepassx.org/downloads) page.
Once downloaded, double click on the file to execute the installer.
### From Source
#### Build Dependencies
The following tools must exist within your PATH:
* make
* cmake (>= 2.8.12)
* g++ (>= 4.7) or clang++ (>= 3.0)
* cmake (>= 2.6.4)
* g++ or clang++
The following libraries are required:
* Qt 5 (>= 5.2): qtbase and qttools5
* libgcrypt (>= 1.6)
* Qt 4 (>= 4.6)
* libgcrypt
* zlib
* libmicrohttpd
* libxi, libxtst, qtx11extras (optional for auto-type on X11)
* libxi, libxtst (optional for auto-type on X11)
On Debian you can install them with:
```bash
sudo apt-get install build-essential cmake libmicrohttpd-dev libxi-dev qtbase5-dev libqt5x11extras5-dev qttools5-dev qttools5-dev-tools libgcrypt20-dev zlib1g-dev
sudo apt-get install build-essential cmake libqt4-dev libgcrypt11-dev zlib1g-dev libxi-dev libxtst-dev
```
#### Build Steps
@@ -39,7 +72,7 @@ To compile from source:
```bash
mkdir build
cd build
cmake -DWITH_TESTS=OFF ..
cmake ..
make [-jX]
```
@@ -88,7 +121,7 @@ Our software isn't always perfect, but we strive to always improve our work. You
Along with our desire to hear your feedback and suggestions, we're also interested in accepting direct assistance in the form of code.
Issue merge requests against our [GitHub repository](https://github.com/keepassxreboot/keepassx).
Issue merge requests against our [GitHub repository](https://github.com/keepassx/keepassx).
### Translations

View File

@@ -1,9 +0,0 @@
find_path(MHD_INCLUDE_DIR microhttpd.h)
find_library(MHD_LIBRARIES microhttpd)
mark_as_advanced(MHD_LIBRARIES MHD_INCLUDE_DIR)
include(FindPackageHandleStandardArgs)
find_package_handle_standard_args(LibMicroHTTPD DEFAULT_MSG MHD_LIBRARIES MHD_INCLUDE_DIR)

View File

@@ -17,9 +17,9 @@ file(GLOB TRANSLATION_FILES *.ts)
get_filename_component(TRANSLATION_EN_ABS keepassx_en.ts ABSOLUTE)
list(REMOVE_ITEM TRANSLATION_FILES keepassx_en.ts)
list(REMOVE_ITEM TRANSLATION_FILES ${TRANSLATION_EN_ABS})
message(STATUS "${TRANSLATION_FILES}")
message(STATUS ${TRANSLATION_FILES})
qt5_add_translation(QM_FILES ${TRANSLATION_FILES})
qt4_add_translation(QM_FILES ${TRANSLATION_FILES})
install(FILES ${QM_FILES} DESTINATION ${DATA_INSTALL_DIR}/translations)
add_custom_target(translations DEPENDS ${QM_FILES})

View File

@@ -1295,14 +1295,6 @@ Dieser Vorgang ist nur in eine Richtung möglich. Die importierte Datenbank kann
<source>Hide window to system tray when minimized</source>
<translation>Fenster verstecken wenn minimiert</translation>
</message>
<message>
<source>Hide window to system tray instead of App Exit</source>
<translation>Fenster zu Taskleistensymbol minimieren statt Programm beenden</translation>
</message>
<message>
<source>Hide window to system tray on App start</source>
<translation>Fenster zu Taskleistensymbol minimieren wenn Programm started</translation>
</message>
<message>
<source>Remember last key files</source>
<translation>Letzte Schlüsseldateien merken</translation>

View File

@@ -1326,14 +1326,6 @@ This is a one-way migration. You won&apos;t be able to open the imported databas
<source>Remember last key files</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Hide window to system tray instead of App Exit</source>
<translation type="unfinished"></translation>
</message>
<message>
<source>Hide window to system tray on App start</source>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>SettingsWidgetSecurity</name>

View File

@@ -54,6 +54,9 @@ set(keepassx_SOURCES
core/ListDeleter.h
core/Metadata.cpp
core/PasswordGenerator.cpp
core/qlockfile.cpp
core/qsavefile.cpp
core/qsavefile_p.h
core/SignalMultiplexer.cpp
core/TimeDelta.cpp
core/TimeInfo.cpp
@@ -61,6 +64,8 @@ set(keepassx_SOURCES
core/Tools.cpp
core/Translator.cpp
core/Uuid.cpp
core/qcommandlineoption.cpp
core/qcommandlineparser.cpp
crypto/Crypto.cpp
crypto/CryptoHash.cpp
crypto/Random.cpp
@@ -116,14 +121,6 @@ set(keepassx_SOURCES
gui/group/EditGroupWidget.cpp
gui/group/GroupModel.cpp
gui/group/GroupView.cpp
http/AccessControlDialog.cpp
http/EntryConfig.cpp
http/HttpPasswordGeneratorWidget.cpp
http/HttpSettings.cpp
http/OptionDialog.cpp
http/Protocol.cpp
http/Server.cpp
http/Service.cpp
keys/CompositeKey.cpp
keys/CompositeKey_p.h
keys/FileKey.cpp
@@ -136,10 +133,94 @@ set(keepassx_SOURCES
streams/SymmetricCipherStream.cpp
)
if(NOT GCRYPT_HAS_SALSA20)
set(keepassx_SOURCES
${keepassx_SOURCES}
crypto/salsa20/ecrypt-config.h
crypto/salsa20/ecrypt-machine.h
crypto/salsa20/ecrypt-portable.h
crypto/salsa20/ecrypt-sync.h
crypto/salsa20/salsa20.c
crypto/SymmetricCipherSalsa20.cpp
)
endif()
if(UNIX)
set(keepassx_SOURCES
${keepassx_SOURCES}
core/qlockfile_unix.cpp
)
elseif(MINGW)
set(keepassx_SOURCES
${keepassx_SOURCES}
core/qlockfile_win.cpp
)
endif()
set(keepassx_SOURCES_MAINEXE
main.cpp
)
set(keepassx_MOC
autotype/AutoType.h
autotype/AutoTypeSelectDialog.h
autotype/AutoTypeSelectView.h
autotype/ShortcutWidget.h
autotype/WindowSelectComboBox.h
core/AutoTypeAssociations.h
core/Config.h
core/Database.h
core/Entry.h
core/EntryAttachments.h
core/EntryAttributes.h
core/Group.h
core/InactivityTimer.h
core/Metadata.h
core/qsavefile.h
gui/AboutDialog.h
gui/Application.h
gui/ChangeMasterKeyWidget.h
gui/Clipboard.h
gui/DatabaseOpenWidget.h
gui/DatabaseRepairWidget.h
gui/DatabaseSettingsWidget.h
gui/DatabaseTabWidget.h
gui/DatabaseWidget.h
gui/DatabaseWidgetStateSync.h
gui/DialogyWidget.h
gui/DragTabBar.h
gui/EditWidget.h
gui/EditWidgetIcons.h
gui/EditWidgetProperties.h
gui/IconModels.h
gui/KeePass1OpenWidget.h
gui/LineEdit.h
gui/MainWindow.h
gui/PasswordEdit.h
gui/PasswordGeneratorWidget.h
gui/PasswordComboBox.h
gui/SettingsWidget.h
gui/SortFilterHideProxyModel.h
gui/UnlockDatabaseWidget.h
gui/WelcomeWidget.h
gui/entry/AutoTypeAssociationsModel.h
gui/entry/EditEntryWidget.h
gui/entry/EntryAttachmentsModel.h
gui/entry/EntryAttributesModel.h
gui/entry/EntryHistoryModel.h
gui/entry/EntryModel.h
gui/entry/EntryView.h
gui/group/EditGroupWidget.h
gui/group/GroupModel.h
gui/group/GroupView.h
keys/CompositeKey_p.h
streams/HashedBlockStream.h
streams/LayeredStream.h
streams/qtiocompressor.h
streams/StoreDataStream.h
streams/SymmetricCipherStream.h
)
set(keepassx_FORMS
gui/AboutDialog.ui
gui/ChangeMasterKeyWidget.ui
@@ -159,9 +240,6 @@ set(keepassx_FORMS
gui/entry/EditEntryWidgetHistory.ui
gui/entry/EditEntryWidgetMain.ui
gui/group/EditGroupWidgetMain.ui
http/AccessControlDialog.ui
http/HttpPasswordGeneratorWidget.ui
http/OptionDialog.ui
)
if(MINGW)
@@ -170,20 +248,17 @@ if(MINGW)
${CMAKE_SOURCE_DIR}/share/windows/icon.rc)
endif()
qt5_wrap_ui(keepassx_SOURCES ${keepassx_FORMS})
qt4_wrap_ui(keepassx_SOURCES ${keepassx_FORMS})
qt4_wrap_cpp(keepassx_SOURCES ${keepassx_MOC})
add_library(keepassx_core STATIC ${keepassx_SOURCES})
set_target_properties(keepassx_core PROPERTIES COMPILE_DEFINITIONS KEEPASSX_BUILDING_CORE)
target_link_libraries(keepassx_core Qt5::Core Qt5::Concurrent Qt5::Widgets Qt5::Network)
add_executable(${PROGNAME} WIN32 MACOSX_BUNDLE ${keepassx_SOURCES_MAINEXE})
target_link_libraries(${PROGNAME}
keepassx_core
${MHD_LIBRARIES}
Qt5::Core
Qt5::Concurrent
Qt5::Widgets
Qt5::Network
${QT_QTCORE_LIBRARY}
${QT_QTGUI_LIBRARY}
${GCRYPT_LIBRARIES}
${ZLIB_LIBRARIES})
@@ -201,7 +276,7 @@ install(TARGETS ${PROGNAME}
add_subdirectory(autotype)
if(APPLE)
if(APPLE AND NOT (${CMAKE_VERSION} VERSION_LESS 2.8.8))
if(QT_MAC_USE_COCOA AND EXISTS "${QT_LIBRARY_DIR}/Resources/qt_menu.nib")
install(DIRECTORY "${QT_LIBRARY_DIR}/Resources/qt_menu.nib"
DESTINATION "${DATA_INSTALL_DIR}")
@@ -219,7 +294,7 @@ if(APPLE)
install_qt4_executable(${PROGNAME}.app "qjpeg;qgif;qico;qtaccessiblewidgets")
endif()
if(MINGW )
if(MINGW AND NOT (${CMAKE_VERSION} VERSION_LESS 2.8.8))
set(CPACK_GENERATOR "ZIP")
set(CPACK_STRIP_FILES ON)
set(CPACK_PACKAGE_FILE_NAME "${PROGNAME}-${KEEPASSX_VERSION_NUM}")

View File

@@ -32,7 +32,7 @@
#include "core/Tools.h"
#include "gui/MessageBox.h"
AutoType* AutoType::m_instance = nullptr;
AutoType* AutoType::m_instance = Q_NULLPTR;
AutoType::AutoType(QObject* parent, bool test)
: QObject(parent)
@@ -40,8 +40,8 @@ AutoType::AutoType(QObject* parent, bool test)
, m_currentGlobalKey(static_cast<Qt::Key>(0))
, m_currentGlobalModifiers(0)
, m_pluginLoader(new QPluginLoader(this))
, m_plugin(nullptr)
, m_executor(nullptr)
, m_plugin(Q_NULLPTR)
, m_executor(Q_NULLPTR)
, m_windowFromGlobal(0)
{
// prevent crash when the plugin has unresolved symbols
@@ -49,7 +49,7 @@ AutoType::AutoType(QObject* parent, bool test)
QString pluginName = "keepassx-autotype-";
if (!test) {
pluginName += QApplication::platformName();
pluginName += Tools::platform();
}
else {
pluginName += "test";
@@ -68,7 +68,7 @@ AutoType::~AutoType()
{
if (m_executor) {
delete m_executor;
m_executor = nullptr;
m_executor = Q_NULLPTR;
}
}
@@ -79,7 +79,7 @@ void AutoType::loadPlugin(const QString& pluginPath)
QObject* pluginInstance = m_pluginLoader->instance();
if (pluginInstance) {
m_plugin = qobject_cast<AutoTypePlatformInterface*>(pluginInstance);
m_executor = nullptr;
m_executor = Q_NULLPTR;
if (m_plugin) {
if (m_plugin->isAvailable()) {
@@ -157,7 +157,7 @@ void AutoType::performAutoType(const Entry* entry, QWidget* hideWindow, const QS
QCoreApplication::processEvents(QEventLoop::AllEvents, 10);
for (AutoTypeAction* action : asConst(actions)) {
Q_FOREACH (AutoTypeAction* action, actions) {
if (m_plugin->activeWindow() != window) {
qWarning("Active window changed, interrupting auto-type.");
break;
@@ -187,9 +187,8 @@ void AutoType::performGlobalAutoType(const QList<Database*>& dbList)
QList<Entry*> entryList;
QHash<Entry*, QString> sequenceHash;
for (Database* db : dbList) {
const QList<Entry*> dbEntries = db->rootGroup()->entriesRecursive();
for (Entry* entry : dbEntries) {
Q_FOREACH (Database* db, dbList) {
Q_FOREACH (Entry* entry, db->rootGroup()->entriesRecursive()) {
QString sequence = autoTypeSequence(entry, windowTitle);
if (!sequence.isEmpty()) {
entryList << entry;
@@ -203,11 +202,11 @@ void AutoType::performGlobalAutoType(const QList<Database*>& dbList)
QString message = tr("Couldn't find an entry that matches the window title:");
message.append("\n\n");
message.append(windowTitle);
MessageBox::information(nullptr, tr("Auto-Type - KeePassX"), message);
MessageBox::information(Q_NULLPTR, tr("Auto-Type - KeePassX"), message);
}
else if ((entryList.size() == 1) && !config()->get("security/autotypeask").toBool()) {
m_inAutoType = false;
performAutoType(entryList.first(), nullptr, sequenceHash[entryList.first()]);
performAutoType(entryList.first(), Q_NULLPTR, sequenceHash[entryList.first()]);
}
else {
m_windowFromGlobal = m_plugin->activeWindow();
@@ -229,7 +228,7 @@ void AutoType::performAutoTypeFromGlobal(Entry* entry, const QString& sequence)
m_plugin->raiseWindow(m_windowFromGlobal);
m_inAutoType = false;
performAutoType(entry, nullptr, sequence, m_windowFromGlobal);
performAutoType(entry, Q_NULLPTR, sequence, m_windowFromGlobal);
}
void AutoType::resetInAutoType()
@@ -243,12 +242,12 @@ void AutoType::unloadPlugin()
{
if (m_executor) {
delete m_executor;
m_executor = nullptr;
m_executor = Q_NULLPTR;
}
if (m_plugin) {
m_plugin->unload();
m_plugin = nullptr;
m_plugin = Q_NULLPTR;
}
}
@@ -301,7 +300,7 @@ bool AutoType::parseActions(const QString& sequence, const Entry* entry, QList<A
QString tmpl;
bool inTmpl = false;
for (const QChar& ch : sequence) {
Q_FOREACH (const QChar& ch, sequence) {
// TODO: implement support for {{}, {}} and {DELAY=X}
if (inTmpl) {
@@ -483,10 +482,10 @@ QList<AutoTypeAction*> AutoType::createActionFromTemplate(const QString& tmpl, c
}
const QString placeholder = QString("{%1}").arg(tmplName);
const QString resolved = entry->resolvePlaceholders(placeholder);
QString placeholder = QString("{%1}").arg(tmplName);
QString resolved = entry->resolvePlaceholders(placeholder);
if (placeholder != resolved) {
for (const QChar& ch : resolved) {
Q_FOREACH (const QChar& ch, resolved) {
if (ch == '\n') {
list.append(new AutoTypeKey(Qt::Key_Enter));
}
@@ -512,8 +511,7 @@ QString AutoType::autoTypeSequence(const Entry* entry, const QString& windowTitl
QString sequence;
if (!windowTitle.isEmpty()) {
bool match = false;
const QList<AutoTypeAssociations::Association> assocList = entry->autoTypeAssociations()->getAll();
for (const AutoTypeAssociations::Association& assoc : assocList) {
Q_FOREACH (const AutoTypeAssociations::Association& assoc, entry->autoTypeAssociations()->getAll()) {
if (windowMatches(windowTitle, assoc.window)) {
if (!assoc.sequence.isEmpty()) {
sequence = assoc.sequence;

View File

@@ -22,6 +22,8 @@
#include <QStringList>
#include <QWidget>
#include "core/Global.h"
class AutoTypeAction;
class AutoTypeExecutor;
class AutoTypePlatformInterface;
@@ -35,7 +37,7 @@ class AutoType : public QObject
public:
QStringList windowTitles();
void performAutoType(const Entry* entry, QWidget* hideWindow = nullptr,
void performAutoType(const Entry* entry, QWidget* hideWindow = Q_NULLPTR,
const QString& customSequence = QString(), WId window = 0);
bool registerGlobalShortcut(Qt::Key key, Qt::KeyboardModifiers modifiers);
void unregisterGlobalShortcut();
@@ -60,7 +62,7 @@ private Q_SLOTS:
void unloadPlugin();
private:
explicit AutoType(QObject* parent = nullptr, bool test = false);
explicit AutoType(QObject* parent = Q_NULLPTR, bool test = false);
~AutoType();
void loadPlugin(const QString& pluginPath);
bool parseActions(const QString& sequence, const Entry* entry, QList<AutoTypeAction*>& actions);

View File

@@ -66,7 +66,7 @@ public:
class KEEPASSX_EXPORT AutoTypeClearField : public AutoTypeAction
{
public:
AutoTypeClearField();
explicit AutoTypeClearField();
AutoTypeAction* clone();
void accept(AutoTypeExecutor* executor);
};

View File

@@ -20,12 +20,10 @@
#include <QApplication>
#include <QDesktopWidget>
#include <QDialogButtonBox>
#include <QHeaderView>
#include <QLabel>
#include <QVBoxLayout>
#include "autotype/AutoTypeSelectView.h"
#include "core/Config.h"
#include "core/FilePath.h"
#include "gui/entry/EntryModel.h"
@@ -41,14 +39,11 @@ AutoTypeSelectDialog::AutoTypeSelectDialog(QWidget* parent)
setWindowTitle(tr("Auto-Type - KeePassX"));
setWindowIcon(filePath()->applicationIcon());
QRect screenGeometry = QApplication::desktop()->availableGeometry(QCursor::pos());
QSize size = config()->get("GUI/AutoTypeSelectDialogSize", QSize(400, 250)).toSize();
size.setWidth(qMin(size.width(), screenGeometry.width()));
size.setHeight(qMin(size.height(), screenGeometry.height()));
QSize size(400, 250);
resize(size);
// move dialog to the center of the screen
QPoint screenCenter = screenGeometry.center();
QPoint screenCenter = QApplication::desktop()->availableGeometry(QCursor::pos()).center();
move(screenCenter.x() - (size.width() / 2), screenCenter.y() - (size.height() / 2));
QVBoxLayout* layout = new QVBoxLayout(this);
@@ -70,15 +65,6 @@ void AutoTypeSelectDialog::setEntries(const QList<Entry*>& entries, const QHash<
{
m_sequences = sequences;
m_view->setEntryList(entries);
m_view->header()->resizeSections(QHeaderView::ResizeToContents);
}
void AutoTypeSelectDialog::done(int r)
{
config()->set("GUI/AutoTypeSelectDialogSize", size());
QDialog::done(r);
}
void AutoTypeSelectDialog::emitEntryActivated(const QModelIndex& index)

View File

@@ -22,6 +22,8 @@
#include <QDialog>
#include <QHash>
#include "core/Global.h"
class AutoTypeSelectView;
class Entry;
@@ -30,15 +32,12 @@ class AutoTypeSelectDialog : public QDialog
Q_OBJECT
public:
explicit AutoTypeSelectDialog(QWidget* parent = nullptr);
explicit AutoTypeSelectDialog(QWidget* parent = Q_NULLPTR);
void setEntries(const QList<Entry*>& entries, const QHash<Entry*, QString>& sequences);
Q_SIGNALS:
void entryActivated(Entry* entry, const QString& sequence);
public Q_SLOTS:
void done(int r) override;
private Q_SLOTS:
void emitEntryActivated(const QModelIndex& index);
void entryRemoved();

View File

@@ -18,6 +18,7 @@
#ifndef KEEPASSX_AUTOTYPESELECTVIEW_H
#define KEEPASSX_AUTOTYPESELECTVIEW_H
#include "core/Global.h"
#include "gui/entry/EntryView.h"
class Entry;
@@ -27,10 +28,10 @@ class AutoTypeSelectView : public EntryView
Q_OBJECT
public:
explicit AutoTypeSelectView(QWidget* parent = nullptr);
explicit AutoTypeSelectView(QWidget* parent = Q_NULLPTR);
protected:
void mouseMoveEvent(QMouseEvent* event) override;
void mouseMoveEvent(QMouseEvent* event) Q_DECL_OVERRIDE;
private Q_SLOTS:
void selectFirstEntry();

View File

@@ -1,14 +1,12 @@
if(UNIX AND NOT APPLE)
if(Q_WS_X11)
find_package(X11)
find_package(Qt5X11Extras 5.2)
if(PRINT_SUMMARY)
add_feature_info(libXi X11_Xi_FOUND "The X11 Xi Protocol library is required for auto-type")
add_feature_info(libXtst X11_XTest_FOUND "The X11 XTEST Protocol library is required for auto-type")
add_feature_info(Qt5X11Extras Qt5X11Extras_FOUND "The Qt5X11Extras library is required for auto-type")
endif()
if(X11_FOUND AND X11_Xi_FOUND AND X11_XTest_FOUND AND Qt5X11Extras_FOUND)
add_subdirectory(xcb)
if(X11_FOUND AND X11_Xi_FOUND AND X11_XTest_FOUND)
add_subdirectory(x11)
endif()
endif()

View File

@@ -20,19 +20,21 @@
#include <QLineEdit>
#include "core/Global.h"
class ShortcutWidget : public QLineEdit
{
Q_OBJECT
public:
explicit ShortcutWidget(QWidget* parent = nullptr);
explicit ShortcutWidget(QWidget* parent = Q_NULLPTR);
Qt::Key key() const;
Qt::KeyboardModifiers modifiers() const;
void setShortcut(Qt::Key key, Qt::KeyboardModifiers modifiers);
protected:
void keyPressEvent(QKeyEvent* event) override;
void keyReleaseEvent(QKeyEvent* event) override;
void keyPressEvent(QKeyEvent* event) Q_DECL_OVERRIDE;
void keyReleaseEvent(QKeyEvent* event) Q_DECL_OVERRIDE;
private:
void keyEvent(QKeyEvent* event);

View File

@@ -70,7 +70,7 @@ bool WildcardMatcher::startOrEndDoesNotMatch(const QStringList& parts)
bool WildcardMatcher::partsMatch(const QStringList& parts)
{
int index = 0;
for (const QString& part : parts) {
Q_FOREACH (const QString& part, parts) {
int matchIndex = getMatchIndex(part, index);
if (noMatchFound(matchIndex)) {
return false;

View File

@@ -20,17 +20,19 @@
#include <QComboBox>
#include "core/Global.h"
class WindowSelectComboBox : public QComboBox
{
Q_OBJECT
public:
explicit WindowSelectComboBox(QWidget* parent = nullptr);
explicit WindowSelectComboBox(QWidget* parent = Q_NULLPTR);
void refreshWindowList();
void showPopup() override;
QSize sizeHint() const override;
QSize minimumSizeHint() const override;
void showPopup() Q_DECL_OVERRIDE;
QSize sizeHint() const Q_DECL_OVERRIDE;
QSize minimumSizeHint() const Q_DECL_OVERRIDE;
};
#endif // KEEPASSX_WINDOWSELECTCOMBOBOX_H

View File

@@ -129,3 +129,5 @@ void AutoTypeExecturorTest::execKey(AutoTypeKey* action)
{
m_platform->addActionKey(action);
}
Q_EXPORT_PLUGIN2(keepassx-autotype-test, AutoTypePlatformTest)

View File

@@ -23,34 +23,34 @@
#include "autotype/AutoTypePlatformPlugin.h"
#include "autotype/AutoTypeAction.h"
#include "autotype/test/AutoTypeTestInterface.h"
#include "core/Global.h"
class AutoTypePlatformTest : public QObject,
public AutoTypePlatformInterface,
public AutoTypeTestInterface
{
Q_OBJECT
Q_PLUGIN_METADATA(IID "org.keepassx.AutoTypePlatformInterface")
Q_INTERFACES(AutoTypePlatformInterface AutoTypeTestInterface)
public:
QString keyToString(Qt::Key key) override;
QString keyToString(Qt::Key key) Q_DECL_OVERRIDE;
bool isAvailable() override;
QStringList windowTitles() override;
WId activeWindow() override;
QString activeWindowTitle() override;
bool registerGlobalShortcut(Qt::Key key, Qt::KeyboardModifiers modifiers) override;
void unregisterGlobalShortcut(Qt::Key key, Qt::KeyboardModifiers modifiers) override;
int platformEventFilter(void* event) override;
int initialTimeout() override;
bool raiseWindow(WId window) override;
AutoTypeExecutor* createExecutor() override;
bool isAvailable() Q_DECL_OVERRIDE;
QStringList windowTitles() Q_DECL_OVERRIDE;
WId activeWindow() Q_DECL_OVERRIDE;
QString activeWindowTitle() Q_DECL_OVERRIDE;
bool registerGlobalShortcut(Qt::Key key, Qt::KeyboardModifiers modifiers) Q_DECL_OVERRIDE;
void unregisterGlobalShortcut(Qt::Key key, Qt::KeyboardModifiers modifiers) Q_DECL_OVERRIDE;
int platformEventFilter(void* event) Q_DECL_OVERRIDE;
int initialTimeout() Q_DECL_OVERRIDE;
bool raiseWindow(WId window) Q_DECL_OVERRIDE;
AutoTypeExecutor* createExecutor() Q_DECL_OVERRIDE;
void setActiveWindowTitle(const QString& title) override;
void setActiveWindowTitle(const QString& title) Q_DECL_OVERRIDE;
QString actionChars() override;
int actionCount() override;
void clearActions() override;
QString actionChars() Q_DECL_OVERRIDE;
int actionCount() Q_DECL_OVERRIDE;
void clearActions() Q_DECL_OVERRIDE;
void addActionChar(AutoTypeChar* action);
void addActionKey(AutoTypeKey* action);
@@ -69,8 +69,8 @@ class AutoTypeExecturorTest : public AutoTypeExecutor
public:
explicit AutoTypeExecturorTest(AutoTypePlatformTest* platform);
void execChar(AutoTypeChar* action) override;
void execKey(AutoTypeKey* action) override;
void execChar(AutoTypeChar* action) Q_DECL_OVERRIDE;
void execKey(AutoTypeKey* action) Q_DECL_OVERRIDE;
private:
AutoTypePlatformTest* const m_platform;

View File

@@ -2,5 +2,11 @@ set(autotype_test_SOURCES
AutoTypeTest.cpp
)
set(autotype_test_MOC
AutoTypeTest.h
)
qt4_wrap_cpp(autotype_test_SOURCES ${autotype_test_MOC})
add_library(keepassx-autotype-test MODULE ${autotype_test_SOURCES})
target_link_libraries(keepassx-autotype-test testautotype Qt5::Core Qt5::Widgets)
target_link_libraries(keepassx-autotype-test testautotype ${QT_QTCORE_LIBRARY} ${QT_QTGUI_LIBRARY})

View File

@@ -16,16 +16,14 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "AutoTypeXCB.h"
#include "AutoTypeX11.h"
#include "KeySymMap.h"
#include "core/Tools.h"
#include <time.h>
#include <xcb/xcb.h>
bool AutoTypePlatformX11::m_catchXErrors = false;
bool AutoTypePlatformX11::m_xErrorOccured = false;
int (*AutoTypePlatformX11::m_oldXErrorHandler)(Display*, XErrorEvent*) = nullptr;
int (*AutoTypePlatformX11::m_oldXErrorHandler)(Display*, XErrorEvent*) = Q_NULLPTR;
AutoTypePlatformX11::AutoTypePlatformX11()
{
@@ -48,8 +46,8 @@ AutoTypePlatformX11::AutoTypePlatformX11()
m_currentGlobalKey = static_cast<Qt::Key>(0);
m_currentGlobalModifiers = 0;
m_keysymTable = nullptr;
m_xkb = nullptr;
m_keysymTable = Q_NULLPTR;
m_xkb = Q_NULLPTR;
m_remapKeycode = 0;
m_currentRemapKeysym = NoSymbol;
m_modifierMask = ControlMask | ShiftMask | Mod1Mask | Mod4Mask;
@@ -121,7 +119,7 @@ WId AutoTypePlatformX11::activeWindow()
Window root;
Window parent;
Window* children = nullptr;
Window* children = Q_NULLPTR;
unsigned int numChildren;
tree = XQueryTree(m_dpy, window, &root, &parent, &children, &numChildren);
window = parent;
@@ -204,42 +202,22 @@ void AutoTypePlatformX11::unregisterGlobalShortcut(Qt::Key key, Qt::KeyboardModi
int AutoTypePlatformX11::platformEventFilter(void* event)
{
xcb_generic_event_t* genericEvent = static_cast<xcb_generic_event_t*>(event);
quint8 type = genericEvent->response_type & 0x7f;
XEvent* xevent = static_cast<XEvent*>(event);
if (type == XCB_KEY_PRESS || type == XCB_KEY_RELEASE) {
xcb_key_press_event_t* keyPressEvent = static_cast<xcb_key_press_event_t*>(event);
if (keyPressEvent->detail == m_currentGlobalKeycode
&& (keyPressEvent->state & m_modifierMask) == m_currentGlobalNativeModifiers
&& (!QApplication::activeWindow() || QApplication::activeWindow()->isMinimized())
&& m_loaded) {
if (type == XCB_KEY_PRESS) {
Q_EMIT globalShortcutTriggered();
}
return 1;
if ((xevent->type == KeyPress || xevent->type == KeyRelease)
&& m_currentGlobalKey
&& xevent->xkey.keycode == m_currentGlobalKeycode
&& (xevent->xkey.state & m_modifierMask) == m_currentGlobalNativeModifiers
&& (!QApplication::activeWindow() || QApplication::activeWindow()->isMinimized())
&& m_loaded) {
if (xevent->type == KeyPress) {
Q_EMIT globalShortcutTriggered();
}
return 1;
}
else if (type == XCB_MAPPING_NOTIFY) {
xcb_mapping_notify_event_t* mappingNotifyEvent = static_cast<xcb_mapping_notify_event_t*>(event);
if (mappingNotifyEvent->request == XCB_MAPPING_KEYBOARD
|| mappingNotifyEvent->request == XCB_MAPPING_MODIFIER)
{
XMappingEvent xMappingEvent;
memset(&xMappingEvent, 0, sizeof(xMappingEvent));
xMappingEvent.type = MappingNotify;
xMappingEvent.display = m_dpy;
if (mappingNotifyEvent->request == XCB_MAPPING_KEYBOARD) {
xMappingEvent.request = MappingKeyboard;
}
else {
xMappingEvent.request = MappingModifier;
}
xMappingEvent.first_keycode = mappingNotifyEvent->first_keycode;
xMappingEvent.count = mappingNotifyEvent->count;
XRefreshKeyboardMapping(&xMappingEvent);
updateKeymap();
}
if (xevent->type == MappingNotify && m_loaded) {
XRefreshKeyboardMapping(reinterpret_cast<XMappingEvent*>(xevent));
updateKeymap();
}
return -1;
@@ -258,7 +236,7 @@ QString AutoTypePlatformX11::windowTitle(Window window, bool useBlacklist)
int format;
unsigned long nitems;
unsigned long after;
unsigned char* data = nullptr;
unsigned char* data = Q_NULLPTR;
// the window manager spec says we should read _NET_WM_NAME first, then fall back to WM_NAME
@@ -272,7 +250,7 @@ QString AutoTypePlatformX11::windowTitle(Window window, bool useBlacklist)
XTextProperty textProp;
retVal = XGetTextProperty(m_dpy, window, &textProp, m_atomWmName);
if ((retVal != 0) && textProp.value) {
char** textList = nullptr;
char** textList = Q_NULLPTR;
int count;
if (textProp.encoding == m_atomUtf8String) {
@@ -324,8 +302,8 @@ QString AutoTypePlatformX11::windowClassName(Window window)
QString className;
XClassHint wmClass;
wmClass.res_name = nullptr;
wmClass.res_class = nullptr;
wmClass.res_name = Q_NULLPTR;
wmClass.res_class = Q_NULLPTR;
if (XGetClassHint(m_dpy, window, &wmClass) && wmClass.res_name) {
className = QString::fromLocal8Bit(wmClass.res_name);
@@ -344,7 +322,7 @@ QList<Window> AutoTypePlatformX11::widgetsToX11Windows(const QWidgetList& widget
{
QList<Window> windows;
for (const QWidget* widget : widgetList) {
Q_FOREACH (const QWidget* widget, widgetList) {
windows.append(widget->effectiveWinId());
}
@@ -364,7 +342,7 @@ QStringList AutoTypePlatformX11::windowTitlesRecursive(Window window)
Window root;
Window parent;
Window* children = nullptr;
Window* children = Q_NULLPTR;
unsigned int numChildren;
if (XQueryTree(m_dpy, window, &root, &parent, &children, &numChildren) && children) {
for (uint i = 0; i < numChildren; i++) {
@@ -413,9 +391,9 @@ KeySym AutoTypePlatformX11::charToKeySym(const QChar& ch)
}
/* mapping table generated from keysymdef.h */
const uint* match = Tools::binaryFind(m_unicodeToKeysymKeys,
m_unicodeToKeysymKeys + m_unicodeToKeysymLen,
unicode);
const uint* match = qBinaryFind(m_unicodeToKeysymKeys,
m_unicodeToKeysymKeys + m_unicodeToKeysymLen,
unicode);
int index = match - m_unicodeToKeysymKeys;
if (index != m_unicodeToKeysymLen) {
return m_unicodeToKeysymValues[index];
@@ -536,7 +514,7 @@ void AutoTypePlatformX11::updateKeymap()
timespec ts;
ts.tv_sec = 0;
ts.tv_nsec = 30 * 1000 * 1000;
nanosleep(&ts, nullptr);
nanosleep(&ts, Q_NULLPTR);
}
bool AutoTypePlatformX11::isRemapKeycodeValid()
@@ -587,7 +565,7 @@ XkbDescPtr AutoTypePlatformX11::getKeyboard()
XID keyboard_id = XkbUseCoreKbd;
XDeviceInfo* devices = XListInputDevices(m_dpy, &num_devices);
if (!devices) {
return nullptr;
return Q_NULLPTR;
}
for (int i = 0; i < num_devices; i++) {
@@ -743,7 +721,7 @@ void AutoTypePlatformX11::SendKeyPressedEvent(KeySym keysym)
event.y = 1;
event.x_root = 1;
event.y_root = 1;
event.same_screen = True;
event.same_screen = TRUE;
Window root, child;
int root_x, root_y, x, y;
@@ -876,3 +854,5 @@ bool AutoTypePlatformX11::raiseWindow(WId window)
return true;
}
Q_EXPORT_PLUGIN2(keepassx-autotype-x11, AutoTypePlatformX11)

View File

@@ -16,8 +16,8 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef KEEPASSX_AUTOTYPEXCB_H
#define KEEPASSX_AUTOTYPEXCB_H
#ifndef KEEPASSX_AUTOTYPEX11_H
#define KEEPASSX_AUTOTYPEX11_H
#include <QApplication>
#include <QSet>
@@ -31,28 +31,28 @@
#include "autotype/AutoTypePlatformPlugin.h"
#include "autotype/AutoTypeAction.h"
#include "core/Global.h"
#define N_MOD_INDICES (Mod5MapIndex + 1)
class AutoTypePlatformX11 : public QObject, public AutoTypePlatformInterface
{
Q_OBJECT
Q_PLUGIN_METADATA(IID "org.keepassx.AutoTypePlatformX11")
Q_INTERFACES(AutoTypePlatformInterface)
public:
AutoTypePlatformX11();
bool isAvailable() override;
void unload() override;
QStringList windowTitles() override;
WId activeWindow() override;
QString activeWindowTitle() override;
bool registerGlobalShortcut(Qt::Key key, Qt::KeyboardModifiers modifiers) override;
void unregisterGlobalShortcut(Qt::Key key, Qt::KeyboardModifiers modifiers) override;
int platformEventFilter(void* event) override;
int initialTimeout() override;
bool raiseWindow(WId window) override;
AutoTypeExecutor* createExecutor() override;
bool isAvailable() Q_DECL_OVERRIDE;
void unload() Q_DECL_OVERRIDE;
QStringList windowTitles() Q_DECL_OVERRIDE;
WId activeWindow() Q_DECL_OVERRIDE;
QString activeWindowTitle() Q_DECL_OVERRIDE;
bool registerGlobalShortcut(Qt::Key key, Qt::KeyboardModifiers modifiers) Q_DECL_OVERRIDE;
void unregisterGlobalShortcut(Qt::Key key, Qt::KeyboardModifiers modifiers) Q_DECL_OVERRIDE;
int platformEventFilter(void* event) Q_DECL_OVERRIDE;
int initialTimeout() Q_DECL_OVERRIDE;
bool raiseWindow(WId window) Q_DECL_OVERRIDE;
AutoTypeExecutor* createExecutor() Q_DECL_OVERRIDE;
KeySym charToKeySym(const QChar& ch);
KeySym keyToKeySym(Qt::Key key);
@@ -124,11 +124,11 @@ class AutoTypeExecturorX11 : public AutoTypeExecutor
public:
explicit AutoTypeExecturorX11(AutoTypePlatformX11* platform);
void execChar(AutoTypeChar* action) override;
void execKey(AutoTypeKey* action) override;
void execChar(AutoTypeChar* action) Q_DECL_OVERRIDE;
void execKey(AutoTypeKey* action) Q_DECL_OVERRIDE;
private:
AutoTypePlatformX11* const m_platform;
};
#endif // KEEPASSX_AUTOTYPEXCB_H
#endif // KEEPASSX_AUTOTYPEX11_H

View File

@@ -0,0 +1,17 @@
include_directories(SYSTEM ${X11_X11_INCLUDE_PATH})
set(autotype_X11_SOURCES
AutoTypeX11.cpp
)
set(autotype_X11_MOC
AutoTypeX11.h
)
qt4_wrap_cpp(autotype_X11_SOURCES ${autotype_X11_MOC})
add_library(keepassx-autotype-x11 MODULE ${autotype_X11_SOURCES})
target_link_libraries(keepassx-autotype-x11 ${QT_QTCORE_LIBRARY} ${QT_QTGUI_LIBRARY} ${X11_X11_LIB} ${X11_Xi_LIB} ${X11_XTest_LIB})
install(TARGETS keepassx-autotype-x11
BUNDLE DESTINATION . COMPONENT Runtime
LIBRARY DESTINATION ${PLUGIN_INSTALL_DIR} COMPONENT Runtime)

View File

@@ -1,11 +0,0 @@
include_directories(SYSTEM ${X11_X11_INCLUDE_PATH})
set(autotype_XCB_SOURCES
AutoTypeXCB.cpp
)
add_library(keepassx-autotype-xcb MODULE ${autotype_XCB_SOURCES})
target_link_libraries(keepassx-autotype-xcb Qt5::Core Qt5::Widgets Qt5::X11Extras ${X11_X11_LIB} ${X11_Xi_LIB} ${X11_XTest_LIB})
install(TARGETS keepassx-autotype-xcb
BUNDLE DESTINATION . COMPONENT Runtime
LIBRARY DESTINATION ${PLUGIN_INSTALL_DIR} COMPONENT Runtime)

View File

@@ -16,4 +16,6 @@
#cmakedefine HAVE_RLIMIT_CORE 1
#cmakedefine HAVE_PT_DENY_ATTACH 1
#cmakedefine GCRYPT_HAS_SALSA20
#endif // KEEPASSX_CONFIG_KEEPASSX_H

View File

@@ -20,6 +20,8 @@
#include <QObject>
#include "core/Global.h"
class AutoTypeAssociations : public QObject
{
Q_OBJECT
@@ -34,7 +36,7 @@ public:
bool operator!=(const AutoTypeAssociations::Association& other) const;
};
explicit AutoTypeAssociations(QObject* parent = nullptr);
explicit AutoTypeAssociations(QObject* parent = Q_NULLPTR);
void copyDataFrom(const AutoTypeAssociations* other);
void add(const AutoTypeAssociations::Association& association);
void remove(int index);

View File

@@ -18,12 +18,12 @@
#include "Config.h"
#include <QCoreApplication>
#include <QDesktopServices>
#include <QDir>
#include <QSettings>
#include <QStandardPaths>
#include <QTemporaryFile>
Config* Config::m_instance(nullptr);
Config* Config::m_instance(Q_NULLPTR);
QVariant Config::get(const QString& key)
{
@@ -53,7 +53,7 @@ Config::Config(QObject* parent)
QString homePath = QDir::homePath();
#if defined(Q_OS_UNIX) && !defined(Q_OS_MAC)
// we can't use QStandardPaths on X11 as it uses XDG_DATA_HOME instead of XDG_CONFIG_HOME
// we can't use QDesktopServices on X11 as it uses XDG_DATA_HOME instead of XDG_CONFIG_HOME
QByteArray env = qgetenv("XDG_CONFIG_HOME");
if (env.isEmpty()) {
userPath = homePath;
@@ -70,7 +70,7 @@ Config::Config(QObject* parent)
userPath += "/keepassx/";
#else
userPath = QDir::fromNativeSeparators(QStandardPaths::writableLocation(QStandardPaths::DataLocation));
userPath = QDir::fromNativeSeparators(QDesktopServices::storageLocation(QDesktopServices::DataLocation));
// storageLocation() appends the application name ("/keepassx") to the end
userPath += "/";
#endif
@@ -106,7 +106,6 @@ void Config::init(const QString& fileName)
m_defaults.insert("GUI/Language", "system");
m_defaults.insert("GUI/ShowTrayIcon", false);
m_defaults.insert("GUI/MinimizeToTray", false);
m_defaults.insert("GUI/MinimizeOnClose", false);
}
Config* Config::instance()

View File

@@ -21,6 +21,8 @@
#include <QScopedPointer>
#include <QVariant>
#include "core/Global.h"
class QSettings;
class Config : public QObject

View File

@@ -23,6 +23,7 @@
#include "core/Group.h"
#include "core/Metadata.h"
#include "core/Tools.h"
#include "crypto/Random.h"
#include "format/KeePass2.h"
@@ -91,22 +92,20 @@ Entry* Database::resolveEntry(const Uuid& uuid)
Entry* Database::recFindEntry(const Uuid& uuid, Group* group)
{
const QList<Entry*> entryList = group->entries();
for (Entry* entry : entryList) {
Q_FOREACH (Entry* entry, group->entries()) {
if (entry->uuid() == uuid) {
return entry;
}
}
const QList<Group*> children = group->children();
for (Group* child : children) {
Q_FOREACH (Group* child, group->children()) {
Entry* result = recFindEntry(uuid, child);
if (result) {
return result;
}
}
return nullptr;
return Q_NULLPTR;
}
Group* Database::resolveGroup(const Uuid& uuid)
@@ -120,15 +119,14 @@ Group* Database::recFindGroup(const Uuid& uuid, Group* group)
return group;
}
const QList<Group*> children = group->children();
for (Group* child : children) {
Q_FOREACH (Group* child, group->children()) {
Group* result = recFindGroup(uuid, child);
if (result) {
return result;
}
}
return nullptr;
return Q_NULLPTR;
}
QList<DeletedObject> Database::deletedObjects()
@@ -145,7 +143,7 @@ void Database::addDeletedObject(const DeletedObject& delObj)
void Database::addDeletedObject(const Uuid& uuid)
{
DeletedObject delObj;
delObj.deletionTime = QDateTime::currentDateTimeUtc();
delObj.deletionTime = Tools::currentDateTimeUtc();
delObj.uuid = uuid;
addDeletedObject(delObj);
@@ -225,7 +223,7 @@ bool Database::setKey(const CompositeKey& key, const QByteArray& transformSeed,
m_data.transformedMasterKey = transformedMasterKey;
m_data.hasKey = true;
if (updateChangedTime) {
m_metadata->setMasterKeyChanged(QDateTime::currentDateTimeUtc());
m_metadata->setMasterKeyChanged(Tools::currentDateTimeUtc());
}
Q_EMIT modifiedImmediate();

View File

@@ -20,7 +20,6 @@
#include <QDateTime>
#include <QHash>
#include <QObject>
#include "core/Uuid.h"
#include "keys/CompositeKey.h"

View File

@@ -19,7 +19,7 @@
#include "core/FilePath.h"
DatabaseIcons* DatabaseIcons::m_instance(nullptr);
DatabaseIcons* DatabaseIcons::m_instance(Q_NULLPTR);
const int DatabaseIcons::IconCount(69);
const int DatabaseIcons::ExpiredIconIndex(45);
const char* const DatabaseIcons::m_indexToName[] = {

View File

@@ -23,6 +23,8 @@
#include <QPixmapCache>
#include <QVector>
#include "core/Global.h"
class DatabaseIcons
{
public:

View File

@@ -21,6 +21,7 @@
#include "core/DatabaseIcons.h"
#include "core/Group.h"
#include "core/Metadata.h"
#include "core/Tools.h"
const int Entry::DefaultIconNumber = 0;
@@ -28,7 +29,7 @@ Entry::Entry()
: m_attributes(new EntryAttributes(this))
, m_attachments(new EntryAttachments(this))
, m_autoTypeAssociations(new AutoTypeAssociations(this))
, m_tmpHistoryItem(nullptr)
, m_tmpHistoryItem(Q_NULLPTR)
, m_modifiedSinceBegin(false)
, m_updateTimeinfo(true)
{
@@ -73,8 +74,8 @@ template <class T> inline bool Entry::set(T& property, const T& value)
void Entry::updateTimeinfo()
{
if (m_updateTimeinfo) {
m_data.timeInfo.setLastModificationTime(QDateTime::currentDateTimeUtc());
m_data.timeInfo.setLastAccessTime(QDateTime::currentDateTimeUtc());
m_data.timeInfo.setLastModificationTime(Tools::currentDateTimeUtc());
m_data.timeInfo.setLastAccessTime(Tools::currentDateTimeUtc());
}
}
@@ -222,7 +223,7 @@ QString Entry::notes() const
bool Entry::isExpired() const
{
return m_data.timeInfo.expires() && m_data.timeInfo.expiryTime() < QDateTime::currentDateTimeUtc();
return m_data.timeInfo.expires() && m_data.timeInfo.expiryTime() < Tools::currentDateTimeUtc();
}
EntryAttributes* Entry::attributes()
@@ -382,7 +383,7 @@ void Entry::removeHistoryItems(const QList<Entry*>& historyEntries)
return;
}
for (Entry* entry : historyEntries) {
Q_FOREACH (Entry* entry, historyEntries) {
Q_ASSERT(!entry->parent());
Q_ASSERT(entry->uuid() == uuid());
Q_ASSERT(m_history.contains(entry));
@@ -431,8 +432,8 @@ void Entry::truncateHistory()
if (size <= histMaxSize) {
size += historyItem->attributes()->attributesSize();
const QSet<QByteArray> newAttachments = historyItem->attachments()->values().toSet() - foundAttachements;
for (const QByteArray& attachment : newAttachments) {
QSet<QByteArray> newAttachments = historyItem->attachments()->values().toSet() - foundAttachements;
Q_FOREACH (const QByteArray& attachment, newAttachments) {
size += attachment.size();
}
foundAttachements += newAttachments;
@@ -461,7 +462,7 @@ Entry* Entry::clone(CloneFlags flags) const
entry->m_attachments->copyDataFrom(m_attachments);
entry->m_autoTypeAssociations->copyDataFrom(this->m_autoTypeAssociations);
if (flags & CloneIncludeHistory) {
for (Entry* historyItem : m_history) {
Q_FOREACH (Entry* historyItem, m_history) {
Entry* historyItemClone = historyItem->clone(flags & ~CloneIncludeHistory & ~CloneNewUuid);
historyItemClone->setUpdateTimeinfo(false);
historyItemClone->setUuid(entry->uuid());
@@ -472,7 +473,7 @@ Entry* Entry::clone(CloneFlags flags) const
entry->setUpdateTimeinfo(true);
if (flags & CloneResetTimeInfo) {
QDateTime now = QDateTime::currentDateTimeUtc();
QDateTime now = Tools::currentDateTimeUtc();
entry->m_data.timeInfo.setCreationTime(now);
entry->m_data.timeInfo.setLastModificationTime(now);
entry->m_data.timeInfo.setLastAccessTime(now);
@@ -508,7 +509,7 @@ void Entry::beginUpdate()
m_modifiedSinceBegin = false;
}
bool Entry::endUpdate()
void Entry::endUpdate()
{
Q_ASSERT(m_tmpHistoryItem);
if (m_modifiedSinceBegin) {
@@ -520,9 +521,7 @@ bool Entry::endUpdate()
delete m_tmpHistoryItem;
}
m_tmpHistoryItem = nullptr;
return m_modifiedSinceBegin;
m_tmpHistoryItem = Q_NULLPTR;
}
void Entry::updateModifiedSinceBegin()
@@ -568,7 +567,7 @@ void Entry::setGroup(Group* group)
QObject::setParent(group);
if (m_updateTimeinfo) {
m_data.timeInfo.setLocationChanged(QDateTime::currentDateTimeUtc());
m_data.timeInfo.setLocationChanged(Tools::currentDateTimeUtc());
}
}
@@ -583,7 +582,7 @@ const Database* Entry::database() const
return m_group->database();
}
else {
return nullptr;
return Q_NULLPTR;
}
}

View File

@@ -29,6 +29,7 @@
#include "core/AutoTypeAssociations.h"
#include "core/EntryAttachments.h"
#include "core/EntryAttributes.h"
#include "core/Global.h"
#include "core/TimeInfo.h"
#include "core/Uuid.h"
@@ -133,7 +134,7 @@ public:
* if the entry has been changed.
*/
void beginUpdate();
bool endUpdate();
void endUpdate();
Group* group();
const Group* group() const;

View File

@@ -21,12 +21,14 @@
#include <QMap>
#include <QObject>
#include "core/Global.h"
class EntryAttachments : public QObject
{
Q_OBJECT
public:
explicit EntryAttachments(QObject* parent = nullptr);
explicit EntryAttachments(QObject* parent = Q_NULLPTR);
QList<QString> keys() const;
bool hasKey(const QString& key) const;
QList<QByteArray> values() const;

View File

@@ -44,8 +44,7 @@ bool EntryAttributes::hasKey(const QString& key) const
QList<QString> EntryAttributes::customKeys()
{
QList<QString> customKeys;
const QList<QString> keyList = keys();
for (const QString& key : keyList) {
Q_FOREACH (const QString& key, keys()) {
if (!isDefaultAttribute(key)) {
customKeys.append(key);
}
@@ -58,11 +57,6 @@ QString EntryAttributes::value(const QString& key) const
return m_attributes.value(key);
}
bool EntryAttributes::contains(const QString &key) const
{
return m_attributes.contains(key);
}
bool EntryAttributes::isProtected(const QString& key) const
{
return m_protectedAttributes.contains(key);
@@ -168,16 +162,14 @@ void EntryAttributes::copyCustomKeysFrom(const EntryAttributes* other)
Q_EMIT aboutToBeReset();
// remove all non-default keys
const QList<QString> keyList = keys();
for (const QString& key : keyList) {
Q_FOREACH (const QString& key, keys()) {
if (!isDefaultAttribute(key)) {
m_attributes.remove(key);
m_protectedAttributes.remove(key);
}
}
const QList<QString> otherKeyList = other->keys();
for (const QString& key : otherKeyList) {
Q_FOREACH (const QString& key, other->keys()) {
if (!isDefaultAttribute(key)) {
m_attributes.insert(key, other->value(key));
if (other->isProtected(key)) {
@@ -197,8 +189,7 @@ bool EntryAttributes::areCustomKeysDifferent(const EntryAttributes* other)
return true;
}
const QList<QString> keyList = keys();
for (const QString& key : keyList) {
Q_FOREACH (const QString& key, keys()) {
if (isDefaultAttribute(key)) {
continue;
}
@@ -243,7 +234,7 @@ void EntryAttributes::clear()
m_attributes.clear();
m_protectedAttributes.clear();
for (const QString& key : DefaultAttributes) {
Q_FOREACH (const QString& key, DefaultAttributes) {
m_attributes.insert(key, "");
}

View File

@@ -23,17 +23,18 @@
#include <QSet>
#include <QStringList>
#include "core/Global.h"
class EntryAttributes : public QObject
{
Q_OBJECT
public:
explicit EntryAttributes(QObject* parent = nullptr);
explicit EntryAttributes(QObject* parent = Q_NULLPTR);
QList<QString> keys() const;
bool hasKey(const QString& key) const;
QList<QString> customKeys();
QString value(const QString& key) const;
bool contains(const QString& key) const;
bool isProtected(const QString& key) const;
void set(const QString& key, const QString& value, bool protect = false);
void remove(const QString& key);

View File

@@ -19,8 +19,7 @@
#include "core/Group.h"
QList<Entry*> EntrySearcher::search(const QString& searchTerm, const Group* group,
Qt::CaseSensitivity caseSensitivity)
QList<Entry*> EntrySearcher::search(const QString &searchTerm, const Group* group, Qt::CaseSensitivity caseSensitivity)
{
if (!group->resolveSearchingEnabled()) {
return QList<Entry*>();
@@ -29,18 +28,14 @@ QList<Entry*> EntrySearcher::search(const QString& searchTerm, const Group* grou
return searchEntries(searchTerm, group, caseSensitivity);
}
QList<Entry*> EntrySearcher::searchEntries(const QString& searchTerm, const Group* group,
Qt::CaseSensitivity caseSensitivity)
QList<Entry*> EntrySearcher::searchEntries(const QString& searchTerm, const Group* group, Qt::CaseSensitivity caseSensitivity)
{
QList<Entry*> searchResult;
const QList<Entry*> entryList = group->entries();
for (Entry* entry : entryList) {
searchResult.append(matchEntry(searchTerm, entry, caseSensitivity));
Q_FOREACH (Entry* entry, group->entries()) {
searchResult.append(matchEntry(searchTerm, entry, caseSensitivity));
}
const QList<Group*> children = group->children();
for (Group* childGroup : children) {
Q_FOREACH (Group* childGroup, group->children()) {
if (childGroup->searchingEnabled() != Group::Disable) {
searchResult.append(searchEntries(searchTerm, childGroup, caseSensitivity));
}
@@ -49,11 +44,10 @@ QList<Entry*> EntrySearcher::searchEntries(const QString& searchTerm, const Grou
return searchResult;
}
QList<Entry*> EntrySearcher::matchEntry(const QString& searchTerm, Entry* entry,
Qt::CaseSensitivity caseSensitivity)
QList<Entry*> EntrySearcher::matchEntry(const QString& searchTerm, Entry* entry, Qt::CaseSensitivity caseSensitivity)
{
const QStringList wordList = searchTerm.split(QRegExp("\\s"), QString::SkipEmptyParts);
for (const QString& word : wordList) {
QStringList wordList = searchTerm.split(QRegExp("\\s"), QString::SkipEmptyParts);
Q_FOREACH (const QString& word, wordList) {
if (!wordMatch(word, entry, caseSensitivity)) {
return QList<Entry*>();
}

View File

@@ -28,11 +28,10 @@ class EntrySearcher
{
public:
QList<Entry*> search(const QString& searchTerm, const Group* group, Qt::CaseSensitivity caseSensitivity);
private:
QList<Entry*> searchEntries(const QString& searchTerm, const Group* group, Qt::CaseSensitivity caseSensitivity);
QList<Entry*> matchEntry(const QString& searchTerm, Entry* entry, Qt::CaseSensitivity caseSensitivity);
bool wordMatch(const QString& word, Entry* entry, Qt::CaseSensitivity caseSensitivity);
bool wordMatch(const QString &word, Entry *entry, Qt::CaseSensitivity caseSensitivity);
};
#endif // KEEPASSX_ENTRYSEARCHER_H

View File

@@ -22,9 +22,8 @@
#include <QLibrary>
#include "config-keepassx.h"
#include "core/Global.h"
FilePath* FilePath::m_instance(nullptr);
FilePath* FilePath::m_instance(Q_NULLPTR);
QString FilePath::dataPath(const QString& name)
{
@@ -41,8 +40,7 @@ QString FilePath::pluginPath(const QString& name)
QStringList pluginPaths;
QDir buildDir(QCoreApplication::applicationDirPath() + "/autotype");
const QStringList buildDirEntryList = buildDir.entryList(QDir::Dirs | QDir::NoDotAndDotDot);
for (const QString& dir : buildDirEntryList) {
Q_FOREACH (const QString& dir, buildDir.entryList(QDir::Dirs | QDir::NoDotAndDotDot)) {
pluginPaths << QCoreApplication::applicationDirPath() + "/autotype/" + dir;
}
@@ -70,10 +68,10 @@ QString FilePath::pluginPath(const QString& name)
QStringList dirFilter;
dirFilter << QString("*%1*").arg(name);
for (const QString& path : asConst(pluginPaths)) {
const QStringList fileCandidates = QDir(path).entryList(dirFilter, QDir::Files);
Q_FOREACH (const QString& path, pluginPaths) {
QStringList fileCandidates = QDir(path).entryList(dirFilter, QDir::Files);
for (const QString& file : fileCandidates) {
Q_FOREACH (const QString& file, fileCandidates) {
QString filePath = path + "/" + file;
if (QLibrary::isLibrary(filePath)) {
@@ -105,9 +103,10 @@ QIcon FilePath::icon(const QString& category, const QString& name, bool fromThem
}
if (icon.isNull()) {
const QList<int> pngSizes = { 16, 22, 24, 32, 48, 64, 128 };
QList<int> pngSizes;
pngSizes << 16 << 22 << 24 << 32 << 48 << 64 << 128;
QString filename;
for (int size : pngSizes) {
Q_FOREACH (int size, pngSizes) {
filename = QString("%1/icons/application/%2x%2/%3.png").arg(m_dataPath, QString::number(size),
combinedName);
if (QFile::exists(filename)) {
@@ -149,9 +148,10 @@ QIcon FilePath::onOffIcon(const QString& category, const QString& name)
stateName = "on";
}
const QList<int> pngSizes = { 16, 22, 24, 32, 48, 64, 128 };
QList<int> pngSizes;
pngSizes << 16 << 22 << 24 << 32 << 48 << 64 << 128;
QString filename;
for (int size : pngSizes) {
Q_FOREACH (int size, pngSizes) {
filename = QString("%1/icons/application/%2x%2/%3-%4.png").arg(m_dataPath, QString::number(size),
combinedName, stateName);
if (QFile::exists(filename)) {

View File

@@ -22,6 +22,8 @@
#include <QIcon>
#include <QString>
#include "core/Global.h"
class FilePath
{
public:

View File

@@ -20,8 +20,104 @@
#ifndef KEEPASSX_GLOBAL_H
#define KEEPASSX_GLOBAL_H
// mostly copied from qcompilerdetection.h which is part of Qt 5
#include <QtGlobal>
#ifdef Q_CC_CLANG
# if __cplusplus >= 201103L || defined(__GXX_EXPERIMENTAL_CXX0X__)
# if __has_feature(cxx_strong_enums)
# define COMPILER_CLASS_ENUM
# endif
# if __has_feature(cxx_constexpr)
# define COMPILER_CONSTEXPR
# endif
# if __has_feature(cxx_decltype) /* && __has_feature(cxx_decltype_incomplete_return_types) */
# define COMPILER_DECLTYPE
# endif
# if __has_feature(cxx_override_control)
# define COMPILER_EXPLICIT_OVERRIDES
# endif
# if __has_feature(cxx_nullptr)
# define COMPILER_NULLPTR
# endif
# if __has_feature(cxx_static_assert)
# define COMPILER_STATIC_ASSERT
# endif
# endif
#endif // Q_CC_CLANG
#if defined(Q_CC_GNU) && !defined(Q_CC_INTEL) && !defined(Q_CC_CLANG)
# if defined(__GXX_EXPERIMENTAL_CXX0X__) || __cplusplus >= 201103L
# if (__GNUC__ * 100 + __GNUC_MINOR__) >= 403
# define COMPILER_DECLTYPE
# define COMPILER_STATIC_ASSERT
# endif
# if (__GNUC__ * 100 + __GNUC_MINOR__) >= 404
# define COMPILER_CLASS_ENUM
# endif
# if (__GNUC__ * 100 + __GNUC_MINOR__) >= 406
# define COMPILER_CONSTEXPR
# define COMPILER_NULLPTR
# endif
# if (__GNUC__ * 100 + __GNUC_MINOR__) >= 407
# define COMPILER_EXPLICIT_OVERRIDES
# endif
# endif
#endif
/*
* C++11 keywords and expressions
*/
#if !defined(Q_NULLPTR)
# ifdef COMPILER_NULLPTR
# define Q_NULLPTR nullptr
# else
# define Q_NULLPTR 0
# endif
#endif
#if !defined(Q_DECL_CONSTEXPR)
# ifdef COMPILER_CONSTEXPR
# define Q_DECL_CONSTEXPR constexpr
# else
# define Q_DECL_CONSTEXPR
# endif
#endif
#if !defined(Q_DECL_OVERRIDE) && !defined(Q_DECL_FINAL) && !defined(Q_DECL_FINAL_CLASS)
# ifdef COMPILER_EXPLICIT_OVERRIDES
# define Q_DECL_OVERRIDE override
# define Q_DECL_FINAL final
# ifdef COMPILER_DECLTYPE
# define Q_DECL_FINAL_CLASS final
# else
# define Q_DECL_FINAL_CLASS
# endif
# else
# define Q_DECL_OVERRIDE
# define Q_DECL_FINAL
# define Q_DECL_FINAL_CLASS
# endif
#endif
#if !defined(Q_STATIC_ASSERT) && !defined(Q_STATIC_ASSERT_X)
#ifdef COMPILER_STATIC_ASSERT
#define Q_STATIC_ASSERT(Condition) static_assert(static_cast<bool>(Condition), #Condition)
#define Q_STATIC_ASSERT_X(Condition, Message) static_assert(static_cast<bool>(Condition), Message)
#else
// Intentionally undefined
template <bool Test> class QStaticAssertFailure;
template <> class QStaticAssertFailure<true> {};
#define Q_STATIC_ASSERT_PRIVATE_JOIN(A, B) Q_STATIC_ASSERT_PRIVATE_JOIN_IMPL(A, B)
#define Q_STATIC_ASSERT_PRIVATE_JOIN_IMPL(A, B) A ## B
#define Q_STATIC_ASSERT(Condition) \
enum {Q_STATIC_ASSERT_PRIVATE_JOIN(q_static_assert_result, __LINE__) = sizeof(QStaticAssertFailure<!!(Condition)>)}
#define Q_STATIC_ASSERT_X(Condition, Message) Q_STATIC_ASSERT(Condition)
#endif // COMPILER_STATIC_ASSERT
#endif // !defined(Q_STATIC_ASSERT) && !defined(Q_STATIC_ASSERT_X)
#if defined(Q_OS_WIN)
# if defined(KEEPASSX_BUILDING_CORE)
# define KEEPASSX_EXPORT Q_DECL_EXPORT
@@ -36,13 +132,4 @@
#define QUINT32_MAX 4294967295U
#endif
template <typename T> struct AddConst { typedef const T Type; };
// this adds const to non-const objects (like std::as_const)
template <typename T>
constexpr typename AddConst<T>::Type& asConst(T &t) noexcept { return t; }
// prevent rvalue arguments:
template <typename T>
void asConst(const T&&) = delete;
#endif // KEEPASSX_GLOBAL_H

View File

@@ -18,9 +18,9 @@
#include "Group.h"
#include "core/Config.h"
#include "core/Global.h"
#include "core/DatabaseIcons.h"
#include "core/Metadata.h"
#include "core/Tools.h"
const int Group::DefaultIconNumber = 48;
const int Group::RecycleBinIconNumber = 43;
@@ -38,19 +38,19 @@ Group::~Group()
{
// Destroy entries and children manually so DeletedObjects can be added
// to database.
const QList<Entry*> entries = m_entries;
for (Entry* entry : entries) {
QList<Entry*> entries = m_entries;
Q_FOREACH (Entry* entry, entries) {
delete entry;
}
const QList<Group*> children = m_children;
for (Group* group : children) {
QList<Group*> children = m_children;
Q_FOREACH (Group* group, children) {
delete group;
}
if (m_db && m_parent) {
DeletedObject delGroup;
delGroup.deletionTime = QDateTime::currentDateTimeUtc();
delGroup.deletionTime = Tools::currentDateTimeUtc();
delGroup.uuid = m_uuid;
m_db->addDeletedObject(delGroup);
}
@@ -84,8 +84,8 @@ template <class P, class V> inline bool Group::set(P& property, const V& value)
void Group::updateTimeinfo()
{
if (m_updateTimeinfo) {
m_data.timeInfo.setLastModificationTime(QDateTime::currentDateTimeUtc());
m_data.timeInfo.setLastAccessTime(QDateTime::currentDateTimeUtc());
m_data.timeInfo.setLastModificationTime(Tools::currentDateTimeUtc());
m_data.timeInfo.setLastAccessTime(Tools::currentDateTimeUtc());
}
}
@@ -203,7 +203,7 @@ Entry* Group::lastTopVisibleEntry() const
bool Group::isExpired() const
{
return m_data.timeInfo.expires() && m_data.timeInfo.expiryTime() < QDateTime::currentDateTimeUtc();
return m_data.timeInfo.expires() && m_data.timeInfo.expiryTime() < Tools::currentDateTimeUtc();
}
void Group::setUuid(const Uuid& uuid)
@@ -365,7 +365,7 @@ void Group::setParent(Group* parent, int index)
}
if (m_updateTimeinfo) {
m_data.timeInfo.setLocationChanged(QDateTime::currentDateTimeUtc());
m_data.timeInfo.setLocationChanged(Tools::currentDateTimeUtc());
}
Q_EMIT modified();
@@ -385,7 +385,7 @@ void Group::setParent(Database* db)
cleanupParent();
m_parent = nullptr;
m_parent = Q_NULLPTR;
recSetDatabase(db);
QObject::setParent(db);
@@ -428,12 +428,12 @@ QList<Entry*> Group::entriesRecursive(bool includeHistoryItems) const
entryList.append(m_entries);
if (includeHistoryItems) {
for (Entry* entry : m_entries) {
Q_FOREACH (Entry* entry, m_entries) {
entryList.append(entry->historyItems());
}
}
for (Group* group : m_children) {
Q_FOREACH (Group* group, m_children) {
entryList.append(group->entriesRecursive(includeHistoryItems));
}
@@ -447,7 +447,7 @@ QList<const Group*> Group::groupsRecursive(bool includeSelf) const
groupList.append(this);
}
for (const Group* group : m_children) {
Q_FOREACH (const Group* group, m_children) {
groupList.append(group->groupsRecursive(true));
}
@@ -461,7 +461,7 @@ QList<Group*> Group::groupsRecursive(bool includeSelf)
groupList.append(this);
}
for (Group* group : asConst(m_children)) {
Q_FOREACH (Group* group, m_children) {
groupList.append(group->groupsRecursive(true));
}
@@ -476,14 +476,13 @@ QSet<Uuid> Group::customIconsRecursive() const
result.insert(iconUuid());
}
const QList<Entry*> entryList = entriesRecursive(true);
for (Entry* entry : entryList) {
Q_FOREACH (Entry* entry, entriesRecursive(true)) {
if (!entry->iconUuid().isNull()) {
result.insert(entry->iconUuid());
}
}
for (Group* group : m_children) {
Q_FOREACH (Group* group, m_children) {
result.unite(group->customIconsRecursive());
}
@@ -499,21 +498,19 @@ Group* Group::clone(Entry::CloneFlags entryFlags) const
clonedGroup->setUuid(Uuid::random());
clonedGroup->m_data = m_data;
const QList<Entry*> entryList = entries();
for (Entry* entry : entryList) {
Q_FOREACH (Entry* entry, entries()) {
Entry* clonedEntry = entry->clone(entryFlags);
clonedEntry->setGroup(clonedGroup);
}
const QList<Group*> childrenGroups = children();
for (Group* groupChild : childrenGroups) {
Q_FOREACH (Group* groupChild, children()) {
Group* clonedGroupChild = groupChild->clone(entryFlags);
clonedGroupChild->setParent(clonedGroup);
}
clonedGroup->setUpdateTimeinfo(true);
QDateTime now = QDateTime::currentDateTimeUtc();
QDateTime now = Tools::currentDateTimeUtc();
clonedGroup->m_data.timeInfo.setCreationTime(now);
clonedGroup->m_data.timeInfo.setLastModificationTime(now);
clonedGroup->m_data.timeInfo.setLastAccessTime(now);
@@ -573,7 +570,7 @@ void Group::recSetDatabase(Database* db)
disconnect(SIGNAL(modified()), m_db);
}
for (Entry* entry : asConst(m_entries)) {
Q_FOREACH (Entry* entry, m_entries) {
if (m_db) {
entry->disconnect(m_db);
}
@@ -595,7 +592,7 @@ void Group::recSetDatabase(Database* db)
m_db = db;
for (Group* group : asConst(m_children)) {
Q_FOREACH (Group* group, m_children) {
group->recSetDatabase(db);
}
}
@@ -613,11 +610,11 @@ void Group::cleanupParent()
void Group::recCreateDelObjects()
{
if (m_db) {
for (Entry* entry : asConst(m_entries)) {
Q_FOREACH (Entry* entry, m_entries) {
m_db->addDeletedObject(entry->uuid());
}
for (Group* group : asConst(m_children)) {
Q_FOREACH (Group* group, m_children) {
group->recCreateDelObjects();
}
m_db->addDeletedObject(m_uuid);

View File

@@ -21,6 +21,8 @@
#include <QMutex>
#include <QObject>
#include "core/Global.h"
class QTimer;
class InactivityTimer : public QObject
@@ -28,7 +30,7 @@ class InactivityTimer : public QObject
Q_OBJECT
public:
explicit InactivityTimer(QObject* parent = nullptr);
explicit InactivityTimer(QObject* parent = Q_NULLPTR);
void setInactivityTimeout(int inactivityTimeout);
void activate();
void deactivate();

View File

@@ -42,7 +42,7 @@ Metadata::Metadata(QObject* parent)
m_data.protectNotes = false;
// m_data.autoEnableVisualHiding = false;
QDateTime now = QDateTime::currentDateTimeUtc();
QDateTime now = Tools::currentDateTimeUtc();
m_data.nameChanged = now;
m_data.descriptionChanged = now;
m_data.defaultUserNameChanged = now;
@@ -67,7 +67,7 @@ template <class P, class V> bool Metadata::set(P& property, const V& value, QDat
if (property != value) {
property = value;
if (m_updateDatetime) {
dateTime = QDateTime::currentDateTimeUtc();
dateTime = Tools::currentDateTimeUtc();
}
Q_EMIT modified();
return true;
@@ -218,7 +218,7 @@ QHash<Uuid, QPixmap> Metadata::customIconsScaledPixmaps() const
{
QHash<Uuid, QPixmap> result;
for (const Uuid& uuid : m_customIconsOrder) {
Q_FOREACH (const Uuid& uuid, m_customIconsOrder) {
result.insert(uuid, customIconScaledPixmap(uuid));
}
@@ -427,7 +427,7 @@ void Metadata::removeCustomIcon(const Uuid& uuid)
void Metadata::copyCustomIcons(const QSet<Uuid>& iconList, const Metadata* otherMetadata)
{
for (const Uuid& uuid : iconList) {
Q_FOREACH (const Uuid& uuid, iconList) {
Q_ASSERT(otherMetadata->containsCustomIcon(uuid));
if (!containsCustomIcon(uuid) && otherMetadata->containsCustomIcon(uuid)) {

View File

@@ -26,6 +26,7 @@
#include <QPixmapCache>
#include <QPointer>
#include "core/Global.h"
#include "core/Uuid.h"
class Database;
@@ -36,7 +37,7 @@ class Metadata : public QObject
Q_OBJECT
public:
explicit Metadata(QObject* parent = nullptr);
explicit Metadata(QObject* parent = Q_NULLPTR);
struct MetadataData
{

View File

@@ -45,11 +45,11 @@ QString PasswordGenerator::generatePassword() const
{
Q_ASSERT(isValid());
const QVector<PasswordGroup> groups = passwordGroups();
QVector<PasswordGroup> groups = passwordGroups();
QVector<QChar> passwordChars;
for (const PasswordGroup& group : groups) {
for (QChar ch : group) {
Q_FOREACH (const PasswordGroup& group, groups) {
Q_FOREACH (QChar ch, group) {
passwordChars.append(ch);
}
}
@@ -89,22 +89,6 @@ QString PasswordGenerator::generatePassword() const
return password;
}
int PasswordGenerator::getbits() const
{
QVector<PasswordGroup> groups = passwordGroups();
int bits = 0;
QVector<QChar> passwordChars;
Q_FOREACH (const PasswordGroup& group, groups) {
bits += group.size();
}
bits *= m_length;
return bits;
}
bool PasswordGenerator::isValid() const
{
if (m_classes == 0) {

View File

@@ -22,6 +22,8 @@
#include <QString>
#include <QVector>
#include "core/Global.h"
typedef QVector<QChar> PasswordGroup;
class PasswordGenerator
@@ -53,7 +55,6 @@ public:
bool isValid() const;
QString generatePassword() const;
int getbits() const;
private:
QVector<PasswordGroup> passwordGroups() const;

View File

@@ -17,8 +17,6 @@
#include "SignalMultiplexer.h"
#include "core/Global.h"
SignalMultiplexer::SignalMultiplexer()
{
}
@@ -26,7 +24,7 @@ SignalMultiplexer::SignalMultiplexer()
SignalMultiplexer::~SignalMultiplexer()
{
// disconnect all connections
setCurrentObject(nullptr);
setCurrentObject(Q_NULLPTR);
}
QObject* SignalMultiplexer::currentObject() const
@@ -47,7 +45,7 @@ void SignalMultiplexer::setCurrentObject(QObject* object)
}
if (m_currentObject) {
for (const Connection& con : asConst(m_connections)) {
Q_FOREACH (const Connection& con, m_connections) {
disconnect(con);
}
}
@@ -55,7 +53,7 @@ void SignalMultiplexer::setCurrentObject(QObject* object)
m_currentObject = object;
if (object) {
for (const Connection& con : asConst(m_connections)) {
Q_FOREACH (const Connection& con, m_connections) {
connect(con);
}
}

View File

@@ -21,6 +21,8 @@
#include <QObject>
#include <QPointer>
#include "core/Global.h"
class SignalMultiplexer
{
public:

View File

@@ -23,7 +23,7 @@ TimeInfo::TimeInfo()
: m_expires(false)
, m_usageCount(0)
{
QDateTime now = QDateTime::currentDateTimeUtc();
QDateTime now = Tools::currentDateTimeUtc();
m_lastModificationTime = now;
m_creationTime = now;
m_lastAccessTime = now;

View File

@@ -23,7 +23,11 @@
#include <QLocale>
#include <QStringList>
#if QT_VERSION >= QT_VERSION_CHECK(4, 7, 0)
#include <QElapsedTimer>
#else
#include <QTime>
#endif
#ifdef Q_OS_WIN
#include <windows.h> // for Sleep(), SetDllDirectoryA() and SetSearchPathMode()
@@ -71,9 +75,7 @@ bool hasChild(const QObject* parent, const QObject* child)
if (!parent || !child) {
return false;
}
const QObjectList children = parent->children();
for (QObject* c : children) {
Q_FOREACH (QObject* c, parent->children()) {
if (child == c || hasChild(c, child)) {
return true;
}
@@ -120,12 +122,21 @@ bool readAllFromDevice(QIODevice* device, QByteArray& data)
}
}
QDateTime currentDateTimeUtc()
{
#if QT_VERSION >= QT_VERSION_CHECK(4, 7, 0)
return QDateTime::currentDateTimeUtc();
#else
return QDateTime::currentDateTime().toUTC();
#endif
}
QString imageReaderFilter()
{
const QList<QByteArray> formats = QImageReader::supportedImageFormats();
QList<QByteArray> formats = QImageReader::supportedImageFormats();
QStringList formatsStringList;
for (const QByteArray& format : formats) {
Q_FOREACH (const QByteArray& format, formats) {
for (int i = 0; i < format.size(); i++) {
if (!QChar(format.at(i)).isLetterOrNumber()) {
continue;
@@ -140,7 +151,7 @@ QString imageReaderFilter()
bool isHex(const QByteArray& ba)
{
for (char c : ba) {
Q_FOREACH (char c, ba) {
if ( !( (c >= '0' && c <= '9') || (c >= 'a' && c <= 'f') || (c >= 'A' && c <= 'F') ) ) {
return false;
}
@@ -173,7 +184,7 @@ void sleep(int ms)
timespec ts;
ts.tv_sec = ms / 1000;
ts.tv_nsec = (ms % 1000) * 1000 * 1000;
nanosleep(&ts, nullptr);
nanosleep(&ts, Q_NULLPTR);
#endif
}
@@ -185,7 +196,11 @@ void wait(int ms)
return;
}
#if QT_VERSION >= QT_VERSION_CHECK(4, 7, 0)
QElapsedTimer timer;
#else
QTime timer;
#endif
timer.start();
if (ms <= 50) {
@@ -200,10 +215,23 @@ void wait(int ms)
QCoreApplication::processEvents(QEventLoop::AllEvents, timeLeft);
sleep(10);
}
} while (!timer.hasExpired(ms));
} while (timer.elapsed() < ms);
}
}
QString platform()
{
#if defined(Q_WS_X11)
return "x11";
#elif defined(Q_WS_MAC)
return "mac";
#elif defined(Q_WS_WIN)
return "win";
#else
return QString();
#endif
}
void disableCoreDumps()
{
// default to true

View File

@@ -18,13 +18,11 @@
#ifndef KEEPASSX_TOOLS_H
#define KEEPASSX_TOOLS_H
#include "core/Global.h"
#include <QDateTime>
#include <QObject>
#include <QString>
#include <algorithm>
#include "core/Global.h"
class QIODevice;
@@ -34,27 +32,16 @@ QString humanReadableFileSize(qint64 bytes);
bool hasChild(const QObject* parent, const QObject* child);
bool readFromDevice(QIODevice* device, QByteArray& data, int size = 16384);
bool readAllFromDevice(QIODevice* device, QByteArray& data);
QDateTime currentDateTimeUtc();
QString imageReaderFilter();
bool isHex(const QByteArray& ba);
bool isBase64(const QByteArray& ba);
void sleep(int ms);
void wait(int ms);
QString platform();
void disableCoreDumps();
void setupSearchPaths();
template <typename RandomAccessIterator, typename T>
RandomAccessIterator binaryFind(RandomAccessIterator begin, RandomAccessIterator end, const T& value)
{
RandomAccessIterator it = std::lower_bound(begin, end, value);
if ((it == end) || (value < *it)) {
return end;
}
else {
return it;
}
}
} // namespace Tools
#endif // KEEPASSX_TOOLS_H

View File

@@ -49,20 +49,18 @@ void Translator::installTranslator()
QList<QPair<QString, QString> > Translator::availableLanguages()
{
const QStringList paths = {
QStringList paths;
#ifdef QT_DEBUG
QString("%1/share/translations").arg(KEEPASSX_BINARY_DIR),
paths.append(QString("%1/share/translations").arg(KEEPASSX_BINARY_DIR));
#endif
filePath()->dataPath("translations")
};
paths.append(filePath()->dataPath("translations"));
QList<QPair<QString, QString> > languages;
languages.append(QPair<QString, QString>("system", "System default"));
QRegExp regExp("keepassx_([a-zA-Z_]+)\\.qm", Qt::CaseInsensitive, QRegExp::RegExp2);
for (const QString& path : paths) {
const QStringList fileList = QDir(path).entryList();
for (const QString& filename : fileList) {
Q_FOREACH (const QString& path, paths) {
Q_FOREACH (const QString& filename, QDir(path).entryList()) {
if (regExp.exactMatch(filename)) {
QString langcode = regExp.cap(1);
if (langcode == "en_plurals") {
@@ -87,14 +85,13 @@ QList<QPair<QString, QString> > Translator::availableLanguages()
bool Translator::installTranslator(const QString& language)
{
const QStringList paths = {
QStringList paths;
#ifdef QT_DEBUG
QString("%1/share/translations").arg(KEEPASSX_BINARY_DIR),
paths.append(QString("%1/share/translations").arg(KEEPASSX_BINARY_DIR));
#endif
filePath()->dataPath("translations")
};
paths.append(filePath()->dataPath("translations"));
for (const QString& path : paths) {
Q_FOREACH (const QString& path, paths) {
if (installTranslator(language, path)) {
return true;
}
@@ -119,7 +116,7 @@ bool Translator::installTranslator(const QString& language, const QString& path)
bool Translator::installQtTranslator(const QString& language)
{
QTranslator* qtTranslator = new QTranslator(qApp);
if (qtTranslator->load(QString("%1/qtbase_%2").arg(QLibraryInfo::location(QLibraryInfo::TranslationsPath), language))) {
if (qtTranslator->load(QString("%1/qt_%2").arg(QLibraryInfo::location(QLibraryInfo::TranslationsPath), language))) {
QCoreApplication::installTranslator(qtTranslator);
return true;
}

View File

@@ -89,12 +89,6 @@ Uuid Uuid::fromBase64(const QString& str)
return Uuid(data);
}
Uuid Uuid::fromHex(const QString& str)
{
QByteArray data = QByteArray::fromHex(str.toLatin1());
return Uuid(data);
}
uint qHash(const Uuid& key)
{
return qHash(key.toByteArray());

View File

@@ -37,7 +37,6 @@ public:
bool operator!=(const Uuid& other) const;
static const int Length;
static Uuid fromBase64(const QString& str);
static Uuid fromHex(const QString& str);
private:
QByteArray m_data;

View File

@@ -0,0 +1,305 @@
/****************************************************************************
**
** Copyright (C) 2013 Laszlo Papp <lpapp@kde.org>
** Copyright (C) 2013 David Faure <faure@kde.org>
** Contact: http://www.qt-project.org/legal
**
** This file is part of the QtCore module of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL$
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and Digia. For licensing terms and
** conditions see http://qt.digia.com/licensing. For further information
** use the contact form at http://qt.digia.com/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file. Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Digia gives you certain additional
** rights. These rights are described in the Digia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3.0 as published by the Free Software
** Foundation and appearing in the file LICENSE.GPL included in the
** packaging of this file. Please review the following information to
** ensure the GNU General Public License version 3.0 requirements will be
** met: http://www.gnu.org/copyleft/gpl.html.
**
**
** $QT_END_LICENSE$
**
****************************************************************************/
#include "qcommandlineoption.h"
#include <QSet>
class QCommandLineOptionPrivate : public QSharedData
{
public:
inline QCommandLineOptionPrivate()
{ }
void setNames(const QStringList &nameList);
//! The list of names used for this option.
QStringList names;
//! The documentation name for the value, if one is expected
//! Example: "-o <file>" means valueName == "file"
QString valueName;
//! The description used for this option.
QString description;
//! The list of default values used for this option.
QStringList defaultValues;
};
/*!
\since 5.2
\class QCommandLineOption
\brief The QCommandLineOption class defines a possible command-line option.
\inmodule QtCore
\ingroup shared
\ingroup tools
This class is used to describe an option on the command line. It allows
different ways of defining the same option with multiple aliases possible.
It is also used to describe how the option is used - it may be a flag (e.g. \c{-v})
or take an argument (e.g. \c{-o file}).
Examples:
\snippet code/src_corelib_tools_qcommandlineoption.cpp 0
\sa QCommandLineParser
*/
/*!
Constructs a command line option object with the given arguments.
The name of the option is set to \a name.
The name can be either short or long. If the name is one character in
length, it is considered a short name. Option names must not be empty,
must not start with a dash or a slash character, must not contain a \c{=}
and cannot be repeated.
The description is set to \a description. It is customary to add a "."
at the end of the description.
In addition, the \a valueName can be set if the option expects a value.
The default value for the option is set to \a defaultValue.
\sa setDescription(), setValueName(), setDefaultValues()
*/
QCommandLineOption::QCommandLineOption(const QString &name, const QString &description,
const QString &valueName,
const QString &defaultValue)
: d(new QCommandLineOptionPrivate)
{
d->setNames(QStringList(name));
setValueName(valueName);
setDescription(description);
setDefaultValue(defaultValue);
}
/*!
Constructs a command line option object with the given arguments.
This overload allows to set multiple names for the option, for instance
\c{o} and \c{output}.
The names of the option are set to \a names.
The names can be either short or long. Any name in the list that is one
character in length is a short name. Option names must not be empty,
must not start with a dash or a slash character, must not contain a \c{=}
and cannot be repeated.
The description is set to \a description. It is customary to add a "."
at the end of the description.
In addition, the \a valueName can be set if the option expects a value.
The default value for the option is set to \a defaultValue.
\sa setDescription(), setValueName(), setDefaultValues()
*/
QCommandLineOption::QCommandLineOption(const QStringList &names, const QString &description,
const QString &valueName,
const QString &defaultValue)
: d(new QCommandLineOptionPrivate)
{
d->setNames(names);
setValueName(valueName);
setDescription(description);
setDefaultValue(defaultValue);
}
/*!
Constructs a QCommandLineOption object that is a copy of the QCommandLineOption
object \a other.
\sa operator=()
*/
QCommandLineOption::QCommandLineOption(const QCommandLineOption &other)
: d(other.d)
{
}
/*!
Destroys the command line option object.
*/
QCommandLineOption::~QCommandLineOption()
{
}
/*!
Makes a copy of the \a other object and assigns it to this QCommandLineOption
object.
*/
QCommandLineOption &QCommandLineOption::operator=(const QCommandLineOption &other)
{
d = other.d;
return *this;
}
/*!
Returns the names set for this option.
*/
QStringList QCommandLineOption::names() const
{
return d->names;
}
void QCommandLineOptionPrivate::setNames(const QStringList &nameList)
{
QStringList newNames;
if (nameList.isEmpty())
qWarning("QCommandLineOption: Options must have at least one name");
Q_FOREACH (const QString &name, nameList) {
if (name.isEmpty()) {
qWarning("QCommandLineOption: Option names cannot be empty");
} else {
const QChar c = name.at(0);
if (c == QLatin1Char('-'))
qWarning("QCommandLineOption: Option names cannot start with a '-'");
else if (c == QLatin1Char('/'))
qWarning("QCommandLineOption: Option names cannot start with a '/'");
else if (name.contains(QLatin1Char('=')))
qWarning("QCommandLineOption: Option names cannot contain a '='");
else
newNames.append(name);
}
}
// commit
names = newNames;
}
/*!
Sets the name of the expected value, for the documentation, to \a valueName.
Options without a value assigned have a boolean-like behavior:
either the user specifies --option or they don't.
Options with a value assigned need to set a name for the expected value,
for the documentation of the option in the help output. An option with names \c{o} and \c{output},
and a value name of \c{file} will appear as \c{-o, --output <file>}.
Call QCommandLineParser::argument() if you expect the option to be present
only once, and QCommandLineParser::arguments() if you expect that option
to be present multiple times.
\sa valueName()
*/
void QCommandLineOption::setValueName(const QString &valueName)
{
d->valueName = valueName;
}
/*!
Returns the name of the expected value.
If empty, the option doesn't take a value.
\sa setValueName()
*/
QString QCommandLineOption::valueName() const
{
return d->valueName;
}
/*!
Sets the description used for this option to \a description.
It is customary to add a "." at the end of the description.
The description is used by QCommandLineParser::showHelp().
\sa description()
*/
void QCommandLineOption::setDescription(const QString &description)
{
d->description = description;
}
/*!
Returns the description set for this option.
\sa setDescription()
*/
QString QCommandLineOption::description() const
{
return d->description;
}
/*!
Sets the default value used for this option to \a defaultValue.
The default value is used if the user of the application does not specify
the option on the command line.
If \a defaultValue is empty, the option has no default values.
\sa defaultValues() setDefaultValues()
*/
void QCommandLineOption::setDefaultValue(const QString &defaultValue)
{
QStringList newDefaultValues;
if (!defaultValue.isEmpty()) {
newDefaultValues << defaultValue;
}
// commit:
d->defaultValues = newDefaultValues;
}
/*!
Sets the list of default values used for this option to \a defaultValues.
The default values are used if the user of the application does not specify
the option on the command line.
\sa defaultValues() setDefaultValue()
*/
void QCommandLineOption::setDefaultValues(const QStringList &defaultValues)
{
d->defaultValues = defaultValues;
}
/*!
Returns the default values set for this option.
\sa setDefaultValues()
*/
QStringList QCommandLineOption::defaultValues() const
{
return d->defaultValues;
}

View File

@@ -0,0 +1,81 @@
/****************************************************************************
**
** Copyright (C) 2013 Laszlo Papp <lpapp@kde.org>
** Contact: http://www.qt-project.org/legal
**
** This file is part of the QtCore module of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL$
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and Digia. For licensing terms and
** conditions see http://qt.digia.com/licensing. For further information
** use the contact form at http://qt.digia.com/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file. Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Digia gives you certain additional
** rights. These rights are described in the Digia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3.0 as published by the Free Software
** Foundation and appearing in the file LICENSE.GPL included in the
** packaging of this file. Please review the following information to
** ensure the GNU General Public License version 3.0 requirements will be
** met: http://www.gnu.org/copyleft/gpl.html.
**
**
** $QT_END_LICENSE$
**
****************************************************************************/
#ifndef QCOMMANDLINEOPTION_H
#define QCOMMANDLINEOPTION_H
#include <QStringList>
#include <QSharedData>
class QCommandLineOptionPrivate;
class QCommandLineOption
{
public:
explicit QCommandLineOption(const QString &name, const QString &description = QString(),
const QString &valueName = QString(),
const QString &defaultValue = QString());
explicit QCommandLineOption(const QStringList &names, const QString &description = QString(),
const QString &valueName = QString(),
const QString &defaultValue = QString());
QCommandLineOption(const QCommandLineOption &other);
~QCommandLineOption();
QCommandLineOption &operator=(const QCommandLineOption &other);
QStringList names() const;
void setValueName(const QString &name);
QString valueName() const;
void setDescription(const QString &description);
QString description() const;
void setDefaultValue(const QString &defaultValue);
void setDefaultValues(const QStringList &defaultValues);
QStringList defaultValues() const;
private:
QSharedDataPointer<QCommandLineOptionPrivate> d;
};
#endif // QCOMMANDLINEOPTION_H

View File

@@ -0,0 +1,944 @@
/****************************************************************************
**
** Copyright (C) 2013 Laszlo Papp <lpapp@kde.org>
** Copyright (C) 2013 David Faure <faure@kde.org>
** Contact: http://www.qt-project.org/legal
**
** This file is part of the QtCore module of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL$
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and Digia. For licensing terms and
** conditions see http://qt.digia.com/licensing. For further information
** use the contact form at http://qt.digia.com/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file. Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Digia gives you certain additional
** rights. These rights are described in the Digia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3.0 as published by the Free Software
** Foundation and appearing in the file LICENSE.GPL included in the
** packaging of this file. Please review the following information to
** ensure the GNU General Public License version 3.0 requirements will be
** met: http://www.gnu.org/copyleft/gpl.html.
**
**
** $QT_END_LICENSE$
**
****************************************************************************/
#include "qcommandlineparser.h"
#include <QCoreApplication>
#include <QHash>
#include <QVector>
#include <stdio.h>
#include <stdlib.h>
typedef QHash<QString, int> NameHash_t;
class QCommandLineParserPrivate
{
public:
inline QCommandLineParserPrivate()
: singleDashWordOptionMode(QCommandLineParser::ParseAsCompactedShortOptions),
builtinVersionOption(false),
builtinHelpOption(false),
needsParsing(true)
{ }
bool parse(const QStringList &args);
void checkParsed(const char *method);
QStringList aliases(const QString &name) const;
QString helpText() const;
bool registerFoundOption(const QString &optionName);
bool parseOptionValue(const QString &optionName, const QString &argument,
QStringList::const_iterator *argumentIterator,
QStringList::const_iterator argsEnd);
//! Error text set when parse() returns false
QString errorText;
//! The command line options used for parsing
QList<QCommandLineOption> commandLineOptionList;
//! Hash mapping option names to their offsets in commandLineOptionList and optionArgumentList.
NameHash_t nameHash;
//! Option values found (only for options with a value)
QHash<int, QStringList> optionValuesHash;
//! Names of options found on the command line.
QStringList optionNames;
//! Arguments which did not belong to any option.
QStringList positionalArgumentList;
//! Names of options which were unknown.
QStringList unknownOptionNames;
//! Application description
QString description;
//! Documentation for positional arguments
struct PositionalArgumentDefinition
{
QString name;
QString description;
QString syntax;
};
QVector<PositionalArgumentDefinition> positionalArgumentDefinitions;
//! The parsing mode for "-abc"
QCommandLineParser::SingleDashWordOptionMode singleDashWordOptionMode;
//! Whether addVersionOption was called
bool builtinVersionOption;
//! Whether addHelpOption was called
bool builtinHelpOption;
//! True if parse() needs to be called
bool needsParsing;
};
QStringList QCommandLineParserPrivate::aliases(const QString &optionName) const
{
const NameHash_t::const_iterator it = nameHash.find(optionName);
if (it == nameHash.end()) {
qWarning("QCommandLineParser: option not defined: \"%s\"", qPrintable(optionName));
return QStringList();
}
return commandLineOptionList.at(*it).names();
}
/*!
\since 5.2
\class QCommandLineParser
\inmodule QtCore
\ingroup tools
\brief The QCommandLineParser class provides a means for handling the
command line options.
QCoreApplication provides the command-line arguments as a simple list of strings.
QCommandLineParser provides the ability to define a set of options, parse the
command-line arguments, and store which options have actually been used, as
well as option values.
Any argument that isn't an option (i.e. doesn't start with a \c{-}) is stored
as a "positional argument".
The parser handles short names, long names, more than one name for the same
option, and option values.
Options on the command line are recognized as starting with a single or
double \c{-} character(s).
The option \c{-} (single dash alone) is a special case, often meaning standard
input, and not treated as an option. The parser will treat everything after the
option \c{--} (double dash) as positional arguments.
Short options are single letters. The option \c{v} would be specified by
passing \c{-v} on the command line. In the default parsing mode, short options
can be written in a compact form, for instance \c{-abc} is equivalent to \c{-a -b -c}.
The parsing mode for can be set to ParseAsLongOptions, in which case \c{-abc}
will be parsed as the long option \c{abc}.
Long options are more than one letter long and cannot be compacted together.
The long option \c{verbose} would be passed as \c{--verbose} or \c{-verbose}.
Passing values to options can be done using the assignment operator: \c{-v=value}
\c{--verbose=value}, or a space: \c{-v value} \c{--verbose value}, i.e. the next
argument is used as value (even if it starts with a \c{-}).
The parser does not support optional values - if an option is set to
require a value, one must be present. If such an option is placed last
and has no value, the option will be treated as if it had not been
specified.
The parser does not automatically support negating or disabling long options
by using the format \c{--disable-option} or \c{--no-option}. However, it is
possible to handle this case explicitly by making an option with \c{no-option}
as one of its names, and handling the option explicitly.
Example:
\snippet code/src_corelib_tools_qcommandlineparser_main.cpp 0
Known limitation: the parsing of Qt options inside QCoreApplication and subclasses
happens before QCommandLineParser exists, so it can't take it into account. This
means any option value that looks like a builtin Qt option, will be treated by
QCoreApplication as a builtin Qt option. Example: \c{--profile -reverse} will
lead to QGuiApplication seeing the -reverse option set, and removing it from
QCoreApplication::arguments() before QCommandLineParser defines the \c{profile}
option and parses the command line.
\sa QCommandLineOption, QCoreApplication
*/
/*!
Constructs a command line parser object.
*/
QCommandLineParser::QCommandLineParser()
: d(new QCommandLineParserPrivate)
{
}
/*!
Destroys the command line parser object.
*/
QCommandLineParser::~QCommandLineParser()
{
delete d;
}
/*!
\enum QCommandLineParser::SingleDashWordOptionMode
This enum describes the way the parser interprets command-line
options that use a single dash followed by multiple letters, as as \c{-abc}.
\value ParseAsCompactedShortOptions \c{-abc} is interpreted as \c{-a -b -c},
i.e. as three short options that have been compacted on the command-line,
if none of the options take a value. If \c{a} takes a value, then it
is interpreted as \c{-a bc}, i.e. the short option \c{a} followed by the value \c{bc}.
This is typically used in tools that behave like compilers, in order
to handle options such as \c{-DDEFINE=VALUE} or \c{-I/include/path}.
This is the default parsing mode. New applications are recommended to
use this mode.
\value ParseAsLongOptions \c{-abc} is interpreted as \c{--abc},
i.e. as the long option named \c{abc}. This is how Qt's own tools
(uic, rcc...) have always been parsing arguments. This mode should be
used for preserving compatibility in applications that were parsing
arguments in such a way.
\sa setSingleDashWordOptionMode()
*/
/*!
Sets the parsing mode to \a singleDashWordOptionMode.
This must be called before process() or parse().
*/
void QCommandLineParser::setSingleDashWordOptionMode(QCommandLineParser::SingleDashWordOptionMode singleDashWordOptionMode)
{
d->singleDashWordOptionMode = singleDashWordOptionMode;
}
/*!
Adds the option \a option to look for while parsing.
Returns \c true if adding the option was successful; otherwise returns \c false.
Adding the option fails if there is no name attached to the option, or
the option has a name that clashes with an option name added before.
*/
bool QCommandLineParser::addOption(const QCommandLineOption &option)
{
QStringList optionNames = option.names();
if (!optionNames.isEmpty()) {
Q_FOREACH (const QString &name, optionNames) {
if (d->nameHash.contains(name))
return false;
}
d->commandLineOptionList.append(option);
const int offset = d->commandLineOptionList.size() - 1;
Q_FOREACH (const QString &name, optionNames)
d->nameHash.insert(name, offset);
return true;
}
return false;
}
/*!
Adds the \c{-v} / \c{--version} option, which displays the version string of the application.
This option is handled automatically by QCommandLineParser.
You can set the actual version string by using QCoreApplication::setApplicationVersion().
Returns the option instance, which can be used to call isSet().
*/
QCommandLineOption QCommandLineParser::addVersionOption()
{
QCommandLineOption opt(QStringList() << "v" << "version", tr("Displays version information."));
addOption(opt);
d->builtinVersionOption = true;
return opt;
}
/*!
Adds the help option (\c{-h}, \c{--help} and \c{-?} on Windows)
This option is handled automatically by QCommandLineParser.
Remember to use setApplicationDescription to set the application description,
which will be displayed when this option is used.
Example:
\snippet code/src_corelib_tools_qcommandlineparser_main.cpp 0
Returns the option instance, which can be used to call isSet().
*/
QCommandLineOption QCommandLineParser::addHelpOption()
{
QCommandLineOption opt(QStringList()
#ifdef Q_OS_WIN
<< "?"
#endif
<< "h"
<< "help", tr("Displays this help."));
addOption(opt);
d->builtinHelpOption = true;
return opt;
}
/*!
Sets the application \a description shown by helpText().
*/
void QCommandLineParser::setApplicationDescription(const QString &description)
{
d->description = description;
}
/*!
Returns the application description set in setApplicationDescription().
*/
QString QCommandLineParser::applicationDescription() const
{
return d->description;
}
/*!
Defines an additional argument to the application, for the benefit of the help text.
The argument \a name and \a description will appear under the \c{Arguments:} section
of the help. If \a syntax is specified, it will be appended to the Usage line, otherwise
the \a name will be appended.
Example:
\snippet code/src_corelib_tools_qcommandlineparser.cpp 2
\sa addHelpOption(), helpText()
*/
void QCommandLineParser::addPositionalArgument(const QString &name, const QString &description, const QString &syntax)
{
QCommandLineParserPrivate::PositionalArgumentDefinition arg;
arg.name = name;
arg.description = description;
arg.syntax = syntax.isEmpty() ? name : syntax;
d->positionalArgumentDefinitions.append(arg);
}
/*!
Clears the definitions of additional arguments from the help text.
This is only needed for the special case of tools which support multiple commands
with different options. Once the actual command has been identified, the options
for this command can be defined, and the help text for the command can be adjusted
accordingly.
Example:
\snippet code/src_corelib_tools_qcommandlineparser.cpp 3
*/
void QCommandLineParser::clearPositionalArguments()
{
d->positionalArgumentDefinitions.clear();
}
/*!
Parses the command line \a arguments.
Most programs don't need to call this, a simple call to process() is enough.
parse() is more low-level, and only does the parsing. The application will have to
take care of the error handling, using errorText() if parse() returns \c false.
This can be useful for instance to show a graphical error message in graphical programs.
Calling parse() instead of process() can also be useful in order to ignore unknown
options temporarily, because more option definitions will be provided later on
(depending on one of the arguments), before calling process().
Don't forget that \a arguments must start with the name of the executable (ignored, though).
Returns \c false in case of a parse error (unknown option or missing value); returns \c true otherwise.
\sa process()
*/
bool QCommandLineParser::parse(const QStringList &arguments)
{
return d->parse(arguments);
}
/*!
Returns a translated error text for the user.
This should only be called when parse() returns \c false.
*/
QString QCommandLineParser::errorText() const
{
if (!d->errorText.isEmpty())
return d->errorText;
if (d->unknownOptionNames.count() == 1)
return tr("Unknown option '%1'.").arg(d->unknownOptionNames.first());
if (d->unknownOptionNames.count() > 1)
return tr("Unknown options: %1.").arg(d->unknownOptionNames.join(", "));
return QString();
}
/*!
Processes the command line \a arguments.
In addition to parsing the options (like parse()), this function also handles the builtin
options and handles errors.
The builtin options are \c{--version} if addVersionOption was called and \c{--help} if addHelpOption was called.
When invoking one of these options, or when an error happens (for instance an unknown option was
passed), the current process will then stop, using the exit() function.
\sa QCoreApplication::arguments(), parse()
*/
void QCommandLineParser::process(const QStringList &arguments)
{
if (!d->parse(arguments)) {
fprintf(stderr, "%s\n", qPrintable(errorText()));
::exit(EXIT_FAILURE);
}
if (d->builtinVersionOption && isSet("version")) {
printf("%s %s\n", qPrintable(QCoreApplication::applicationName()), qPrintable(QCoreApplication::applicationVersion()));
::exit(EXIT_SUCCESS);
}
if (d->builtinHelpOption && isSet("help"))
showHelp(EXIT_SUCCESS);
}
/*!
\overload
The command line is obtained from the QCoreApplication instance \a app.
*/
void QCommandLineParser::process(const QCoreApplication &app)
{
// QCoreApplication::arguments() is static, but the app instance must exist so we require it as parameter
Q_UNUSED(app);
process(QCoreApplication::arguments());
}
void QCommandLineParserPrivate::checkParsed(const char *method)
{
if (needsParsing)
qWarning("QCommandLineParser: call process() or parse() before %s", method);
}
/*!
\internal
Looks up the option \a optionName (found on the command line) and register it as found.
Returns \c true on success.
*/
bool QCommandLineParserPrivate::registerFoundOption(const QString &optionName)
{
if (nameHash.contains(optionName)) {
optionNames.append(optionName);
return true;
} else {
unknownOptionNames.append(optionName);
return false;
}
}
/*!
\internal
\brief Parse the value for a given option, if it was defined to expect one.
The value is taken from the next argument, or after the equal sign in \a argument.
\param optionName the short option name
\param argument the argument from the command line currently parsed. Only used for -k=value parsing.
\param argumentIterator iterator to the currently parsed argument. Incremented if the next argument contains the value.
\param argsEnd args.end(), to check if ++argumentIterator goes out of bounds
Returns \c true on success.
*/
bool QCommandLineParserPrivate::parseOptionValue(const QString &optionName, const QString &argument,
QStringList::const_iterator *argumentIterator, QStringList::const_iterator argsEnd)
{
const QLatin1Char assignChar('=');
const NameHash_t::const_iterator nameHashIt = nameHash.constFind(optionName);
if (nameHashIt != nameHash.constEnd()) {
const int assignPos = argument.indexOf(assignChar);
const NameHash_t::mapped_type optionOffset = *nameHashIt;
const bool withValue = !commandLineOptionList.at(optionOffset).valueName().isEmpty();
if (withValue) {
if (assignPos == -1) {
++(*argumentIterator);
if (*argumentIterator == argsEnd) {
errorText = QCommandLineParser::tr("Missing value after '%1'.").arg(argument);
return false;
}
optionValuesHash[optionOffset].append(*(*argumentIterator));
} else {
optionValuesHash[optionOffset].append(argument.mid(assignPos + 1));
}
} else {
if (assignPos != -1) {
errorText = QCommandLineParser::tr("Unexpected value after '%1'.").arg(argument.left(assignPos));
return false;
}
}
}
return true;
}
/*!
\internal
Parse the list of arguments \a args, and fills in
optionNames, optionValuesHash, unknownOptionNames, positionalArguments, and errorText.
Any results from a previous parse operation are removed.
The parser will not look for further options once it encounters the option
\c{--}; this does not include when \c{--} follows an option that requires a value.
*/
bool QCommandLineParserPrivate::parse(const QStringList &args)
{
needsParsing = false;
bool error = false;
const QString doubleDashString("--");
const QLatin1Char dashChar('-');
const QLatin1Char assignChar('=');
bool doubleDashFound = false;
errorText.clear();
positionalArgumentList.clear();
optionNames.clear();
unknownOptionNames.clear();
optionValuesHash.clear();
if (args.isEmpty()) {
qWarning("QCommandLineParser: argument list cannot be empty, it should contain at least the executable name");
return false;
}
QStringList::const_iterator argumentIterator = args.begin();
++argumentIterator; // skip executable name
for (; argumentIterator != args.end() ; ++argumentIterator) {
QString argument = *argumentIterator;
if (doubleDashFound) {
positionalArgumentList.append(argument);
} else if (argument.startsWith(doubleDashString)) {
if (argument.length() > 2) {
QString optionName = argument.mid(2).section(assignChar, 0, 0);
if (registerFoundOption(optionName)) {
if (!parseOptionValue(optionName, argument, &argumentIterator, args.end()))
error = true;
} else {
error = true;
}
} else {
doubleDashFound = true;
}
} else if (argument.startsWith(dashChar)) {
if (argument.size() == 1) { // single dash ("stdin")
positionalArgumentList.append(argument);
continue;
}
switch (singleDashWordOptionMode) {
case QCommandLineParser::ParseAsCompactedShortOptions:
{
QString optionName;
bool valueFound = false;
for (int pos = 1 ; pos < argument.size(); ++pos) {
optionName = argument.mid(pos, 1);
if (!registerFoundOption(optionName)) {
error = true;
} else {
const NameHash_t::const_iterator nameHashIt = nameHash.constFind(optionName);
Q_ASSERT(nameHashIt != nameHash.constEnd()); // checked by registerFoundOption
const NameHash_t::mapped_type optionOffset = *nameHashIt;
const bool withValue = !commandLineOptionList.at(optionOffset).valueName().isEmpty();
if (withValue) {
if (pos + 1 < argument.size()) {
if (argument.at(pos + 1) == assignChar)
++pos;
optionValuesHash[optionOffset].append(argument.mid(pos + 1));
valueFound = true;
}
break;
}
if (pos + 1 < argument.size() && argument.at(pos + 1) == assignChar)
break;
}
}
if (!valueFound && !parseOptionValue(optionName, argument, &argumentIterator, args.end()))
error = true;
break;
}
case QCommandLineParser::ParseAsLongOptions:
{
const QString optionName = argument.mid(1).section(assignChar, 0, 0);
if (registerFoundOption(optionName)) {
if (!parseOptionValue(optionName, argument, &argumentIterator, args.end()))
error = true;
} else {
error = true;
}
break;
}
}
} else {
positionalArgumentList.append(argument);
}
if (argumentIterator == args.end())
break;
}
return !error;
}
/*!
Checks whether the option \a name was passed to the application.
Returns \c true if the option \a name was set, false otherwise.
The name provided can be any long or short name of any option that was
added with \c addOption(). All the options names are treated as being
equivalent. If the name is not recognized or that option was not present,
false is returned.
Example:
\snippet code/src_corelib_tools_qcommandlineparser.cpp 0
*/
bool QCommandLineParser::isSet(const QString &name) const
{
d->checkParsed("isSet");
if (d->optionNames.contains(name))
return true;
const QStringList aliases = d->aliases(name);
Q_FOREACH (const QString &optionName, d->optionNames) {
if (aliases.contains(optionName))
return true;
}
return false;
}
/*!
Returns the option value found for the given option name \a optionName, or
an empty string if not found.
The name provided can be any long or short name of any option that was
added with \c addOption(). All the option names are treated as being
equivalent. If the name is not recognized or that option was not present, an
empty string is returned.
For options found by the parser, the last value found for
that option is returned. If the option wasn't specified on the command line,
the default value is returned.
An empty string is returned if the option does not take a value.
\sa values(), QCommandLineOption::setDefaultValue(), QCommandLineOption::setDefaultValues()
*/
QString QCommandLineParser::value(const QString &optionName) const
{
d->checkParsed("value");
const QStringList valueList = values(optionName);
if (!valueList.isEmpty())
return valueList.last();
return QString();
}
/*!
Returns a list of option values found for the given option name \a
optionName, or an empty list if not found.
The name provided can be any long or short name of any option that was
added with \c addOption(). All the options names are treated as being
equivalent. If the name is not recognized or that option was not present, an
empty list is returned.
For options found by the parser, the list will contain an entry for
each time the option was encountered by the parser. If the option wasn't
specified on the command line, the default values are returned.
An empty list is returned if the option does not take a value.
\sa value(), QCommandLineOption::setDefaultValue(), QCommandLineOption::setDefaultValues()
*/
QStringList QCommandLineParser::values(const QString &optionName) const
{
d->checkParsed("values");
const NameHash_t::const_iterator it = d->nameHash.constFind(optionName);
if (it != d->nameHash.constEnd()) {
const int optionOffset = *it;
QStringList values = d->optionValuesHash.value(optionOffset);
if (values.isEmpty())
values = d->commandLineOptionList.at(optionOffset).defaultValues();
return values;
}
qWarning("QCommandLineParser: option not defined: \"%s\"", qPrintable(optionName));
return QStringList();
}
/*!
\overload
Checks whether the \a option was passed to the application.
Returns \c true if the \a option was set, false otherwise.
This is the recommended way to check for options with no values.
Example:
\snippet code/src_corelib_tools_qcommandlineparser.cpp 1
*/
bool QCommandLineParser::isSet(const QCommandLineOption &option) const
{
// option.names() might be empty if the constructor failed
return !option.names().isEmpty() && isSet(option.names().first());
}
/*!
\overload
Returns the option value found for the given \a option, or
an empty string if not found.
For options found by the parser, the last value found for
that option is returned. If the option wasn't specified on the command line,
the default value is returned.
An empty string is returned if the option does not take a value.
\sa values(), QCommandLineOption::setDefaultValue(), QCommandLineOption::setDefaultValues()
*/
QString QCommandLineParser::value(const QCommandLineOption &option) const
{
return value(option.names().first());
}
/*!
\overload
Returns a list of option values found for the given \a option,
or an empty list if not found.
For options found by the parser, the list will contain an entry for
each time the option was encountered by the parser. If the option wasn't
specified on the command line, the default values are returned.
An empty list is returned if the option does not take a value.
\sa value(), QCommandLineOption::setDefaultValue(), QCommandLineOption::setDefaultValues()
*/
QStringList QCommandLineParser::values(const QCommandLineOption &option) const
{
return values(option.names().first());
}
/*!
Returns a list of positional arguments.
These are all of the arguments that were not recognized as part of an
option.
*/
QStringList QCommandLineParser::positionalArguments() const
{
d->checkParsed("positionalArguments");
return d->positionalArgumentList;
}
/*!
Returns a list of option names that were found.
This returns a list of all the recognized option names found by the
parser, in the order in which they were found. For any long options
that were in the form {--option=value}, the value part will have been
dropped.
The names in this list do not include the preceding dash characters.
Names may appear more than once in this list if they were encountered
more than once by the parser.
Any entry in the list can be used with \c value() or with
\c values() to get any relevant option values.
*/
QStringList QCommandLineParser::optionNames() const
{
d->checkParsed("optionNames");
return d->optionNames;
}
/*!
Returns a list of unknown option names.
This list will include both long an short name options that were not
recognized. For any long options that were in the form {--option=value},
the value part will have been dropped and only the long name is added.
The names in this list do not include the preceding dash characters.
Names may appear more than once in this list if they were encountered
more than once by the parser.
\sa optionNames()
*/
QStringList QCommandLineParser::unknownOptionNames() const
{
d->checkParsed("unknownOptionNames");
return d->unknownOptionNames;
}
/*!
Displays the help information, and exits the application.
This is automatically triggered by the --help option, but can also
be used to display the help when the user is not invoking the
application correctly.
The exit code is set to \a exitCode. It should be set to 0 if the
user requested to see the help, and to any other value in case of
an error.
\sa helpText()
*/
void QCommandLineParser::showHelp(int exitCode)
{
fprintf(stdout, "%s", qPrintable(d->helpText()));
::exit(exitCode);
}
/*!
Returns a string containing the complete help information.
\sa showHelp()
*/
QString QCommandLineParser::helpText() const
{
return d->helpText();
}
static QString wrapText(const QString &names, int longestOptionNameString, const QString &description)
{
const QLatin1Char nl('\n');
QString text = QString(" ") + names.leftJustified(longestOptionNameString) + QLatin1Char(' ');
const int indent = text.length();
int lineStart = 0;
int lastBreakable = -1;
const int max = 79 - indent;
int x = 0;
const int len = description.length();
for (int i = 0; i < len; ++i) {
++x;
const QChar c = description.at(i);
if (c.isSpace())
lastBreakable = i;
int breakAt = -1;
int nextLineStart = -1;
if (x > max && lastBreakable != -1) {
// time to break and we know where
breakAt = lastBreakable;
nextLineStart = lastBreakable + 1;
} else if ((x > max - 1 && lastBreakable == -1) || i == len - 1) {
// time to break but found nowhere [-> break here], or end of last line
breakAt = i + 1;
nextLineStart = breakAt;
} else if (c == nl) {
// forced break
breakAt = i;
nextLineStart = i + 1;
}
if (breakAt != -1) {
const int numChars = breakAt - lineStart;
//qDebug() << "breakAt=" << description.at(breakAt) << "breakAtSpace=" << breakAtSpace << lineStart << "to" << breakAt << description.mid(lineStart, numChars);
if (lineStart > 0)
text += QString(indent, QLatin1Char(' '));
text += description.mid(lineStart, numChars) + nl;
x = 0;
lastBreakable = -1;
lineStart = nextLineStart;
if (lineStart < len && description.at(lineStart).isSpace())
++lineStart; // don't start a line with a space
i = lineStart;
}
}
return text;
}
QString QCommandLineParserPrivate::helpText() const
{
const QLatin1Char nl('\n');
QString text;
const QString exeName = QCoreApplication::instance()->arguments().first();
QString usage = exeName;
if (!commandLineOptionList.isEmpty()) {
usage += QLatin1Char(' ');
usage += QCommandLineParser::tr("[options]");
}
Q_FOREACH (const PositionalArgumentDefinition &arg, positionalArgumentDefinitions) {
usage += QLatin1Char(' ');
usage += arg.syntax;
}
text += QCommandLineParser::tr("Usage: %1").arg(usage) + nl;
if (!description.isEmpty())
text += description + nl;
text += nl;
if (!commandLineOptionList.isEmpty())
text += QCommandLineParser::tr("Options:") + nl;
QStringList optionNameList;
int longestOptionNameString = 0;
Q_FOREACH (const QCommandLineOption &option, commandLineOptionList) {
QStringList optionNames;
Q_FOREACH (const QString &optionName, option.names()) {
if (optionName.length() == 1)
optionNames.append(QLatin1Char('-') + optionName);
else
optionNames.append(QString("--") + optionName);
}
QString optionNamesString = optionNames.join(", ");
if (!option.valueName().isEmpty())
optionNamesString += QString(" <") + option.valueName() + QLatin1Char('>');
optionNameList.append(optionNamesString);
longestOptionNameString = qMax(longestOptionNameString, optionNamesString.length());
}
++longestOptionNameString;
for (int i = 0; i < commandLineOptionList.count(); ++i) {
const QCommandLineOption &option = commandLineOptionList.at(i);
text += wrapText(optionNameList.at(i), longestOptionNameString, option.description());
}
if (!positionalArgumentDefinitions.isEmpty()) {
if (!commandLineOptionList.isEmpty())
text += nl;
text += QCommandLineParser::tr("Arguments:") + nl;
Q_FOREACH (const PositionalArgumentDefinition &arg, positionalArgumentDefinitions) {
text += wrapText(arg.name, longestOptionNameString, arg.description);
}
}
return text;
}

View File

@@ -0,0 +1,102 @@
/****************************************************************************
**
** Copyright (C) 2013 Laszlo Papp <lpapp@kde.org>
** Contact: http://www.qt-project.org/legal
**
** This file is part of the QtCore module of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL$
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and Digia. For licensing terms and
** conditions see http://qt.digia.com/licensing. For further information
** use the contact form at http://qt.digia.com/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file. Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Digia gives you certain additional
** rights. These rights are described in the Digia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3.0 as published by the Free Software
** Foundation and appearing in the file LICENSE.GPL included in the
** packaging of this file. Please review the following information to
** ensure the GNU General Public License version 3.0 requirements will be
** met: http://www.gnu.org/copyleft/gpl.html.
**
**
** $QT_END_LICENSE$
**
****************************************************************************/
#ifndef QCOMMANDLINEPARSER_H
#define QCOMMANDLINEPARSER_H
#include <QStringList>
#include <QCoreApplication>
#include "qcommandlineoption.h"
class QCommandLineParserPrivate;
class QCoreApplication;
class QCommandLineParser
{
Q_DECLARE_TR_FUNCTIONS(QCommandLineParser)
public:
QCommandLineParser();
~QCommandLineParser();
enum SingleDashWordOptionMode {
ParseAsCompactedShortOptions,
ParseAsLongOptions
};
void setSingleDashWordOptionMode(SingleDashWordOptionMode parsingMode);
bool addOption(const QCommandLineOption &commandLineOption);
QCommandLineOption addVersionOption();
QCommandLineOption addHelpOption();
void setApplicationDescription(const QString &description);
QString applicationDescription() const;
void addPositionalArgument(const QString &name, const QString &description, const QString &syntax = QString());
void clearPositionalArguments();
void process(const QStringList &arguments);
void process(const QCoreApplication &app);
bool parse(const QStringList &arguments);
QString errorText() const;
bool isSet(const QString &name) const;
QString value(const QString &name) const;
QStringList values(const QString &name) const;
bool isSet(const QCommandLineOption &option) const;
QString value(const QCommandLineOption &option) const;
QStringList values(const QCommandLineOption &option) const;
QStringList positionalArguments() const;
QStringList optionNames() const;
QStringList unknownOptionNames() const;
void showHelp(int exitCode = 0);
QString helpText() const;
private:
Q_DISABLE_COPY(QCommandLineParser)
QCommandLineParserPrivate * const d;
};
#endif // QCOMMANDLINEPARSER_H

344
src/core/qlockfile.cpp Normal file
View File

@@ -0,0 +1,344 @@
/****************************************************************************
**
** Copyright (C) 2013 David Faure <faure+bluesystems@kde.org>
** Contact: http://www.qt-project.org/legal
**
** This file is part of the QtCore module of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL21$
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and Digia. For licensing terms and
** conditions see http://qt.digia.com/licensing. For further information
** use the contact form at http://qt.digia.com/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 or version 3 as published by the Free
** Software Foundation and appearing in the file LICENSE.LGPLv21 and
** LICENSE.LGPLv3 included in the packaging of this file. Please review the
** following information to ensure the GNU Lesser General Public License
** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Digia gives you certain additional
** rights. These rights are described in the Digia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** $QT_END_LICENSE$
**
****************************************************************************/
#include "qlockfile.h"
#include "qlockfile_p.h"
#if QT_VERSION >= QT_VERSION_CHECK(4, 7, 0)
# include <QElapsedTimer>
#else
# include <QTime>
#endif
#include <QDateTime>
QT_BEGIN_NAMESPACE
/*!
\class QLockFile
\inmodule QtCore
\brief The QLockFile class provides locking between processes using a file.
\since 5.1
A lock file can be used to prevent multiple processes from accessing concurrently
the same resource. For instance, a configuration file on disk, or a socket, a port,
a region of shared memory...
Serialization is only guaranteed if all processes that access the shared resource
use QLockFile, with the same file path.
QLockFile supports two use cases:
to protect a resource for a short-term operation (e.g. verifying if a configuration
file has changed before saving new settings), and for long-lived protection of a
resource (e.g. a document opened by a user in an editor) for an indefinite amount of time.
When protecting for a short-term operation, it is acceptable to call lock() and wait
until any running operation finishes.
When protecting a resource over a long time, however, the application should always
call setStaleLockTime(0) and then tryLock() with a short timeout, in order to
warn the user that the resource is locked.
If the process holding the lock crashes, the lock file stays on disk and can prevent
any other process from accessing the shared resource, ever. For this reason, QLockFile
tries to detect such a "stale" lock file, based on the process ID written into the file,
and (in case that process ID got reused meanwhile), on the last modification time of
the lock file (30s by default, for the use case of a short-lived operation).
If the lock file is found to be stale, it will be deleted.
For the use case of protecting a resource over a long time, you should therefore call
setStaleLockTime(0), and when tryLock() returns LockFailedError, inform the user
that the document is locked, possibly using getLockInfo() for more details.
*/
/*!
\enum QLockFile::LockError
This enum describes the result of the last call to lock() or tryLock().
\value NoError The lock was acquired successfully.
\value LockFailedError The lock could not be acquired because another process holds it.
\value PermissionError The lock file could not be created, for lack of permissions
in the parent directory.
\value UnknownError Another error happened, for instance a full partition
prevented writing out the lock file.
*/
/*!
Constructs a new lock file object.
The object is created in an unlocked state.
When calling lock() or tryLock(), a lock file named \a fileName will be created,
if it doesn't already exist.
\sa lock(), unlock()
*/
QLockFile::QLockFile(const QString &fileName)
: d_ptr(new QLockFilePrivate(fileName))
{
}
/*!
Destroys the lock file object.
If the lock was acquired, this will release the lock, by deleting the lock file.
*/
QLockFile::~QLockFile()
{
unlock();
}
/*!
Sets \a staleLockTime to be the time in milliseconds after which
a lock file is considered stale.
The default value is 30000, i.e. 30 seconds.
If your application typically keeps the file locked for more than 30 seconds
(for instance while saving megabytes of data for 2 minutes), you should set
a bigger value using setStaleLockTime().
The value of \a staleLockTime is used by lock() and tryLock() in order
to determine when an existing lock file is considered stale, i.e. left over
by a crashed process. This is useful for the case where the PID got reused
meanwhile, so the only way to detect a stale lock file is by the fact that
it has been around for a long time.
\sa staleLockTime()
*/
void QLockFile::setStaleLockTime(int staleLockTime)
{
Q_D(QLockFile);
d->staleLockTime = staleLockTime;
}
/*!
Returns the time in milliseconds after which
a lock file is considered stale.
\sa setStaleLockTime()
*/
int QLockFile::staleLockTime() const
{
Q_D(const QLockFile);
return d->staleLockTime;
}
/*!
Returns \c true if the lock was acquired by this QLockFile instance,
otherwise returns \c false.
\sa lock(), unlock(), tryLock()
*/
bool QLockFile::isLocked() const
{
Q_D(const QLockFile);
return d->isLocked;
}
/*!
Creates the lock file.
If another process (or another thread) has created the lock file already,
this function will block until that process (or thread) releases it.
Calling this function multiple times on the same lock from the same
thread without unlocking first is not allowed. This function will
\e dead-lock when the file is locked recursively.
Returns \c true if the lock was acquired, false if it could not be acquired
due to an unrecoverable error, such as no permissions in the parent directory.
\sa unlock(), tryLock()
*/
bool QLockFile::lock()
{
return tryLock(-1);
}
/*!
Attempts to create the lock file. This function returns \c true if the
lock was obtained; otherwise it returns \c false. If another process (or
another thread) has created the lock file already, this function will
wait for at most \a timeout milliseconds for the lock file to become
available.
Note: Passing a negative number as the \a timeout is equivalent to
calling lock(), i.e. this function will wait forever until the lock
file can be locked if \a timeout is negative.
If the lock was obtained, it must be released with unlock()
before another process (or thread) can successfully lock it.
Calling this function multiple times on the same lock from the same
thread without unlocking first is not allowed, this function will
\e always return false when attempting to lock the file recursively.
\sa lock(), unlock()
*/
bool QLockFile::tryLock(int timeout)
{
Q_D(QLockFile);
#if QT_VERSION >= QT_VERSION_CHECK(4, 7, 0)
QElapsedTimer timer;
#else
QTime timer;
#endif
if (timeout > 0)
timer.start();
int sleepTime = 100;
Q_FOREVER {
d->lockError = d->tryLock_sys();
switch (d->lockError) {
case NoError:
d->isLocked = true;
return true;
case PermissionError:
case UnknownError:
return false;
case LockFailedError:
if (!d->isLocked && d->isApparentlyStale()) {
// Stale lock from another thread/process
// Ensure two processes don't remove it at the same time
QLockFile rmlock(d->fileName + QLatin1String(".rmlock"));
if (rmlock.tryLock()) {
if (d->isApparentlyStale() && d->removeStaleLock())
continue;
}
}
break;
}
if (timeout == 0 || (timeout > 0 && (timer.elapsed() > timeout)))
return false;
QLockFileThread::msleep(sleepTime);
if (sleepTime < 5 * 1000)
sleepTime *= 2;
}
// not reached
return false;
}
/*!
\fn void QLockFile::unlock()
Releases the lock, by deleting the lock file.
Calling unlock() without locking the file first, does nothing.
\sa lock(), tryLock()
*/
/*!
Retrieves information about the current owner of the lock file.
If tryLock() returns \c false, and error() returns LockFailedError,
this function can be called to find out more information about the existing
lock file:
\list
\li the PID of the application (returned in \a pid)
\li the \a hostname it's running on (useful in case of networked filesystems),
\li the name of the application which created it (returned in \a appname),
\endlist
Note that tryLock() automatically deleted the file if there is no
running application with this PID, so LockFailedError can only happen if there is
an application with this PID (it could be unrelated though).
This can be used to inform users about the existing lock file and give them
the choice to delete it. After removing the file using removeStaleLockFile(),
the application can call tryLock() again.
This function returns \c true if the information could be successfully retrieved, false
if the lock file doesn't exist or doesn't contain the expected data.
This can happen if the lock file was deleted between the time where tryLock() failed
and the call to this function. Simply call tryLock() again if this happens.
*/
bool QLockFile::getLockInfo(qint64 *pid, QString *hostname, QString *appname) const
{
Q_D(const QLockFile);
return d->getLockInfo(pid, hostname, appname);
}
bool QLockFilePrivate::getLockInfo(qint64 *pid, QString *hostname, QString *appname) const
{
QFile reader(fileName);
if (!reader.open(QIODevice::ReadOnly))
return false;
QByteArray pidLine = reader.readLine();
pidLine.chop(1);
QByteArray appNameLine = reader.readLine();
appNameLine.chop(1);
QByteArray hostNameLine = reader.readLine();
hostNameLine.chop(1);
if (pidLine.isEmpty())
return false;
qint64 thePid = pidLine.toLongLong();
if (pid)
*pid = thePid;
if (appname)
*appname = QString::fromUtf8(appNameLine);
if (hostname)
*hostname = QString::fromUtf8(hostNameLine);
return thePid > 0;
}
/*!
Attempts to forcefully remove an existing lock file.
Calling this is not recommended when protecting a short-lived operation: QLockFile
already takes care of removing lock files after they are older than staleLockTime().
This method should only be called when protecting a resource for a long time, i.e.
with staleLockTime(0), and after tryLock() returned LockFailedError, and the user
agreed on removing the lock file.
Returns \c true on success, false if the lock file couldn't be removed. This happens
on Windows, when the application owning the lock is still running.
*/
bool QLockFile::removeStaleLockFile()
{
Q_D(QLockFile);
if (d->isLocked) {
qWarning("removeStaleLockFile can only be called when not holding the lock");
return false;
}
return d->removeStaleLock();
}
/*!
Returns the lock file error status.
If tryLock() returns \c false, this function can be called to find out
the reason why the locking failed.
*/
QLockFile::LockError QLockFile::error() const
{
Q_D(const QLockFile);
return d->lockError;
}
QT_END_NAMESPACE

79
src/core/qlockfile.h Normal file
View File

@@ -0,0 +1,79 @@
/****************************************************************************
**
** Copyright (C) 2013 David Faure <faure+bluesystems@kde.org>
** Contact: http://www.qt-project.org/legal
**
** This file is part of the QtCore module of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL21$
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and Digia. For licensing terms and
** conditions see http://qt.digia.com/licensing. For further information
** use the contact form at http://qt.digia.com/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 or version 3 as published by the Free
** Software Foundation and appearing in the file LICENSE.LGPLv21 and
** LICENSE.LGPLv3 included in the packaging of this file. Please review the
** following information to ensure the GNU Lesser General Public License
** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Digia gives you certain additional
** rights. These rights are described in the Digia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** $QT_END_LICENSE$
**
****************************************************************************/
#ifndef QLOCKFILE_H
#define QLOCKFILE_H
#include <QString>
#include <QScopedPointer>
QT_BEGIN_NAMESPACE
class QLockFilePrivate;
class QLockFile
{
public:
QLockFile(const QString &fileName);
~QLockFile();
bool lock();
bool tryLock(int timeout = 0);
void unlock();
void setStaleLockTime(int);
int staleLockTime() const;
bool isLocked() const;
bool getLockInfo(qint64 *pid, QString *hostname, QString *appname) const;
bool removeStaleLockFile();
enum LockError {
NoError = 0,
LockFailedError = 1,
PermissionError = 2,
UnknownError = 3
};
LockError error() const;
protected:
QScopedPointer<QLockFilePrivate> d_ptr;
private:
Q_DECLARE_PRIVATE(QLockFile)
Q_DISABLE_COPY(QLockFile)
};
QT_END_NAMESPACE
#endif // QLOCKFILE_H

101
src/core/qlockfile_p.h Normal file
View File

@@ -0,0 +1,101 @@
/****************************************************************************
**
** Copyright (C) 2013 David Faure <faure+bluesystems@kde.org>
** Contact: http://www.qt-project.org/legal
**
** This file is part of the QtCore module of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL21$
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and Digia. For licensing terms and
** conditions see http://qt.digia.com/licensing. For further information
** use the contact form at http://qt.digia.com/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 or version 3 as published by the Free
** Software Foundation and appearing in the file LICENSE.LGPLv21 and
** LICENSE.LGPLv3 included in the packaging of this file. Please review the
** following information to ensure the GNU Lesser General Public License
** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Digia gives you certain additional
** rights. These rights are described in the Digia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** $QT_END_LICENSE$
**
****************************************************************************/
#ifndef QLOCKFILE_P_H
#define QLOCKFILE_P_H
//
// W A R N I N G
// -------------
//
// This file is not part of the Qt API. It exists purely as an
// implementation detail. This header file may change from version to
// version without notice, or even be removed.
//
// We mean it.
//
#include "qlockfile.h"
#include <QFile>
#include <QThread>
#ifdef Q_OS_WIN
#include <qt_windows.h>
#endif
QT_BEGIN_NAMESPACE
class QLockFileThread : public QThread
{
public:
static void msleep(unsigned long msecs) { QThread::msleep(msecs); }
};
class QLockFilePrivate
{
public:
QLockFilePrivate(const QString &fn)
: fileName(fn),
#ifdef Q_OS_WIN
fileHandle(INVALID_HANDLE_VALUE),
#else
fileHandle(-1),
#endif
staleLockTime(30 * 1000), // 30 seconds
lockError(QLockFile::NoError),
isLocked(false)
{
}
QLockFile::LockError tryLock_sys();
bool removeStaleLock();
bool getLockInfo(qint64 *pid, QString *hostname, QString *appname) const;
// Returns \c true if the lock belongs to dead PID, or is old.
// The attempt to delete it will tell us if it was really stale or not, though.
bool isApparentlyStale() const;
static QString processNameByPid(qint64 pid);
QString fileName;
#ifdef Q_OS_WIN
Qt::HANDLE fileHandle;
#else
int fileHandle;
#endif
int staleLockTime; // "int milliseconds" is big enough for 24 days
QLockFile::LockError lockError;
bool isLocked;
};
QT_END_NAMESPACE
#endif /* QLOCKFILE_P_H */

244
src/core/qlockfile_unix.cpp Normal file
View File

@@ -0,0 +1,244 @@
/****************************************************************************
**
** Copyright (C) 2013 David Faure <faure+bluesystems@kde.org>
** Copyright (C) 2015 The Qt Company Ltd.
** Contact: http://www.qt-project.org/legal
**
** This file is part of the QtCore module of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL21$
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and Digia. For licensing terms and
** conditions see http://qt.digia.com/licensing. For further information
** use the contact form at http://qt.digia.com/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 or version 3 as published by the Free
** Software Foundation and appearing in the file LICENSE.LGPLv21 and
** LICENSE.LGPLv3 included in the packaging of this file. Please review the
** following information to ensure the GNU Lesser General Public License
** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Digia gives you certain additional
** rights. These rights are described in the Digia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** $QT_END_LICENSE$
**
****************************************************************************/
#include "qlockfile_p.h"
#include <QTemporaryFile>
#include <QCoreApplication>
#include <QFileInfo>
#include <QDebug>
#include <QDateTime>
#include <sys/file.h> // flock
#include <sys/types.h> // kill
#include <signal.h> // kill
#include <unistd.h> // gethostname
#include <errno.h>
#if defined(Q_OS_MAC)
# include <libproc.h>
#elif defined(Q_OS_LINUX)
# include <unistd.h>
# include <cstdio>
#endif
QT_BEGIN_NAMESPACE
#define EINTR_LOOP(var, cmd) \
do { \
var = cmd; \
} while (var == -1 && errno == EINTR)
// don't call QT_OPEN or ::open
// call qt_safe_open
static inline int qt_safe_open(const char *pathname, int flags, mode_t mode = 0777)
{
#ifdef O_CLOEXEC
flags |= O_CLOEXEC;
#endif
int fd;
EINTR_LOOP(fd, ::open(pathname, flags, mode));
// unknown flags are ignored, so we have no way of verifying if
// O_CLOEXEC was accepted
if (fd != -1)
::fcntl(fd, F_SETFD, FD_CLOEXEC);
return fd;
}
static inline qint64 qt_safe_write(int fd, const void *data, qint64 len)
{
qint64 ret = 0;
EINTR_LOOP(ret, ::write(fd, data, len));
return ret;
}
static QByteArray localHostName() // from QHostInfo::localHostName(), modified to return a QByteArray
{
QByteArray hostName(512, Qt::Uninitialized);
if (gethostname(hostName.data(), hostName.size()) == -1)
return QByteArray();
hostName.truncate(strlen(hostName.data()));
return hostName;
}
// ### merge into qt_safe_write?
static qint64 qt_write_loop(int fd, const char *data, qint64 len)
{
qint64 pos = 0;
while (pos < len) {
const qint64 ret = qt_safe_write(fd, data + pos, len - pos);
if (ret == -1) // e.g. partition full
return pos;
pos += ret;
}
return pos;
}
static bool setNativeLocks(int fd)
{
#if defined(LOCK_EX) && defined(LOCK_NB)
if (flock(fd, LOCK_EX | LOCK_NB) == -1) // other threads, and other processes on a local fs
return false;
#endif
struct flock flockData;
flockData.l_type = F_WRLCK;
flockData.l_whence = SEEK_SET;
flockData.l_start = 0;
flockData.l_len = 0; // 0 = entire file
flockData.l_pid = getpid();
if (fcntl(fd, F_SETLK, &flockData) == -1) // for networked filesystems
return false;
return true;
}
QLockFile::LockError QLockFilePrivate::tryLock_sys()
{
// Assemble data, to write in a single call to write
// (otherwise we'd have to check every write call)
// Use operator% from the fast builder to avoid multiple memory allocations.
QByteArray fileData = QByteArray::number(QCoreApplication::applicationPid()) + '\n'
+ QCoreApplication::applicationName().toUtf8() + '\n'
+ localHostName() + '\n';
const QByteArray lockFileName = QFile::encodeName(fileName);
const int fd = qt_safe_open(lockFileName.constData(), O_WRONLY | O_CREAT | O_EXCL, 0644);
if (fd < 0) {
switch (errno) {
case EEXIST:
return QLockFile::LockFailedError;
case EACCES:
case EROFS:
return QLockFile::PermissionError;
default:
return QLockFile::UnknownError;
}
}
// Ensure nobody else can delete the file while we have it
if (!setNativeLocks(fd))
qWarning() << "setNativeLocks failed:" << strerror(errno);
if (qt_write_loop(fd, fileData.constData(), fileData.size()) < fileData.size()) {
close(fd);
if (!QFile::remove(fileName))
qWarning("QLockFile: Could not remove our own lock file %s.", qPrintable(fileName));
return QLockFile::UnknownError; // partition full
}
// We hold the lock, continue.
fileHandle = fd;
return QLockFile::NoError;
}
bool QLockFilePrivate::removeStaleLock()
{
const QByteArray lockFileName = QFile::encodeName(fileName);
const int fd = qt_safe_open(lockFileName.constData(), O_WRONLY, 0644);
if (fd < 0) // gone already?
return false;
#ifdef Q_OS_MAC
// ugly workaround: ignore setNativeLocks() result on Mac since it's broken there
setNativeLocks(fd);
bool success = (::unlink(lockFileName) == 0);
#else
bool success = setNativeLocks(fd) && (::unlink(lockFileName) == 0);
#endif
close(fd);
return success;
}
bool QLockFilePrivate::isApparentlyStale() const
{
qint64 pid;
QString hostname, appname;
if (getLockInfo(&pid, &hostname, &appname)) {
if (hostname.isEmpty() || hostname == QString::fromLocal8Bit(localHostName())) {
if (::kill(pid, 0) == -1 && errno == ESRCH)
return true; // PID doesn't exist anymore
const QString processName = processNameByPid(pid);
if (!processName.isEmpty()) {
QFileInfo fi(appname);
if (fi.isSymLink())
fi.setFile(fi.symLinkTarget());
if (processName.toLower() != fi.fileName().toLower())
return true; // PID got reused by a different application.
}
}
}
const qint64 age = QFileInfo(fileName).lastModified().secsTo(QDateTime::currentDateTime()) * 1000;
return staleLockTime > 0 && age > staleLockTime;
}
QString QLockFilePrivate::processNameByPid(qint64 pid)
{
#if defined(Q_OS_MAC)
char name[1024];
proc_name(pid, name, sizeof(name) / sizeof(char));
return QFile::decodeName(name);
#elif defined(Q_OS_LINUX)
if (!QFile::exists(QString("/proc/version")))
return QString();
char exePath[64];
char buf[PATH_MAX + 1];
sprintf(exePath, "/proc/%lld/exe", pid);
size_t len = static_cast<size_t>(readlink(exePath, buf, sizeof(buf)));
if (len >= sizeof(buf)) {
// The pid is gone. Return some invalid process name to fail the test.
return QString("/ERROR/");
}
buf[len] = 0;
return QFileInfo(QFile::decodeName(buf)).fileName();
#else
return QString();
#endif
}
void QLockFile::unlock()
{
Q_D(QLockFile);
if (!d->isLocked)
return;
close(d->fileHandle);
d->fileHandle = -1;
if (!QFile::remove(d->fileName)) {
qWarning() << "Could not remove our own lock file" << d->fileName << "maybe permissions changed meanwhile?";
// This is bad because other users of this lock file will now have to wait for the stale-lock-timeout...
}
d->lockError = QLockFile::NoError;
d->isLocked = false;
}
QT_END_NAMESPACE

227
src/core/qlockfile_win.cpp Normal file
View File

@@ -0,0 +1,227 @@
/****************************************************************************
**
** Copyright (C) 2013 David Faure <faure+bluesystems@kde.org>
** Copyright (C) 2015 The Qt Company Ltd.
** Contact: http://www.qt.io/licensing/
**
** This file is part of the QtCore module of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL21$
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and The Qt Company. For licensing terms
** and conditions see http://www.qt.io/terms-conditions. For further
** information use the contact form at http://www.qt.io/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 or version 3 as published by the Free
** Software Foundation and appearing in the file LICENSE.LGPLv21 and
** LICENSE.LGPLv3 included in the packaging of this file. Please review the
** following information to ensure the GNU Lesser General Public License
** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** As a special exception, The Qt Company gives you certain additional
** rights. These rights are described in The Qt Company LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** $QT_END_LICENSE$
**
****************************************************************************/
#ifndef _UNICODE
#define _UNICODE
#endif
#ifndef UNICODE
#define UNICODE
#endif
#include "qlockfile_p.h"
#include <qt_windows.h>
#include <QCoreApplication>
#include <QDir>
#include <QFileInfo>
#include <QDateTime>
#include <QDebug>
QT_BEGIN_NAMESPACE
static inline QByteArray localHostName()
{
return qgetenv("COMPUTERNAME");
}
static inline bool fileExists(const wchar_t *fileName)
{
WIN32_FILE_ATTRIBUTE_DATA data;
return GetFileAttributesEx(fileName, GetFileExInfoStandard, &data);
}
QLockFile::LockError QLockFilePrivate::tryLock_sys()
{
const ushort* nativePath = QDir::toNativeSeparators(fileName).utf16();
// When writing, allow others to read.
// When reading, QFile will allow others to read and write, all good.
// Adding FILE_SHARE_DELETE would allow forceful deletion of stale files,
// but Windows doesn't allow recreating it while this handle is open anyway,
// so this would only create confusion (can't lock, but no lock file to read from).
const DWORD dwShareMode = FILE_SHARE_READ;
#ifndef Q_OS_WINRT
SECURITY_ATTRIBUTES securityAtts = { sizeof(SECURITY_ATTRIBUTES), NULL, FALSE };
HANDLE fh = CreateFile((const wchar_t*)nativePath,
GENERIC_WRITE,
dwShareMode,
&securityAtts,
CREATE_NEW, // error if already exists
FILE_ATTRIBUTE_NORMAL,
NULL);
#else // !Q_OS_WINRT
HANDLE fh = CreateFile2((const wchar_t*)nativePath,
GENERIC_WRITE,
dwShareMode,
CREATE_NEW, // error if already exists
NULL);
#endif // Q_OS_WINRT
if (fh == INVALID_HANDLE_VALUE) {
const DWORD lastError = GetLastError();
switch (lastError) {
case ERROR_SHARING_VIOLATION:
case ERROR_ALREADY_EXISTS:
case ERROR_FILE_EXISTS:
return QLockFile::LockFailedError;
case ERROR_ACCESS_DENIED:
// readonly file, or file still in use by another process.
// Assume the latter if the file exists, since we don't create it readonly.
return fileExists((const wchar_t*)nativePath)
? QLockFile::LockFailedError
: QLockFile::PermissionError;
default:
qWarning() << "Got unexpected locking error" << lastError;
return QLockFile::UnknownError;
}
}
// We hold the lock, continue.
fileHandle = fh;
// Assemble data, to write in a single call to write
// (otherwise we'd have to check every write call)
QByteArray fileData;
fileData += QByteArray::number(QCoreApplication::applicationPid());
fileData += '\n';
fileData += QCoreApplication::applicationName().toUtf8();
fileData += '\n';
fileData += localHostName();
fileData += '\n';
DWORD bytesWritten = 0;
QLockFile::LockError error = QLockFile::NoError;
if (!WriteFile(fh, fileData.constData(), fileData.size(), &bytesWritten, NULL) || !FlushFileBuffers(fh))
error = QLockFile::UnknownError; // partition full
return error;
}
bool QLockFilePrivate::removeStaleLock()
{
// QFile::remove fails on Windows if the other process is still using the file, so it's not stale.
return QFile::remove(fileName);
}
bool QLockFilePrivate::isApparentlyStale() const
{
qint64 pid;
QString hostname, appname;
// On WinRT there seems to be no way of obtaining information about other
// processes due to sandboxing
#ifndef Q_OS_WINRT
if (getLockInfo(&pid, &hostname, &appname)) {
if (hostname.isEmpty() || hostname == QString::fromLocal8Bit(localHostName())) {
HANDLE procHandle = ::OpenProcess(PROCESS_QUERY_INFORMATION, FALSE, pid);
if (!procHandle)
return true;
// We got a handle but check if process is still alive
DWORD dwR = ::WaitForSingleObject(procHandle, 0);
::CloseHandle(procHandle);
if (dwR == WAIT_TIMEOUT)
return true;
const QString processName = processNameByPid(pid);
if (!processName.isEmpty() && processName != appname)
return true; // PID got reused by a different application.
}
}
#else // !Q_OS_WINRT
Q_UNUSED(pid);
Q_UNUSED(hostname);
Q_UNUSED(appname);
#endif // Q_OS_WINRT
const qint64 age = QFileInfo(fileName).lastModified().msecsTo(QDateTime::currentDateTime());
return staleLockTime > 0 && age > staleLockTime;
}
QString QLockFilePrivate::processNameByPid(qint64 pid)
{
#if !defined(Q_OS_WINRT) && !defined(Q_OS_WINCE)
typedef DWORD (WINAPI *GetModuleFileNameExFunc)(HANDLE, HMODULE, LPTSTR, DWORD);
HMODULE hPsapi = LoadLibraryA("psapi");
if (!hPsapi)
return QString();
GetModuleFileNameExFunc qGetModuleFileNameEx
= (GetModuleFileNameExFunc)GetProcAddress(hPsapi, "GetModuleFileNameExW");
if (!qGetModuleFileNameEx) {
FreeLibrary(hPsapi);
return QString();
}
HANDLE hProcess = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE, DWORD(pid));
if (!hProcess) {
FreeLibrary(hPsapi);
return QString();
}
wchar_t buf[MAX_PATH];
const DWORD length = qGetModuleFileNameEx(hProcess, NULL, buf, sizeof(buf) / sizeof(wchar_t));
CloseHandle(hProcess);
FreeLibrary(hPsapi);
if (!length)
return QString();
QString name = QString::fromWCharArray(buf, length);
int i = name.lastIndexOf(QLatin1Char('\\'));
if (i >= 0)
name.remove(0, i + 1);
i = name.lastIndexOf(QLatin1Char('.'));
if (i >= 0)
name.truncate(i);
return name;
#else
Q_UNUSED(pid);
return QString();
#endif
}
void QLockFile::unlock()
{
Q_D(QLockFile);
if (!d->isLocked)
return;
CloseHandle(d->fileHandle);
int attempts = 0;
static const int maxAttempts = 500; // 500ms
while (!QFile::remove(d->fileName) && ++attempts < maxAttempts) {
// Someone is reading the lock file right now (on Windows this prevents deleting it).
QLockFileThread::msleep(1);
}
if (attempts == maxAttempts) {
qWarning() << "Could not remove our own lock file" << d->fileName << ". Either other users of the lock file are reading it constantly for 500 ms, or we (no longer) have permissions to delete the file";
// This is bad because other users of this lock file will now have to wait for the stale-lock-timeout...
}
d->lockError = QLockFile::NoError;
d->isLocked = false;
}
QT_END_NAMESPACE

452
src/core/qsavefile.cpp Normal file
View File

@@ -0,0 +1,452 @@
/****************************************************************************
**
** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/
**
** This file is part of the QtCore module of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL$
** GNU Lesser General Public License Usage
** This file may be used under the terms of the GNU Lesser General Public
** License version 2.1 as published by the Free Software Foundation and
** appearing in the file LICENSE.LGPL included in the packaging of this
** file. Please review the following information to ensure the GNU Lesser
** General Public License version 2.1 requirements will be met:
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Nokia gives you certain additional
** rights. These rights are described in the Nokia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU General
** Public License version 3.0 as published by the Free Software Foundation
** and appearing in the file LICENSE.GPL included in the packaging of this
** file. Please review the following information to ensure the GNU General
** Public License version 3.0 requirements will be met:
** http://www.gnu.org/copyleft/gpl.html.
**
** Other Usage
** Alternatively, this file may be used in accordance with the terms and
** conditions contained in a signed written agreement between you and Nokia.
**
**
**
**
**
**
** $QT_END_LICENSE$
**
****************************************************************************/
#include "qsavefile.h"
#include "qsavefile_p.h"
#include <QAbstractFileEngine>
#include <QFileInfo>
#include <QTemporaryFile>
#ifdef Q_OS_WIN
# include <windows.h>
#else
# include <unistd.h>
#endif
QSaveFilePrivate::QSaveFilePrivate()
: tempFile(0), error(QFile::NoError)
{
}
QSaveFilePrivate::~QSaveFilePrivate()
{
}
/*!
\class QSaveFile
\brief The QSaveFile class provides an interface for safely writing to files.
\ingroup io
\reentrant
QSaveFile is an I/O device for writing text and binary files, without losing
existing data if the writing operation fails.
While writing, the contents will be written to a temporary file, and if
no error happened, commit() will move it to the final file. This ensures that
no data at the final file is lost in case an error happens while writing,
and no partially-written file is ever present at the final location. Always
use QSaveFile when saving entire documents to disk.
QSaveFile automatically detects errors while writing, such as the full partition
situation, where write() cannot write all the bytes. It will remember that
an error happened, and will discard the temporary file in commit().
Much like with QFile, the file is opened with open(). Data is usually read
and written using QDataStream or QTextStream, but you can also call the
QIODevice-inherited functions read(), readLine(), readAll(), write().
Unlike QFile, calling close() is not allowed. commit() replaces it. If commit()
was not called and the QSaveFile instance is destroyed, the temporary file is
discarded.
\sa QTextStream, QDataStream, QFileInfo, QDir, QFile, QTemporaryFile
*/
/*!
\internal
*/
QSaveFile::QSaveFile()
: QIODevice(), d_ptr(new QSaveFilePrivate)
{
}
/*!
Constructs a new file object with the given \a parent.
*/
QSaveFile::QSaveFile(QObject *parent)
: QIODevice(parent), d_ptr(new QSaveFilePrivate)
{
}
/*!
Constructs a new file object to represent the file with the given \a name.
*/
QSaveFile::QSaveFile(const QString &name)
: QIODevice(0), d_ptr(new QSaveFilePrivate)
{
Q_D(QSaveFile);
d->fileName = name;
}
/*!
Constructs a new file object with the given \a parent to represent the
file with the specified \a name.
*/
QSaveFile::QSaveFile(const QString &name, QObject *parent)
: QIODevice(parent), d_ptr(new QSaveFilePrivate)
{
Q_D(QSaveFile);
d->fileName = name;
}
/*!
Destroys the file object, discarding the saved contents unless commit() was called.
*/
QSaveFile::~QSaveFile()
{
Q_D(QSaveFile);
if (d->tempFile) {
d->tempFile->setAutoRemove(true);
delete d->tempFile;
}
QIODevice::close();
delete d;
}
/*!
Returns false since temporary files support random access.
\sa QIODevice::isSequential()
*/
bool QSaveFile::isSequential() const
{
return false;
}
/*!
Returns the file error status.
The I/O device status returns an error code. For example, if open()
returns false, or a read/write operation returns -1, this function can
be called to find out the reason why the operation failed.
Unlike QFile which clears the error on the next operation, QSaveFile remembers
the error until the file is closed, in order to discard the file contents in close().
\sa unsetError()
*/
QFile::FileError QSaveFile::error() const
{
return d_func()->error;
}
/*!
Sets the file's error to QFile::NoError.
This will make QSaveFile forget that an error happened during saving, so you
probably don't want to call this, unless you're really sure that you want to
save the file anyway.
\sa error()
*/
void QSaveFile::unsetError()
{
d_func()->error = QFile::NoError;
setErrorString(QString());
}
/*!
Returns the name set by setFileName() or to the QSaveFile
constructor.
\sa setFileName()
*/
QString QSaveFile::fileName() const
{
return d_func()->fileName;
}
/*!
Sets the \a name of the file. The name can have no path, a
relative path, or an absolute path.
\sa QFile::setFileName(), fileName()
*/
void QSaveFile::setFileName(const QString &name)
{
d_func()->fileName = name;
}
/*!
Opens the file using OpenMode \a mode, returning true if successful;
otherwise false.
Important: the \a mode must be QIODevice::WriteOnly.
It may also have additional flags, such as QIODevice::Text and QIODevice::Unbuffered.
QIODevice::ReadWrite and QIODevice::Append are not supported at the moment.
\sa QIODevice::OpenMode, setFileName()
*/
bool QSaveFile::open(OpenMode mode)
{
Q_D(QSaveFile);
if (isOpen()) {
qWarning("QSaveFile::open: File (%s) already open", qPrintable(fileName()));
return false;
}
unsetError();
if ((mode & (ReadOnly | WriteOnly)) == 0) {
qWarning("QSaveFile::open: Open mode not specified");
return false;
}
// In the future we could implement Append and ReadWrite by copying from the existing file to the temp file...
if ((mode & ReadOnly) || (mode & Append)) {
qWarning("QSaveFile::open: Unsupported open mode %d", int(mode));
return false;
}
// check if existing file is writable
QFileInfo existingFile(d->fileName);
if (existingFile.exists() && !existingFile.isWritable()) {
d->error = QFile::WriteError;
setErrorString(QSaveFile::tr("Existing file %1 is not writable").arg(d->fileName));
return false;
}
d->tempFile = new QTemporaryFile;
d->tempFile->setAutoRemove(false);
d->tempFile->setFileTemplate(d->fileName);
if (!d->tempFile->open()) {
d->error = d->tempFile->error();
setErrorString(d->tempFile->errorString());
delete d->tempFile;
d->tempFile = 0;
return false;
}
QIODevice::open(mode);
if (existingFile.exists())
d->tempFile->setPermissions(existingFile.permissions());
return true;
}
/*!
\reimp
Cannot be called.
Call commit() instead.
*/
void QSaveFile::close()
{
qFatal("QSaveFile::close called");
}
/*
Commits the changes to disk, if all previous writes were successful.
It is mandatory to call this at the end of the saving operation, otherwise the file will be
discarded.
If an error happened during writing, deletes the temporary file and returns false.
Otherwise, renames it to the final fileName and returns true on success.
Finally, closes the device.
\sa cancelWriting()
*/
bool QSaveFile::commit()
{
Q_D(QSaveFile);
if (!d->tempFile)
return false;
if (!isOpen()) {
qWarning("QSaveFile::commit: File (%s) is not open", qPrintable(fileName()));
return false;
}
flush();
#ifdef Q_OS_WIN
FlushFileBuffers(reinterpret_cast<HANDLE>(handle()));
#elif defined(_POSIX_SYNCHRONIZED_IO) && _POSIX_SYNCHRONIZED_IO > 0
fdatasync(d->tempFile->handle());
#else
fsync(d->tempFile->handle());
#endif
QIODevice::close();
if (d->error != QFile::NoError) {
d->tempFile->remove();
unsetError();
delete d->tempFile;
d->tempFile = 0;
return false;
}
d->tempFile->close();
#ifdef Q_OS_WIN
// On Windows QAbstractFileEngine::rename() fails if the the target exists,
// so we have to rename the target.
// Ideally the winapi ReplaceFile() method should be used.
QString bakname = d->fileName + "~";
QFile::remove(bakname);
QFile::rename(d->fileName, bakname);
#endif
QAbstractFileEngine* fileEngine = d->tempFile->fileEngine();
Q_ASSERT(fileEngine);
if (!fileEngine->rename(d->fileName)) {
d->error = fileEngine->error();
setErrorString(fileEngine->errorString());
d->tempFile->remove();
delete d->tempFile;
d->tempFile = 0;
#ifdef Q_OS_WIN
QFile::rename(bakname, d->fileName);
#endif
return false;
}
delete d->tempFile;
d->tempFile = 0;
#ifdef Q_OS_WIN
QFile::remove(bakname);
#endif
return true;
}
/*!
Sets an error code so that commit() discards the temporary file.
Further write operations are possible after calling this method, but none
of it will have any effect, the written file will be discarded.
\sa commit()
*/
void QSaveFile::cancelWriting()
{
if (!isOpen())
return;
d_func()->error = QFile::WriteError;
setErrorString(QSaveFile::tr("Writing canceled by application"));
}
/*!
Returns the size of the file.
\sa QFile::size()
*/
qint64 QSaveFile::size() const
{
Q_D(const QSaveFile);
return d->tempFile ? d->tempFile->size() : qint64(-1);
}
/*!
\reimp
*/
qint64 QSaveFile::pos() const
{
Q_D(const QSaveFile);
return d->tempFile ? d->tempFile->pos() : qint64(-1);
}
/*!
\reimp
*/
bool QSaveFile::seek(qint64 offset)
{
Q_D(QSaveFile);
return d->tempFile ? d->tempFile->seek(offset) : false;
}
/*!
\reimp
*/
bool QSaveFile::atEnd() const
{
Q_D(const QSaveFile);
return d->tempFile ? d->tempFile->atEnd() : true;
}
/*!
Flushes any buffered data to the file. Returns true if successful;
otherwise returns false.
*/
bool QSaveFile::flush()
{
Q_D(QSaveFile);
if (d->tempFile) {
if (!d->tempFile->flush()) {
d->error = d->tempFile->error();
setErrorString(d->tempFile->errorString());
return false;
}
return true;
}
return false;
}
/*!
Returns the file handle of the temporary file.
\sa QFile::handle()
*/
int QSaveFile::handle() const
{
Q_D(const QSaveFile);
return d->tempFile ? d->tempFile->handle() : -1;
}
/*!
\reimp
*/
qint64 QSaveFile::readData(char *data, qint64 maxlen)
{
Q_D(QSaveFile);
return d->tempFile ? d->tempFile->read(data, maxlen) : -1;
}
/*!
\reimp
*/
qint64 QSaveFile::writeData(const char *data, qint64 len)
{
Q_D(QSaveFile);
if (!d->tempFile)
return -1;
const qint64 written = d->tempFile->write(data, len);
if (written != len) {
d->error = QFile::WriteError;
setErrorString(QSaveFile::tr("Partial write. Partition full?"));
}
return written;
}
/*!
\reimp
*/
qint64 QSaveFile::readLineData(char *data, qint64 maxlen)
{
Q_D(QSaveFile);
return d->tempFile ? d->tempFile->readLine(data, maxlen) : -1;
}

105
src/core/qsavefile.h Normal file
View File

@@ -0,0 +1,105 @@
/****************************************************************************
**
** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/
**
** This file is part of the QtCore module of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL$
** GNU Lesser General Public License Usage
** This file may be used under the terms of the GNU Lesser General Public
** License version 2.1 as published by the Free Software Foundation and
** appearing in the file LICENSE.LGPL included in the packaging of this
** file. Please review the following information to ensure the GNU Lesser
** General Public License version 2.1 requirements will be met:
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Nokia gives you certain additional
** rights. These rights are described in the Nokia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU General
** Public License version 3.0 as published by the Free Software Foundation
** and appearing in the file LICENSE.GPL included in the packaging of this
** file. Please review the following information to ensure the GNU General
** Public License version 3.0 requirements will be met:
** http://www.gnu.org/copyleft/gpl.html.
**
** Other Usage
** Alternatively, this file may be used in accordance with the terms and
** conditions contained in a signed written agreement between you and Nokia.
**
**
**
**
**
**
** $QT_END_LICENSE$
**
****************************************************************************/
#ifndef QSAVEFILE_H
#define QSAVEFILE_H
#include <QFile>
#include <QString>
#ifdef open
#error qsavefile.h must be included before any header file that defines open
#endif
class QAbstractFileEngine;
class QSaveFilePrivate;
class QSaveFile : public QIODevice
{
Q_OBJECT
Q_DECLARE_PRIVATE(QSaveFile)
public:
QSaveFile();
explicit QSaveFile(const QString &name);
explicit QSaveFile(QObject *parent);
QSaveFile(const QString &name, QObject *parent);
~QSaveFile();
QFile::FileError error() const;
void unsetError();
QString fileName() const;
void setFileName(const QString &name);
bool isSequential() const;
virtual bool open(OpenMode flags);
bool commit();
void cancelWriting();
qint64 size() const;
qint64 pos() const;
bool seek(qint64 offset);
bool atEnd() const;
bool flush();
bool resize(qint64 sz);
int handle() const;
protected:
qint64 readData(char *data, qint64 maxlen);
qint64 writeData(const char *data, qint64 len);
qint64 readLineData(char *data, qint64 maxlen);
private:
virtual void close();
private:
Q_DISABLE_COPY(QSaveFile)
QSaveFilePrivate* const d_ptr;
};
#endif // QSAVEFILE_H

71
src/core/qsavefile_p.h Normal file
View File

@@ -0,0 +1,71 @@
/****************************************************************************
**
** Copyright (C) 2012 Nokia Corporation and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/
**
** This file is part of the QtCore module of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL$
** GNU Lesser General Public License Usage
** This file may be used under the terms of the GNU Lesser General Public
** License version 2.1 as published by the Free Software Foundation and
** appearing in the file LICENSE.LGPL included in the packaging of this
** file. Please review the following information to ensure the GNU Lesser
** General Public License version 2.1 requirements will be met:
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Nokia gives you certain additional
** rights. These rights are described in the Nokia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU General
** Public License version 3.0 as published by the Free Software Foundation
** and appearing in the file LICENSE.GPL included in the packaging of this
** file. Please review the following information to ensure the GNU General
** Public License version 3.0 requirements will be met:
** http://www.gnu.org/copyleft/gpl.html.
**
** Other Usage
** Alternatively, this file may be used in accordance with the terms and
** conditions contained in a signed written agreement between you and Nokia.
**
**
**
**
**
**
** $QT_END_LICENSE$
**
****************************************************************************/
#ifndef QSAVEFILE_P_H
#define QSAVEFILE_P_H
//
// W A R N I N G
// -------------
//
// This file is not part of the Qt API. It exists purely as an
// implementation detail. This header file may change from version to
// version without notice, or even be removed.
//
// We mean it.
//
#include <QTemporaryFile>
class QSaveFilePrivate
{
public:
QSaveFilePrivate();
~QSaveFilePrivate();
QString fileName;
QTemporaryFile *tempFile;
QFile::FileError error;
};
#endif // QSAVEFILE_P_H

View File

@@ -29,6 +29,43 @@ bool Crypto::m_initalized(false);
QString Crypto::m_errorStr;
QString Crypto::m_backendVersion;
#if !defined(GCRYPT_VERSION_NUMBER) || (GCRYPT_VERSION_NUMBER < 0x010600)
static int gcry_qt_mutex_init(void** p_sys)
{
*p_sys = new QMutex();
return 0;
}
static int gcry_qt_mutex_destroy(void** p_sys)
{
delete reinterpret_cast<QMutex*>(*p_sys);
return 0;
}
static int gcry_qt_mutex_lock(void** p_sys)
{
reinterpret_cast<QMutex*>(*p_sys)->lock();
return 0;
}
static int gcry_qt_mutex_unlock(void** p_sys)
{
reinterpret_cast<QMutex*>(*p_sys)->unlock();
return 0;
}
static const struct gcry_thread_cbs gcry_threads_qt =
{
GCRY_THREAD_OPTION_USER,
0,
gcry_qt_mutex_init,
gcry_qt_mutex_destroy,
gcry_qt_mutex_lock,
gcry_qt_mutex_unlock,
0, 0, 0, 0, 0, 0, 0, 0
};
#endif
Crypto::Crypto()
{
}
@@ -40,6 +77,10 @@ bool Crypto::init()
return true;
}
// libgcrypt >= 1.6 doesn't allow custom thread callbacks anymore.
#if !defined(GCRYPT_VERSION_NUMBER) || (GCRYPT_VERSION_NUMBER < 0x010600)
gcry_control(GCRYCTL_SET_THREAD_CBS, &gcry_threads_qt);
#endif
m_backendVersion = QString::fromLocal8Bit(gcry_check_version(0));
gcry_control(GCRYCTL_INITIALIZATION_FINISHED, 0);
@@ -80,21 +121,23 @@ bool Crypto::backendSelfTest()
bool Crypto::checkAlgorithms()
{
if (gcry_cipher_algo_info(GCRY_CIPHER_AES256, GCRYCTL_TEST_ALGO, nullptr, nullptr) != 0) {
if (gcry_cipher_algo_info(GCRY_CIPHER_AES256, GCRYCTL_TEST_ALGO, Q_NULLPTR, Q_NULLPTR) != 0) {
m_errorStr = "GCRY_CIPHER_AES256 not found.";
qWarning("Crypto::checkAlgorithms: %s", qPrintable(m_errorStr));
return false;
}
if (gcry_cipher_algo_info(GCRY_CIPHER_TWOFISH, GCRYCTL_TEST_ALGO, nullptr, nullptr) != 0) {
if (gcry_cipher_algo_info(GCRY_CIPHER_TWOFISH, GCRYCTL_TEST_ALGO, Q_NULLPTR, Q_NULLPTR) != 0) {
m_errorStr = "GCRY_CIPHER_TWOFISH not found.";
qWarning("Crypto::checkAlgorithms: %s", qPrintable(m_errorStr));
return false;
}
if (gcry_cipher_algo_info(GCRY_CIPHER_SALSA20, GCRYCTL_TEST_ALGO, nullptr, nullptr) != 0) {
#ifdef GCRYPT_HAS_SALSA20
if (gcry_cipher_algo_info(GCRY_CIPHER_SALSA20, GCRYCTL_TEST_ALGO, Q_NULLPTR, Q_NULLPTR) != 0) {
m_errorStr = "GCRY_CIPHER_SALSA20 not found.";
qWarning("Crypto::checkAlgorithms: %s", qPrintable(m_errorStr));
return false;
}
#endif
if (gcry_md_test_algo(GCRY_MD_SHA256) != 0) {
m_errorStr = "GCRY_MD_SHA256 not found.";
qWarning("Crypto::checkAlgorithms: %s", qPrintable(m_errorStr));

View File

@@ -20,6 +20,8 @@
#include <QString>
#include "core/Global.h"
class Crypto
{
public:

View File

@@ -19,16 +19,15 @@
#include <gcrypt.h>
#include "core/Global.h"
#include "crypto/Crypto.h"
class RandomBackendGcrypt : public RandomBackend
{
public:
void randomize(void* data, int len) override;
void randomize(void* data, int len) Q_DECL_OVERRIDE;
};
Random* Random::m_instance(nullptr);
Random* Random::m_instance(Q_NULLPTR);
void Random::randomize(QByteArray& ba)
{

View File

@@ -19,6 +19,7 @@
#include "config-keepassx.h"
#include "crypto/SymmetricCipherGcrypt.h"
#include "crypto/SymmetricCipherSalsa20.h"
SymmetricCipher::SymmetricCipher(SymmetricCipher::Algorithm algo, SymmetricCipher::Mode mode,
SymmetricCipher::Direction direction)
@@ -60,12 +61,19 @@ SymmetricCipherBackend* SymmetricCipher::createBackend(SymmetricCipher::Algorith
switch (algo) {
case SymmetricCipher::Aes256:
case SymmetricCipher::Twofish:
#if defined(GCRYPT_HAS_SALSA20)
case SymmetricCipher::Salsa20:
#endif
return new SymmetricCipherGcrypt(algo, mode, direction);
#if !defined(GCRYPT_HAS_SALSA20)
case SymmetricCipher::Salsa20:
return new SymmetricCipherSalsa20(algo, mode, direction);
#endif
default:
Q_ASSERT(false);
return nullptr;
return Q_NULLPTR;
}
}

View File

@@ -22,6 +22,7 @@
#include <QScopedPointer>
#include <QString>
#include "core/Global.h"
#include "crypto/SymmetricCipherBackend.h"
class SymmetricCipher

View File

@@ -22,7 +22,7 @@
SymmetricCipherGcrypt::SymmetricCipherGcrypt(SymmetricCipher::Algorithm algo, SymmetricCipher::Mode mode,
SymmetricCipher::Direction direction)
: m_ctx(nullptr)
: m_ctx(Q_NULLPTR)
, m_algo(gcryptAlgo(algo))
, m_mode(gcryptMode(mode))
, m_direction(direction)
@@ -44,8 +44,10 @@ int SymmetricCipherGcrypt::gcryptAlgo(SymmetricCipher::Algorithm algo)
case SymmetricCipher::Twofish:
return GCRY_CIPHER_TWOFISH;
#ifdef GCRYPT_HAS_SALSA20
case SymmetricCipher::Salsa20:
return GCRY_CIPHER_SALSA20;
#endif
default:
Q_ASSERT(false);
@@ -93,7 +95,7 @@ bool SymmetricCipherGcrypt::init()
}
size_t blockSizeT;
error = gcry_cipher_algo_info(m_algo, GCRYCTL_GET_BLKLEN, nullptr, &blockSizeT);
error = gcry_cipher_algo_info(m_algo, GCRYCTL_GET_BLKLEN, Q_NULLPTR, &blockSizeT);
if (error != 0) {
setErrorString(error);
return false;
@@ -161,10 +163,10 @@ bool SymmetricCipherGcrypt::processInPlace(QByteArray& data)
gcry_error_t error;
if (m_direction == SymmetricCipher::Decrypt) {
error = gcry_cipher_decrypt(m_ctx, data.data(), data.size(), nullptr, 0);
error = gcry_cipher_decrypt(m_ctx, data.data(), data.size(), Q_NULLPTR, 0);
}
else {
error = gcry_cipher_encrypt(m_ctx, data.data(), data.size(), nullptr, 0);
error = gcry_cipher_encrypt(m_ctx, data.data(), data.size(), Q_NULLPTR, 0);
}
if (error != 0) {
@@ -186,7 +188,7 @@ bool SymmetricCipherGcrypt::processInPlace(QByteArray& data, quint64 rounds)
if (m_direction == SymmetricCipher::Decrypt) {
for (quint64 i = 0; i != rounds; ++i) {
error = gcry_cipher_decrypt(m_ctx, rawData, size, nullptr, 0);
error = gcry_cipher_decrypt(m_ctx, rawData, size, Q_NULLPTR, 0);
if (error != 0) {
setErrorString(error);
@@ -196,7 +198,7 @@ bool SymmetricCipherGcrypt::processInPlace(QByteArray& data, quint64 rounds)
}
else {
for (quint64 i = 0; i != rounds; ++i) {
error = gcry_cipher_encrypt(m_ctx, rawData, size, nullptr, 0);
error = gcry_cipher_encrypt(m_ctx, rawData, size, Q_NULLPTR, 0);
if (error != 0) {
setErrorString(error);

View File

@@ -0,0 +1,260 @@
/* ecrypt-config.h */
/* *** Normally, it should not be necessary to edit this file. *** */
#ifndef ECRYPT_CONFIG
#define ECRYPT_CONFIG
/* ------------------------------------------------------------------------- */
/* Guess the endianness of the target architecture. */
#include <QtGlobal>
#if Q_BYTE_ORDER == Q_LITTLE_ENDIAN
#define ECRYPT_LITTLE_ENDIAN
#elif Q_BYTE_ORDER == Q_BIG_ENDIAN
#define ECRYPT_BIG_ENDIAN
#else
#define ECRYPT_UNKNOWN
#endif
/* ------------------------------------------------------------------------- */
/*
* Find minimal-width types to store 8-bit, 16-bit, 32-bit, and 64-bit
* integers.
*
* Note: to enable 64-bit types on 32-bit compilers, it might be
* necessary to switch from ISO C90 mode to ISO C99 mode (e.g., gcc
* -std=c99), or to allow compiler-specific extensions.
*/
#include <limits.h>
/* --- check char --- */
#if (UCHAR_MAX / 0xFU > 0xFU)
#ifndef I8T
#define I8T char
#define U8C(v) (v##U)
#if (UCHAR_MAX == 0xFFU)
#define ECRYPT_I8T_IS_BYTE
#endif
#endif
#if (UCHAR_MAX / 0xFFU > 0xFFU)
#ifndef I16T
#define I16T char
#define U16C(v) (v##U)
#endif
#if (UCHAR_MAX / 0xFFFFU > 0xFFFFU)
#ifndef I32T
#define I32T char
#define U32C(v) (v##U)
#endif
#if (UCHAR_MAX / 0xFFFFFFFFU > 0xFFFFFFFFU)
#ifndef I64T
#define I64T char
#define U64C(v) (v##U)
#define ECRYPT_NATIVE64
#endif
#endif
#endif
#endif
#endif
/* --- check short --- */
#if (USHRT_MAX / 0xFU > 0xFU)
#ifndef I8T
#define I8T short
#define U8C(v) (v##U)
#if (USHRT_MAX == 0xFFU)
#define ECRYPT_I8T_IS_BYTE
#endif
#endif
#if (USHRT_MAX / 0xFFU > 0xFFU)
#ifndef I16T
#define I16T short
#define U16C(v) (v##U)
#endif
#if (USHRT_MAX / 0xFFFFU > 0xFFFFU)
#ifndef I32T
#define I32T short
#define U32C(v) (v##U)
#endif
#if (USHRT_MAX / 0xFFFFFFFFU > 0xFFFFFFFFU)
#ifndef I64T
#define I64T short
#define U64C(v) (v##U)
#define ECRYPT_NATIVE64
#endif
#endif
#endif
#endif
#endif
/* --- check int --- */
#if (UINT_MAX / 0xFU > 0xFU)
#ifndef I8T
#define I8T int
#define U8C(v) (v##U)
#if (ULONG_MAX == 0xFFU)
#define ECRYPT_I8T_IS_BYTE
#endif
#endif
#if (UINT_MAX / 0xFFU > 0xFFU)
#ifndef I16T
#define I16T int
#define U16C(v) (v##U)
#endif
#if (UINT_MAX / 0xFFFFU > 0xFFFFU)
#ifndef I32T
#define I32T int
#define U32C(v) (v##U)
#endif
#if (UINT_MAX / 0xFFFFFFFFU > 0xFFFFFFFFU)
#ifndef I64T
#define I64T int
#define U64C(v) (v##U)
#define ECRYPT_NATIVE64
#endif
#endif
#endif
#endif
#endif
/* --- check long --- */
#if (ULONG_MAX / 0xFUL > 0xFUL)
#ifndef I8T
#define I8T long
#define U8C(v) (v##UL)
#if (ULONG_MAX == 0xFFUL)
#define ECRYPT_I8T_IS_BYTE
#endif
#endif
#if (ULONG_MAX / 0xFFUL > 0xFFUL)
#ifndef I16T
#define I16T long
#define U16C(v) (v##UL)
#endif
#if (ULONG_MAX / 0xFFFFUL > 0xFFFFUL)
#ifndef I32T
#define I32T long
#define U32C(v) (v##UL)
#endif
#if (ULONG_MAX / 0xFFFFFFFFUL > 0xFFFFFFFFUL)
#ifndef I64T
#define I64T long
#define U64C(v) (v##UL)
#define ECRYPT_NATIVE64
#endif
#endif
#endif
#endif
#endif
/* --- check long long --- */
#ifdef ULLONG_MAX
#if (ULLONG_MAX / 0xFULL > 0xFULL)
#ifndef I8T
#define I8T long long
#define U8C(v) (v##ULL)
#if (ULLONG_MAX == 0xFFULL)
#define ECRYPT_I8T_IS_BYTE
#endif
#endif
#if (ULLONG_MAX / 0xFFULL > 0xFFULL)
#ifndef I16T
#define I16T long long
#define U16C(v) (v##ULL)
#endif
#if (ULLONG_MAX / 0xFFFFULL > 0xFFFFULL)
#ifndef I32T
#define I32T long long
#define U32C(v) (v##ULL)
#endif
#if (ULLONG_MAX / 0xFFFFFFFFULL > 0xFFFFFFFFULL)
#ifndef I64T
#define I64T long long
#define U64C(v) (v##ULL)
#endif
#endif
#endif
#endif
#endif
#endif
/* --- check __int64 --- */
#if !defined(__STDC__) && defined(_UI64_MAX)
#ifndef I64T
#define I64T __int64
#define U64C(v) (v##ui64)
#endif
#endif
/* ------------------------------------------------------------------------- */
/* find the largest type on this platform (used for alignment) */
#if defined(__SSE__) || (defined(_MSC_VER) && (_MSC_VER >= 1300))
#include <xmmintrin.h>
#define MAXT __m128
#elif defined(__MMX__)
#include <mmintrin.h>
#define MAXT __m64
#elif defined(__ALTIVEC__)
#define MAXT __vector int
#else
#define MAXT long
#endif
/* ------------------------------------------------------------------------- */
#endif

View File

@@ -0,0 +1,49 @@
/* ecrypt-machine.h */
/*
* This file is included by 'ecrypt-portable.h'. It allows to override
* the default macros for specific platforms. Please carefully check
* the machine code generated by your compiler (with optimisations
* turned on) before deciding to edit this file.
*/
/* ------------------------------------------------------------------------- */
#if (defined(ECRYPT_DEFAULT_ROT) && !defined(ECRYPT_MACHINE_ROT))
#define ECRYPT_MACHINE_ROT
#if (defined(WIN32) && defined(_MSC_VER))
#undef ROTL32
#undef ROTR32
#undef ROTL64
#undef ROTR64
#include <stdlib.h>
#pragma intrinsic(_lrotl) /* compile rotations "inline" */
#pragma intrinsic(_lrotr)
#define ROTL32(v, n) _lrotl(v, n)
#define ROTR32(v, n) _lrotr(v, n)
#define ROTL64(v, n) _rotl64(v, n)
#define ROTR64(v, n) _rotr64(v, n)
#endif
#endif
/* ------------------------------------------------------------------------- */
#if (defined(ECRYPT_DEFAULT_SWAP) && !defined(ECRYPT_MACHINE_SWAP))
#define ECRYPT_MACHINE_SWAP
/*
* If you want to overwrite the default swap macros, put it here. And so on.
*/
#endif
/* ------------------------------------------------------------------------- */

View File

@@ -0,0 +1,310 @@
/* ecrypt-portable.h */
/*
* WARNING: the conversions defined below are implemented as macros,
* and should be used carefully. They should NOT be used with
* parameters which perform some action. E.g., the following two lines
* are not equivalent:
*
* 1) ++x; y = ROTL32(x, n);
* 2) y = ROTL32(++x, n);
*/
/*
* *** Please do not edit this file. ***
*
* The default macros can be overridden for specific architectures by
* editing 'ecrypt-machine.h'.
*/
#ifndef ECRYPT_PORTABLE
#define ECRYPT_PORTABLE
#include "ecrypt-config.h"
/* ------------------------------------------------------------------------- */
/*
* The following types are defined (if available):
*
* u8: unsigned integer type, at least 8 bits
* u16: unsigned integer type, at least 16 bits
* u32: unsigned integer type, at least 32 bits
* u64: unsigned integer type, at least 64 bits
*
* s8, s16, s32, s64 -> signed counterparts of u8, u16, u32, u64
*
* The selection of minimum-width integer types is taken care of by
* 'ecrypt-config.h'. Note: to enable 64-bit types on 32-bit
* compilers, it might be necessary to switch from ISO C90 mode to ISO
* C99 mode (e.g., gcc -std=c99).
*/
#ifdef I8T
typedef signed I8T s8;
typedef unsigned I8T u8;
#endif
#ifdef I16T
typedef signed I16T s16;
typedef unsigned I16T u16;
#endif
#ifdef I32T
typedef signed I32T s32;
typedef unsigned I32T u32;
#endif
#ifdef I64T
typedef signed I64T s64;
typedef unsigned I64T u64;
#endif
/*
* The following macros are used to obtain exact-width results.
*/
#define U8V(v) ((u8)(v) & U8C(0xFF))
#define U16V(v) ((u16)(v) & U16C(0xFFFF))
#define U32V(v) ((u32)(v) & U32C(0xFFFFFFFF))
#define U64V(v) ((u64)(v) & U64C(0xFFFFFFFFFFFFFFFF))
/* ------------------------------------------------------------------------- */
/*
* The following macros return words with their bits rotated over n
* positions to the left/right.
*/
#define ECRYPT_DEFAULT_ROT
#define ROTL8(v, n) \
(U8V((v) << (n)) | ((v) >> (8 - (n))))
#define ROTL16(v, n) \
(U16V((v) << (n)) | ((v) >> (16 - (n))))
#define ROTL32(v, n) \
(U32V((v) << (n)) | ((v) >> (32 - (n))))
#define ROTL64(v, n) \
(U64V((v) << (n)) | ((v) >> (64 - (n))))
#define ROTR8(v, n) ROTL8(v, 8 - (n))
#define ROTR16(v, n) ROTL16(v, 16 - (n))
#define ROTR32(v, n) ROTL32(v, 32 - (n))
#define ROTR64(v, n) ROTL64(v, 64 - (n))
#include "ecrypt-machine.h"
/* ------------------------------------------------------------------------- */
/*
* The following macros return a word with bytes in reverse order.
*/
#define ECRYPT_DEFAULT_SWAP
#define SWAP16(v) \
ROTL16(v, 8)
#define SWAP32(v) \
((ROTL32(v, 8) & U32C(0x00FF00FF)) | \
(ROTL32(v, 24) & U32C(0xFF00FF00)))
#ifdef ECRYPT_NATIVE64
#define SWAP64(v) \
((ROTL64(v, 8) & U64C(0x000000FF000000FF)) | \
(ROTL64(v, 24) & U64C(0x0000FF000000FF00)) | \
(ROTL64(v, 40) & U64C(0x00FF000000FF0000)) | \
(ROTL64(v, 56) & U64C(0xFF000000FF000000)))
#else
#define SWAP64(v) \
(((u64)SWAP32(U32V(v)) << 32) | (u64)SWAP32(U32V(v >> 32)))
#endif
#include "ecrypt-machine.h"
#define ECRYPT_DEFAULT_WTOW
#ifdef ECRYPT_LITTLE_ENDIAN
#define U16TO16_LITTLE(v) (v)
#define U32TO32_LITTLE(v) (v)
#define U64TO64_LITTLE(v) (v)
#define U16TO16_BIG(v) SWAP16(v)
#define U32TO32_BIG(v) SWAP32(v)
#define U64TO64_BIG(v) SWAP64(v)
#endif
#ifdef ECRYPT_BIG_ENDIAN
#define U16TO16_LITTLE(v) SWAP16(v)
#define U32TO32_LITTLE(v) SWAP32(v)
#define U64TO64_LITTLE(v) SWAP64(v)
#define U16TO16_BIG(v) (v)
#define U32TO32_BIG(v) (v)
#define U64TO64_BIG(v) (v)
#endif
#include "ecrypt-machine.h"
/*
* The following macros load words from an array of bytes with
* different types of endianness, and vice versa.
*/
#define ECRYPT_DEFAULT_BTOW
#if (!defined(ECRYPT_UNKNOWN) && defined(ECRYPT_I8T_IS_BYTE))
#define U8TO16_LITTLE(p) U16TO16_LITTLE(((u16*)(p))[0])
#define U8TO32_LITTLE(p) U32TO32_LITTLE(((u32*)(p))[0])
#define U8TO64_LITTLE(p) U64TO64_LITTLE(((u64*)(p))[0])
#define U8TO16_BIG(p) U16TO16_BIG(((u16*)(p))[0])
#define U8TO32_BIG(p) U32TO32_BIG(((u32*)(p))[0])
#define U8TO64_BIG(p) U64TO64_BIG(((u64*)(p))[0])
#define U16TO8_LITTLE(p, v) (((u16*)(p))[0] = U16TO16_LITTLE(v))
#define U32TO8_LITTLE(p, v) (((u32*)(p))[0] = U32TO32_LITTLE(v))
#define U64TO8_LITTLE(p, v) (((u64*)(p))[0] = U64TO64_LITTLE(v))
#define U16TO8_BIG(p, v) (((u16*)(p))[0] = U16TO16_BIG(v))
#define U32TO8_BIG(p, v) (((u32*)(p))[0] = U32TO32_BIG(v))
#define U64TO8_BIG(p, v) (((u64*)(p))[0] = U64TO64_BIG(v))
#else
#define U8TO16_LITTLE(p) \
(((u16)((p)[0]) ) | \
((u16)((p)[1]) << 8))
#define U8TO32_LITTLE(p) \
(((u32)((p)[0]) ) | \
((u32)((p)[1]) << 8) | \
((u32)((p)[2]) << 16) | \
((u32)((p)[3]) << 24))
#ifdef ECRYPT_NATIVE64
#define U8TO64_LITTLE(p) \
(((u64)((p)[0]) ) | \
((u64)((p)[1]) << 8) | \
((u64)((p)[2]) << 16) | \
((u64)((p)[3]) << 24) | \
((u64)((p)[4]) << 32) | \
((u64)((p)[5]) << 40) | \
((u64)((p)[6]) << 48) | \
((u64)((p)[7]) << 56))
#else
#define U8TO64_LITTLE(p) \
((u64)U8TO32_LITTLE(p) | ((u64)U8TO32_LITTLE((p) + 4) << 32))
#endif
#define U8TO16_BIG(p) \
(((u16)((p)[0]) << 8) | \
((u16)((p)[1]) ))
#define U8TO32_BIG(p) \
(((u32)((p)[0]) << 24) | \
((u32)((p)[1]) << 16) | \
((u32)((p)[2]) << 8) | \
((u32)((p)[3]) ))
#ifdef ECRYPT_NATIVE64
#define U8TO64_BIG(p) \
(((u64)((p)[0]) << 56) | \
((u64)((p)[1]) << 48) | \
((u64)((p)[2]) << 40) | \
((u64)((p)[3]) << 32) | \
((u64)((p)[4]) << 24) | \
((u64)((p)[5]) << 16) | \
((u64)((p)[6]) << 8) | \
((u64)((p)[7]) ))
#else
#define U8TO64_BIG(p) \
(((u64)U8TO32_BIG(p) << 32) | (u64)U8TO32_BIG((p) + 4))
#endif
#define U16TO8_LITTLE(p, v) \
do { \
(p)[0] = U8V((v) ); \
(p)[1] = U8V((v) >> 8); \
} while (0)
#define U32TO8_LITTLE(p, v) \
do { \
(p)[0] = U8V((v) ); \
(p)[1] = U8V((v) >> 8); \
(p)[2] = U8V((v) >> 16); \
(p)[3] = U8V((v) >> 24); \
} while (0)
#ifdef ECRYPT_NATIVE64
#define U64TO8_LITTLE(p, v) \
do { \
(p)[0] = U8V((v) ); \
(p)[1] = U8V((v) >> 8); \
(p)[2] = U8V((v) >> 16); \
(p)[3] = U8V((v) >> 24); \
(p)[4] = U8V((v) >> 32); \
(p)[5] = U8V((v) >> 40); \
(p)[6] = U8V((v) >> 48); \
(p)[7] = U8V((v) >> 56); \
} while (0)
#else
#define U64TO8_LITTLE(p, v) \
do { \
U32TO8_LITTLE((p), U32V((v) )); \
U32TO8_LITTLE((p) + 4, U32V((v) >> 32)); \
} while (0)
#endif
#define U16TO8_BIG(p, v) \
do { \
(p)[0] = U8V((v) ); \
(p)[1] = U8V((v) >> 8); \
} while (0)
#define U32TO8_BIG(p, v) \
do { \
(p)[0] = U8V((v) >> 24); \
(p)[1] = U8V((v) >> 16); \
(p)[2] = U8V((v) >> 8); \
(p)[3] = U8V((v) ); \
} while (0)
#ifdef ECRYPT_NATIVE64
#define U64TO8_BIG(p, v) \
do { \
(p)[0] = U8V((v) >> 56); \
(p)[1] = U8V((v) >> 48); \
(p)[2] = U8V((v) >> 40); \
(p)[3] = U8V((v) >> 32); \
(p)[4] = U8V((v) >> 24); \
(p)[5] = U8V((v) >> 16); \
(p)[6] = U8V((v) >> 8); \
(p)[7] = U8V((v) ); \
} while (0)
#else
#define U64TO8_BIG(p, v) \
do { \
U32TO8_BIG((p), U32V((v) >> 32)); \
U32TO8_BIG((p) + 4, U32V((v) )); \
} while (0)
#endif
#endif
#include "ecrypt-machine.h"
/* ------------------------------------------------------------------------- */
#define AT_LEAST_ONE(n) (((n) < 1) ? 1 : (n))
#define ALIGN(t, v, n) \
union { t b[n]; MAXT l[AT_LEAST_ONE(n * sizeof(t) / sizeof(MAXT))]; } v
/* ------------------------------------------------------------------------- */
#endif

View File

@@ -0,0 +1,287 @@
/* ecrypt-sync.h */
/*
* Header file for synchronous stream ciphers without authentication
* mechanism.
*
* *** Please only edit parts marked with "[edit]". ***
*/
#ifndef ECRYPT_SYNC
#define ECRYPT_SYNC
#ifdef __cplusplus
extern "C" {
#endif
#include "ecrypt-portable.h"
/* ------------------------------------------------------------------------- */
/* Cipher parameters */
/*
* The name of your cipher.
*/
#define ECRYPT_NAME "Salsa20" /* [edit] */
#define ECRYPT_PROFILE "S!_H."
/*
* Specify which key and IV sizes are supported by your cipher. A user
* should be able to enumerate the supported sizes by running the
* following code:
*
* for (i = 0; ECRYPT_KEYSIZE(i) <= ECRYPT_MAXKEYSIZE; ++i)
* {
* keysize = ECRYPT_KEYSIZE(i);
*
* ...
* }
*
* All sizes are in bits.
*/
#define ECRYPT_MAXKEYSIZE 256 /* [edit] */
#define ECRYPT_KEYSIZE(i) (128 + (i)*128) /* [edit] */
#define ECRYPT_MAXIVSIZE 64 /* [edit] */
#define ECRYPT_IVSIZE(i) (64 + (i)*64) /* [edit] */
/* ------------------------------------------------------------------------- */
/* Data structures */
/*
* ECRYPT_ctx is the structure containing the representation of the
* internal state of your cipher.
*/
typedef struct
{
u32 input[16]; /* could be compressed */
/*
* [edit]
*
* Put here all state variable needed during the encryption process.
*/
} ECRYPT_ctx;
/* ------------------------------------------------------------------------- */
/* Mandatory functions */
/*
* Key and message independent initialization. This function will be
* called once when the program starts (e.g., to build expanded S-box
* tables).
*/
void ECRYPT_init();
/*
* Key setup. It is the user's responsibility to select the values of
* keysize and ivsize from the set of supported values specified
* above.
*/
void ECRYPT_keysetup(
ECRYPT_ctx* ctx,
const u8* key,
u32 keysize, /* Key size in bits. */
u32 ivsize); /* IV size in bits. */
/*
* IV setup. After having called ECRYPT_keysetup(), the user is
* allowed to call ECRYPT_ivsetup() different times in order to
* encrypt/decrypt different messages with the same key but different
* IV's.
*/
void ECRYPT_ivsetup(
ECRYPT_ctx* ctx,
const u8* iv);
/*
* Encryption/decryption of arbitrary length messages.
*
* For efficiency reasons, the API provides two types of
* encrypt/decrypt functions. The ECRYPT_encrypt_bytes() function
* (declared here) encrypts byte strings of arbitrary length, while
* the ECRYPT_encrypt_blocks() function (defined later) only accepts
* lengths which are multiples of ECRYPT_BLOCKLENGTH.
*
* The user is allowed to make multiple calls to
* ECRYPT_encrypt_blocks() to incrementally encrypt a long message,
* but he is NOT allowed to make additional encryption calls once he
* has called ECRYPT_encrypt_bytes() (unless he starts a new message
* of course). For example, this sequence of calls is acceptable:
*
* ECRYPT_keysetup();
*
* ECRYPT_ivsetup();
* ECRYPT_encrypt_blocks();
* ECRYPT_encrypt_blocks();
* ECRYPT_encrypt_bytes();
*
* ECRYPT_ivsetup();
* ECRYPT_encrypt_blocks();
* ECRYPT_encrypt_blocks();
*
* ECRYPT_ivsetup();
* ECRYPT_encrypt_bytes();
*
* The following sequence is not:
*
* ECRYPT_keysetup();
* ECRYPT_ivsetup();
* ECRYPT_encrypt_blocks();
* ECRYPT_encrypt_bytes();
* ECRYPT_encrypt_blocks();
*/
void ECRYPT_encrypt_bytes(
ECRYPT_ctx* ctx,
const u8* plaintext,
u8* ciphertext,
u32 msglen); /* Message length in bytes. */
void ECRYPT_decrypt_bytes(
ECRYPT_ctx* ctx,
const u8* ciphertext,
u8* plaintext,
u32 msglen); /* Message length in bytes. */
/* ------------------------------------------------------------------------- */
/* Optional features */
/*
* For testing purposes it can sometimes be useful to have a function
* which immediately generates keystream without having to provide it
* with a zero plaintext. If your cipher cannot provide this function
* (e.g., because it is not strictly a synchronous cipher), please
* reset the ECRYPT_GENERATES_KEYSTREAM flag.
*/
#define ECRYPT_GENERATES_KEYSTREAM
#ifdef ECRYPT_GENERATES_KEYSTREAM
void ECRYPT_keystream_bytes(
ECRYPT_ctx* ctx,
u8* keystream,
u32 length); /* Length of keystream in bytes. */
#endif
/* ------------------------------------------------------------------------- */
/* Optional optimizations */
/*
* By default, the functions in this section are implemented using
* calls to functions declared above. However, you might want to
* implement them differently for performance reasons.
*/
/*
* All-in-one encryption/decryption of (short) packets.
*
* The default definitions of these functions can be found in
* "ecrypt-sync.c". If you want to implement them differently, please
* undef the ECRYPT_USES_DEFAULT_ALL_IN_ONE flag.
*/
#define ECRYPT_USES_DEFAULT_ALL_IN_ONE /* [edit] */
void ECRYPT_encrypt_packet(
ECRYPT_ctx* ctx,
const u8* iv,
const u8* plaintext,
u8* ciphertext,
u32 msglen);
void ECRYPT_decrypt_packet(
ECRYPT_ctx* ctx,
const u8* iv,
const u8* ciphertext,
u8* plaintext,
u32 msglen);
/*
* Encryption/decryption of blocks.
*
* By default, these functions are defined as macros. If you want to
* provide a different implementation, please undef the
* ECRYPT_USES_DEFAULT_BLOCK_MACROS flag and implement the functions
* declared below.
*/
#define ECRYPT_BLOCKLENGTH 64 /* [edit] */
#define ECRYPT_USES_DEFAULT_BLOCK_MACROS /* [edit] */
#ifdef ECRYPT_USES_DEFAULT_BLOCK_MACROS
#define ECRYPT_encrypt_blocks(ctx, plaintext, ciphertext, blocks) \
ECRYPT_encrypt_bytes(ctx, plaintext, ciphertext, \
(blocks) * ECRYPT_BLOCKLENGTH)
#define ECRYPT_decrypt_blocks(ctx, ciphertext, plaintext, blocks) \
ECRYPT_decrypt_bytes(ctx, ciphertext, plaintext, \
(blocks) * ECRYPT_BLOCKLENGTH)
#ifdef ECRYPT_GENERATES_KEYSTREAM
#define ECRYPT_keystream_blocks(ctx, keystream, blocks) \
ECRYPT_keystream_bytes(ctx, keystream, \
(blocks) * ECRYPT_BLOCKLENGTH)
#endif
#else
void ECRYPT_encrypt_blocks(
ECRYPT_ctx* ctx,
const u8* plaintext,
u8* ciphertext,
u32 blocks); /* Message length in blocks. */
void ECRYPT_decrypt_blocks(
ECRYPT_ctx* ctx,
const u8* ciphertext,
u8* plaintext,
u32 blocks); /* Message length in blocks. */
#ifdef ECRYPT_GENERATES_KEYSTREAM
void ECRYPT_keystream_blocks(
ECRYPT_ctx* ctx,
const u8* keystream,
u32 blocks); /* Keystream length in blocks. */
#endif
#endif
/*
* If your cipher can be implemented in different ways, you can use
* the ECRYPT_VARIANT parameter to allow the user to choose between
* them at compile time (e.g., gcc -DECRYPT_VARIANT=3 ...). Please
* only use this possibility if you really think it could make a
* significant difference and keep the number of variants
* (ECRYPT_MAXVARIANT) as small as possible (definitely not more than
* 10). Note also that all variants should have exactly the same
* external interface (i.e., the same ECRYPT_BLOCKLENGTH, etc.).
*/
#define ECRYPT_MAXVARIANT 1 /* [edit] */
#ifndef ECRYPT_VARIANT
#define ECRYPT_VARIANT 1
#endif
#if (ECRYPT_VARIANT > ECRYPT_MAXVARIANT)
#error this variant does not exist
#endif
/* ------------------------------------------------------------------------- */
#ifdef __cplusplus
}
#endif
#endif

View File

@@ -0,0 +1,133 @@
/*
salsa20-ref.c version 20051118
D. J. Bernstein
Public domain.
*/
#include "ecrypt-sync.h"
#define ROTATE(v,c) (ROTL32(v,c))
#define XOR(v,w) ((v) ^ (w))
#define PLUS(v,w) (U32V((v) + (w)))
#define PLUSONE(v) (PLUS((v),1))
static void salsa20_wordtobyte(u8 output[64],const u32 input[16])
{
u32 x[16];
int i;
for (i = 0;i < 16;++i) x[i] = input[i];
for (i = 20;i > 0;i -= 2) {
x[ 4] = XOR(x[ 4],ROTATE(PLUS(x[ 0],x[12]), 7));
x[ 8] = XOR(x[ 8],ROTATE(PLUS(x[ 4],x[ 0]), 9));
x[12] = XOR(x[12],ROTATE(PLUS(x[ 8],x[ 4]),13));
x[ 0] = XOR(x[ 0],ROTATE(PLUS(x[12],x[ 8]),18));
x[ 9] = XOR(x[ 9],ROTATE(PLUS(x[ 5],x[ 1]), 7));
x[13] = XOR(x[13],ROTATE(PLUS(x[ 9],x[ 5]), 9));
x[ 1] = XOR(x[ 1],ROTATE(PLUS(x[13],x[ 9]),13));
x[ 5] = XOR(x[ 5],ROTATE(PLUS(x[ 1],x[13]),18));
x[14] = XOR(x[14],ROTATE(PLUS(x[10],x[ 6]), 7));
x[ 2] = XOR(x[ 2],ROTATE(PLUS(x[14],x[10]), 9));
x[ 6] = XOR(x[ 6],ROTATE(PLUS(x[ 2],x[14]),13));
x[10] = XOR(x[10],ROTATE(PLUS(x[ 6],x[ 2]),18));
x[ 3] = XOR(x[ 3],ROTATE(PLUS(x[15],x[11]), 7));
x[ 7] = XOR(x[ 7],ROTATE(PLUS(x[ 3],x[15]), 9));
x[11] = XOR(x[11],ROTATE(PLUS(x[ 7],x[ 3]),13));
x[15] = XOR(x[15],ROTATE(PLUS(x[11],x[ 7]),18));
x[ 1] = XOR(x[ 1],ROTATE(PLUS(x[ 0],x[ 3]), 7));
x[ 2] = XOR(x[ 2],ROTATE(PLUS(x[ 1],x[ 0]), 9));
x[ 3] = XOR(x[ 3],ROTATE(PLUS(x[ 2],x[ 1]),13));
x[ 0] = XOR(x[ 0],ROTATE(PLUS(x[ 3],x[ 2]),18));
x[ 6] = XOR(x[ 6],ROTATE(PLUS(x[ 5],x[ 4]), 7));
x[ 7] = XOR(x[ 7],ROTATE(PLUS(x[ 6],x[ 5]), 9));
x[ 4] = XOR(x[ 4],ROTATE(PLUS(x[ 7],x[ 6]),13));
x[ 5] = XOR(x[ 5],ROTATE(PLUS(x[ 4],x[ 7]),18));
x[11] = XOR(x[11],ROTATE(PLUS(x[10],x[ 9]), 7));
x[ 8] = XOR(x[ 8],ROTATE(PLUS(x[11],x[10]), 9));
x[ 9] = XOR(x[ 9],ROTATE(PLUS(x[ 8],x[11]),13));
x[10] = XOR(x[10],ROTATE(PLUS(x[ 9],x[ 8]),18));
x[12] = XOR(x[12],ROTATE(PLUS(x[15],x[14]), 7));
x[13] = XOR(x[13],ROTATE(PLUS(x[12],x[15]), 9));
x[14] = XOR(x[14],ROTATE(PLUS(x[13],x[12]),13));
x[15] = XOR(x[15],ROTATE(PLUS(x[14],x[13]),18));
}
for (i = 0;i < 16;++i) x[i] = PLUS(x[i],input[i]);
for (i = 0;i < 16;++i) U32TO8_LITTLE(output + 4 * i,x[i]);
}
void ECRYPT_init(void)
{
return;
}
static const char sigma[16] = "expand 32-byte k";
static const char tau[16] = "expand 16-byte k";
void ECRYPT_keysetup(ECRYPT_ctx *x,const u8 *k,u32 kbits,u32 ivbits)
{
(void)ivbits;
const char *constants;
x->input[1] = U8TO32_LITTLE(k + 0);
x->input[2] = U8TO32_LITTLE(k + 4);
x->input[3] = U8TO32_LITTLE(k + 8);
x->input[4] = U8TO32_LITTLE(k + 12);
if (kbits == 256) { /* recommended */
k += 16;
constants = sigma;
} else { /* kbits == 128 */
constants = tau;
}
x->input[11] = U8TO32_LITTLE(k + 0);
x->input[12] = U8TO32_LITTLE(k + 4);
x->input[13] = U8TO32_LITTLE(k + 8);
x->input[14] = U8TO32_LITTLE(k + 12);
x->input[0] = U8TO32_LITTLE(constants + 0);
x->input[5] = U8TO32_LITTLE(constants + 4);
x->input[10] = U8TO32_LITTLE(constants + 8);
x->input[15] = U8TO32_LITTLE(constants + 12);
}
void ECRYPT_ivsetup(ECRYPT_ctx *x,const u8 *iv)
{
x->input[6] = U8TO32_LITTLE(iv + 0);
x->input[7] = U8TO32_LITTLE(iv + 4);
x->input[8] = 0;
x->input[9] = 0;
}
void ECRYPT_encrypt_bytes(ECRYPT_ctx *x,const u8 *m,u8 *c,u32 bytes)
{
u8 output[64];
u32 i;
if (!bytes) return;
for (;;) {
salsa20_wordtobyte(output,x->input);
x->input[8] = PLUSONE(x->input[8]);
if (!x->input[8]) {
x->input[9] = PLUSONE(x->input[9]);
/* stopping at 2^70 bytes per nonce is user's responsibility */
}
if (bytes <= 64) {
for (i = 0;i < bytes;++i) c[i] = m[i] ^ output[i];
return;
}
for (i = 0;i < 64;++i) c[i] = m[i] ^ output[i];
bytes -= 64;
c += 64;
m += 64;
}
}
void ECRYPT_decrypt_bytes(ECRYPT_ctx *x,const u8 *c,u8 *m,u32 bytes)
{
ECRYPT_encrypt_bytes(x,c,m,bytes);
}
void ECRYPT_keystream_bytes(ECRYPT_ctx *x,u8 *stream,u32 bytes)
{
u32 i;
for (i = 0;i < bytes;++i) stream[i] = 0;
ECRYPT_encrypt_bytes(x,stream,stream,bytes);
}

View File

@@ -64,8 +64,7 @@ bool CsvExporter::writeGroup(QIODevice* device, const Group* group, QString grou
}
groupPath.append(group->name());
const QList<Entry*> entryList = group->entries();
for (const Entry* entry : entryList) {
Q_FOREACH (const Entry* entry, group->entries()) {
QString line;
addColumn(line, groupPath);
@@ -83,8 +82,7 @@ bool CsvExporter::writeGroup(QIODevice* device, const Group* group, QString grou
}
}
const QList<Group*> children = group->children();
for (const Group* child : children) {
Q_FOREACH (const Group* child, group->children()) {
if (!writeGroup(device, child, groupPath)) {
return false;
}

View File

@@ -49,9 +49,9 @@ private:
KeePass1Reader::KeePass1Reader()
: m_db(nullptr)
, m_tmpParent(nullptr)
, m_device(nullptr)
: m_db(Q_NULLPTR)
, m_tmpParent(Q_NULLPTR)
, m_device(Q_NULLPTR)
, m_encryptionFlags(0)
, m_transformRounds(0)
, m_error(false)
@@ -72,16 +72,16 @@ Database* KeePass1Reader::readDatabase(QIODevice* device, const QString& passwor
if (keyfileData.isEmpty()) {
raiseError(tr("Unable to read keyfile.").append("\n").append(keyfileDevice->errorString()));
return nullptr;
return Q_NULLPTR;
}
if (!keyfileDevice->seek(0)) {
raiseError(tr("Unable to read keyfile.").append("\n").append(keyfileDevice->errorString()));
return nullptr;
return Q_NULLPTR;
}
if (!newFileKey.load(keyfileDevice)) {
raiseError(tr("Unable to read keyfile.").append("\n").append(keyfileDevice->errorString()));
return nullptr;
return Q_NULLPTR;
}
}
@@ -96,72 +96,72 @@ Database* KeePass1Reader::readDatabase(QIODevice* device, const QString& passwor
quint32 signature1 = Endian::readUInt32(m_device, KeePass1::BYTEORDER, &ok);
if (!ok || signature1 != KeePass1::SIGNATURE_1) {
raiseError(tr("Not a KeePass database."));
return nullptr;
return Q_NULLPTR;
}
quint32 signature2 = Endian::readUInt32(m_device, KeePass1::BYTEORDER, &ok);
if (!ok || signature2 != KeePass1::SIGNATURE_2) {
raiseError(tr("Not a KeePass database."));
return nullptr;
return Q_NULLPTR;
}
m_encryptionFlags = Endian::readUInt32(m_device, KeePass1::BYTEORDER, &ok);
if (!ok || !(m_encryptionFlags & KeePass1::Rijndael || m_encryptionFlags & KeePass1::Twofish)) {
raiseError(tr("Unsupported encryption algorithm."));
return nullptr;
return Q_NULLPTR;
}
quint32 version = Endian::readUInt32(m_device, KeePass1::BYTEORDER, &ok);
if (!ok || (version & KeePass1::FILE_VERSION_CRITICAL_MASK)
!= (KeePass1::FILE_VERSION & KeePass1::FILE_VERSION_CRITICAL_MASK)) {
raiseError(tr("Unsupported KeePass database version."));
return nullptr;
return Q_NULLPTR;
}
m_masterSeed = m_device->read(16);
if (m_masterSeed.size() != 16) {
raiseError("Unable to read master seed");
return nullptr;
return Q_NULLPTR;
}
m_encryptionIV = m_device->read(16);
if (m_encryptionIV.size() != 16) {
raiseError("Unable to read encryption IV");
return nullptr;
return Q_NULLPTR;
}
quint32 numGroups = Endian::readUInt32(m_device, KeePass1::BYTEORDER, &ok);
if (!ok) {
raiseError("Invalid number of groups");
return nullptr;
return Q_NULLPTR;
}
quint32 numEntries = Endian::readUInt32(m_device, KeePass1::BYTEORDER, &ok);
if (!ok) {
raiseError("Invalid number of entries");
return nullptr;
return Q_NULLPTR;
}
m_contentHashHeader = m_device->read(32);
if (m_contentHashHeader.size() != 32) {
raiseError("Invalid content hash size");
return nullptr;
return Q_NULLPTR;
}
m_transformSeed = m_device->read(32);
if (m_transformSeed.size() != 32) {
raiseError("Invalid transform seed size");
return nullptr;
return Q_NULLPTR;
}
m_transformRounds = Endian::readUInt32(m_device, KeePass1::BYTEORDER, &ok);
if (!ok) {
raiseError("Invalid number of transform rounds");
return nullptr;
return Q_NULLPTR;
}
if (!m_db->setTransformRounds(m_transformRounds)) {
raiseError(tr("Unable to calculate master key"));
return nullptr;
return Q_NULLPTR;
}
qint64 contentPos = m_device->pos();
@@ -169,14 +169,14 @@ Database* KeePass1Reader::readDatabase(QIODevice* device, const QString& passwor
QScopedPointer<SymmetricCipherStream> cipherStream(testKeys(password, keyfileData, contentPos));
if (!cipherStream) {
return nullptr;
return Q_NULLPTR;
}
QList<Group*> groups;
for (quint32 i = 0; i < numGroups; i++) {
Group* group = readGroup(cipherStream.data());
if (!group) {
return nullptr;
return Q_NULLPTR;
}
groups.append(group);
}
@@ -185,17 +185,17 @@ Database* KeePass1Reader::readDatabase(QIODevice* device, const QString& passwor
for (quint32 i = 0; i < numEntries; i++) {
Entry* entry = readEntry(cipherStream.data());
if (!entry) {
return nullptr;
return Q_NULLPTR;
}
entries.append(entry);
}
if (!constructGroupTree(groups)) {
raiseError("Unable to construct group tree");
return nullptr;
return Q_NULLPTR;
}
for (Entry* entry : asConst(entries)) {
Q_FOREACH (Entry* entry, entries) {
if (isMetaStream(entry)) {
parseMetaStream(entry);
@@ -215,8 +215,7 @@ Database* KeePass1Reader::readDatabase(QIODevice* device, const QString& passwor
db->rootGroup()->setName(tr("Root"));
const QList<Group*> children = db->rootGroup()->children();
for (Group* group : children) {
Q_FOREACH (Group* group, db->rootGroup()->children()) {
if (group->name() == "Backup") {
group->setSearchingEnabled(Group::Disable);
group->setAutoTypeEnabled(Group::Disable);
@@ -226,12 +225,11 @@ Database* KeePass1Reader::readDatabase(QIODevice* device, const QString& passwor
Q_ASSERT(m_tmpParent->children().isEmpty());
Q_ASSERT(m_tmpParent->entries().isEmpty());
for (Group* group : asConst(groups)) {
Q_FOREACH (Group* group, groups) {
group->setUpdateTimeinfo(true);
}
const QList<Entry*> dbEntries = m_db->rootGroup()->entriesRecursive();
for (Entry* entry : dbEntries) {
Q_FOREACH (Entry* entry, m_db->rootGroup()->entriesRecursive()) {
entry->setUpdateTimeinfo(true);
}
@@ -245,7 +243,7 @@ Database* KeePass1Reader::readDatabase(QIODevice* device, const QString& passwor
if (!db->setKey(key)) {
raiseError(tr("Unable to calculate master key"));
return nullptr;
return Q_NULLPTR;
}
return db.take();
@@ -259,7 +257,7 @@ Database* KeePass1Reader::readDatabase(QIODevice* device, const QString& passwor
keyFile.reset(new QFile(keyfileName));
if (!keyFile->open(QFile::ReadOnly)) {
raiseError(keyFile->errorString());
return nullptr;
return Q_NULLPTR;
}
}
@@ -274,14 +272,14 @@ Database* KeePass1Reader::readDatabase(const QString& filename, const QString& p
QFile dbFile(filename);
if (!dbFile.open(QFile::ReadOnly)) {
raiseError(dbFile.errorString());
return nullptr;
return Q_NULLPTR;
}
Database* db = readDatabase(&dbFile, password, keyfileName);
if (dbFile.error() != QFile::NoError) {
raiseError(dbFile.errorString());
return nullptr;
return Q_NULLPTR;
}
return db;
@@ -300,14 +298,15 @@ QString KeePass1Reader::errorString()
SymmetricCipherStream* KeePass1Reader::testKeys(const QString& password, const QByteArray& keyfileData,
qint64 contentPos)
{
const QList<PasswordEncoding> encodings = { Windows1252, Latin1, UTF8 };
QList<PasswordEncoding> encodings;
encodings << Windows1252 << Latin1 << UTF8;
QScopedPointer<SymmetricCipherStream> cipherStream;
QByteArray passwordData;
QTextCodec* codec = QTextCodec::codecForName("Windows-1252");
QByteArray passwordDataCorrect = codec->fromUnicode(password);
for (PasswordEncoding encoding : encodings) {
Q_FOREACH (PasswordEncoding encoding, encodings) {
if (encoding == Windows1252) {
passwordData = passwordDataCorrect;
}
@@ -338,7 +337,7 @@ SymmetricCipherStream* KeePass1Reader::testKeys(const QString& password, const Q
QByteArray finalKey = key(passwordData, keyfileData);
if (finalKey.isEmpty()) {
return nullptr;
return Q_NULLPTR;
}
if (m_encryptionFlags & KeePass1::Rijndael) {
cipherStream.reset(new SymmetricCipherStream(m_device, SymmetricCipher::Aes256,
@@ -351,11 +350,11 @@ SymmetricCipherStream* KeePass1Reader::testKeys(const QString& password, const Q
if (!cipherStream->init(finalKey, m_encryptionIV)) {
raiseError(cipherStream->errorString());
return nullptr;
return Q_NULLPTR;
}
if (!cipherStream->open(QIODevice::ReadOnly)) {
raiseError(cipherStream->errorString());
return nullptr;
return Q_NULLPTR;
}
bool success = verifyKey(cipherStream.data());
@@ -369,7 +368,7 @@ SymmetricCipherStream* KeePass1Reader::testKeys(const QString& password, const Q
}
raiseError(msg);
return nullptr;
return Q_NULLPTR;
}
cipherStream->open(QIODevice::ReadOnly);
@@ -447,19 +446,19 @@ Group* KeePass1Reader::readGroup(QIODevice* cipherStream)
quint16 fieldType = Endian::readUInt16(cipherStream, KeePass1::BYTEORDER, &ok);
if (!ok) {
raiseError("Invalid group field type number");
return nullptr;
return Q_NULLPTR;
}
int fieldSize = static_cast<int>(Endian::readUInt32(cipherStream, KeePass1::BYTEORDER, &ok));
if (!ok) {
raiseError("Invalid group field size");
return nullptr;
return Q_NULLPTR;
}
QByteArray fieldData = cipherStream->read(fieldSize);
if (fieldData.size() != fieldSize) {
raiseError("Read group field data doesn't match size");
return nullptr;
return Q_NULLPTR;
}
switch (fieldType) {
@@ -469,7 +468,7 @@ Group* KeePass1Reader::readGroup(QIODevice* cipherStream)
case 0x0001:
if (fieldSize != 4) {
raiseError("Incorrect group id field size");
return nullptr;
return Q_NULLPTR;
}
groupId = Endian::bytesToUInt32(fieldData, KeePass1::BYTEORDER);
groupIdSet = true;
@@ -481,7 +480,7 @@ Group* KeePass1Reader::readGroup(QIODevice* cipherStream)
{
if (fieldSize != 5) {
raiseError("Incorrect group creation time field size");
return nullptr;
return Q_NULLPTR;
}
QDateTime dateTime = dateFromPackedStruct(fieldData);
if (dateTime.isValid()) {
@@ -493,7 +492,7 @@ Group* KeePass1Reader::readGroup(QIODevice* cipherStream)
{
if (fieldSize != 5) {
raiseError("Incorrect group modification time field size");
return nullptr;
return Q_NULLPTR;
}
QDateTime dateTime = dateFromPackedStruct(fieldData);
if (dateTime.isValid()) {
@@ -528,7 +527,7 @@ Group* KeePass1Reader::readGroup(QIODevice* cipherStream)
{
if (fieldSize != 4) {
raiseError("Incorrect group icon field size");
return nullptr;
return Q_NULLPTR;
}
quint32 iconNumber = Endian::bytesToUInt32(fieldData, KeePass1::BYTEORDER);
group->setIcon(iconNumber);
@@ -538,7 +537,7 @@ Group* KeePass1Reader::readGroup(QIODevice* cipherStream)
{
if (fieldSize != 2) {
raiseError("Incorrect group level field size");
return nullptr;
return Q_NULLPTR;
}
groupLevel = Endian::bytesToUInt16(fieldData, KeePass1::BYTEORDER);
groupLevelSet = true;
@@ -553,13 +552,13 @@ Group* KeePass1Reader::readGroup(QIODevice* cipherStream)
default:
// invalid field
raiseError("Invalid group field type");
return nullptr;
return Q_NULLPTR;
}
} while (!reachedEnd);
if (!groupIdSet || !groupLevelSet) {
raiseError("Missing group id or level");
return nullptr;
return Q_NULLPTR;
}
group->setUuid(Uuid::random());
@@ -585,19 +584,19 @@ Entry* KeePass1Reader::readEntry(QIODevice* cipherStream)
quint16 fieldType = Endian::readUInt16(cipherStream, KeePass1::BYTEORDER, &ok);
if (!ok) {
raiseError("Missing entry field type number");
return nullptr;
return Q_NULLPTR;
}
int fieldSize = static_cast<int>(Endian::readUInt32(cipherStream, KeePass1::BYTEORDER, &ok));
if (!ok) {
raiseError("Invalid entry field size");
return nullptr;
return Q_NULLPTR;
}
QByteArray fieldData = cipherStream->read(fieldSize);
if (fieldData.size() != fieldSize) {
raiseError("Read entry field data doesn't match size");
return nullptr;
return Q_NULLPTR;
}
switch (fieldType) {
@@ -607,7 +606,7 @@ Entry* KeePass1Reader::readEntry(QIODevice* cipherStream)
case 0x0001:
if (fieldSize != 16) {
raiseError("Invalid entry uuid field size");
return nullptr;
return Q_NULLPTR;
}
m_entryUuids.insert(fieldData, entry.data());
break;
@@ -615,7 +614,7 @@ Entry* KeePass1Reader::readEntry(QIODevice* cipherStream)
{
if (fieldSize != 4) {
raiseError("Invalid entry group id field size");
return nullptr;
return Q_NULLPTR;
}
quint32 groupId = Endian::bytesToUInt32(fieldData, KeePass1::BYTEORDER);
m_entryGroupIds.insert(entry.data(), groupId);
@@ -625,7 +624,7 @@ Entry* KeePass1Reader::readEntry(QIODevice* cipherStream)
{
if (fieldSize != 4) {
raiseError("Invalid entry icon field size");
return nullptr;
return Q_NULLPTR;
}
quint32 iconNumber = Endian::bytesToUInt32(fieldData, KeePass1::BYTEORDER);
entry->setIcon(iconNumber);
@@ -650,7 +649,7 @@ Entry* KeePass1Reader::readEntry(QIODevice* cipherStream)
{
if (fieldSize != 5) {
raiseError("Invalid entry creation time field size");
return nullptr;
return Q_NULLPTR;
}
QDateTime dateTime = dateFromPackedStruct(fieldData);
if (dateTime.isValid()) {
@@ -662,7 +661,7 @@ Entry* KeePass1Reader::readEntry(QIODevice* cipherStream)
{
if (fieldSize != 5) {
raiseError("Invalid entry modification time field size");
return nullptr;
return Q_NULLPTR;
}
QDateTime dateTime = dateFromPackedStruct(fieldData);
if (dateTime.isValid()) {
@@ -674,7 +673,7 @@ Entry* KeePass1Reader::readEntry(QIODevice* cipherStream)
{
if (fieldSize != 5) {
raiseError("Invalid entry creation time field size");
return nullptr;
return Q_NULLPTR;
}
QDateTime dateTime = dateFromPackedStruct(fieldData);
if (dateTime.isValid()) {
@@ -686,7 +685,7 @@ Entry* KeePass1Reader::readEntry(QIODevice* cipherStream)
{
if (fieldSize != 5) {
raiseError("Invalid entry expiry time field size");
return nullptr;
return Q_NULLPTR;
}
QDateTime dateTime = dateFromPackedStruct(fieldData);
if (dateTime.isValid()) {
@@ -709,7 +708,7 @@ Entry* KeePass1Reader::readEntry(QIODevice* cipherStream)
default:
// invalid field
raiseError("Invalid entry field type");
return nullptr;
return Q_NULLPTR;
}
} while (!reachedEnd);
@@ -728,8 +727,7 @@ void KeePass1Reader::parseNotes(const QString& rawNotes, Entry* entry)
QStringList notes;
bool lastLineAutoType = false;
const QStringList rawNotesLines = rawNotes.split("\n");
for (QString line : rawNotesLines) {
Q_FOREACH (QString line, rawNotes.split("\n")) {
line.remove("\r");
if (sequenceRegexp.exactMatch(line)) {
@@ -771,9 +769,8 @@ void KeePass1Reader::parseNotes(const QString& rawNotes, Entry* entry)
i.next();
QString sequence = sequences.value(i.key());
const QStringList windowList = i.value();
for (const QString& window : windowList) {
Q_FOREACH (const QString& window, i.value()) {
AutoTypeAssociations::Association assoc;
assoc.window = window;
assoc.sequence = sequence;

View File

@@ -34,12 +34,12 @@
#include "streams/SymmetricCipherStream.h"
KeePass2Reader::KeePass2Reader()
: m_device(nullptr)
, m_headerStream(nullptr)
: m_device(Q_NULLPTR)
, m_headerStream(Q_NULLPTR)
, m_error(false)
, m_headerEnd(false)
, m_saveXml(false)
, m_db(nullptr)
, m_db(Q_NULLPTR)
{
}
@@ -67,7 +67,7 @@ Database* KeePass2Reader::readDatabase(QIODevice* device, const CompositeKey& ke
quint32 signature1 = Endian::readUInt32(m_headerStream, KeePass2::BYTEORDER, &ok);
if (!ok || signature1 != KeePass2::SIGNATURE_1) {
raiseError(tr("Not a KeePass database."));
return nullptr;
return Q_NULLPTR;
}
quint32 signature2 = Endian::readUInt32(m_headerStream, KeePass2::BYTEORDER, &ok);
@@ -76,11 +76,11 @@ Database* KeePass2Reader::readDatabase(QIODevice* device, const CompositeKey& ke
"You can import it by clicking on Database > 'Import KeePass 1 database'.\n"
"This is a one-way migration. You won't be able to open the imported "
"database with the old KeePassX 0.4 version."));
return nullptr;
return Q_NULLPTR;
}
else if (!ok || signature2 != KeePass2::SIGNATURE_2) {
raiseError(tr("Not a KeePass database."));
return nullptr;
return Q_NULLPTR;
}
quint32 version = Endian::readUInt32(m_headerStream, KeePass2::BYTEORDER, &ok)
@@ -88,7 +88,7 @@ Database* KeePass2Reader::readDatabase(QIODevice* device, const CompositeKey& ke
quint32 maxVersion = KeePass2::FILE_VERSION & KeePass2::FILE_VERSION_CRITICAL_MASK;
if (!ok || (version < KeePass2::FILE_VERSION_MIN) || (version > maxVersion)) {
raiseError(tr("Unsupported KeePass database version."));
return nullptr;
return Q_NULLPTR;
}
while (readHeaderField() && !hasError()) {
@@ -97,7 +97,7 @@ Database* KeePass2Reader::readDatabase(QIODevice* device, const CompositeKey& ke
headerStream.close();
if (hasError()) {
return nullptr;
return Q_NULLPTR;
}
// check if all required headers were present
@@ -105,12 +105,12 @@ Database* KeePass2Reader::readDatabase(QIODevice* device, const CompositeKey& ke
|| m_streamStartBytes.isEmpty() || m_protectedStreamKey.isEmpty()
|| m_db->cipher().isNull()) {
raiseError("missing database headers");
return nullptr;
return Q_NULLPTR;
}
if (!m_db->setKey(key, m_transformSeed, false)) {
raiseError(tr("Unable to calculate master key"));
return nullptr;
return Q_NULLPTR;
}
CryptoHash hash(CryptoHash::Sha256);
@@ -122,24 +122,24 @@ Database* KeePass2Reader::readDatabase(QIODevice* device, const CompositeKey& ke
SymmetricCipher::Cbc, SymmetricCipher::Decrypt);
if (!cipherStream.init(finalKey, m_encryptionIV)) {
raiseError(cipherStream.errorString());
return nullptr;
return Q_NULLPTR;
}
if (!cipherStream.open(QIODevice::ReadOnly)) {
raiseError(cipherStream.errorString());
return nullptr;
return Q_NULLPTR;
}
QByteArray realStart = cipherStream.read(32);
if (realStart != m_streamStartBytes) {
raiseError(tr("Wrong key or database file is corrupt."));
return nullptr;
return Q_NULLPTR;
}
HashedBlockStream hashedStream(&cipherStream);
if (!hashedStream.open(QIODevice::ReadOnly)) {
raiseError(hashedStream.errorString());
return nullptr;
return Q_NULLPTR;
}
QIODevice* xmlDevice;
@@ -153,7 +153,7 @@ Database* KeePass2Reader::readDatabase(QIODevice* device, const CompositeKey& ke
ioCompressor->setStreamFormat(QtIOCompressor::GzipFormat);
if (!ioCompressor->open(QIODevice::ReadOnly)) {
raiseError(ioCompressor->errorString());
return nullptr;
return Q_NULLPTR;
}
xmlDevice = ioCompressor.data();
}
@@ -161,7 +161,7 @@ Database* KeePass2Reader::readDatabase(QIODevice* device, const CompositeKey& ke
KeePass2RandomStream randomStream;
if (!randomStream.init(m_protectedStreamKey)) {
raiseError(randomStream.errorString());
return nullptr;
return Q_NULLPTR;
}
QScopedPointer<QBuffer> buffer;
@@ -182,7 +182,7 @@ Database* KeePass2Reader::readDatabase(QIODevice* device, const CompositeKey& ke
return db.take();
}
else {
return nullptr;
return Q_NULLPTR;
}
}
@@ -204,14 +204,14 @@ Database* KeePass2Reader::readDatabase(const QString& filename, const CompositeK
QFile file(filename);
if (!file.open(QFile::ReadOnly)) {
raiseError(file.errorString());
return nullptr;
return Q_NULLPTR;
}
QScopedPointer<Database> db(readDatabase(&file, key));
if (file.error() != QFile::NoError) {
raiseError(file.errorString());
return nullptr;
return Q_NULLPTR;
}
return db.take();

View File

@@ -25,13 +25,13 @@
#include "format/KeePass2XmlReader.h"
KeePass2Repair::KeePass2Repair()
: m_db(nullptr)
: m_db(Q_NULLPTR)
{
}
KeePass2Repair::RepairResult KeePass2Repair::repairDatabase(QIODevice* device, const CompositeKey& key)
{
m_db = nullptr;
m_db = Q_NULLPTR;
m_errorStr.clear();
KeePass2Reader reader;

View File

@@ -31,10 +31,10 @@
typedef QPair<QString, QString> StringPair;
KeePass2XmlReader::KeePass2XmlReader()
: m_randomStream(nullptr)
, m_db(nullptr)
, m_meta(nullptr)
, m_tmpParent(nullptr)
: m_randomStream(Q_NULLPTR)
, m_db(Q_NULLPTR)
, m_meta(Q_NULLPTR)
, m_tmpParent(Q_NULLPTR)
, m_error(false)
, m_strictMode(false)
{
@@ -86,17 +86,17 @@ void KeePass2XmlReader::readDatabase(QIODevice* device, Database* db, KeePass2Ra
}
}
const QSet<QString> poolKeys = m_binaryPool.keys().toSet();
const QSet<QString> entryKeys = m_binaryMap.keys().toSet();
const QSet<QString> unmappedKeys = entryKeys - poolKeys;
const QSet<QString> unusedKeys = poolKeys - entryKeys;
QSet<QString> poolKeys = m_binaryPool.keys().toSet();
QSet<QString> entryKeys = m_binaryMap.keys().toSet();
QSet<QString> unmappedKeys = entryKeys - poolKeys;
QSet<QString> unusedKeys = poolKeys - entryKeys;
if (!unmappedKeys.isEmpty()) {
raiseError("Unmapped keys left.");
}
if (!m_xml.error()) {
for (const QString& key : unusedKeys) {
Q_FOREACH (const QString& key, unusedKeys) {
qWarning("KeePass2XmlReader::readDatabase: found unused key \"%s\"", qPrintable(key));
}
}
@@ -118,8 +118,7 @@ void KeePass2XmlReader::readDatabase(QIODevice* device, Database* db, KeePass2Ra
for (iEntry = m_entries.constBegin(); iEntry != m_entries.constEnd(); ++iEntry) {
iEntry.value()->setUpdateTimeinfo(true);
const QList<Entry*> historyItems = iEntry.value()->historyItems();
for (Entry* histEntry : historyItems) {
Q_FOREACH (Entry* histEntry, iEntry.value()->historyItems()) {
histEntry->setUpdateTimeinfo(true);
}
}
@@ -615,11 +614,11 @@ Group* KeePass2XmlReader::parseGroup()
raiseError("No group uuid found");
}
for (Group* child : asConst(children)) {
Q_FOREACH (Group* child, children) {
child->setParent(group);
}
for (Entry* entry : asConst(entries)) {
Q_FOREACH (Entry* entry, entries) {
entry->setGroup(group);
}
@@ -778,7 +777,7 @@ Entry* KeePass2XmlReader::parseEntry(bool history)
raiseError("No entry uuid found");
}
for (Entry* historyItem : asConst(historyItems)) {
Q_FOREACH (Entry* historyItem, historyItems) {
if (historyItem->uuid() != entry->uuid()) {
if (m_strictMode) {
raiseError("History element with different uuid");
@@ -789,7 +788,7 @@ Entry* KeePass2XmlReader::parseEntry(bool history)
entry->addHistoryItem(historyItem);
}
for (const StringPair& ref : asConst(binaryRefs)) {
Q_FOREACH (const StringPair& ref, binaryRefs) {
m_binaryMap.insertMulti(ref.first, qMakePair(entry, ref.second));
}
@@ -1053,7 +1052,7 @@ QDateTime KeePass2XmlReader::readDateTime()
raiseError("Invalid date time value");
}
else {
dt = QDateTime::currentDateTimeUtc();
dt = Tools::currentDateTimeUtc();
}
}
@@ -1154,7 +1153,7 @@ QByteArray KeePass2XmlReader::readCompressedBinary()
Group* KeePass2XmlReader::getGroup(const Uuid& uuid)
{
if (uuid.isNull()) {
return nullptr;
return Q_NULLPTR;
}
if (m_groups.contains(uuid)) {
@@ -1173,7 +1172,7 @@ Group* KeePass2XmlReader::getGroup(const Uuid& uuid)
Entry* KeePass2XmlReader::getEntry(const Uuid& uuid)
{
if (uuid.isNull()) {
return nullptr;
return Q_NULLPTR;
}
if (m_entries.contains(uuid)) {

View File

@@ -25,6 +25,7 @@
#include <QPair>
#include <QXmlStreamReader>
#include "core/Global.h"
#include "core/TimeInfo.h"
#include "core/Uuid.h"
@@ -41,7 +42,7 @@ class KeePass2XmlReader
public:
KeePass2XmlReader();
Database* readDatabase(QIODevice* device);
void readDatabase(QIODevice* device, Database* db, KeePass2RandomStream* randomStream = nullptr);
void readDatabase(QIODevice* device, Database* db, KeePass2RandomStream* randomStream = Q_NULLPTR);
Database* readDatabase(const QString& filename);
bool hasError();
QString errorString();

View File

@@ -25,9 +25,9 @@
#include "streams/QtIOCompressor"
KeePass2XmlWriter::KeePass2XmlWriter()
: m_db(nullptr)
, m_meta(nullptr)
, m_randomStream(nullptr)
: m_db(Q_NULLPTR)
, m_meta(Q_NULLPTR)
, m_randomStream(Q_NULLPTR)
, m_error(false)
{
m_xml.setAutoFormatting(true);
@@ -58,9 +58,11 @@ void KeePass2XmlWriter::writeDatabase(QIODevice* device, Database* db, KeePass2R
m_xml.writeEndDocument();
#if QT_VERSION >= QT_VERSION_CHECK(4, 8, 0)
if (m_xml.hasError()) {
raiseError(device->errorString());
}
#endif
}
void KeePass2XmlWriter::writeDatabase(const QString& filename, Database* db)
@@ -82,12 +84,11 @@ QString KeePass2XmlWriter::errorString()
void KeePass2XmlWriter::generateIdMap()
{
const QList<Entry*> allEntries = m_db->rootGroup()->entriesRecursive(true);
QList<Entry*> allEntries = m_db->rootGroup()->entriesRecursive(true);
int nextId = 0;
for (Entry* entry : allEntries) {
const QList<QString> attachmentKeys = entry->attachments()->keys();
for (const QString& key : attachmentKeys) {
Q_FOREACH (Entry* entry, allEntries) {
Q_FOREACH (const QString& key, entry->attachments()->keys()) {
QByteArray data = entry->attachments()->value(key);
if (!m_idMap.contains(data)) {
m_idMap.insert(data, nextId++);
@@ -150,8 +151,7 @@ void KeePass2XmlWriter::writeCustomIcons()
{
m_xml.writeStartElement("CustomIcons");
const QList<Uuid> customIconsOrder = m_meta->customIconsOrder();
for (const Uuid& uuid : customIconsOrder) {
Q_FOREACH (const Uuid& uuid, m_meta->customIconsOrder()) {
writeIcon(uuid, m_meta->customIcon(uuid));
}
@@ -222,8 +222,7 @@ void KeePass2XmlWriter::writeCustomData()
m_xml.writeStartElement("CustomData");
QHash<QString, QString> customFields = m_meta->customFields();
const QList<QString> keyList = customFields.keys();
for (const QString& key : keyList) {
Q_FOREACH (const QString& key, customFields.keys()) {
writeCustomDataItem(key, customFields.value(key));
}
@@ -276,13 +275,11 @@ void KeePass2XmlWriter::writeGroup(const Group* group)
writeUuid("LastTopVisibleEntry", group->lastTopVisibleEntry());
const QList<Entry*> entryList = group->entries();
for (const Entry* entry : entryList) {
Q_FOREACH (const Entry* entry, group->entries()) {
writeEntry(entry);
}
const QList<Group*> children = group->children();
for (const Group* child : children) {
Q_FOREACH (const Group* child, group->children()) {
writeGroup(child);
}
@@ -308,8 +305,7 @@ void KeePass2XmlWriter::writeDeletedObjects()
{
m_xml.writeStartElement("DeletedObjects");
const QList<DeletedObject> delObjList = m_db->deletedObjects();
for (const DeletedObject& delObj : delObjList) {
Q_FOREACH (const DeletedObject& delObj, m_db->deletedObjects()) {
writeDeletedObject(delObj);
}
@@ -343,8 +339,7 @@ void KeePass2XmlWriter::writeEntry(const Entry* entry)
writeString("Tags", entry->tags());
writeTimes(entry->timeInfo());
const QList<QString> attributesKeyList = entry->attributes()->keys();
for (const QString& key : attributesKeyList) {
Q_FOREACH (const QString& key, entry->attributes()->keys()) {
m_xml.writeStartElement("String");
bool protect = ( ((key == "Title") && m_meta->protectTitle()) ||
@@ -386,8 +381,7 @@ void KeePass2XmlWriter::writeEntry(const Entry* entry)
m_xml.writeEndElement();
}
const QList<QString> attachmentsKeyList = entry->attachments()->keys();
for (const QString& key : attachmentsKeyList) {
Q_FOREACH (const QString& key, entry->attachments()->keys()) {
m_xml.writeStartElement("Binary");
writeString("Key", key);
@@ -416,8 +410,7 @@ void KeePass2XmlWriter::writeAutoType(const Entry* entry)
writeNumber("DataTransferObfuscation", entry->autoTypeObfuscation());
writeString("DefaultSequence", entry->defaultAutoTypeSequence());
const QList<AutoTypeAssociations::Association> autoTypeAssociations = entry->autoTypeAssociations()->getAll();
for (const AutoTypeAssociations::Association& assoc : autoTypeAssociations) {
Q_FOREACH (const AutoTypeAssociations::Association& assoc, entry->autoTypeAssociations()->getAll()) {
writeAutoTypeAssoc(assoc);
}
@@ -439,7 +432,7 @@ void KeePass2XmlWriter::writeEntryHistory(const Entry* entry)
m_xml.writeStartElement("History");
const QList<Entry*>& historyItems = entry->historyItems();
for (const Entry* item : historyItems) {
Q_FOREACH (const Entry* item, historyItems) {
writeEntry(item);
}

View File

@@ -36,7 +36,7 @@ class KeePass2XmlWriter
{
public:
KeePass2XmlWriter();
void writeDatabase(QIODevice* device, Database* db, KeePass2RandomStream* randomStream = nullptr,
void writeDatabase(QIODevice* device, Database* db, KeePass2RandomStream* randomStream = Q_NULLPTR,
const QByteArray& headerHash = QByteArray());
void writeDatabase(const QString& filename, Database* db);
bool hasError();

View File

@@ -21,6 +21,8 @@
#include <QDialog>
#include <QScopedPointer>
#include "core/Global.h"
namespace Ui {
class AboutDialog;
}
@@ -30,7 +32,7 @@ class AboutDialog : public QDialog
Q_OBJECT
public:
explicit AboutDialog(QWidget* parent = nullptr);
explicit AboutDialog(QWidget* parent = Q_NULLPTR);
~AboutDialog();
private:

View File

@@ -18,38 +18,14 @@
#include "Application.h"
#include <QAbstractNativeEventFilter>
#include <QFileOpenEvent>
#include "autotype/AutoType.h"
#if defined(Q_OS_UNIX) && !defined(Q_OS_OSX)
class XcbEventFilter : public QAbstractNativeEventFilter
{
public:
bool nativeEventFilter(const QByteArray& eventType, void* message, long* result) override
{
Q_UNUSED(result)
if (eventType == QByteArrayLiteral("xcb_generic_event_t")) {
int retCode = autoType()->callEventFilter(message);
if (retCode == 1) {
return true;
}
}
return false;
}
};
#endif
Application::Application(int& argc, char** argv)
: QApplication(argc, argv)
, m_mainWindow(nullptr)
, m_mainWindow(Q_NULLPTR)
{
#if defined(Q_OS_UNIX) && !defined(Q_OS_OSX)
installNativeEventFilter(new XcbEventFilter());
#endif
}
void Application::setMainWindow(QWidget* mainWindow)
@@ -77,3 +53,19 @@ bool Application::event(QEvent* event)
return QApplication::event(event);
}
#ifdef Q_WS_X11
bool Application::x11EventFilter(XEvent* event)
{
int retCode = autoType()->callEventFilter(event);
if (retCode == 0) {
return false;
}
else if (retCode == 1) {
return true;
}
return QApplication::x11EventFilter(event);
}
#endif

View File

@@ -21,6 +21,8 @@
#include <QApplication>
#include "core/Global.h"
class Application : public QApplication
{
Q_OBJECT
@@ -29,7 +31,10 @@ public:
Application(int& argc, char** argv);
void setMainWindow(QWidget* mainWindow);
bool event(QEvent* event) override;
bool event(QEvent* event) Q_DECL_OVERRIDE;
#ifdef Q_WS_X11
bool x11EventFilter(XEvent* event) Q_DECL_OVERRIDE;
#endif
Q_SIGNALS:
void openFile(const QString& filename);

View File

@@ -33,7 +33,7 @@ class ChangeMasterKeyWidget : public DialogyWidget
Q_OBJECT
public:
explicit ChangeMasterKeyWidget(QWidget* parent = nullptr);
explicit ChangeMasterKeyWidget(QWidget* parent = Q_NULLPTR);
~ChangeMasterKeyWidget();
void clearForms();
CompositeKey newMasterKey();

View File

@@ -23,7 +23,7 @@
#include "core/Config.h"
Clipboard* Clipboard::m_instance(nullptr);
Clipboard* Clipboard::m_instance(Q_NULLPTR);
Clipboard::Clipboard(QObject* parent)
: QObject(parent)

View File

@@ -20,6 +20,8 @@
#include <QObject>
#include "core/Global.h"
class QTimer;
class Clipboard : public QObject
@@ -38,7 +40,7 @@ private Q_SLOTS:
void clearClipboard();
private:
explicit Clipboard(QObject* parent = nullptr);
explicit Clipboard(QObject* parent = Q_NULLPTR);
static Clipboard* m_instance;

View File

@@ -21,7 +21,6 @@
#include "core/Config.h"
#include "core/Database.h"
#include "core/FilePath.h"
#include "gui/MainWindow.h"
#include "gui/FileDialog.h"
#include "gui/MessageBox.h"
#include "format/KeePass2Reader.h"
@@ -31,7 +30,7 @@
DatabaseOpenWidget::DatabaseOpenWidget(QWidget* parent)
: DialogyWidget(parent)
, m_ui(new Ui::DatabaseOpenWidget())
, m_db(nullptr)
, m_db(Q_NULLPTR)
{
m_ui->setupUi(this);
@@ -113,12 +112,6 @@ void DatabaseOpenWidget::openDatabase()
if (m_db) {
Q_EMIT editFinished(true);
// this is a c++11 equivalent foreach construct
// if c++11 is not available another iteration loop style is needed!
for (auto widget : qApp->topLevelWidgets()) {
if(widget->inherits("QMainWindow"))
static_cast<MainWindow*>(widget)->configuredMinimizeWindow();
}
}
else {
MessageBox::warning(this, tr("Error"), tr("Unable to open the database.").append("\n")

View File

@@ -35,7 +35,7 @@ class DatabaseOpenWidget : public DialogyWidget
Q_OBJECT
public:
explicit DatabaseOpenWidget(QWidget* parent = nullptr);
explicit DatabaseOpenWidget(QWidget* parent = Q_NULLPTR);
~DatabaseOpenWidget();
void load(const QString& filename);
void enterKey(const QString& pw, const QString& keyFile);

View File

@@ -25,14 +25,14 @@ class DatabaseRepairWidget : public DatabaseOpenWidget
Q_OBJECT
public:
explicit DatabaseRepairWidget(QWidget* parent = nullptr);
explicit DatabaseRepairWidget(QWidget* parent = Q_NULLPTR);
Q_SIGNALS:
void success();
void error();
protected:
void openDatabase() override;
void openDatabase() Q_DECL_OVERRIDE;
private Q_SLOTS:
void processEditFinished(bool result);

View File

@@ -26,7 +26,7 @@
DatabaseSettingsWidget::DatabaseSettingsWidget(QWidget* parent)
: DialogyWidget(parent)
, m_ui(new Ui::DatabaseSettingsWidget())
, m_db(nullptr)
, m_db(Q_NULLPTR)
{
m_ui->setupUi(this);
@@ -139,8 +139,8 @@ void DatabaseSettingsWidget::transformRoundsBenchmark()
void DatabaseSettingsWidget::truncateHistories()
{
const QList<Entry*> allEntries = m_db->rootGroup()->entriesRecursive(false);
for (Entry* entry : allEntries) {
QList<Entry*> allEntries = m_db->rootGroup()->entriesRecursive(false);
Q_FOREACH (Entry* entry, allEntries) {
entry->truncateHistory();
}
}

Some files were not shown because too many files have changed in this diff Show More