mirror of
https://github.com/keepassxreboot/keepassxc.git
synced 2025-12-04 15:39:34 +01:00
Compare commits
3 Commits
2.0.3-http
...
2.0.3
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
c8857ac2ba | ||
|
|
367fbbba39 | ||
|
|
abf469f743 |
28
.travis.yml
28
.travis.yml
@@ -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
|
||||
|
||||
@@ -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)
|
||||
|
||||
63
README.md
63
README.md
@@ -1,35 +1,68 @@
|
||||
# KeePassX v2.0.2 + keepasshttp
|
||||
|
||||

|
||||
# 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
|
||||
|
||||
|
||||
@@ -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)
|
||||
@@ -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})
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -1326,14 +1326,6 @@ This is a one-way migration. You won'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>
|
||||
|
||||
@@ -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}")
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -66,7 +66,7 @@ public:
|
||||
class KEEPASSX_EXPORT AutoTypeClearField : public AutoTypeAction
|
||||
{
|
||||
public:
|
||||
AutoTypeClearField();
|
||||
explicit AutoTypeClearField();
|
||||
AutoTypeAction* clone();
|
||||
void accept(AutoTypeExecutor* executor);
|
||||
};
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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()
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -129,3 +129,5 @@ void AutoTypeExecturorTest::execKey(AutoTypeKey* action)
|
||||
{
|
||||
m_platform->addActionKey(action);
|
||||
}
|
||||
|
||||
Q_EXPORT_PLUGIN2(keepassx-autotype-test, AutoTypePlatformTest)
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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})
|
||||
|
||||
@@ -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)
|
||||
@@ -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
|
||||
17
src/autotype/x11/CMakeLists.txt
Normal file
17
src/autotype/x11/CMakeLists.txt
Normal 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)
|
||||
@@ -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)
|
||||
@@ -16,4 +16,6 @@
|
||||
#cmakedefine HAVE_RLIMIT_CORE 1
|
||||
#cmakedefine HAVE_PT_DENY_ATTACH 1
|
||||
|
||||
#cmakedefine GCRYPT_HAS_SALSA20
|
||||
|
||||
#endif // KEEPASSX_CONFIG_KEEPASSX_H
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -21,6 +21,8 @@
|
||||
#include <QScopedPointer>
|
||||
#include <QVariant>
|
||||
|
||||
#include "core/Global.h"
|
||||
|
||||
class QSettings;
|
||||
|
||||
class Config : public QObject
|
||||
|
||||
@@ -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();
|
||||
|
||||
|
||||
@@ -20,7 +20,6 @@
|
||||
|
||||
#include <QDateTime>
|
||||
#include <QHash>
|
||||
#include <QObject>
|
||||
|
||||
#include "core/Uuid.h"
|
||||
#include "keys/CompositeKey.h"
|
||||
|
||||
@@ -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[] = {
|
||||
|
||||
@@ -23,6 +23,8 @@
|
||||
#include <QPixmapCache>
|
||||
#include <QVector>
|
||||
|
||||
#include "core/Global.h"
|
||||
|
||||
class DatabaseIcons
|
||||
{
|
||||
public:
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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, "");
|
||||
}
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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*>();
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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)) {
|
||||
|
||||
@@ -22,6 +22,8 @@
|
||||
#include <QIcon>
|
||||
#include <QString>
|
||||
|
||||
#include "core/Global.h"
|
||||
|
||||
class FilePath
|
||||
{
|
||||
public:
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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)) {
|
||||
|
||||
@@ -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
|
||||
{
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -21,6 +21,8 @@
|
||||
#include <QObject>
|
||||
#include <QPointer>
|
||||
|
||||
#include "core/Global.h"
|
||||
|
||||
class SignalMultiplexer
|
||||
{
|
||||
public:
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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());
|
||||
|
||||
@@ -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;
|
||||
|
||||
305
src/core/qcommandlineoption.cpp
Normal file
305
src/core/qcommandlineoption.cpp
Normal 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;
|
||||
}
|
||||
81
src/core/qcommandlineoption.h
Normal file
81
src/core/qcommandlineoption.h
Normal 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
|
||||
944
src/core/qcommandlineparser.cpp
Normal file
944
src/core/qcommandlineparser.cpp
Normal 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;
|
||||
}
|
||||
102
src/core/qcommandlineparser.h
Normal file
102
src/core/qcommandlineparser.h
Normal 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
344
src/core/qlockfile.cpp
Normal 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
79
src/core/qlockfile.h
Normal 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
101
src/core/qlockfile_p.h
Normal 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
244
src/core/qlockfile_unix.cpp
Normal 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
227
src/core/qlockfile_win.cpp
Normal 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
452
src/core/qsavefile.cpp
Normal 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
105
src/core/qsavefile.h
Normal 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
71
src/core/qsavefile_p.h
Normal 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
|
||||
|
||||
@@ -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));
|
||||
|
||||
@@ -20,6 +20,8 @@
|
||||
|
||||
#include <QString>
|
||||
|
||||
#include "core/Global.h"
|
||||
|
||||
class Crypto
|
||||
{
|
||||
public:
|
||||
|
||||
@@ -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)
|
||||
{
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -22,6 +22,7 @@
|
||||
#include <QScopedPointer>
|
||||
#include <QString>
|
||||
|
||||
#include "core/Global.h"
|
||||
#include "crypto/SymmetricCipherBackend.h"
|
||||
|
||||
class SymmetricCipher
|
||||
|
||||
@@ -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);
|
||||
|
||||
260
src/crypto/salsa20/ecrypt-config.h
Normal file
260
src/crypto/salsa20/ecrypt-config.h
Normal 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
|
||||
49
src/crypto/salsa20/ecrypt-machine.h
Normal file
49
src/crypto/salsa20/ecrypt-machine.h
Normal 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
|
||||
|
||||
/* ------------------------------------------------------------------------- */
|
||||
310
src/crypto/salsa20/ecrypt-portable.h
Normal file
310
src/crypto/salsa20/ecrypt-portable.h
Normal 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
|
||||
287
src/crypto/salsa20/ecrypt-sync.h
Normal file
287
src/crypto/salsa20/ecrypt-sync.h
Normal 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
|
||||
133
src/crypto/salsa20/salsa20.c
Normal file
133
src/crypto/salsa20/salsa20.c
Normal 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);
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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)) {
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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")
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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
Reference in New Issue
Block a user