aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--CMakeLists.txt136
-rw-r--r--include/rapidjson/document.h2575
-rw-r--r--include/rapidjson/error/error.h155
-rw-r--r--include/rapidjson/internal/biginteger.h290
-rw-r--r--include/rapidjson/internal/diyfp.h258
-rw-r--r--include/rapidjson/internal/ieee754.h78
-rw-r--r--include/rapidjson/internal/itoa.h304
-rw-r--r--include/rapidjson/internal/meta.h181
-rw-r--r--include/rapidjson/internal/pow10.h55
-rw-r--r--include/rapidjson/internal/regex.h701
-rw-r--r--include/rapidjson/internal/stack.h230
-rw-r--r--include/rapidjson/internal/strfunc.h55
-rw-r--r--include/rapidjson/memorybuffer.h70
-rw-r--r--include/rapidjson/pointer.h1358
-rw-r--r--include/rapidjson/reader.h1879
-rw-r--r--include/rapidjson/schema.h2006
-rw-r--r--include/rapidjson/stringbuffer.h117
-rw-r--r--include/rapidjson/writer.h610
-rwxr-xr-xinclude/ui/KeyMgmt.h108
-rw-r--r--include/ui/KeyServerImportDialog.h93
-rw-r--r--include/ui/SendMailDialog.h66
-rwxr-xr-xinclude/ui/SettingsDialog.h263
-rw-r--r--include/ui/Wizard.h124
-rw-r--r--include/ui/keygen/KeygenDialog.h109
-rw-r--r--include/ui/keygen/SubkeyGenerateDialog.h91
-rw-r--r--include/ui/keypair_details/KeyPairDetailTab.h101
-rw-r--r--include/ui/keypair_details/KeyPairSubkeyTab.h90
-rw-r--r--include/ui/widgets/EditorPage.h108
-rw-r--r--include/ui/widgets/FilePage.h88
-rw-r--r--include/ui/widgets/InfoBoardWidget.h119
-rw-r--r--include/ui/widgets/KeyList.h135
-rw-r--r--include/ui/widgets/TextEdit.h298
-rw-r--r--src/MainWindow.cpp245
-rw-r--r--src/MainWindow.h415
-rw-r--r--src/gpg/CMakeLists.txt14
-rw-r--r--src/gpg/GpgConstants.cpp14
-rw-r--r--src/gpg/GpgConstants.h10
-rw-r--r--src/gpg/GpgModel.h25
-rw-r--r--src/gpg/function/BasicOperator.cpp12
-rw-r--r--src/gpg/function/BasicOperator.h12
-rw-r--r--src/gpg/function/GpgFileOpera.h2
-rw-r--r--src/gpg/function/GpgKeyGetter.cpp11
-rw-r--r--src/gpg/function/GpgKeyGetter.h4
-rw-r--r--src/gpg/function/GpgKeyImportExportor.cpp8
-rw-r--r--src/gpg/function/GpgKeyImportExportor.h6
-rw-r--r--src/gpg/function/GpgKeyManager.cpp41
-rw-r--r--src/gpg/function/GpgKeyManager.h24
-rw-r--r--src/gpg/function/GpgKeyOpera.cpp45
-rw-r--r--src/gpg/function/GpgKeyOpera.h28
-rw-r--r--src/gpg/function/UidOperator.cpp30
-rw-r--r--src/gpg/function/UidOperator.h33
-rw-r--r--src/gpg/model/GpgData.cpp11
-rw-r--r--src/gpg/model/GpgData.h12
-rw-r--r--src/gpg/model/GpgSubKey.h18
-rw-r--r--src/gpg/result_analyse/ResultAnalyse.cpp8
-rw-r--r--src/gpg/result_analyse/ResultAnalyse.h12
-rw-r--r--src/main.cpp147
-rw-r--r--src/ui/CMakeLists.txt2
-rwxr-xr-xsrc/ui/FileEncryptionDialog.cpp466
-rwxr-xr-xsrc/ui/FileEncryptionDialog.h (renamed from include/ui/FileEncryptionDialog.h)153
-rw-r--r--src/ui/FindWidget.cpp236
-rw-r--r--src/ui/FindWidget.h (renamed from include/ui/FindWidget.h)51
-rw-r--r--src/ui/GpgFrontendUI.h35
-rw-r--r--src/ui/KeyImportDetailDialog.cpp265
-rw-r--r--src/ui/KeyImportDetailDialog.h (renamed from include/ui/KeyImportDetailDialog.h)39
-rwxr-xr-xsrc/ui/KeyMgmt.cpp572
-rwxr-xr-xsrc/ui/KeyMgmt.h111
-rw-r--r--src/ui/KeyServerImportDialog.cpp796
-rw-r--r--src/ui/KeyServerImportDialog.h94
-rw-r--r--src/ui/KeyUploadDialog.cpp175
-rw-r--r--src/ui/KeyUploadDialog.h (renamed from include/ui/KeyUploadDialog.h)36
-rw-r--r--src/ui/MainWindow.cpp249
-rw-r--r--src/ui/MainWindow.h425
-rwxr-xr-xsrc/ui/QuitDialog.cpp181
-rwxr-xr-xsrc/ui/QuitDialog.h (renamed from include/ui/QuitDialog.h)28
-rw-r--r--src/ui/SendMailDialog.cpp294
-rw-r--r--src/ui/SendMailDialog.h71
-rwxr-xr-xsrc/ui/SettingsDialog.h255
-rw-r--r--src/ui/ShowCopyDialog.cpp53
-rw-r--r--src/ui/ShowCopyDialog.h (renamed from include/ui/ShowCopyDialog.h)27
-rw-r--r--src/ui/VerifyDetailsDialog.cpp93
-rw-r--r--src/ui/VerifyDetailsDialog.h (renamed from include/ui/VerifyDetailsDialog.h)46
-rw-r--r--src/ui/WaitingDialog.cpp60
-rw-r--r--src/ui/WaitingDialog.h (renamed from include/ui/WaitingDialog.h)21
-rw-r--r--src/ui/Wizard.cpp408
-rw-r--r--src/ui/Wizard.h129
-rw-r--r--src/ui/help/AboutDialog.cpp335
-rw-r--r--src/ui/help/AboutDialog.h (renamed from include/ui/help/AboutDialog.h)61
-rw-r--r--src/ui/help/VersionCheckThread.cpp65
-rw-r--r--src/ui/help/VersionCheckThread.h (renamed from include/ui/help/VersionCheckThread.h)30
-rw-r--r--src/ui/keygen/KeygenDialog.cpp537
-rw-r--r--src/ui/keygen/KeygenDialog.h114
-rw-r--r--src/ui/keygen/SubkeyGenerateDialog.cpp421
-rw-r--r--src/ui/keygen/SubkeyGenerateDialog.h94
-rw-r--r--src/ui/keypair_details/EditSubKeyDialog.h (renamed from include/ui/keypair_details/EditSubKeyDialog.h)0
-rw-r--r--src/ui/keypair_details/KeyDetailsDialog.cpp33
-rw-r--r--src/ui/keypair_details/KeyDetailsDialog.h (renamed from include/ui/keypair_details/KeyDetailsDialog.h)23
-rw-r--r--src/ui/keypair_details/KeyNewUIDDialog.cpp134
-rw-r--r--src/ui/keypair_details/KeyNewUIDDialog.h (renamed from include/ui/keypair_details/KeyNewUIDDialog.h)45
-rw-r--r--src/ui/keypair_details/KeyPairDetailTab.cpp592
-rw-r--r--src/ui/keypair_details/KeyPairDetailTab.h104
-rw-r--r--src/ui/keypair_details/KeyPairSubkeyTab.cpp436
-rw-r--r--src/ui/keypair_details/KeyPairSubkeyTab.h85
-rw-r--r--src/ui/keypair_details/KeyPairUIDTab.cpp750
-rw-r--r--src/ui/keypair_details/KeyPairUIDTab.h (renamed from include/ui/keypair_details/KeyPairUIDTab.h)80
-rw-r--r--src/ui/keypair_details/KeySetExpireDateDialog.cpp92
-rw-r--r--src/ui/keypair_details/KeySetExpireDateDialog.h (renamed from include/ui/keypair_details/KeySetExpireDateDialog.h)46
-rw-r--r--src/ui/keypair_details/KeyUIDSignDialog.cpp168
-rw-r--r--src/ui/keypair_details/KeyUIDSignDialog.h (renamed from include/ui/keypair_details/KeyUIDSignDialog.h)40
-rw-r--r--src/ui/main_window/MainWindowFileSlotFunction.cpp1002
-rw-r--r--src/ui/main_window/MainWindowServerSlotFunction.cpp372
-rw-r--r--src/ui/main_window/MainWindowSlotFunction.cpp897
-rw-r--r--src/ui/main_window/MainWindowSlotUI.cpp281
-rw-r--r--src/ui/main_window/MainWindowUI.cpp847
-rw-r--r--src/ui/settings/SettingsAdvanced.cpp67
-rw-r--r--src/ui/settings/SettingsAppearance.cpp293
-rw-r--r--src/ui/settings/SettingsDialog.cpp283
-rw-r--r--src/ui/settings/SettingsGeneral.cpp562
-rw-r--r--src/ui/settings/SettingsKeyServer.cpp198
-rw-r--r--src/ui/settings/SettingsSendMail.cpp297
-rw-r--r--src/ui/widgets/EditorPage.cpp132
-rw-r--r--src/ui/widgets/EditorPage.h108
-rw-r--r--src/ui/widgets/FilePage.cpp397
-rw-r--r--src/ui/widgets/FilePage.h86
-rw-r--r--src/ui/widgets/HelpPage.cpp71
-rw-r--r--src/ui/widgets/HelpPage.h (renamed from include/ui/widgets/HelpPage.h)29
-rw-r--r--src/ui/widgets/InfoBoardWidget.cpp280
-rw-r--r--src/ui/widgets/InfoBoardWidget.h118
-rw-r--r--src/ui/widgets/KeyList.cpp638
-rw-r--r--src/ui/widgets/KeyList.h124
-rw-r--r--src/ui/widgets/SignersPicker.cpp54
-rw-r--r--src/ui/widgets/SignersPicker.h (renamed from include/ui/widgets/SignersPicker.h)21
-rw-r--r--src/ui/widgets/TextEdit.cpp104
-rw-r--r--src/ui/widgets/TextEdit.h301
-rw-r--r--src/ui/widgets/VerifyKeyDetailBox.cpp323
-rw-r--r--src/ui/widgets/VerifyKeyDetailBox.h (renamed from include/ui/widgets/VerifyKeyDetailBox.h)31
-rw-r--r--test/GpgCoreTestBasicOpera.cpp18
-rw-r--r--third_party/rapidjson/allocators.h (renamed from include/rapidjson/allocators.h)0
-rw-r--r--third_party/rapidjson/document.h3231
-rw-r--r--third_party/rapidjson/encodedstream.h (renamed from include/rapidjson/encodedstream.h)0
-rw-r--r--third_party/rapidjson/encodings.h (renamed from include/rapidjson/encodings.h)0
-rw-r--r--third_party/rapidjson/error/en.h (renamed from include/rapidjson/error/en.h)0
-rw-r--r--third_party/rapidjson/error/error.h172
-rw-r--r--third_party/rapidjson/filereadstream.h (renamed from include/rapidjson/filereadstream.h)0
-rw-r--r--third_party/rapidjson/filewritestream.h (renamed from include/rapidjson/filewritestream.h)0
-rw-r--r--third_party/rapidjson/fwd.h (renamed from include/rapidjson/fwd.h)0
-rw-r--r--third_party/rapidjson/internal/biginteger.h319
-rw-r--r--third_party/rapidjson/internal/diyfp.h307
-rw-r--r--third_party/rapidjson/internal/dtoa.h (renamed from include/rapidjson/internal/dtoa.h)0
-rw-r--r--third_party/rapidjson/internal/ieee754.h100
-rw-r--r--third_party/rapidjson/internal/itoa.h303
-rw-r--r--third_party/rapidjson/internal/meta.h238
-rw-r--r--third_party/rapidjson/internal/pow10.h77
-rw-r--r--third_party/rapidjson/internal/regex.h733
-rw-r--r--third_party/rapidjson/internal/stack.h243
-rw-r--r--third_party/rapidjson/internal/strfunc.h63
-rw-r--r--third_party/rapidjson/internal/strtod.h (renamed from include/rapidjson/internal/strtod.h)0
-rw-r--r--third_party/rapidjson/internal/swap.h (renamed from include/rapidjson/internal/swap.h)38
-rw-r--r--third_party/rapidjson/istreamwrapper.h (renamed from include/rapidjson/istreamwrapper.h)0
-rw-r--r--third_party/rapidjson/memorybuffer.h78
-rw-r--r--third_party/rapidjson/memorystream.h (renamed from include/rapidjson/memorystream.h)0
-rw-r--r--third_party/rapidjson/msinttypes/inttypes.h (renamed from include/rapidjson/msinttypes/inttypes.h)0
-rw-r--r--third_party/rapidjson/msinttypes/stdint.h (renamed from include/rapidjson/msinttypes/stdint.h)0
-rw-r--r--third_party/rapidjson/ostreamwrapper.h (renamed from include/rapidjson/ostreamwrapper.h)0
-rw-r--r--third_party/rapidjson/pointer.h1716
-rw-r--r--third_party/rapidjson/prettywriter.h (renamed from include/rapidjson/prettywriter.h)0
-rw-r--r--third_party/rapidjson/rapidjson.h (renamed from include/rapidjson/rapidjson.h)0
-rw-r--r--third_party/rapidjson/reader.h2113
-rw-r--r--third_party/rapidjson/schema.h2399
-rw-r--r--third_party/rapidjson/stream.h (renamed from include/rapidjson/stream.h)0
-rw-r--r--third_party/rapidjson/stringbuffer.h127
-rw-r--r--third_party/rapidjson/writer.h715
172 files changed, 23548 insertions, 21052 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 56548f06..3c551fa6 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -20,7 +20,7 @@ elseif ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "Intel")
elseif ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "MSVC")
# using Visual Studio C++
message(STATUS "Using Complier Msvc")
-endif()
+endif ()
# Using Standard C++-17 (Consider compatibility)
set(CMAKE_CXX_STANDARD 17)
@@ -33,69 +33,72 @@ set(CMAKE_EXPORT_COMPILE_COMMANDS ON)
# Check Env Variables Before Configuring
-if(CMAKE_BUILD_TYPE)
+if (CMAKE_BUILD_TYPE)
message(STATUS "PreCheck CMAKE_BUILD_TYPE ${CMAKE_BUILD_TYPE}")
-else()
+else ()
set(CMAKE_BUILD_TYPE "Release")
message(STATUS "Set CMAKE_BUILD_TYPE ${CMAKE_BUILD_TYPE}")
-endif()
+endif ()
# Specify different compilation modes
-if(BUILD_CONFIG)
+if (BUILD_CONFIG)
# Test Build
- if(${BUILD_CONFIG} STREQUAL "test")
+ if (${BUILD_CONFIG} STREQUAL "test")
message(STATUS "Switch TEST_BUILD")
set(TEST_BUILD 1)
set(AppName GpgFrontendTest)
- # Test Build With Coverage Test
- elseif(${BUILD_CONFIG} STREQUAL "test_coverage")
+ # Test Build With Coverage Test
+ elseif (${BUILD_CONFIG} STREQUAL "test_coverage")
message(STATUS "Switch TEST_COVERAGE_BUILD")
set(TEST_BUILD 1)
- if(USING_COMPILER_CLANG OR USING_COMPILER_GCC)
+ if (USING_COMPILER_CLANG OR USING_COMPILER_GCC)
set(TEST_COVERAGE_BUILD 1)
set(CMAKE_CXX_OUTPUT_EXTENSION_REPLACE 1)
- else()
+ else ()
message(WARNING "Branch testing is disabled")
message(WARNING "Please use gcc or clang for branch coverage test.")
- endif()
+ endif ()
set(AppName GpgFrontendTest)
- endif()
-else()
+ elseif (${BUILD_CONFIG} STREQUAL "test_ui")
+ set(MINIMUM_APPLICATION_BUILD 1)
+ set(AppName GpgFrontend)
+ endif ()
+else ()
message(STATUS "Switch Default FULL_APPLICATION_BUILD")
set(FULL_APPLICATION_BUILD 1)
set(AppName GpgFrontend)
-endif()
+endif ()
-if(EXECUTABLE_OUTPUT_PATH)
+if (EXECUTABLE_OUTPUT_PATH)
message(STATUS "PreCheck EXECUTABLE_OUTPUT_PATH ${EXECUTABLE_OUTPUT_PATH}")
-else()
+else ()
set(EXECUTABLE_OUTPUT_PATH "./")
message(STATUS "Set EXECUTABLE_OUTPUT_PATH ${EXECUTABLE_OUTPUT_PATH}")
-endif()
+endif ()
# Output Env Variables
message(STATUS "Define EXECUTABLE_OUTPUT_PATH ${EXECUTABLE_OUTPUT_PATH}")
message(STATUS "Define CMAKE_BUILD_TYPE ${CMAKE_BUILD_TYPE}")
-if(${CMAKE_BUILD_TYPE} STREQUAL "Release")
+if (${CMAKE_BUILD_TYPE} STREQUAL "Release")
set(BUILD_FLAG 0)
message(STATUS "Build Type RELEASE")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -O2")
-else()
+else ()
set(BUILD_FLAG 1)
message(STATUS "Build Type DEBUG")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -g")
# Generate branch coverage information using gcc
- if(TEST_COVERAGE_BUILD)
- if(USING_COMPILER_GCC)
+ if (TEST_COVERAGE_BUILD)
+ if (USING_COMPILER_GCC)
message(STATUS "Set branch coverage test parameters for Gcc")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} --coverage")
- elseif(USING_COMPILER_CLANG)
+ elseif (USING_COMPILER_CLANG)
message(STATUS "Set branch coverage test parameters for Clang")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fprofile-instr-generate -fcoverage-mapping")
- endif()
- endif()
-endif()
+ endif ()
+ endif ()
+endif ()
message(STATUS "Build Flags " ${CMAKE_CXX_FLAGS})
@@ -104,7 +107,7 @@ message(STATUS "Build Flags " ${CMAKE_CXX_FLAGS})
set(GIT_COMMIT_HASH "")
set(GIT_BRANCH_NAME "")
find_package(Git QUIET)
-if(GIT_FOUND)
+if (GIT_FOUND)
execute_process(
COMMAND ${GIT_EXECUTABLE} log -1 --pretty=format:%H
OUTPUT_VARIABLE GIT_COMMIT_HASH
@@ -119,7 +122,7 @@ if(GIT_FOUND)
ERROR_QUIET
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
)
-endif()
+endif ()
set(BUILD_VERSION ${PROJECT_VERSION}_${CMAKE_SYSTEM}_${CMAKE_SYSTEM_PROCESSOR}_${CMAKE_BUILD_TYPE})
set(GIT_VERSION ${GIT_BRANCH_NAME}_${GIT_COMMIT_HASH})
@@ -131,25 +134,25 @@ message(STATUS "Git Version ${GIT_VERSION}")
IF (MINGW)
- message(STATUS "Configuration For OS Platform Microsoft Windows")
- message(STATUS "Build Environment MINGW")
+ message(STATUS "Configuration For OS Platform Microsoft Windows")
+ message(STATUS "Build Environment MINGW")
set(OS_PLATFORM 0)
set(CMAKE_EXE_LINKER_FLAGS "-static-libgcc -static-libstdc++ -static")
include_directories(
- ${CMAKE_CURRENT_SOURCE_DIR}/src
- ${CMAKE_CURRENT_SOURCE_DIR}/third_party
- /mingw64/include
+ ${CMAKE_CURRENT_SOURCE_DIR}/src
+ ${CMAKE_CURRENT_SOURCE_DIR}/third_party
+ /mingw64/include
)
- link_directories(
- /mingw64/lib
+ link_directories(
+ /mingw64/lib
)
-endif()
+endif ()
-if(APPLE)
+if (APPLE)
message(STATUS "Configuration For OS Platform MacOS")
@@ -158,38 +161,38 @@ if(APPLE)
set(ENV{Qt5_DIR} /usr/local/opt/qt5/lib/cmake)
include_directories(
- ${CMAKE_CURRENT_SOURCE_DIR}/src
- ${CMAKE_CURRENT_SOURCE_DIR}/third_party
- /usr/local/include
+ ${CMAKE_CURRENT_SOURCE_DIR}/src
+ ${CMAKE_CURRENT_SOURCE_DIR}/third_party
+ /usr/local/include
)
link_directories(
- /usr/local/lib
- /usr/local/opt/openssl/lib
+ /usr/local/lib
+ /usr/local/opt/openssl/lib
)
-endif()
+endif ()
-if(UNIX AND NOT APPLE)
+if (UNIX AND NOT APPLE)
set(LINUX TRUE)
-endif()
+endif ()
-if(LINUX)
+if (LINUX)
message(STATUS "Configuration For OS Platform LINUX")
set(OS_PLATFORM 2)
include_directories(
- ${CMAKE_CURRENT_SOURCE_DIR}/src
- ${CMAKE_CURRENT_SOURCE_DIR}/third_party
- /usr/include
- /usr/local/include
+ ${CMAKE_CURRENT_SOURCE_DIR}/src
+ ${CMAKE_CURRENT_SOURCE_DIR}/third_party
+ /usr/include
+ /usr/local/include
)
link_directories(${CMAKE_CURRENT_SOURCE_DIR}/lib/)
link_directories(
- /lib/
- /usr/lib/
- /usr/local/lib/
+ /lib/
+ /usr/lib/
+ /usr/local/lib/
)
-endif()
+endif ()
message(STATUS "OS_PLATFORM ${OS_PLATFORM}")
@@ -200,7 +203,7 @@ set(BASIC_ENV_CONFIG 1)
set(QT_MOC_CONFIG 1)
set(ESAY_LOGGING_PP 1)
-if(FULL_APPLICATION_BUILD)
+if (FULL_APPLICATION_BUILD)
message(STATUS "Build Full Application")
set(QT5_ENV_SUPPORT 1)
set(QT_MOC_CONFIG 1)
@@ -212,32 +215,39 @@ if(FULL_APPLICATION_BUILD)
set(APPLICATION_BUILD 1)
set(BASIC_ENV_CONFIG 1)
set(MULTI_LANG_SUPPORT 1)
-elseif(TEST_BUILD)
+elseif (MINIMUM_APPLICATION_BUILD)
+ set(QT5_ENV_SUPPORT 1)
+ set(QT_MOC_CONFIG 1)
+ set(GPG_CORE 1)
+ set(UI_CORE 1)
+ set(APPLICATION_BUILD 1)
+ set(BASIC_ENV_CONFIG 1)
+elseif (TEST_BUILD)
message(STATUS "Build Test Cases")
- if(MODULES)
- else()
+ if (MODULES)
+ else ()
message(STATUS "Build Default Modules")
set(GPG_CORE 1)
- endif()
+ endif ()
-endif()
+endif ()
-if(QT5_ENV_SUPPORT)
+if (QT5_ENV_SUPPORT)
# Find
find_package(Qt5 5.15.2 EXACT COMPONENTS Core Test Widgets PrintSupport Network LinguistTools REQUIRED)
# Qt
set(CMAKE_AUTOMOC ON)
set(CMAKE_AUTORCC ON)
set(CMAKE_AUTOUIC ON)
-endif()
+endif ()
add_subdirectory(third_party)
add_subdirectory(src)
-if(TEST_BUILD)
+if (TEST_BUILD)
include(CTest)
enable_testing()
add_subdirectory(test)
-endif()
+endif ()
diff --git a/include/rapidjson/document.h b/include/rapidjson/document.h
deleted file mode 100644
index e3e20dfb..00000000
--- a/include/rapidjson/document.h
+++ /dev/null
@@ -1,2575 +0,0 @@
-// Tencent is pleased to support the open source community by making RapidJSON available.
-//
-// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
-//
-// Licensed under the MIT License (the "License"); you may not use this file except
-// in compliance with the License. You may obtain a copy of the License at
-//
-// http://opensource.org/licenses/MIT
-//
-// Unless required by applicable law or agreed to in writing, software distributed
-// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
-// CONDITIONS OF ANY KIND, either express or implied. See the License for the
-// specific language governing permissions and limitations under the License.
-
-#ifndef RAPIDJSON_DOCUMENT_H_
-#define RAPIDJSON_DOCUMENT_H_
-
-/*! \file document.h */
-
-#include "reader.h"
-#include "internal/meta.h"
-#include "internal/strfunc.h"
-#include "memorystream.h"
-#include "encodedstream.h"
-#include <new> // placement new
-#include <limits>
-
-RAPIDJSON_DIAG_PUSH
-#ifdef _MSC_VER
-RAPIDJSON_DIAG_OFF(4127) // conditional expression is constant
-RAPIDJSON_DIAG_OFF(4244) // conversion from kXxxFlags to 'uint16_t', possible loss of data
-#endif
-
-#ifdef __clang__
-RAPIDJSON_DIAG_OFF(padded)
-RAPIDJSON_DIAG_OFF(switch-enum)
-RAPIDJSON_DIAG_OFF(c++98-compat)
-#endif
-
-#ifdef __GNUC__
-RAPIDJSON_DIAG_OFF(effc++)
-#if __GNUC__ >= 6
-RAPIDJSON_DIAG_OFF(terminate) // ignore throwing RAPIDJSON_ASSERT in RAPIDJSON_NOEXCEPT functions
-#endif
-#endif // __GNUC__
-
-#ifndef RAPIDJSON_NOMEMBERITERATORCLASS
-#include <iterator> // std::iterator, std::random_access_iterator_tag
-#endif
-
-#if RAPIDJSON_HAS_CXX11_RVALUE_REFS
-#include <utility> // std::move
-#endif
-
-RAPIDJSON_NAMESPACE_BEGIN
-
-// Forward declaration.
-template <typename Encoding, typename Allocator>
-class GenericValue;
-
-template <typename Encoding, typename Allocator, typename StackAllocator>
-class GenericDocument;
-
-//! Name-value pair in a JSON object value.
-/*!
- This class was internal to GenericValue. It used to be a inner struct.
- But a compiler (IBM XL C/C++ for AIX) have reported to have problem with that so it moved as a namespace scope struct.
- https://code.google.com/p/rapidjson/issues/detail?id=64
-*/
-template <typename Encoding, typename Allocator>
-struct GenericMember {
- GenericValue<Encoding, Allocator> name; //!< name of member (must be a string)
- GenericValue<Encoding, Allocator> value; //!< value of member.
-};
-
-///////////////////////////////////////////////////////////////////////////////
-// GenericMemberIterator
-
-#ifndef RAPIDJSON_NOMEMBERITERATORCLASS
-
-//! (Constant) member iterator for a JSON object value
-/*!
- \tparam Const Is this a constant iterator?
- \tparam Encoding Encoding of the value. (Even non-string values need to have the same encoding in a document)
- \tparam Allocator Allocator type for allocating memory of object, array and string.
-
- This class implements a Random Access Iterator for GenericMember elements
- of a GenericValue, see ISO/IEC 14882:2003(E) C++ standard, 24.1 [lib.iterator.requirements].
-
- \note This iterator implementation is mainly intended to avoid implicit
- conversions from iterator values to \c NULL,
- e.g. from GenericValue::FindMember.
-
- \note Define \c RAPIDJSON_NOMEMBERITERATORCLASS to fall back to a
- pointer-based implementation, if your platform doesn't provide
- the C++ <iterator> header.
-
- \see GenericMember, GenericValue::MemberIterator, GenericValue::ConstMemberIterator
- */
-template <bool Const, typename Encoding, typename Allocator>
-class GenericMemberIterator
- : public std::iterator<std::random_access_iterator_tag
- , typename internal::MaybeAddConst<Const,GenericMember<Encoding,Allocator> >::Type> {
-
- friend class GenericValue<Encoding,Allocator>;
- template <bool, typename, typename> friend class GenericMemberIterator;
-
- typedef GenericMember<Encoding,Allocator> PlainType;
- typedef typename internal::MaybeAddConst<Const,PlainType>::Type ValueType;
- typedef std::iterator<std::random_access_iterator_tag,ValueType> BaseType;
-
-public:
- //! Iterator type itself
- typedef GenericMemberIterator Iterator;
- //! Constant iterator type
- typedef GenericMemberIterator<true,Encoding,Allocator> ConstIterator;
- //! Non-constant iterator type
- typedef GenericMemberIterator<false,Encoding,Allocator> NonConstIterator;
-
- //! Pointer to (const) GenericMember
- typedef typename BaseType::pointer Pointer;
- //! Reference to (const) GenericMember
- typedef typename BaseType::reference Reference;
- //! Signed integer type (e.g. \c ptrdiff_t)
- typedef typename BaseType::difference_type DifferenceType;
-
- //! Default constructor (singular value)
- /*! Creates an iterator pointing to no element.
- \note All operations, except for comparisons, are undefined on such values.
- */
- GenericMemberIterator() : ptr_() {}
-
- //! Iterator conversions to more const
- /*!
- \param it (Non-const) iterator to copy from
-
- Allows the creation of an iterator from another GenericMemberIterator
- that is "less const". Especially, creating a non-constant iterator
- from a constant iterator are disabled:
- \li const -> non-const (not ok)
- \li const -> const (ok)
- \li non-const -> const (ok)
- \li non-const -> non-const (ok)
-
- \note If the \c Const template parameter is already \c false, this
- constructor effectively defines a regular copy-constructor.
- Otherwise, the copy constructor is implicitly defined.
- */
- GenericMemberIterator(const NonConstIterator & it) : ptr_(it.ptr_) {}
- Iterator& operator=(const NonConstIterator & it) { ptr_ = it.ptr_; return *this; }
-
- //! @name stepping
- //@{
- Iterator& operator++(){ ++ptr_; return *this; }
- Iterator& operator--(){ --ptr_; return *this; }
- Iterator operator++(int){ Iterator old(*this); ++ptr_; return old; }
- Iterator operator--(int){ Iterator old(*this); --ptr_; return old; }
- //@}
-
- //! @name increment/decrement
- //@{
- Iterator operator+(DifferenceType n) const { return Iterator(ptr_+n); }
- Iterator operator-(DifferenceType n) const { return Iterator(ptr_-n); }
-
- Iterator& operator+=(DifferenceType n) { ptr_+=n; return *this; }
- Iterator& operator-=(DifferenceType n) { ptr_-=n; return *this; }
- //@}
-
- //! @name relations
- //@{
- bool operator==(ConstIterator that) const { return ptr_ == that.ptr_; }
- bool operator!=(ConstIterator that) const { return ptr_ != that.ptr_; }
- bool operator<=(ConstIterator that) const { return ptr_ <= that.ptr_; }
- bool operator>=(ConstIterator that) const { return ptr_ >= that.ptr_; }
- bool operator< (ConstIterator that) const { return ptr_ < that.ptr_; }
- bool operator> (ConstIterator that) const { return ptr_ > that.ptr_; }
- //@}
-
- //! @name dereference
- //@{
- Reference operator*() const { return *ptr_; }
- Pointer operator->() const { return ptr_; }
- Reference operator[](DifferenceType n) const { return ptr_[n]; }
- //@}
-
- //! Distance
- DifferenceType operator-(ConstIterator that) const { return ptr_-that.ptr_; }
-
-private:
- //! Internal constructor from plain pointer
- explicit GenericMemberIterator(Pointer p) : ptr_(p) {}
-
- Pointer ptr_; //!< raw pointer
-};
-
-#else // RAPIDJSON_NOMEMBERITERATORCLASS
-
-// class-based member iterator implementation disabled, use plain pointers
-
-template <bool Const, typename Encoding, typename Allocator>
-struct GenericMemberIterator;
-
-//! non-const GenericMemberIterator
-template <typename Encoding, typename Allocator>
-struct GenericMemberIterator<false,Encoding,Allocator> {
- //! use plain pointer as iterator type
- typedef GenericMember<Encoding,Allocator>* Iterator;
-};
-//! const GenericMemberIterator
-template <typename Encoding, typename Allocator>
-struct GenericMemberIterator<true,Encoding,Allocator> {
- //! use plain const pointer as iterator type
- typedef const GenericMember<Encoding,Allocator>* Iterator;
-};
-
-#endif // RAPIDJSON_NOMEMBERITERATORCLASS
-
-///////////////////////////////////////////////////////////////////////////////
-// GenericStringRef
-
-//! Reference to a constant string (not taking a copy)
-/*!
- \tparam CharType character type of the string
-
- This helper class is used to automatically infer constant string
- references for string literals, especially from \c const \b (!)
- character arrays.
-
- The main use is for creating JSON string values without copying the
- source string via an \ref Allocator. This requires that the referenced
- string pointers have a sufficient lifetime, which exceeds the lifetime
- of the associated GenericValue.
-
- \b Example
- \code
- Value v("foo"); // ok, no need to copy & calculate length
- const char foo[] = "foo";
- v.SetString(foo); // ok
-
- const char* bar = foo;
- // Value x(bar); // not ok, can't rely on bar's lifetime
- Value x(StringRef(bar)); // lifetime explicitly guaranteed by user
- Value y(StringRef(bar, 3)); // ok, explicitly pass length
- \endcode
-
- \see StringRef, GenericValue::SetString
-*/
-template<typename CharType>
-struct GenericStringRef {
- typedef CharType Ch; //!< character type of the string
-
- //! Create string reference from \c const character array
-#ifndef __clang__ // -Wdocumentation
- /*!
- This constructor implicitly creates a constant string reference from
- a \c const character array. It has better performance than
- \ref StringRef(const CharType*) by inferring the string \ref length
- from the array length, and also supports strings containing null
- characters.
-
- \tparam N length of the string, automatically inferred
-
- \param str Constant character array, lifetime assumed to be longer
- than the use of the string in e.g. a GenericValue
-
- \post \ref s == str
-
- \note Constant complexity.
- \note There is a hidden, private overload to disallow references to
- non-const character arrays to be created via this constructor.
- By this, e.g. function-scope arrays used to be filled via
- \c snprintf are excluded from consideration.
- In such cases, the referenced string should be \b copied to the
- GenericValue instead.
- */
-#endif
- template<SizeType N>
- GenericStringRef(const CharType (&str)[N]) RAPIDJSON_NOEXCEPT
- : s(str), length(N-1) {}
-
- //! Explicitly create string reference from \c const character pointer
-#ifndef __clang__ // -Wdocumentation
- /*!
- This constructor can be used to \b explicitly create a reference to
- a constant string pointer.
-
- \see StringRef(const CharType*)
-
- \param str Constant character pointer, lifetime assumed to be longer
- than the use of the string in e.g. a GenericValue
-
- \post \ref s == str
-
- \note There is a hidden, private overload to disallow references to
- non-const character arrays to be created via this constructor.
- By this, e.g. function-scope arrays used to be filled via
- \c snprintf are excluded from consideration.
- In such cases, the referenced string should be \b copied to the
- GenericValue instead.
- */
-#endif
- explicit GenericStringRef(const CharType* str)
- : s(str), length(internal::StrLen(str)){ RAPIDJSON_ASSERT(s != 0); }
-
- //! Create constant string reference from pointer and length
-#ifndef __clang__ // -Wdocumentation
- /*! \param str constant string, lifetime assumed to be longer than the use of the string in e.g. a GenericValue
- \param len length of the string, excluding the trailing NULL terminator
-
- \post \ref s == str && \ref length == len
- \note Constant complexity.
- */
-#endif
- GenericStringRef(const CharType* str, SizeType len)
- : s(str), length(len) { RAPIDJSON_ASSERT(s != 0); }
-
- GenericStringRef(const GenericStringRef& rhs) : s(rhs.s), length(rhs.length) {}
-
- GenericStringRef& operator=(const GenericStringRef& rhs) { s = rhs.s; length = rhs.length; }
-
- //! implicit conversion to plain CharType pointer
- operator const Ch *() const { return s; }
-
- const Ch* const s; //!< plain CharType pointer
- const SizeType length; //!< length of the string (excluding the trailing NULL terminator)
-
-private:
- //! Disallow construction from non-const array
- template<SizeType N>
- GenericStringRef(CharType (&str)[N]) /* = delete */;
-};
-
-//! Mark a character pointer as constant string
-/*! Mark a plain character pointer as a "string literal". This function
- can be used to avoid copying a character string to be referenced as a
- value in a JSON GenericValue object, if the string's lifetime is known
- to be valid long enough.
- \tparam CharType Character type of the string
- \param str Constant string, lifetime assumed to be longer than the use of the string in e.g. a GenericValue
- \return GenericStringRef string reference object
- \relatesalso GenericStringRef
-
- \see GenericValue::GenericValue(StringRefType), GenericValue::operator=(StringRefType), GenericValue::SetString(StringRefType), GenericValue::PushBack(StringRefType, Allocator&), GenericValue::AddMember
-*/
-template<typename CharType>
-inline GenericStringRef<CharType> StringRef(const CharType* str) {
- return GenericStringRef<CharType>(str, internal::StrLen(str));
-}
-
-//! Mark a character pointer as constant string
-/*! Mark a plain character pointer as a "string literal". This function
- can be used to avoid copying a character string to be referenced as a
- value in a JSON GenericValue object, if the string's lifetime is known
- to be valid long enough.
-
- This version has better performance with supplied length, and also
- supports string containing null characters.
-
- \tparam CharType character type of the string
- \param str Constant string, lifetime assumed to be longer than the use of the string in e.g. a GenericValue
- \param length The length of source string.
- \return GenericStringRef string reference object
- \relatesalso GenericStringRef
-*/
-template<typename CharType>
-inline GenericStringRef<CharType> StringRef(const CharType* str, size_t length) {
- return GenericStringRef<CharType>(str, SizeType(length));
-}
-
-#if RAPIDJSON_HAS_STDSTRING
-//! Mark a string object as constant string
-/*! Mark a string object (e.g. \c std::string) as a "string literal".
- This function can be used to avoid copying a string to be referenced as a
- value in a JSON GenericValue object, if the string's lifetime is known
- to be valid long enough.
-
- \tparam CharType character type of the string
- \param str Constant string, lifetime assumed to be longer than the use of the string in e.g. a GenericValue
- \return GenericStringRef string reference object
- \relatesalso GenericStringRef
- \note Requires the definition of the preprocessor symbol \ref RAPIDJSON_HAS_STDSTRING.
-*/
-template<typename CharType>
-inline GenericStringRef<CharType> StringRef(const std::basic_string<CharType>& str) {
- return GenericStringRef<CharType>(str.data(), SizeType(str.size()));
-}
-#endif
-
-///////////////////////////////////////////////////////////////////////////////
-// GenericValue type traits
-namespace internal {
-
-template <typename T, typename Encoding = void, typename Allocator = void>
-struct IsGenericValueImpl : FalseType {};
-
-// select candidates according to nested encoding and allocator types
-template <typename T> struct IsGenericValueImpl<T, typename Void<typename T::EncodingType>::Type, typename Void<typename T::AllocatorType>::Type>
- : IsBaseOf<GenericValue<typename T::EncodingType, typename T::AllocatorType>, T>::Type {};
-
-// helper to match arbitrary GenericValue instantiations, including derived classes
-template <typename T> struct IsGenericValue : IsGenericValueImpl<T>::Type {};
-
-} // namespace internal
-
-///////////////////////////////////////////////////////////////////////////////
-// TypeHelper
-
-namespace internal {
-
-template <typename ValueType, typename T>
-struct TypeHelper {};
-
-template<typename ValueType>
-struct TypeHelper<ValueType, bool> {
- static bool Is(const ValueType& v) { return v.IsBool(); }
- static bool Get(const ValueType& v) { return v.GetBool(); }
- static ValueType& Set(ValueType& v, bool data) { return v.SetBool(data); }
- static ValueType& Set(ValueType& v, bool data, typename ValueType::AllocatorType&) { return v.SetBool(data); }
-};
-
-template<typename ValueType>
-struct TypeHelper<ValueType, int> {
- static bool Is(const ValueType& v) { return v.IsInt(); }
- static int Get(const ValueType& v) { return v.GetInt(); }
- static ValueType& Set(ValueType& v, int data) { return v.SetInt(data); }
- static ValueType& Set(ValueType& v, int data, typename ValueType::AllocatorType&) { return v.SetInt(data); }
-};
-
-template<typename ValueType>
-struct TypeHelper<ValueType, unsigned> {
- static bool Is(const ValueType& v) { return v.IsUint(); }
- static unsigned Get(const ValueType& v) { return v.GetUint(); }
- static ValueType& Set(ValueType& v, unsigned data) { return v.SetUint(data); }
- static ValueType& Set(ValueType& v, unsigned data, typename ValueType::AllocatorType&) { return v.SetUint(data); }
-};
-
-template<typename ValueType>
-struct TypeHelper<ValueType, int64_t> {
- static bool Is(const ValueType& v) { return v.IsInt64(); }
- static int64_t Get(const ValueType& v) { return v.GetInt64(); }
- static ValueType& Set(ValueType& v, int64_t data) { return v.SetInt64(data); }
- static ValueType& Set(ValueType& v, int64_t data, typename ValueType::AllocatorType&) { return v.SetInt64(data); }
-};
-
-template<typename ValueType>
-struct TypeHelper<ValueType, uint64_t> {
- static bool Is(const ValueType& v) { return v.IsUint64(); }
- static uint64_t Get(const ValueType& v) { return v.GetUint64(); }
- static ValueType& Set(ValueType& v, uint64_t data) { return v.SetUint64(data); }
- static ValueType& Set(ValueType& v, uint64_t data, typename ValueType::AllocatorType&) { return v.SetUint64(data); }
-};
-
-template<typename ValueType>
-struct TypeHelper<ValueType, double> {
- static bool Is(const ValueType& v) { return v.IsDouble(); }
- static double Get(const ValueType& v) { return v.GetDouble(); }
- static ValueType& Set(ValueType& v, double data) { return v.SetDouble(data); }
- static ValueType& Set(ValueType& v, double data, typename ValueType::AllocatorType&) { return v.SetDouble(data); }
-};
-
-template<typename ValueType>
-struct TypeHelper<ValueType, float> {
- static bool Is(const ValueType& v) { return v.IsFloat(); }
- static float Get(const ValueType& v) { return v.GetFloat(); }
- static ValueType& Set(ValueType& v, float data) { return v.SetFloat(data); }
- static ValueType& Set(ValueType& v, float data, typename ValueType::AllocatorType&) { return v.SetFloat(data); }
-};
-
-template<typename ValueType>
-struct TypeHelper<ValueType, const typename ValueType::Ch*> {
- typedef const typename ValueType::Ch* StringType;
- static bool Is(const ValueType& v) { return v.IsString(); }
- static StringType Get(const ValueType& v) { return v.GetString(); }
- static ValueType& Set(ValueType& v, const StringType data) { return v.SetString(typename ValueType::StringRefType(data)); }
- static ValueType& Set(ValueType& v, const StringType data, typename ValueType::AllocatorType& a) { return v.SetString(data, a); }
-};
-
-#if RAPIDJSON_HAS_STDSTRING
-template<typename ValueType>
-struct TypeHelper<ValueType, std::basic_string<typename ValueType::Ch> > {
- typedef std::basic_string<typename ValueType::Ch> StringType;
- static bool Is(const ValueType& v) { return v.IsString(); }
- static StringType Get(const ValueType& v) { return StringType(v.GetString(), v.GetStringLength()); }
- static ValueType& Set(ValueType& v, const StringType& data, typename ValueType::AllocatorType& a) { return v.SetString(data, a); }
-};
-#endif
-
-template<typename ValueType>
-struct TypeHelper<ValueType, typename ValueType::Array> {
- typedef typename ValueType::Array ArrayType;
- static bool Is(const ValueType& v) { return v.IsArray(); }
- static ArrayType Get(ValueType& v) { return v.GetArray(); }
- static ValueType& Set(ValueType& v, ArrayType data) { return v = data; }
- static ValueType& Set(ValueType& v, ArrayType data, typename ValueType::AllocatorType&) { return v = data; }
-};
-
-template<typename ValueType>
-struct TypeHelper<ValueType, typename ValueType::ConstArray> {
- typedef typename ValueType::ConstArray ArrayType;
- static bool Is(const ValueType& v) { return v.IsArray(); }
- static ArrayType Get(const ValueType& v) { return v.GetArray(); }
-};
-
-template<typename ValueType>
-struct TypeHelper<ValueType, typename ValueType::Object> {
- typedef typename ValueType::Object ObjectType;
- static bool Is(const ValueType& v) { return v.IsObject(); }
- static ObjectType Get(ValueType& v) { return v.GetObject(); }
- static ValueType& Set(ValueType& v, ObjectType data) { return v = data; }
- static ValueType& Set(ValueType& v, ObjectType data, typename ValueType::AllocatorType&) { v = data; }
-};
-
-template<typename ValueType>
-struct TypeHelper<ValueType, typename ValueType::ConstObject> {
- typedef typename ValueType::ConstObject ObjectType;
- static bool Is(const ValueType& v) { return v.IsObject(); }
- static ObjectType Get(const ValueType& v) { return v.GetObject(); }
-};
-
-} // namespace internal
-
-// Forward declarations
-template <bool, typename> class GenericArray;
-template <bool, typename> class GenericObject;
-
-///////////////////////////////////////////////////////////////////////////////
-// GenericValue
-
-//! Represents a JSON value. Use Value for UTF8 encoding and default allocator.
-/*!
- A JSON value can be one of 7 types. This class is a variant type supporting
- these types.
-
- Use the Value if UTF8 and default allocator
-
- \tparam Encoding Encoding of the value. (Even non-string values need to have the same encoding in a document)
- \tparam Allocator Allocator type for allocating memory of object, array and string.
-*/
-template <typename Encoding, typename Allocator = MemoryPoolAllocator<> >
-class GenericValue {
-public:
- //! Name-value pair in an object.
- typedef GenericMember<Encoding, Allocator> Member;
- typedef Encoding EncodingType; //!< Encoding type from template parameter.
- typedef Allocator AllocatorType; //!< Allocator type from template parameter.
- typedef typename Encoding::Ch Ch; //!< Character type derived from Encoding.
- typedef GenericStringRef<Ch> StringRefType; //!< Reference to a constant string
- typedef typename GenericMemberIterator<false,Encoding,Allocator>::Iterator MemberIterator; //!< Member iterator for iterating in object.
- typedef typename GenericMemberIterator<true,Encoding,Allocator>::Iterator ConstMemberIterator; //!< Constant member iterator for iterating in object.
- typedef GenericValue* ValueIterator; //!< Value iterator for iterating in array.
- typedef const GenericValue* ConstValueIterator; //!< Constant value iterator for iterating in array.
- typedef GenericValue<Encoding, Allocator> ValueType; //!< Value type of itself.
- typedef GenericArray<false, ValueType> Array;
- typedef GenericArray<true, ValueType> ConstArray;
- typedef GenericObject<false, ValueType> Object;
- typedef GenericObject<true, ValueType> ConstObject;
-
- //!@name Constructors and destructor.
- //@{
-
- //! Default constructor creates a null value.
- GenericValue() RAPIDJSON_NOEXCEPT : data_() { data_.f.flags = kNullFlag; }
-
-#if RAPIDJSON_HAS_CXX11_RVALUE_REFS
- //! Move constructor in C++11
- GenericValue(GenericValue&& rhs) RAPIDJSON_NOEXCEPT : data_(rhs.data_) {
- rhs.data_.f.flags = kNullFlag; // give up contents
- }
-#endif
-
-private:
- //! Copy constructor is not permitted.
- GenericValue(const GenericValue& rhs);
-
-#if RAPIDJSON_HAS_CXX11_RVALUE_REFS
- //! Moving from a GenericDocument is not permitted.
- template <typename StackAllocator>
- GenericValue(GenericDocument<Encoding,Allocator,StackAllocator>&& rhs);
-
- //! Move assignment from a GenericDocument is not permitted.
- template <typename StackAllocator>
- GenericValue& operator=(GenericDocument<Encoding,Allocator,StackAllocator>&& rhs);
-#endif
-
-public:
-
- //! Constructor with JSON value type.
- /*! This creates a Value of specified type with default content.
- \param type Type of the value.
- \note Default content for number is zero.
- */
- explicit GenericValue(Type type) RAPIDJSON_NOEXCEPT : data_() {
- static const uint16_t defaultFlags[7] = {
- kNullFlag, kFalseFlag, kTrueFlag, kObjectFlag, kArrayFlag, kShortStringFlag,
- kNumberAnyFlag
- };
- RAPIDJSON_ASSERT(type <= kNumberType);
- data_.f.flags = defaultFlags[type];
-
- // Use ShortString to store empty string.
- if (type == kStringType)
- data_.ss.SetLength(0);
- }
-
- //! Explicit copy constructor (with allocator)
- /*! Creates a copy of a Value by using the given Allocator
- \tparam SourceAllocator allocator of \c rhs
- \param rhs Value to copy from (read-only)
- \param allocator Allocator for allocating copied elements and buffers. Commonly use GenericDocument::GetAllocator().
- \see CopyFrom()
- */
- template< typename SourceAllocator >
- GenericValue(const GenericValue<Encoding, SourceAllocator>& rhs, Allocator & allocator);
-
- //! Constructor for boolean value.
- /*! \param b Boolean value
- \note This constructor is limited to \em real boolean values and rejects
- implicitly converted types like arbitrary pointers. Use an explicit cast
- to \c bool, if you want to construct a boolean JSON value in such cases.
- */
-#ifndef RAPIDJSON_DOXYGEN_RUNNING // hide SFINAE from Doxygen
- template <typename T>
- explicit GenericValue(T b, RAPIDJSON_ENABLEIF((internal::IsSame<bool, T>))) RAPIDJSON_NOEXCEPT // See #472
-#else
- explicit GenericValue(bool b) RAPIDJSON_NOEXCEPT
-#endif
- : data_() {
- // safe-guard against failing SFINAE
- RAPIDJSON_STATIC_ASSERT((internal::IsSame<bool,T>::Value));
- data_.f.flags = b ? kTrueFlag : kFalseFlag;
- }
-
- //! Constructor for int value.
- explicit GenericValue(int i) RAPIDJSON_NOEXCEPT : data_() {
- data_.n.i64 = i;
- data_.f.flags = (i >= 0) ? (kNumberIntFlag | kUintFlag | kUint64Flag) : kNumberIntFlag;
- }
-
- //! Constructor for unsigned value.
- explicit GenericValue(unsigned u) RAPIDJSON_NOEXCEPT : data_() {
- data_.n.u64 = u;
- data_.f.flags = (u & 0x80000000) ? kNumberUintFlag : (kNumberUintFlag | kIntFlag | kInt64Flag);
- }
-
- //! Constructor for int64_t value.
- explicit GenericValue(int64_t i64) RAPIDJSON_NOEXCEPT : data_() {
- data_.n.i64 = i64;
- data_.f.flags = kNumberInt64Flag;
- if (i64 >= 0) {
- data_.f.flags |= kNumberUint64Flag;
- if (!(static_cast<uint64_t>(i64) & RAPIDJSON_UINT64_C2(0xFFFFFFFF, 0x00000000)))
- data_.f.flags |= kUintFlag;
- if (!(static_cast<uint64_t>(i64) & RAPIDJSON_UINT64_C2(0xFFFFFFFF, 0x80000000)))
- data_.f.flags |= kIntFlag;
- }
- else if (i64 >= static_cast<int64_t>(RAPIDJSON_UINT64_C2(0xFFFFFFFF, 0x80000000)))
- data_.f.flags |= kIntFlag;
- }
-
- //! Constructor for uint64_t value.
- explicit GenericValue(uint64_t u64) RAPIDJSON_NOEXCEPT : data_() {
- data_.n.u64 = u64;
- data_.f.flags = kNumberUint64Flag;
- if (!(u64 & RAPIDJSON_UINT64_C2(0x80000000, 0x00000000)))
- data_.f.flags |= kInt64Flag;
- if (!(u64 & RAPIDJSON_UINT64_C2(0xFFFFFFFF, 0x00000000)))
- data_.f.flags |= kUintFlag;
- if (!(u64 & RAPIDJSON_UINT64_C2(0xFFFFFFFF, 0x80000000)))
- data_.f.flags |= kIntFlag;
- }
-
- //! Constructor for double value.
- explicit GenericValue(double d) RAPIDJSON_NOEXCEPT : data_() { data_.n.d = d; data_.f.flags = kNumberDoubleFlag; }
-
- //! Constructor for constant string (i.e. do not make a copy of string)
- GenericValue(const Ch* s, SizeType length) RAPIDJSON_NOEXCEPT : data_() { SetStringRaw(StringRef(s, length)); }
-
- //! Constructor for constant string (i.e. do not make a copy of string)
- explicit GenericValue(StringRefType s) RAPIDJSON_NOEXCEPT : data_() { SetStringRaw(s); }
-
- //! Constructor for copy-string (i.e. do make a copy of string)
- GenericValue(const Ch* s, SizeType length, Allocator& allocator) : data_() { SetStringRaw(StringRef(s, length), allocator); }
-
- //! Constructor for copy-string (i.e. do make a copy of string)
- GenericValue(const Ch*s, Allocator& allocator) : data_() { SetStringRaw(StringRef(s), allocator); }
-
-#if RAPIDJSON_HAS_STDSTRING
- //! Constructor for copy-string from a string object (i.e. do make a copy of string)
- /*! \note Requires the definition of the preprocessor symbol \ref RAPIDJSON_HAS_STDSTRING.
- */
- GenericValue(const std::basic_string<Ch>& s, Allocator& allocator) : data_() { SetStringRaw(StringRef(s), allocator); }
-#endif
-
- //! Constructor for Array.
- /*!
- \param a An array obtained by \c GetArray().
- \note \c Array is always pass-by-value.
- \note the source array is moved into this value and the sourec array becomes empty.
- */
- GenericValue(Array a) RAPIDJSON_NOEXCEPT : data_(a.value_.data_) {
- a.value_.data_ = Data();
- a.value_.data_.f.flags = kArrayFlag;
- }
-
- //! Constructor for Object.
- /*!
- \param o An object obtained by \c GetObject().
- \note \c Object is always pass-by-value.
- \note the source object is moved into this value and the sourec object becomes empty.
- */
- GenericValue(Object o) RAPIDJSON_NOEXCEPT : data_(o.value_.data_) {
- o.value_.data_ = Data();
- o.value_.data_.f.flags = kObjectFlag;
- }
-
- //! Destructor.
- /*! Need to destruct elements of array, members of object, or copy-string.
- */
- ~GenericValue() {
- if (Allocator::kNeedFree) { // Shortcut by Allocator's trait
- switch(data_.f.flags) {
- case kArrayFlag:
- {
- GenericValue* e = GetElementsPointer();
- for (GenericValue* v = e; v != e + data_.a.size; ++v)
- v->~GenericValue();
- Allocator::Free(e);
- }
- break;
-
- case kObjectFlag:
- for (MemberIterator m = MemberBegin(); m != MemberEnd(); ++m)
- m->~Member();
- Allocator::Free(GetMembersPointer());
- break;
-
- case kCopyStringFlag:
- Allocator::Free(const_cast<Ch*>(GetStringPointer()));
- break;
-
- default:
- break; // Do nothing for other types.
- }
- }
- }
-
- //@}
-
- //!@name Assignment operators
- //@{
-
- //! Assignment with move semantics.
- /*! \param rhs Source of the assignment. It will become a null value after assignment.
- */
- GenericValue& operator=(GenericValue& rhs) RAPIDJSON_NOEXCEPT {
- RAPIDJSON_ASSERT(this != &rhs);
- this->~GenericValue();
- RawAssign(rhs);
- return *this;
- }
-
-#if RAPIDJSON_HAS_CXX11_RVALUE_REFS
- //! Move assignment in C++11
- GenericValue& operator=(GenericValue&& rhs) RAPIDJSON_NOEXCEPT {
- return *this = rhs.Move();
- }
-#endif
-
- //! Assignment of constant string reference (no copy)
- /*! \param str Constant string reference to be assigned
- \note This overload is needed to avoid clashes with the generic primitive type assignment overload below.
- \see GenericStringRef, operator=(T)
- */
- GenericValue& operator=(StringRefType str) RAPIDJSON_NOEXCEPT {
- GenericValue s(str);
- return *this = s;
- }
-
- //! Assignment with primitive types.
- /*! \tparam T Either \ref Type, \c int, \c unsigned, \c int64_t, \c uint64_t
- \param value The value to be assigned.
-
- \note The source type \c T explicitly disallows all pointer types,
- especially (\c const) \ref Ch*. This helps avoiding implicitly
- referencing character strings with insufficient lifetime, use
- \ref SetString(const Ch*, Allocator&) (for copying) or
- \ref StringRef() (to explicitly mark the pointer as constant) instead.
- All other pointer types would implicitly convert to \c bool,
- use \ref SetBool() instead.
- */
- template <typename T>
- RAPIDJSON_DISABLEIF_RETURN((internal::IsPointer<T>), (GenericValue&))
- operator=(T value) {
- GenericValue v(value);
- return *this = v;
- }
-
- //! Deep-copy assignment from Value
- /*! Assigns a \b copy of the Value to the current Value object
- \tparam SourceAllocator Allocator type of \c rhs
- \param rhs Value to copy from (read-only)
- \param allocator Allocator to use for copying
- */
- template <typename SourceAllocator>
- GenericValue& CopyFrom(const GenericValue<Encoding, SourceAllocator>& rhs, Allocator& allocator) {
- RAPIDJSON_ASSERT(static_cast<void*>(this) != static_cast<void const*>(&rhs));
- this->~GenericValue();
- new (this) GenericValue(rhs, allocator);
- return *this;
- }
-
- //! Exchange the contents of this value with those of other.
- /*!
- \param other Another value.
- \note Constant complexity.
- */
- GenericValue& Swap(GenericValue& other) RAPIDJSON_NOEXCEPT {
- GenericValue temp;
- temp.RawAssign(*this);
- RawAssign(other);
- other.RawAssign(temp);
- return *this;
- }
-
- //! free-standing swap function helper
- /*!
- Helper function to enable support for common swap implementation pattern based on \c std::swap:
- \code
- void swap(MyClass& a, MyClass& b) {
- using std::swap;
- swap(a.value, b.value);
- // ...
- }
- \endcode
- \see Swap()
- */
- friend inline void swap(GenericValue& a, GenericValue& b) RAPIDJSON_NOEXCEPT { a.Swap(b); }
-
- //! Prepare Value for move semantics
- /*! \return *this */
- GenericValue& Move() RAPIDJSON_NOEXCEPT { return *this; }
- //@}
-
- //!@name Equal-to and not-equal-to operators
- //@{
- //! Equal-to operator
- /*!
- \note If an object contains duplicated named member, comparing equality with any object is always \c false.
- \note Linear time complexity (number of all values in the subtree and total lengths of all strings).
- */
- template <typename SourceAllocator>
- bool operator==(const GenericValue<Encoding, SourceAllocator>& rhs) const {
- typedef GenericValue<Encoding, SourceAllocator> RhsType;
- if (GetType() != rhs.GetType())
- return false;
-
- switch (GetType()) {
- case kObjectType: // Warning: O(n^2) inner-loop
- if (data_.o.size != rhs.data_.o.size)
- return false;
- for (ConstMemberIterator lhsMemberItr = MemberBegin(); lhsMemberItr != MemberEnd(); ++lhsMemberItr) {
- typename RhsType::ConstMemberIterator rhsMemberItr = rhs.FindMember(lhsMemberItr->name);
- if (rhsMemberItr == rhs.MemberEnd() || lhsMemberItr->value != rhsMemberItr->value)
- return false;
- }
- return true;
-
- case kArrayType:
- if (data_.a.size != rhs.data_.a.size)
- return false;
- for (SizeType i = 0; i < data_.a.size; i++)
- if ((*this)[i] != rhs[i])
- return false;
- return true;
-
- case kStringType:
- return StringEqual(rhs);
-
- case kNumberType:
- if (IsDouble() || rhs.IsDouble()) {
- double a = GetDouble(); // May convert from integer to double.
- double b = rhs.GetDouble(); // Ditto
- return a >= b && a <= b; // Prevent -Wfloat-equal
- }
- else
- return data_.n.u64 == rhs.data_.n.u64;
-
- default:
- return true;
- }
- }
-
- //! Equal-to operator with const C-string pointer
- bool operator==(const Ch* rhs) const { return *this == GenericValue(StringRef(rhs)); }
-
-#if RAPIDJSON_HAS_STDSTRING
- //! Equal-to operator with string object
- /*! \note Requires the definition of the preprocessor symbol \ref RAPIDJSON_HAS_STDSTRING.
- */
- bool operator==(const std::basic_string<Ch>& rhs) const { return *this == GenericValue(StringRef(rhs)); }
-#endif
-
- //! Equal-to operator with primitive types
- /*! \tparam T Either \ref Type, \c int, \c unsigned, \c int64_t, \c uint64_t, \c double, \c true, \c false
- */
- template <typename T> RAPIDJSON_DISABLEIF_RETURN((internal::OrExpr<internal::IsPointer<T>,internal::IsGenericValue<T> >), (bool)) operator==(const T& rhs) const { return *this == GenericValue(rhs); }
-
- //! Not-equal-to operator
- /*! \return !(*this == rhs)
- */
- template <typename SourceAllocator>
- bool operator!=(const GenericValue<Encoding, SourceAllocator>& rhs) const { return !(*this == rhs); }
-
- //! Not-equal-to operator with const C-string pointer
- bool operator!=(const Ch* rhs) const { return !(*this == rhs); }
-
- //! Not-equal-to operator with arbitrary types
- /*! \return !(*this == rhs)
- */
- template <typename T> RAPIDJSON_DISABLEIF_RETURN((internal::IsGenericValue<T>), (bool)) operator!=(const T& rhs) const { return !(*this == rhs); }
-
- //! Equal-to operator with arbitrary types (symmetric version)
- /*! \return (rhs == lhs)
- */
- template <typename T> friend RAPIDJSON_DISABLEIF_RETURN((internal::IsGenericValue<T>), (bool)) operator==(const T& lhs, const GenericValue& rhs) { return rhs == lhs; }
-
- //! Not-Equal-to operator with arbitrary types (symmetric version)
- /*! \return !(rhs == lhs)
- */
- template <typename T> friend RAPIDJSON_DISABLEIF_RETURN((internal::IsGenericValue<T>), (bool)) operator!=(const T& lhs, const GenericValue& rhs) { return !(rhs == lhs); }
- //@}
-
- //!@name Type
- //@{
-
- Type GetType() const { return static_cast<Type>(data_.f.flags & kTypeMask); }
- bool IsNull() const { return data_.f.flags == kNullFlag; }
- bool IsFalse() const { return data_.f.flags == kFalseFlag; }
- bool IsTrue() const { return data_.f.flags == kTrueFlag; }
- bool IsBool() const { return (data_.f.flags & kBoolFlag) != 0; }
- bool IsObject() const { return data_.f.flags == kObjectFlag; }
- bool IsArray() const { return data_.f.flags == kArrayFlag; }
- bool IsNumber() const { return (data_.f.flags & kNumberFlag) != 0; }
- bool IsInt() const { return (data_.f.flags & kIntFlag) != 0; }
- bool IsUint() const { return (data_.f.flags & kUintFlag) != 0; }
- bool IsInt64() const { return (data_.f.flags & kInt64Flag) != 0; }
- bool IsUint64() const { return (data_.f.flags & kUint64Flag) != 0; }
- bool IsDouble() const { return (data_.f.flags & kDoubleFlag) != 0; }
- bool IsString() const { return (data_.f.flags & kStringFlag) != 0; }
-
- // Checks whether a number can be losslessly converted to a double.
- bool IsLosslessDouble() const {
- if (!IsNumber()) return false;
- if (IsUint64()) {
- uint64_t u = GetUint64();
- volatile double d = static_cast<double>(u);
- return (d >= 0.0)
- && (d < static_cast<double>(std::numeric_limits<uint64_t>::max()))
- && (u == static_cast<uint64_t>(d));
- }
- if (IsInt64()) {
- int64_t i = GetInt64();
- volatile double d = static_cast<double>(i);
- return (d >= static_cast<double>(std::numeric_limits<int64_t>::min()))
- && (d < static_cast<double>(std::numeric_limits<int64_t>::max()))
- && (i == static_cast<int64_t>(d));
- }
- return true; // double, int, uint are always lossless
- }
-
- // Checks whether a number is a float (possible lossy).
- bool IsFloat() const {
- if ((data_.f.flags & kDoubleFlag) == 0)
- return false;
- double d = GetDouble();
- return d >= -3.4028234e38 && d <= 3.4028234e38;
- }
- // Checks whether a number can be losslessly converted to a float.
- bool IsLosslessFloat() const {
- if (!IsNumber()) return false;
- double a = GetDouble();
- if (a < static_cast<double>(-std::numeric_limits<float>::max())
- || a > static_cast<double>(std::numeric_limits<float>::max()))
- return false;
- double b = static_cast<double>(static_cast<float>(a));
- return a >= b && a <= b; // Prevent -Wfloat-equal
- }
-
- //@}
-
- //!@name Null
- //@{
-
- GenericValue& SetNull() { this->~GenericValue(); new (this) GenericValue(); return *this; }
-
- //@}
-
- //!@name Bool
- //@{
-
- bool GetBool() const { RAPIDJSON_ASSERT(IsBool()); return data_.f.flags == kTrueFlag; }
- //!< Set boolean value
- /*! \post IsBool() == true */
- GenericValue& SetBool(bool b) { this->~GenericValue(); new (this) GenericValue(b); return *this; }
-
- //@}
-
- //!@name Object
- //@{
-
- //! Set this value as an empty object.
- /*! \post IsObject() == true */
- GenericValue& SetObject() { this->~GenericValue(); new (this) GenericValue(kObjectType); return *this; }
-
- //! Get the number of members in the object.
- SizeType MemberCount() const { RAPIDJSON_ASSERT(IsObject()); return data_.o.size; }
-
- //! Check whether the object is empty.
- bool ObjectEmpty() const { RAPIDJSON_ASSERT(IsObject()); return data_.o.size == 0; }
-
- //! Get a value from an object associated with the name.
- /*! \pre IsObject() == true
- \tparam T Either \c Ch or \c const \c Ch (template used for disambiguation with \ref operator[](SizeType))
- \note In version 0.1x, if the member is not found, this function returns a null value. This makes issue 7.
- Since 0.2, if the name is not correct, it will assert.
- If user is unsure whether a member exists, user should use HasMember() first.
- A better approach is to use FindMember().
- \note Linear time complexity.
- */
- template <typename T>
- RAPIDJSON_DISABLEIF_RETURN((internal::NotExpr<internal::IsSame<typename internal::RemoveConst<T>::Type, Ch> >),(GenericValue&)) operator[](T* name) {
- GenericValue n(StringRef(name));
- return (*this)[n];
- }
- template <typename T>
- RAPIDJSON_DISABLEIF_RETURN((internal::NotExpr<internal::IsSame<typename internal::RemoveConst<T>::Type, Ch> >),(const GenericValue&)) operator[](T* name) const { return const_cast<GenericValue&>(*this)[name]; }
-
- //! Get a value from an object associated with the name.
- /*! \pre IsObject() == true
- \tparam SourceAllocator Allocator of the \c name value
-
- \note Compared to \ref operator[](T*), this version is faster because it does not need a StrLen().
- And it can also handle strings with embedded null characters.
-
- \note Linear time complexity.
- */
- template <typename SourceAllocator>
- GenericValue& operator[](const GenericValue<Encoding, SourceAllocator>& name) {
- MemberIterator member = FindMember(name);
- if (member != MemberEnd())
- return member->value;
- else {
- RAPIDJSON_ASSERT(false); // see above note
-
- // This will generate -Wexit-time-destructors in clang
- // static GenericValue NullValue;
- // return NullValue;
-
- // Use static buffer and placement-new to prevent destruction
- static char buffer[sizeof(GenericValue)];
- return *new (buffer) GenericValue();
- }
- }
- template <typename SourceAllocator>
- const GenericValue& operator[](const GenericValue<Encoding, SourceAllocator>& name) const { return const_cast<GenericValue&>(*this)[name]; }
-
-#if RAPIDJSON_HAS_STDSTRING
- //! Get a value from an object associated with name (string object).
- GenericValue& operator[](const std::basic_string<Ch>& name) { return (*this)[GenericValue(StringRef(name))]; }
- const GenericValue& operator[](const std::basic_string<Ch>& name) const { return (*this)[GenericValue(StringRef(name))]; }
-#endif
-
- //! Const member iterator
- /*! \pre IsObject() == true */
- ConstMemberIterator MemberBegin() const { RAPIDJSON_ASSERT(IsObject()); return ConstMemberIterator(GetMembersPointer()); }
- //! Const \em past-the-end member iterator
- /*! \pre IsObject() == true */
- ConstMemberIterator MemberEnd() const { RAPIDJSON_ASSERT(IsObject()); return ConstMemberIterator(GetMembersPointer() + data_.o.size); }
- //! Member iterator
- /*! \pre IsObject() == true */
- MemberIterator MemberBegin() { RAPIDJSON_ASSERT(IsObject()); return MemberIterator(GetMembersPointer()); }
- //! \em Past-the-end member iterator
- /*! \pre IsObject() == true */
- MemberIterator MemberEnd() { RAPIDJSON_ASSERT(IsObject()); return MemberIterator(GetMembersPointer() + data_.o.size); }
-
- //! Check whether a member exists in the object.
- /*!
- \param name Member name to be searched.
- \pre IsObject() == true
- \return Whether a member with that name exists.
- \note It is better to use FindMember() directly if you need the obtain the value as well.
- \note Linear time complexity.
- */
- bool HasMember(const Ch* name) const { return FindMember(name) != MemberEnd(); }
-
-#if RAPIDJSON_HAS_STDSTRING
- //! Check whether a member exists in the object with string object.
- /*!
- \param name Member name to be searched.
- \pre IsObject() == true
- \return Whether a member with that name exists.
- \note It is better to use FindMember() directly if you need the obtain the value as well.
- \note Linear time complexity.
- */
- bool HasMember(const std::basic_string<Ch>& name) const { return FindMember(name) != MemberEnd(); }
-#endif
-
- //! Check whether a member exists in the object with GenericValue name.
- /*!
- This version is faster because it does not need a StrLen(). It can also handle string with null character.
- \param name Member name to be searched.
- \pre IsObject() == true
- \return Whether a member with that name exists.
- \note It is better to use FindMember() directly if you need the obtain the value as well.
- \note Linear time complexity.
- */
- template <typename SourceAllocator>
- bool HasMember(const GenericValue<Encoding, SourceAllocator>& name) const { return FindMember(name) != MemberEnd(); }
-
- //! Find member by name.
- /*!
- \param name Member name to be searched.
- \pre IsObject() == true
- \return Iterator to member, if it exists.
- Otherwise returns \ref MemberEnd().
-
- \note Earlier versions of Rapidjson returned a \c NULL pointer, in case
- the requested member doesn't exist. For consistency with e.g.
- \c std::map, this has been changed to MemberEnd() now.
- \note Linear time complexity.
- */
- MemberIterator FindMember(const Ch* name) {
- GenericValue n(StringRef(name));
- return FindMember(n);
- }
-
- ConstMemberIterator FindMember(const Ch* name) const { return const_cast<GenericValue&>(*this).FindMember(name); }
-
- //! Find member by name.
- /*!
- This version is faster because it does not need a StrLen(). It can also handle string with null character.
- \param name Member name to be searched.
- \pre IsObject() == true
- \return Iterator to member, if it exists.
- Otherwise returns \ref MemberEnd().
-
- \note Earlier versions of Rapidjson returned a \c NULL pointer, in case
- the requested member doesn't exist. For consistency with e.g.
- \c std::map, this has been changed to MemberEnd() now.
- \note Linear time complexity.
- */
- template <typename SourceAllocator>
- MemberIterator FindMember(const GenericValue<Encoding, SourceAllocator>& name) {
- RAPIDJSON_ASSERT(IsObject());
- RAPIDJSON_ASSERT(name.IsString());
- MemberIterator member = MemberBegin();
- for ( ; member != MemberEnd(); ++member)
- if (name.StringEqual(member->name))
- break;
- return member;
- }
- template <typename SourceAllocator> ConstMemberIterator FindMember(const GenericValue<Encoding, SourceAllocator>& name) const { return const_cast<GenericValue&>(*this).FindMember(name); }
-
-#if RAPIDJSON_HAS_STDSTRING
- //! Find member by string object name.
- /*!
- \param name Member name to be searched.
- \pre IsObject() == true
- \return Iterator to member, if it exists.
- Otherwise returns \ref MemberEnd().
- */
- MemberIterator FindMember(const std::basic_string<Ch>& name) { return FindMember(GenericValue(StringRef(name))); }
- ConstMemberIterator FindMember(const std::basic_string<Ch>& name) const { return FindMember(GenericValue(StringRef(name))); }
-#endif
-
- //! Add a member (name-value pair) to the object.
- /*! \param name A string value as name of member.
- \param value Value of any type.
- \param allocator Allocator for reallocating memory. It must be the same one as used before. Commonly use GenericDocument::GetAllocator().
- \return The value itself for fluent API.
- \note The ownership of \c name and \c value will be transferred to this object on success.
- \pre IsObject() && name.IsString()
- \post name.IsNull() && value.IsNull()
- \note Amortized Constant time complexity.
- */
- GenericValue& AddMember(GenericValue& name, GenericValue& value, Allocator& allocator) {
- RAPIDJSON_ASSERT(IsObject());
- RAPIDJSON_ASSERT(name.IsString());
-
- ObjectData& o = data_.o;
- if (o.size >= o.capacity) {
- if (o.capacity == 0) {
- o.capacity = kDefaultObjectCapacity;
- SetMembersPointer(reinterpret_cast<Member*>(allocator.Malloc(o.capacity * sizeof(Member))));
- }
- else {
- SizeType oldCapacity = o.capacity;
- o.capacity += (oldCapacity + 1) / 2; // grow by factor 1.5
- SetMembersPointer(reinterpret_cast<Member*>(allocator.Realloc(GetMembersPointer(), oldCapacity * sizeof(Member), o.capacity * sizeof(Member))));
- }
- }
- Member* members = GetMembersPointer();
- members[o.size].name.RawAssign(name);
- members[o.size].value.RawAssign(value);
- o.size++;
- return *this;
- }
-
- //! Add a constant string value as member (name-value pair) to the object.
- /*! \param name A string value as name of member.
- \param value constant string reference as value of member.
- \param allocator Allocator for reallocating memory. It must be the same one as used before. Commonly use GenericDocument::GetAllocator().
- \return The value itself for fluent API.
- \pre IsObject()
- \note This overload is needed to avoid clashes with the generic primitive type AddMember(GenericValue&,T,Allocator&) overload below.
- \note Amortized Constant time complexity.
- */
- GenericValue& AddMember(GenericValue& name, StringRefType value, Allocator& allocator) {
- GenericValue v(value);
- return AddMember(name, v, allocator);
- }
-
-#if RAPIDJSON_HAS_STDSTRING
- //! Add a string object as member (name-value pair) to the object.
- /*! \param name A string value as name of member.
- \param value constant string reference as value of member.
- \param allocator Allocator for reallocating memory. It must be the same one as used before. Commonly use GenericDocument::GetAllocator().
- \return The value itself for fluent API.
- \pre IsObject()
- \note This overload is needed to avoid clashes with the generic primitive type AddMember(GenericValue&,T,Allocator&) overload below.
- \note Amortized Constant time complexity.
- */
- GenericValue& AddMember(GenericValue& name, std::basic_string<Ch>& value, Allocator& allocator) {
- GenericValue v(value, allocator);
- return AddMember(name, v, allocator);
- }
-#endif
-
- //! Add any primitive value as member (name-value pair) to the object.
- /*! \tparam T Either \ref Type, \c int, \c unsigned, \c int64_t, \c uint64_t
- \param name A string value as name of member.
- \param value Value of primitive type \c T as value of member
- \param allocator Allocator for reallocating memory. Commonly use GenericDocument::GetAllocator().
- \return The value itself for fluent API.
- \pre IsObject()
-
- \note The source type \c T explicitly disallows all pointer types,
- especially (\c const) \ref Ch*. This helps avoiding implicitly
- referencing character strings with insufficient lifetime, use
- \ref AddMember(StringRefType, GenericValue&, Allocator&) or \ref
- AddMember(StringRefType, StringRefType, Allocator&).
- All other pointer types would implicitly convert to \c bool,
- use an explicit cast instead, if needed.
- \note Amortized Constant time complexity.
- */
- template <typename T>
- RAPIDJSON_DISABLEIF_RETURN((internal::OrExpr<internal::IsPointer<T>, internal::IsGenericValue<T> >), (GenericValue&))
- AddMember(GenericValue& name, T value, Allocator& allocator) {
- GenericValue v(value);
- return AddMember(name, v, allocator);
- }
-
-#if RAPIDJSON_HAS_CXX11_RVALUE_REFS
- GenericValue& AddMember(GenericValue&& name, GenericValue&& value, Allocator& allocator) {
- return AddMember(name, value, allocator);
- }
- GenericValue& AddMember(GenericValue&& name, GenericValue& value, Allocator& allocator) {
- return AddMember(name, value, allocator);
- }
- GenericValue& AddMember(GenericValue& name, GenericValue&& value, Allocator& allocator) {
- return AddMember(name, value, allocator);
- }
- GenericValue& AddMember(StringRefType name, GenericValue&& value, Allocator& allocator) {
- GenericValue n(name);
- return AddMember(n, value, allocator);
- }
-#endif // RAPIDJSON_HAS_CXX11_RVALUE_REFS
-
-
- //! Add a member (name-value pair) to the object.
- /*! \param name A constant string reference as name of member.
- \param value Value of any type.
- \param allocator Allocator for reallocating memory. It must be the same one as used before. Commonly use GenericDocument::GetAllocator().
- \return The value itself for fluent API.
- \note The ownership of \c value will be transferred to this object on success.
- \pre IsObject()
- \post value.IsNull()
- \note Amortized Constant time complexity.
- */
- GenericValue& AddMember(StringRefType name, GenericValue& value, Allocator& allocator) {
- GenericValue n(name);
- return AddMember(n, value, allocator);
- }
-
- //! Add a constant string value as member (name-value pair) to the object.
- /*! \param name A constant string reference as name of member.
- \param value constant string reference as value of member.
- \param allocator Allocator for reallocating memory. It must be the same one as used before. Commonly use GenericDocument::GetAllocator().
- \return The value itself for fluent API.
- \pre IsObject()
- \note This overload is needed to avoid clashes with the generic primitive type AddMember(StringRefType,T,Allocator&) overload below.
- \note Amortized Constant time complexity.
- */
- GenericValue& AddMember(StringRefType name, StringRefType value, Allocator& allocator) {
- GenericValue v(value);
- return AddMember(name, v, allocator);
- }
-
- //! Add any primitive value as member (name-value pair) to the object.
- /*! \tparam T Either \ref Type, \c int, \c unsigned, \c int64_t, \c uint64_t
- \param name A constant string reference as name of member.
- \param value Value of primitive type \c T as value of member
- \param allocator Allocator for reallocating memory. Commonly use GenericDocument::GetAllocator().
- \return The value itself for fluent API.
- \pre IsObject()
-
- \note The source type \c T explicitly disallows all pointer types,
- especially (\c const) \ref Ch*. This helps avoiding implicitly
- referencing character strings with insufficient lifetime, use
- \ref AddMember(StringRefType, GenericValue&, Allocator&) or \ref
- AddMember(StringRefType, StringRefType, Allocator&).
- All other pointer types would implicitly convert to \c bool,
- use an explicit cast instead, if needed.
- \note Amortized Constant time complexity.
- */
- template <typename T>
- RAPIDJSON_DISABLEIF_RETURN((internal::OrExpr<internal::IsPointer<T>, internal::IsGenericValue<T> >), (GenericValue&))
- AddMember(StringRefType name, T value, Allocator& allocator) {
- GenericValue n(name);
- return AddMember(n, value, allocator);
- }
-
- //! Remove all members in the object.
- /*! This function do not deallocate memory in the object, i.e. the capacity is unchanged.
- \note Linear time complexity.
- */
- void RemoveAllMembers() {
- RAPIDJSON_ASSERT(IsObject());
- for (MemberIterator m = MemberBegin(); m != MemberEnd(); ++m)
- m->~Member();
- data_.o.size = 0;
- }
-
- //! Remove a member in object by its name.
- /*! \param name Name of member to be removed.
- \return Whether the member existed.
- \note This function may reorder the object members. Use \ref
- EraseMember(ConstMemberIterator) if you need to preserve the
- relative order of the remaining members.
- \note Linear time complexity.
- */
- bool RemoveMember(const Ch* name) {
- GenericValue n(StringRef(name));
- return RemoveMember(n);
- }
-
-#if RAPIDJSON_HAS_STDSTRING
- bool RemoveMember(const std::basic_string<Ch>& name) { return RemoveMember(GenericValue(StringRef(name))); }
-#endif
-
- template <typename SourceAllocator>
- bool RemoveMember(const GenericValue<Encoding, SourceAllocator>& name) {
- MemberIterator m = FindMember(name);
- if (m != MemberEnd()) {
- RemoveMember(m);
- return true;
- }
- else
- return false;
- }
-
- //! Remove a member in object by iterator.
- /*! \param m member iterator (obtained by FindMember() or MemberBegin()).
- \return the new iterator after removal.
- \note This function may reorder the object members. Use \ref
- EraseMember(ConstMemberIterator) if you need to preserve the
- relative order of the remaining members.
- \note Constant time complexity.
- */
- MemberIterator RemoveMember(MemberIterator m) {
- RAPIDJSON_ASSERT(IsObject());
- RAPIDJSON_ASSERT(data_.o.size > 0);
- RAPIDJSON_ASSERT(GetMembersPointer() != 0);
- RAPIDJSON_ASSERT(m >= MemberBegin() && m < MemberEnd());
-
- MemberIterator last(GetMembersPointer() + (data_.o.size - 1));
- if (data_.o.size > 1 && m != last)
- *m = *last; // Move the last one to this place
- else
- m->~Member(); // Only one left, just destroy
- --data_.o.size;
- return m;
- }
-
- //! Remove a member from an object by iterator.
- /*! \param pos iterator to the member to remove
- \pre IsObject() == true && \ref MemberBegin() <= \c pos < \ref MemberEnd()
- \return Iterator following the removed element.
- If the iterator \c pos refers to the last element, the \ref MemberEnd() iterator is returned.
- \note This function preserves the relative order of the remaining object
- members. If you do not need this, use the more efficient \ref RemoveMember(MemberIterator).
- \note Linear time complexity.
- */
- MemberIterator EraseMember(ConstMemberIterator pos) {
- return EraseMember(pos, pos +1);
- }
-
- //! Remove members in the range [first, last) from an object.
- /*! \param first iterator to the first member to remove
- \param last iterator following the last member to remove
- \pre IsObject() == true && \ref MemberBegin() <= \c first <= \c last <= \ref MemberEnd()
- \return Iterator following the last removed element.
- \note This function preserves the relative order of the remaining object
- members.
- \note Linear time complexity.
- */
- MemberIterator EraseMember(ConstMemberIterator first, ConstMemberIterator last) {
- RAPIDJSON_ASSERT(IsObject());
- RAPIDJSON_ASSERT(data_.o.size > 0);
- RAPIDJSON_ASSERT(GetMembersPointer() != 0);
- RAPIDJSON_ASSERT(first >= MemberBegin());
- RAPIDJSON_ASSERT(first <= last);
- RAPIDJSON_ASSERT(last <= MemberEnd());
-
- MemberIterator pos = MemberBegin() + (first - MemberBegin());
- for (MemberIterator itr = pos; itr != last; ++itr)
- itr->~Member();
- std::memmove(&*pos, &*last, static_cast<size_t>(MemberEnd() - last) * sizeof(Member));
- data_.o.size -= static_cast<SizeType>(last - first);
- return pos;
- }
-
- //! Erase a member in object by its name.
- /*! \param name Name of member to be removed.
- \return Whether the member existed.
- \note Linear time complexity.
- */
- bool EraseMember(const Ch* name) {
- GenericValue n(StringRef(name));
- return EraseMember(n);
- }
-
-#if RAPIDJSON_HAS_STDSTRING
- bool EraseMember(const std::basic_string<Ch>& name) { return EraseMember(GenericValue(StringRef(name))); }
-#endif
-
- template <typename SourceAllocator>
- bool EraseMember(const GenericValue<Encoding, SourceAllocator>& name) {
- MemberIterator m = FindMember(name);
- if (m != MemberEnd()) {
- EraseMember(m);
- return true;
- }
- else
- return false;
- }
-
- Object GetObject() { RAPIDJSON_ASSERT(IsObject()); return Object(*this); }
- ConstObject GetObject() const { RAPIDJSON_ASSERT(IsObject()); return ConstObject(*this); }
-
- //@}
-
- //!@name Array
- //@{
-
- //! Set this value as an empty array.
- /*! \post IsArray == true */
- GenericValue& SetArray() { this->~GenericValue(); new (this) GenericValue(kArrayType); return *this; }
-
- //! Get the number of elements in array.
- SizeType Size() const { RAPIDJSON_ASSERT(IsArray()); return data_.a.size; }
-
- //! Get the capacity of array.
- SizeType Capacity() const { RAPIDJSON_ASSERT(IsArray()); return data_.a.capacity; }
-
- //! Check whether the array is empty.
- bool Empty() const { RAPIDJSON_ASSERT(IsArray()); return data_.a.size == 0; }
-
- //! Remove all elements in the array.
- /*! This function do not deallocate memory in the array, i.e. the capacity is unchanged.
- \note Linear time complexity.
- */
- void Clear() {
- RAPIDJSON_ASSERT(IsArray());
- GenericValue* e = GetElementsPointer();
- for (GenericValue* v = e; v != e + data_.a.size; ++v)
- v->~GenericValue();
- data_.a.size = 0;
- }
-
- //! Get an element from array by index.
- /*! \pre IsArray() == true
- \param index Zero-based index of element.
- \see operator[](T*)
- */
- GenericValue& operator[](SizeType index) {
- RAPIDJSON_ASSERT(IsArray());
- RAPIDJSON_ASSERT(index < data_.a.size);
- return GetElementsPointer()[index];
- }
- const GenericValue& operator[](SizeType index) const { return const_cast<GenericValue&>(*this)[index]; }
-
- //! Element iterator
- /*! \pre IsArray() == true */
- ValueIterator Begin() { RAPIDJSON_ASSERT(IsArray()); return GetElementsPointer(); }
- //! \em Past-the-end element iterator
- /*! \pre IsArray() == true */
- ValueIterator End() { RAPIDJSON_ASSERT(IsArray()); return GetElementsPointer() + data_.a.size; }
- //! Constant element iterator
- /*! \pre IsArray() == true */
- ConstValueIterator Begin() const { return const_cast<GenericValue&>(*this).Begin(); }
- //! Constant \em past-the-end element iterator
- /*! \pre IsArray() == true */
- ConstValueIterator End() const { return const_cast<GenericValue&>(*this).End(); }
-
- //! Request the array to have enough capacity to store elements.
- /*! \param newCapacity The capacity that the array at least need to have.
- \param allocator Allocator for reallocating memory. It must be the same one as used before. Commonly use GenericDocument::GetAllocator().
- \return The value itself for fluent API.
- \note Linear time complexity.
- */
- GenericValue& Reserve(SizeType newCapacity, Allocator &allocator) {
- RAPIDJSON_ASSERT(IsArray());
- if (newCapacity > data_.a.capacity) {
- SetElementsPointer(reinterpret_cast<GenericValue*>(allocator.Realloc(GetElementsPointer(), data_.a.capacity * sizeof(GenericValue), newCapacity * sizeof(GenericValue))));
- data_.a.capacity = newCapacity;
- }
- return *this;
- }
-
- //! Append a GenericValue at the end of the array.
- /*! \param value Value to be appended.
- \param allocator Allocator for reallocating memory. It must be the same one as used before. Commonly use GenericDocument::GetAllocator().
- \pre IsArray() == true
- \post value.IsNull() == true
- \return The value itself for fluent API.
- \note The ownership of \c value will be transferred to this array on success.
- \note If the number of elements to be appended is known, calls Reserve() once first may be more efficient.
- \note Amortized constant time complexity.
- */
- GenericValue& PushBack(GenericValue& value, Allocator& allocator) {
- RAPIDJSON_ASSERT(IsArray());
- if (data_.a.size >= data_.a.capacity)
- Reserve(data_.a.capacity == 0 ? kDefaultArrayCapacity : (data_.a.capacity + (data_.a.capacity + 1) / 2), allocator);
- GetElementsPointer()[data_.a.size++].RawAssign(value);
- return *this;
- }
-
-#if RAPIDJSON_HAS_CXX11_RVALUE_REFS
- GenericValue& PushBack(GenericValue&& value, Allocator& allocator) {
- return PushBack(value, allocator);
- }
-#endif // RAPIDJSON_HAS_CXX11_RVALUE_REFS
-
- //! Append a constant string reference at the end of the array.
- /*! \param value Constant string reference to be appended.
- \param allocator Allocator for reallocating memory. It must be the same one used previously. Commonly use GenericDocument::GetAllocator().
- \pre IsArray() == true
- \return The value itself for fluent API.
- \note If the number of elements to be appended is known, calls Reserve() once first may be more efficient.
- \note Amortized constant time complexity.
- \see GenericStringRef
- */
- GenericValue& PushBack(StringRefType value, Allocator& allocator) {
- return (*this).template PushBack<StringRefType>(value, allocator);
- }
-
- //! Append a primitive value at the end of the array.
- /*! \tparam T Either \ref Type, \c int, \c unsigned, \c int64_t, \c uint64_t
- \param value Value of primitive type T to be appended.
- \param allocator Allocator for reallocating memory. It must be the same one as used before. Commonly use GenericDocument::GetAllocator().
- \pre IsArray() == true
- \return The value itself for fluent API.
- \note If the number of elements to be appended is known, calls Reserve() once first may be more efficient.
-
- \note The source type \c T explicitly disallows all pointer types,
- especially (\c const) \ref Ch*. This helps avoiding implicitly
- referencing character strings with insufficient lifetime, use
- \ref PushBack(GenericValue&, Allocator&) or \ref
- PushBack(StringRefType, Allocator&).
- All other pointer types would implicitly convert to \c bool,
- use an explicit cast instead, if needed.
- \note Amortized constant time complexity.
- */
- template <typename T>
- RAPIDJSON_DISABLEIF_RETURN((internal::OrExpr<internal::IsPointer<T>, internal::IsGenericValue<T> >), (GenericValue&))
- PushBack(T value, Allocator& allocator) {
- GenericValue v(value);
- return PushBack(v, allocator);
- }
-
- //! Remove the last element in the array.
- /*!
- \note Constant time complexity.
- */
- GenericValue& PopBack() {
- RAPIDJSON_ASSERT(IsArray());
- RAPIDJSON_ASSERT(!Empty());
- GetElementsPointer()[--data_.a.size].~GenericValue();
- return *this;
- }
-
- //! Remove an element of array by iterator.
- /*!
- \param pos iterator to the element to remove
- \pre IsArray() == true && \ref Begin() <= \c pos < \ref End()
- \return Iterator following the removed element. If the iterator pos refers to the last element, the End() iterator is returned.
- \note Linear time complexity.
- */
- ValueIterator Erase(ConstValueIterator pos) {
- return Erase(pos, pos + 1);
- }
-
- //! Remove elements in the range [first, last) of the array.
- /*!
- \param first iterator to the first element to remove
- \param last iterator following the last element to remove
- \pre IsArray() == true && \ref Begin() <= \c first <= \c last <= \ref End()
- \return Iterator following the last removed element.
- \note Linear time complexity.
- */
- ValueIterator Erase(ConstValueIterator first, ConstValueIterator last) {
- RAPIDJSON_ASSERT(IsArray());
- RAPIDJSON_ASSERT(data_.a.size > 0);
- RAPIDJSON_ASSERT(GetElementsPointer() != 0);
- RAPIDJSON_ASSERT(first >= Begin());
- RAPIDJSON_ASSERT(first <= last);
- RAPIDJSON_ASSERT(last <= End());
- ValueIterator pos = Begin() + (first - Begin());
- for (ValueIterator itr = pos; itr != last; ++itr)
- itr->~GenericValue();
- std::memmove(pos, last, static_cast<size_t>(End() - last) * sizeof(GenericValue));
- data_.a.size -= static_cast<SizeType>(last - first);
- return pos;
- }
-
- Array GetArray() { RAPIDJSON_ASSERT(IsArray()); return Array(*this); }
- ConstArray GetArray() const { RAPIDJSON_ASSERT(IsArray()); return ConstArray(*this); }
-
- //@}
-
- //!@name Number
- //@{
-
- int GetInt() const { RAPIDJSON_ASSERT(data_.f.flags & kIntFlag); return data_.n.i.i; }
- unsigned GetUint() const { RAPIDJSON_ASSERT(data_.f.flags & kUintFlag); return data_.n.u.u; }
- int64_t GetInt64() const { RAPIDJSON_ASSERT(data_.f.flags & kInt64Flag); return data_.n.i64; }
- uint64_t GetUint64() const { RAPIDJSON_ASSERT(data_.f.flags & kUint64Flag); return data_.n.u64; }
-
- //! Get the value as double type.
- /*! \note If the value is 64-bit integer type, it may lose precision. Use \c IsLosslessDouble() to check whether the converison is lossless.
- */
- double GetDouble() const {
- RAPIDJSON_ASSERT(IsNumber());
- if ((data_.f.flags & kDoubleFlag) != 0) return data_.n.d; // exact type, no conversion.
- if ((data_.f.flags & kIntFlag) != 0) return data_.n.i.i; // int -> double
- if ((data_.f.flags & kUintFlag) != 0) return data_.n.u.u; // unsigned -> double
- if ((data_.f.flags & kInt64Flag) != 0) return static_cast<double>(data_.n.i64); // int64_t -> double (may lose precision)
- RAPIDJSON_ASSERT((data_.f.flags & kUint64Flag) != 0); return static_cast<double>(data_.n.u64); // uint64_t -> double (may lose precision)
- }
-
- //! Get the value as float type.
- /*! \note If the value is 64-bit integer type, it may lose precision. Use \c IsLosslessFloat() to check whether the converison is lossless.
- */
- float GetFloat() const {
- return static_cast<float>(GetDouble());
- }
-
- GenericValue& SetInt(int i) { this->~GenericValue(); new (this) GenericValue(i); return *this; }
- GenericValue& SetUint(unsigned u) { this->~GenericValue(); new (this) GenericValue(u); return *this; }
- GenericValue& SetInt64(int64_t i64) { this->~GenericValue(); new (this) GenericValue(i64); return *this; }
- GenericValue& SetUint64(uint64_t u64) { this->~GenericValue(); new (this) GenericValue(u64); return *this; }
- GenericValue& SetDouble(double d) { this->~GenericValue(); new (this) GenericValue(d); return *this; }
- GenericValue& SetFloat(float f) { this->~GenericValue(); new (this) GenericValue(f); return *this; }
-
- //@}
-
- //!@name String
- //@{
-
- const Ch* GetString() const { RAPIDJSON_ASSERT(IsString()); return (data_.f.flags & kInlineStrFlag) ? data_.ss.str : GetStringPointer(); }
-
- //! Get the length of string.
- /*! Since rapidjson permits "\\u0000" in the json string, strlen(v.GetString()) may not equal to v.GetStringLength().
- */
- SizeType GetStringLength() const { RAPIDJSON_ASSERT(IsString()); return ((data_.f.flags & kInlineStrFlag) ? (data_.ss.GetLength()) : data_.s.length); }
-
- //! Set this value as a string without copying source string.
- /*! This version has better performance with supplied length, and also support string containing null character.
- \param s source string pointer.
- \param length The length of source string, excluding the trailing null terminator.
- \return The value itself for fluent API.
- \post IsString() == true && GetString() == s && GetStringLength() == length
- \see SetString(StringRefType)
- */
- GenericValue& SetString(const Ch* s, SizeType length) { return SetString(StringRef(s, length)); }
-
- //! Set this value as a string without copying source string.
- /*! \param s source string reference
- \return The value itself for fluent API.
- \post IsString() == true && GetString() == s && GetStringLength() == s.length
- */
- GenericValue& SetString(StringRefType s) { this->~GenericValue(); SetStringRaw(s); return *this; }
-
- //! Set this value as a string by copying from source string.
- /*! This version has better performance with supplied length, and also support string containing null character.
- \param s source string.
- \param length The length of source string, excluding the trailing null terminator.
- \param allocator Allocator for allocating copied buffer. Commonly use GenericDocument::GetAllocator().
- \return The value itself for fluent API.
- \post IsString() == true && GetString() != s && strcmp(GetString(),s) == 0 && GetStringLength() == length
- */
- GenericValue& SetString(const Ch* s, SizeType length, Allocator& allocator) { this->~GenericValue(); SetStringRaw(StringRef(s, length), allocator); return *this; }
-
- //! Set this value as a string by copying from source string.
- /*! \param s source string.
- \param allocator Allocator for allocating copied buffer. Commonly use GenericDocument::GetAllocator().
- \return The value itself for fluent API.
- \post IsString() == true && GetString() != s && strcmp(GetString(),s) == 0 && GetStringLength() == length
- */
- GenericValue& SetString(const Ch* s, Allocator& allocator) { return SetString(s, internal::StrLen(s), allocator); }
-
-#if RAPIDJSON_HAS_STDSTRING
- //! Set this value as a string by copying from source string.
- /*! \param s source string.
- \param allocator Allocator for allocating copied buffer. Commonly use GenericDocument::GetAllocator().
- \return The value itself for fluent API.
- \post IsString() == true && GetString() != s.data() && strcmp(GetString(),s.data() == 0 && GetStringLength() == s.size()
- \note Requires the definition of the preprocessor symbol \ref RAPIDJSON_HAS_STDSTRING.
- */
- GenericValue& SetString(const std::basic_string<Ch>& s, Allocator& allocator) { return SetString(s.data(), SizeType(s.size()), allocator); }
-#endif
-
- //@}
-
- //!@name Array
- //@{
-
- //! Templated version for checking whether this value is type T.
- /*!
- \tparam T Either \c bool, \c int, \c unsigned, \c int64_t, \c uint64_t, \c double, \c float, \c const \c char*, \c std::basic_string<Ch>
- */
- template <typename T>
- bool Is() const { return internal::TypeHelper<ValueType, T>::Is(*this); }
-
- template <typename T>
- T Get() const { return internal::TypeHelper<ValueType, T>::Get(*this); }
-
- template <typename T>
- T Get() { return internal::TypeHelper<ValueType, T>::Get(*this); }
-
- template<typename T>
- ValueType& Set(const T& data) { return internal::TypeHelper<ValueType, T>::Set(*this, data); }
-
- template<typename T>
- ValueType& Set(const T& data, AllocatorType& allocator) { return internal::TypeHelper<ValueType, T>::Set(*this, data, allocator); }
-
- //@}
-
- //! Generate events of this value to a Handler.
- /*! This function adopts the GoF visitor pattern.
- Typical usage is to output this JSON value as JSON text via Writer, which is a Handler.
- It can also be used to deep clone this value via GenericDocument, which is also a Handler.
- \tparam Handler type of handler.
- \param handler An object implementing concept Handler.
- */
- template <typename Handler>
- bool Accept(Handler& handler) const {
- switch(GetType()) {
- case kNullType: return handler.Null();
- case kFalseType: return handler.Bool(false);
- case kTrueType: return handler.Bool(true);
-
- case kObjectType:
- if (RAPIDJSON_UNLIKELY(!handler.StartObject()))
- return false;
- for (ConstMemberIterator m = MemberBegin(); m != MemberEnd(); ++m) {
- RAPIDJSON_ASSERT(m->name.IsString()); // User may change the type of name by MemberIterator.
- if (RAPIDJSON_UNLIKELY(!handler.Key(m->name.GetString(), m->name.GetStringLength(), (m->name.data_.f.flags & kCopyFlag) != 0)))
- return false;
- if (RAPIDJSON_UNLIKELY(!m->value.Accept(handler)))
- return false;
- }
- return handler.EndObject(data_.o.size);
-
- case kArrayType:
- if (RAPIDJSON_UNLIKELY(!handler.StartArray()))
- return false;
- for (const GenericValue* v = Begin(); v != End(); ++v)
- if (RAPIDJSON_UNLIKELY(!v->Accept(handler)))
- return false;
- return handler.EndArray(data_.a.size);
-
- case kStringType:
- return handler.String(GetString(), GetStringLength(), (data_.f.flags & kCopyFlag) != 0);
-
- default:
- RAPIDJSON_ASSERT(GetType() == kNumberType);
- if (IsDouble()) return handler.Double(data_.n.d);
- else if (IsInt()) return handler.Int(data_.n.i.i);
- else if (IsUint()) return handler.Uint(data_.n.u.u);
- else if (IsInt64()) return handler.Int64(data_.n.i64);
- else return handler.Uint64(data_.n.u64);
- }
- }
-
-private:
- template <typename, typename> friend class GenericValue;
- template <typename, typename, typename> friend class GenericDocument;
-
- enum {
- kBoolFlag = 0x0008,
- kNumberFlag = 0x0010,
- kIntFlag = 0x0020,
- kUintFlag = 0x0040,
- kInt64Flag = 0x0080,
- kUint64Flag = 0x0100,
- kDoubleFlag = 0x0200,
- kStringFlag = 0x0400,
- kCopyFlag = 0x0800,
- kInlineStrFlag = 0x1000,
-
- // Initial flags of different types.
- kNullFlag = kNullType,
- kTrueFlag = kTrueType | kBoolFlag,
- kFalseFlag = kFalseType | kBoolFlag,
- kNumberIntFlag = kNumberType | kNumberFlag | kIntFlag | kInt64Flag,
- kNumberUintFlag = kNumberType | kNumberFlag | kUintFlag | kUint64Flag | kInt64Flag,
- kNumberInt64Flag = kNumberType | kNumberFlag | kInt64Flag,
- kNumberUint64Flag = kNumberType | kNumberFlag | kUint64Flag,
- kNumberDoubleFlag = kNumberType | kNumberFlag | kDoubleFlag,
- kNumberAnyFlag = kNumberType | kNumberFlag | kIntFlag | kInt64Flag | kUintFlag | kUint64Flag | kDoubleFlag,
- kConstStringFlag = kStringType | kStringFlag,
- kCopyStringFlag = kStringType | kStringFlag | kCopyFlag,
- kShortStringFlag = kStringType | kStringFlag | kCopyFlag | kInlineStrFlag,
- kObjectFlag = kObjectType,
- kArrayFlag = kArrayType,
-
- kTypeMask = 0x07
- };
-
- static const SizeType kDefaultArrayCapacity = 16;
- static const SizeType kDefaultObjectCapacity = 16;
-
- struct Flag {
-#if RAPIDJSON_48BITPOINTER_OPTIMIZATION
- char payload[sizeof(SizeType) * 2 + 6]; // 2 x SizeType + lower 48-bit pointer
-#elif RAPIDJSON_64BIT
- char payload[sizeof(SizeType) * 2 + sizeof(void*) + 6]; // 6 padding bytes
-#else
- char payload[sizeof(SizeType) * 2 + sizeof(void*) + 2]; // 2 padding bytes
-#endif
- uint16_t flags;
- };
-
- struct String {
- SizeType length;
- SizeType hashcode; //!< reserved
- const Ch* str;
- }; // 12 bytes in 32-bit mode, 16 bytes in 64-bit mode
-
- // implementation detail: ShortString can represent zero-terminated strings up to MaxSize chars
- // (excluding the terminating zero) and store a value to determine the length of the contained
- // string in the last character str[LenPos] by storing "MaxSize - length" there. If the string
- // to store has the maximal length of MaxSize then str[LenPos] will be 0 and therefore act as
- // the string terminator as well. For getting the string length back from that value just use
- // "MaxSize - str[LenPos]".
- // This allows to store 13-chars strings in 32-bit mode, 21-chars strings in 64-bit mode,
- // 13-chars strings for RAPIDJSON_48BITPOINTER_OPTIMIZATION=1 inline (for `UTF8`-encoded strings).
- struct ShortString {
- enum { MaxChars = sizeof(static_cast<Flag*>(0)->payload) / sizeof(Ch), MaxSize = MaxChars - 1, LenPos = MaxSize };
- Ch str[MaxChars];
-
- inline static bool Usable(SizeType len) { return (MaxSize >= len); }
- inline void SetLength(SizeType len) { str[LenPos] = static_cast<Ch>(MaxSize - len); }
- inline SizeType GetLength() const { return static_cast<SizeType>(MaxSize - str[LenPos]); }
- }; // at most as many bytes as "String" above => 12 bytes in 32-bit mode, 16 bytes in 64-bit mode
-
- // By using proper binary layout, retrieval of different integer types do not need conversions.
- union Number {
-#if RAPIDJSON_ENDIAN == RAPIDJSON_LITTLEENDIAN
- struct I {
- int i;
- char padding[4];
- }i;
- struct U {
- unsigned u;
- char padding2[4];
- }u;
-#else
- struct I {
- char padding[4];
- int i;
- }i;
- struct U {
- char padding2[4];
- unsigned u;
- }u;
-#endif
- int64_t i64;
- uint64_t u64;
- double d;
- }; // 8 bytes
-
- struct ObjectData {
- SizeType size;
- SizeType capacity;
- Member* members;
- }; // 12 bytes in 32-bit mode, 16 bytes in 64-bit mode
-
- struct ArrayData {
- SizeType size;
- SizeType capacity;
- GenericValue* elements;
- }; // 12 bytes in 32-bit mode, 16 bytes in 64-bit mode
-
- union Data {
- String s;
- ShortString ss;
- Number n;
- ObjectData o;
- ArrayData a;
- Flag f;
- }; // 16 bytes in 32-bit mode, 24 bytes in 64-bit mode, 16 bytes in 64-bit with RAPIDJSON_48BITPOINTER_OPTIMIZATION
-
- RAPIDJSON_FORCEINLINE const Ch* GetStringPointer() const { return RAPIDJSON_GETPOINTER(Ch, data_.s.str); }
- RAPIDJSON_FORCEINLINE const Ch* SetStringPointer(const Ch* str) { return RAPIDJSON_SETPOINTER(Ch, data_.s.str, str); }
- RAPIDJSON_FORCEINLINE GenericValue* GetElementsPointer() const { return RAPIDJSON_GETPOINTER(GenericValue, data_.a.elements); }
- RAPIDJSON_FORCEINLINE GenericValue* SetElementsPointer(GenericValue* elements) { return RAPIDJSON_SETPOINTER(GenericValue, data_.a.elements, elements); }
- RAPIDJSON_FORCEINLINE Member* GetMembersPointer() const { return RAPIDJSON_GETPOINTER(Member, data_.o.members); }
- RAPIDJSON_FORCEINLINE Member* SetMembersPointer(Member* members) { return RAPIDJSON_SETPOINTER(Member, data_.o.members, members); }
-
- // Initialize this value as array with initial data, without calling destructor.
- void SetArrayRaw(GenericValue* values, SizeType count, Allocator& allocator) {
- data_.f.flags = kArrayFlag;
- if (count) {
- GenericValue* e = static_cast<GenericValue*>(allocator.Malloc(count * sizeof(GenericValue)));
- SetElementsPointer(e);
- std::memcpy(e, values, count * sizeof(GenericValue));
- }
- else
- SetElementsPointer(0);
- data_.a.size = data_.a.capacity = count;
- }
-
- //! Initialize this value as object with initial data, without calling destructor.
- void SetObjectRaw(Member* members, SizeType count, Allocator& allocator) {
- data_.f.flags = kObjectFlag;
- if (count) {
- Member* m = static_cast<Member*>(allocator.Malloc(count * sizeof(Member)));
- SetMembersPointer(m);
- std::memcpy(m, members, count * sizeof(Member));
- }
- else
- SetMembersPointer(0);
- data_.o.size = data_.o.capacity = count;
- }
-
- //! Initialize this value as constant string, without calling destructor.
- void SetStringRaw(StringRefType s) RAPIDJSON_NOEXCEPT {
- data_.f.flags = kConstStringFlag;
- SetStringPointer(s);
- data_.s.length = s.length;
- }
-
- //! Initialize this value as copy string with initial data, without calling destructor.
- void SetStringRaw(StringRefType s, Allocator& allocator) {
- Ch* str = 0;
- if (ShortString::Usable(s.length)) {
- data_.f.flags = kShortStringFlag;
- data_.ss.SetLength(s.length);
- str = data_.ss.str;
- } else {
- data_.f.flags = kCopyStringFlag;
- data_.s.length = s.length;
- str = static_cast<Ch *>(allocator.Malloc((s.length + 1) * sizeof(Ch)));
- SetStringPointer(str);
- }
- std::memcpy(str, s, s.length * sizeof(Ch));
- str[s.length] = '\0';
- }
-
- //! Assignment without calling destructor
- void RawAssign(GenericValue& rhs) RAPIDJSON_NOEXCEPT {
- data_ = rhs.data_;
- // data_.f.flags = rhs.data_.f.flags;
- rhs.data_.f.flags = kNullFlag;
- }
-
- template <typename SourceAllocator>
- bool StringEqual(const GenericValue<Encoding, SourceAllocator>& rhs) const {
- RAPIDJSON_ASSERT(IsString());
- RAPIDJSON_ASSERT(rhs.IsString());
-
- const SizeType len1 = GetStringLength();
- const SizeType len2 = rhs.GetStringLength();
- if(len1 != len2) { return false; }
-
- const Ch* const str1 = GetString();
- const Ch* const str2 = rhs.GetString();
- if(str1 == str2) { return true; } // fast path for constant string
-
- return (std::memcmp(str1, str2, sizeof(Ch) * len1) == 0);
- }
-
- Data data_;
-};
-
-//! GenericValue with UTF8 encoding
-typedef GenericValue<UTF8<> > Value;
-
-///////////////////////////////////////////////////////////////////////////////
-// GenericDocument
-
-//! A document for parsing JSON text as DOM.
-/*!
- \note implements Handler concept
- \tparam Encoding Encoding for both parsing and string storage.
- \tparam Allocator Allocator for allocating memory for the DOM
- \tparam StackAllocator Allocator for allocating memory for stack during parsing.
- \warning Although GenericDocument inherits from GenericValue, the API does \b not provide any virtual functions, especially no virtual destructor. To avoid memory leaks, do not \c delete a GenericDocument object via a pointer to a GenericValue.
-*/
-template <typename Encoding, typename Allocator = MemoryPoolAllocator<>, typename StackAllocator = CrtAllocator>
-class GenericDocument : public GenericValue<Encoding, Allocator> {
-public:
- typedef typename Encoding::Ch Ch; //!< Character type derived from Encoding.
- typedef GenericValue<Encoding, Allocator> ValueType; //!< Value type of the document.
- typedef Allocator AllocatorType; //!< Allocator type from template parameter.
-
- //! Constructor
- /*! Creates an empty document of specified type.
- \param type Mandatory type of object to create.
- \param allocator Optional allocator for allocating memory.
- \param stackCapacity Optional initial capacity of stack in bytes.
- \param stackAllocator Optional allocator for allocating memory for stack.
- */
- explicit GenericDocument(Type type, Allocator* allocator = 0, size_t stackCapacity = kDefaultStackCapacity, StackAllocator* stackAllocator = 0) :
- GenericValue<Encoding, Allocator>(type), allocator_(allocator), ownAllocator_(0), stack_(stackAllocator, stackCapacity), parseResult_()
- {
- if (!allocator_)
- ownAllocator_ = allocator_ = RAPIDJSON_NEW(Allocator());
- }
-
- //! Constructor
- /*! Creates an empty document which type is Null.
- \param allocator Optional allocator for allocating memory.
- \param stackCapacity Optional initial capacity of stack in bytes.
- \param stackAllocator Optional allocator for allocating memory for stack.
- */
- GenericDocument(Allocator* allocator = 0, size_t stackCapacity = kDefaultStackCapacity, StackAllocator* stackAllocator = 0) :
- allocator_(allocator), ownAllocator_(0), stack_(stackAllocator, stackCapacity), parseResult_()
- {
- if (!allocator_)
- ownAllocator_ = allocator_ = RAPIDJSON_NEW(Allocator());
- }
-
-#if RAPIDJSON_HAS_CXX11_RVALUE_REFS
- //! Move constructor in C++11
- GenericDocument(GenericDocument&& rhs) RAPIDJSON_NOEXCEPT
- : ValueType(std::forward<ValueType>(rhs)), // explicit cast to avoid prohibited move from Document
- allocator_(rhs.allocator_),
- ownAllocator_(rhs.ownAllocator_),
- stack_(std::move(rhs.stack_)),
- parseResult_(rhs.parseResult_)
- {
- rhs.allocator_ = 0;
- rhs.ownAllocator_ = 0;
- rhs.parseResult_ = ParseResult();
- }
-#endif
-
- ~GenericDocument() {
- Destroy();
- }
-
-#if RAPIDJSON_HAS_CXX11_RVALUE_REFS
- //! Move assignment in C++11
- GenericDocument& operator=(GenericDocument&& rhs) RAPIDJSON_NOEXCEPT
- {
- // The cast to ValueType is necessary here, because otherwise it would
- // attempt to call GenericValue's templated assignment operator.
- ValueType::operator=(std::forward<ValueType>(rhs));
-
- // Calling the destructor here would prematurely call stack_'s destructor
- Destroy();
-
- allocator_ = rhs.allocator_;
- ownAllocator_ = rhs.ownAllocator_;
- stack_ = std::move(rhs.stack_);
- parseResult_ = rhs.parseResult_;
-
- rhs.allocator_ = 0;
- rhs.ownAllocator_ = 0;
- rhs.parseResult_ = ParseResult();
-
- return *this;
- }
-#endif
-
- //! Exchange the contents of this document with those of another.
- /*!
- \param rhs Another document.
- \note Constant complexity.
- \see GenericValue::Swap
- */
- GenericDocument& Swap(GenericDocument& rhs) RAPIDJSON_NOEXCEPT {
- ValueType::Swap(rhs);
- stack_.Swap(rhs.stack_);
- internal::Swap(allocator_, rhs.allocator_);
- internal::Swap(ownAllocator_, rhs.ownAllocator_);
- internal::Swap(parseResult_, rhs.parseResult_);
- return *this;
- }
-
- //! free-standing swap function helper
- /*!
- Helper function to enable support for common swap implementation pattern based on \c std::swap:
- \code
- void swap(MyClass& a, MyClass& b) {
- using std::swap;
- swap(a.doc, b.doc);
- // ...
- }
- \endcode
- \see Swap()
- */
- friend inline void swap(GenericDocument& a, GenericDocument& b) RAPIDJSON_NOEXCEPT { a.Swap(b); }
-
- //! Populate this document by a generator which produces SAX events.
- /*! \tparam Generator A functor with <tt>bool f(Handler)</tt> prototype.
- \param g Generator functor which sends SAX events to the parameter.
- \return The document itself for fluent API.
- */
- template <typename Generator>
- GenericDocument& Populate(Generator& g) {
- ClearStackOnExit scope(*this);
- if (g(*this)) {
- RAPIDJSON_ASSERT(stack_.GetSize() == sizeof(ValueType)); // Got one and only one root object
- ValueType::operator=(*stack_.template Pop<ValueType>(1));// Move value from stack to document
- }
- return *this;
- }
-
- //!@name Parse from stream
- //!@{
-
- //! Parse JSON text from an input stream (with Encoding conversion)
- /*! \tparam parseFlags Combination of \ref ParseFlag.
- \tparam SourceEncoding Encoding of input stream
- \tparam InputStream Type of input stream, implementing Stream concept
- \param is Input stream to be parsed.
- \return The document itself for fluent API.
- */
- template <unsigned parseFlags, typename SourceEncoding, typename InputStream>
- GenericDocument& ParseStream(InputStream& is) {
- GenericReader<SourceEncoding, Encoding, StackAllocator> reader(
- stack_.HasAllocator() ? &stack_.GetAllocator() : 0);
- ClearStackOnExit scope(*this);
- parseResult_ = reader.template Parse<parseFlags>(is, *this);
- if (parseResult_) {
- RAPIDJSON_ASSERT(stack_.GetSize() == sizeof(ValueType)); // Got one and only one root object
- ValueType::operator=(*stack_.template Pop<ValueType>(1));// Move value from stack to document
- }
- return *this;
- }
-
- //! Parse JSON text from an input stream
- /*! \tparam parseFlags Combination of \ref ParseFlag.
- \tparam InputStream Type of input stream, implementing Stream concept
- \param is Input stream to be parsed.
- \return The document itself for fluent API.
- */
- template <unsigned parseFlags, typename InputStream>
- GenericDocument& ParseStream(InputStream& is) {
- return ParseStream<parseFlags, Encoding, InputStream>(is);
- }
-
- //! Parse JSON text from an input stream (with \ref kParseDefaultFlags)
- /*! \tparam InputStream Type of input stream, implementing Stream concept
- \param is Input stream to be parsed.
- \return The document itself for fluent API.
- */
- template <typename InputStream>
- GenericDocument& ParseStream(InputStream& is) {
- return ParseStream<kParseDefaultFlags, Encoding, InputStream>(is);
- }
- //!@}
-
- //!@name Parse in-place from mutable string
- //!@{
-
- //! Parse JSON text from a mutable string
- /*! \tparam parseFlags Combination of \ref ParseFlag.
- \param str Mutable zero-terminated string to be parsed.
- \return The document itself for fluent API.
- */
- template <unsigned parseFlags>
- GenericDocument& ParseInsitu(Ch* str) {
- GenericInsituStringStream<Encoding> s(str);
- return ParseStream<parseFlags | kParseInsituFlag>(s);
- }
-
- //! Parse JSON text from a mutable string (with \ref kParseDefaultFlags)
- /*! \param str Mutable zero-terminated string to be parsed.
- \return The document itself for fluent API.
- */
- GenericDocument& ParseInsitu(Ch* str) {
- return ParseInsitu<kParseDefaultFlags>(str);
- }
- //!@}
-
- //!@name Parse from read-only string
- //!@{
-
- //! Parse JSON text from a read-only string (with Encoding conversion)
- /*! \tparam parseFlags Combination of \ref ParseFlag (must not contain \ref kParseInsituFlag).
- \tparam SourceEncoding Transcoding from input Encoding
- \param str Read-only zero-terminated string to be parsed.
- */
- template <unsigned parseFlags, typename SourceEncoding>
- GenericDocument& Parse(const typename SourceEncoding::Ch* str) {
- RAPIDJSON_ASSERT(!(parseFlags & kParseInsituFlag));
- GenericStringStream<SourceEncoding> s(str);
- return ParseStream<parseFlags, SourceEncoding>(s);
- }
-
- //! Parse JSON text from a read-only string
- /*! \tparam parseFlags Combination of \ref ParseFlag (must not contain \ref kParseInsituFlag).
- \param str Read-only zero-terminated string to be parsed.
- */
- template <unsigned parseFlags>
- GenericDocument& Parse(const Ch* str) {
- return Parse<parseFlags, Encoding>(str);
- }
-
- //! Parse JSON text from a read-only string (with \ref kParseDefaultFlags)
- /*! \param str Read-only zero-terminated string to be parsed.
- */
- GenericDocument& Parse(const Ch* str) {
- return Parse<kParseDefaultFlags>(str);
- }
-
- template <unsigned parseFlags, typename SourceEncoding>
- GenericDocument& Parse(const typename SourceEncoding::Ch* str, size_t length) {
- RAPIDJSON_ASSERT(!(parseFlags & kParseInsituFlag));
- MemoryStream ms(static_cast<const char*>(str), length * sizeof(typename SourceEncoding::Ch));
- EncodedInputStream<SourceEncoding, MemoryStream> is(ms);
- ParseStream<parseFlags, SourceEncoding>(is);
- return *this;
- }
-
- template <unsigned parseFlags>
- GenericDocument& Parse(const Ch* str, size_t length) {
- return Parse<parseFlags, Encoding>(str, length);
- }
-
- GenericDocument& Parse(const Ch* str, size_t length) {
- return Parse<kParseDefaultFlags>(str, length);
- }
-
-#if RAPIDJSON_HAS_STDSTRING
- template <unsigned parseFlags, typename SourceEncoding>
- GenericDocument& Parse(const std::basic_string<typename SourceEncoding::Ch>& str) {
- // c_str() is constant complexity according to standard. Should be faster than Parse(const char*, size_t)
- return Parse<parseFlags, SourceEncoding>(str.c_str());
- }
-
- template <unsigned parseFlags>
- GenericDocument& Parse(const std::basic_string<Ch>& str) {
- return Parse<parseFlags, Encoding>(str.c_str());
- }
-
- GenericDocument& Parse(const std::basic_string<Ch>& str) {
- return Parse<kParseDefaultFlags>(str);
- }
-#endif // RAPIDJSON_HAS_STDSTRING
-
- //!@}
-
- //!@name Handling parse errors
- //!@{
-
- //! Whether a parse error has occured in the last parsing.
- bool HasParseError() const { return parseResult_.IsError(); }
-
- //! Get the \ref ParseErrorCode of last parsing.
- ParseErrorCode GetParseError() const { return parseResult_.Code(); }
-
- //! Get the position of last parsing error in input, 0 otherwise.
- size_t GetErrorOffset() const { return parseResult_.Offset(); }
-
- //! Implicit conversion to get the last parse result
-#ifndef __clang // -Wdocumentation
- /*! \return \ref ParseResult of the last parse operation
-
- \code
- Document doc;
- ParseResult ok = doc.Parse(json);
- if (!ok)
- printf( "JSON parse error: %s (%u)\n", GetParseError_En(ok.Code()), ok.Offset());
- \endcode
- */
-#endif
- operator ParseResult() const { return parseResult_; }
- //!@}
-
- //! Get the allocator of this document.
- Allocator& GetAllocator() {
- RAPIDJSON_ASSERT(allocator_);
- return *allocator_;
- }
-
- //! Get the capacity of stack in bytes.
- size_t GetStackCapacity() const { return stack_.GetCapacity(); }
-
-private:
- // clear stack on any exit from ParseStream, e.g. due to exception
- struct ClearStackOnExit {
- explicit ClearStackOnExit(GenericDocument& d) : d_(d) {}
- ~ClearStackOnExit() { d_.ClearStack(); }
- private:
- ClearStackOnExit(const ClearStackOnExit&);
- ClearStackOnExit& operator=(const ClearStackOnExit&);
- GenericDocument& d_;
- };
-
- // callers of the following private Handler functions
- // template <typename,typename,typename> friend class GenericReader; // for parsing
- template <typename, typename> friend class GenericValue; // for deep copying
-
-public:
- // Implementation of Handler
- bool Null() { new (stack_.template Push<ValueType>()) ValueType(); return true; }
- bool Bool(bool b) { new (stack_.template Push<ValueType>()) ValueType(b); return true; }
- bool Int(int i) { new (stack_.template Push<ValueType>()) ValueType(i); return true; }
- bool Uint(unsigned i) { new (stack_.template Push<ValueType>()) ValueType(i); return true; }
- bool Int64(int64_t i) { new (stack_.template Push<ValueType>()) ValueType(i); return true; }
- bool Uint64(uint64_t i) { new (stack_.template Push<ValueType>()) ValueType(i); return true; }
- bool Double(double d) { new (stack_.template Push<ValueType>()) ValueType(d); return true; }
-
- bool RawNumber(const Ch* str, SizeType length, bool copy) {
- if (copy)
- new (stack_.template Push<ValueType>()) ValueType(str, length, GetAllocator());
- else
- new (stack_.template Push<ValueType>()) ValueType(str, length);
- return true;
- }
-
- bool String(const Ch* str, SizeType length, bool copy) {
- if (copy)
- new (stack_.template Push<ValueType>()) ValueType(str, length, GetAllocator());
- else
- new (stack_.template Push<ValueType>()) ValueType(str, length);
- return true;
- }
-
- bool StartObject() { new (stack_.template Push<ValueType>()) ValueType(kObjectType); return true; }
-
- bool Key(const Ch* str, SizeType length, bool copy) { return String(str, length, copy); }
-
- bool EndObject(SizeType memberCount) {
- typename ValueType::Member* members = stack_.template Pop<typename ValueType::Member>(memberCount);
- stack_.template Top<ValueType>()->SetObjectRaw(members, memberCount, GetAllocator());
- return true;
- }
-
- bool StartArray() { new (stack_.template Push<ValueType>()) ValueType(kArrayType); return true; }
-
- bool EndArray(SizeType elementCount) {
- ValueType* elements = stack_.template Pop<ValueType>(elementCount);
- stack_.template Top<ValueType>()->SetArrayRaw(elements, elementCount, GetAllocator());
- return true;
- }
-
-private:
- //! Prohibit copying
- GenericDocument(const GenericDocument&);
- //! Prohibit assignment
- GenericDocument& operator=(const GenericDocument&);
-
- void ClearStack() {
- if (Allocator::kNeedFree)
- while (stack_.GetSize() > 0) // Here assumes all elements in stack array are GenericValue (Member is actually 2 GenericValue objects)
- (stack_.template Pop<ValueType>(1))->~ValueType();
- else
- stack_.Clear();
- stack_.ShrinkToFit();
- }
-
- void Destroy() {
- RAPIDJSON_DELETE(ownAllocator_);
- }
-
- static const size_t kDefaultStackCapacity = 1024;
- Allocator* allocator_;
- Allocator* ownAllocator_;
- internal::Stack<StackAllocator> stack_;
- ParseResult parseResult_;
-};
-
-//! GenericDocument with UTF8 encoding
-typedef GenericDocument<UTF8<> > Document;
-
-// defined here due to the dependency on GenericDocument
-template <typename Encoding, typename Allocator>
-template <typename SourceAllocator>
-inline
-GenericValue<Encoding,Allocator>::GenericValue(const GenericValue<Encoding,SourceAllocator>& rhs, Allocator& allocator)
-{
- switch (rhs.GetType()) {
- case kObjectType:
- case kArrayType: { // perform deep copy via SAX Handler
- GenericDocument<Encoding,Allocator> d(&allocator);
- rhs.Accept(d);
- RawAssign(*d.stack_.template Pop<GenericValue>(1));
- }
- break;
- case kStringType:
- if (rhs.data_.f.flags == kConstStringFlag) {
- data_.f.flags = rhs.data_.f.flags;
- data_ = *reinterpret_cast<const Data*>(&rhs.data_);
- } else {
- SetStringRaw(StringRef(rhs.GetString(), rhs.GetStringLength()), allocator);
- }
- break;
- default:
- data_.f.flags = rhs.data_.f.flags;
- data_ = *reinterpret_cast<const Data*>(&rhs.data_);
- break;
- }
-}
-
-//! Helper class for accessing Value of array type.
-/*!
- Instance of this helper class is obtained by \c GenericValue::GetArray().
- In addition to all APIs for array type, it provides range-based for loop if \c RAPIDJSON_HAS_CXX11_RANGE_FOR=1.
-*/
-template <bool Const, typename ValueT>
-class GenericArray {
-public:
- typedef GenericArray<true, ValueT> ConstArray;
- typedef GenericArray<false, ValueT> Array;
- typedef ValueT PlainType;
- typedef typename internal::MaybeAddConst<Const,PlainType>::Type ValueType;
- typedef ValueType* ValueIterator; // This may be const or non-const iterator
- typedef const ValueT* ConstValueIterator;
- typedef typename ValueType::AllocatorType AllocatorType;
- typedef typename ValueType::StringRefType StringRefType;
-
- template <typename, typename>
- friend class GenericValue;
-
- GenericArray(const GenericArray& rhs) : value_(rhs.value_) {}
- GenericArray& operator=(const GenericArray& rhs) { value_ = rhs.value_; return *this; }
- ~GenericArray() {}
-
- SizeType Size() const { return value_.Size(); }
- SizeType Capacity() const { return value_.Capacity(); }
- bool Empty() const { return value_.Empty(); }
- void Clear() const { value_.Clear(); }
- ValueType& operator[](SizeType index) const { return value_[index]; }
- ValueIterator Begin() const { return value_.Begin(); }
- ValueIterator End() const { return value_.End(); }
- GenericArray Reserve(SizeType newCapacity, AllocatorType &allocator) const { value_.Reserve(newCapacity, allocator); return *this; }
- GenericArray PushBack(ValueType& value, AllocatorType& allocator) const { value_.PushBack(value, allocator); return *this; }
-#if RAPIDJSON_HAS_CXX11_RVALUE_REFS
- GenericArray PushBack(ValueType&& value, AllocatorType& allocator) const { value_.PushBack(value, allocator); return *this; }
-#endif // RAPIDJSON_HAS_CXX11_RVALUE_REFS
- GenericArray PushBack(StringRefType value, AllocatorType& allocator) const { value_.PushBack(value, allocator); return *this; }
- template <typename T> RAPIDJSON_DISABLEIF_RETURN((internal::OrExpr<internal::IsPointer<T>, internal::IsGenericValue<T> >), (const GenericArray&)) PushBack(T value, AllocatorType& allocator) const { value_.PushBack(value, allocator); return *this; }
- GenericArray PopBack() const { value_.PopBack(); return *this; }
- ValueIterator Erase(ConstValueIterator pos) const { return value_.Erase(pos); }
- ValueIterator Erase(ConstValueIterator first, ConstValueIterator last) const { return value_.Erase(first, last); }
-
-#if RAPIDJSON_HAS_CXX11_RANGE_FOR
- ValueIterator begin() const { return value_.Begin(); }
- ValueIterator end() const { return value_.End(); }
-#endif
-
-private:
- GenericArray();
- GenericArray(ValueType& value) : value_(value) {}
- ValueType& value_;
-};
-
-//! Helper class for accessing Value of object type.
-/*!
- Instance of this helper class is obtained by \c GenericValue::GetObject().
- In addition to all APIs for array type, it provides range-based for loop if \c RAPIDJSON_HAS_CXX11_RANGE_FOR=1.
-*/
-template <bool Const, typename ValueT>
-class GenericObject {
-public:
- typedef GenericObject<true, ValueT> ConstObject;
- typedef GenericObject<false, ValueT> Object;
- typedef ValueT PlainType;
- typedef typename internal::MaybeAddConst<Const,PlainType>::Type ValueType;
- typedef GenericMemberIterator<Const, typename ValueT::EncodingType, typename ValueT::AllocatorType> MemberIterator; // This may be const or non-const iterator
- typedef GenericMemberIterator<true, typename ValueT::EncodingType, typename ValueT::AllocatorType> ConstMemberIterator;
- typedef typename ValueType::AllocatorType AllocatorType;
- typedef typename ValueType::StringRefType StringRefType;
- typedef typename ValueType::EncodingType EncodingType;
- typedef typename ValueType::Ch Ch;
-
- template <typename, typename>
- friend class GenericValue;
-
- GenericObject(const GenericObject& rhs) : value_(rhs.value_) {}
- GenericObject& operator=(const GenericObject& rhs) { value_ = rhs.value_; return *this; }
- ~GenericObject() {}
-
- SizeType MemberCount() const { return value_.MemberCount(); }
- bool ObjectEmpty() const { return value_.ObjectEmpty(); }
- template <typename T> ValueType& operator[](T* name) const { return value_[name]; }
- template <typename SourceAllocator> ValueType& operator[](const GenericValue<EncodingType, SourceAllocator>& name) const { return value_[name]; }
-#if RAPIDJSON_HAS_STDSTRING
- ValueType& operator[](const std::basic_string<Ch>& name) const { return value_[name]; }
-#endif
- MemberIterator MemberBegin() const { return value_.MemberBegin(); }
- MemberIterator MemberEnd() const { return value_.MemberEnd(); }
- bool HasMember(const Ch* name) const { return value_.HasMember(name); }
-#if RAPIDJSON_HAS_STDSTRING
- bool HasMember(const std::basic_string<Ch>& name) const { return value_.HasMember(name); }
-#endif
- template <typename SourceAllocator> bool HasMember(const GenericValue<EncodingType, SourceAllocator>& name) const { return value_.HasMember(name); }
- MemberIterator FindMember(const Ch* name) const { return value_.FindMember(name); }
- template <typename SourceAllocator> MemberIterator FindMember(const GenericValue<EncodingType, SourceAllocator>& name) const { return value_.FindMember(name); }
-#if RAPIDJSON_HAS_STDSTRING
- MemberIterator FindMember(const std::basic_string<Ch>& name) const { return value_.FindMember(name); }
-#endif
- GenericObject AddMember(ValueType& name, ValueType& value, AllocatorType& allocator) const { value_.AddMember(name, value, allocator); return *this; }
- GenericObject AddMember(ValueType& name, StringRefType value, AllocatorType& allocator) const { value_.AddMember(name, value, allocator); return *this; }
-#if RAPIDJSON_HAS_STDSTRING
- GenericObject AddMember(ValueType& name, std::basic_string<Ch>& value, AllocatorType& allocator) const { value_.AddMember(name, value, allocator); return *this; }
-#endif
- template <typename T> RAPIDJSON_DISABLEIF_RETURN((internal::OrExpr<internal::IsPointer<T>, internal::IsGenericValue<T> >), (ValueType&)) AddMember(ValueType& name, T value, AllocatorType& allocator) const { value_.AddMember(name, value, allocator); return *this; }
-#if RAPIDJSON_HAS_CXX11_RVALUE_REFS
- GenericObject AddMember(ValueType&& name, ValueType&& value, AllocatorType& allocator) const { value_.AddMember(name, value, allocator); return *this; }
- GenericObject AddMember(ValueType&& name, ValueType& value, AllocatorType& allocator) const { value_.AddMember(name, value, allocator); return *this; }
- GenericObject AddMember(ValueType& name, ValueType&& value, AllocatorType& allocator) const { value_.AddMember(name, value, allocator); return *this; }
- GenericObject AddMember(StringRefType name, ValueType&& value, AllocatorType& allocator) const { value_.AddMember(name, value, allocator); return *this; }
-#endif // RAPIDJSON_HAS_CXX11_RVALUE_REFS
- GenericObject AddMember(StringRefType name, ValueType& value, AllocatorType& allocator) const { value_.AddMember(name, value, allocator); return *this; }
- GenericObject AddMember(StringRefType name, StringRefType value, AllocatorType& allocator) const { value_.AddMember(name, value, allocator); return *this; }
- template <typename T> RAPIDJSON_DISABLEIF_RETURN((internal::OrExpr<internal::IsPointer<T>, internal::IsGenericValue<T> >), (GenericObject)) AddMember(StringRefType name, T value, AllocatorType& allocator) const { value_.AddMember(name, value, allocator); return *this; }
- void RemoveAllMembers() { return value_.RemoveAllMembers(); }
- bool RemoveMember(const Ch* name) const { return value_.RemoveMember(name); }
-#if RAPIDJSON_HAS_STDSTRING
- bool RemoveMember(const std::basic_string<Ch>& name) const { return value_.RemoveMember(name); }
-#endif
- template <typename SourceAllocator> bool RemoveMember(const GenericValue<EncodingType, SourceAllocator>& name) const { return value_.RemoveMember(name); }
- MemberIterator RemoveMember(MemberIterator m) const { return value_.RemoveMember(m); }
- MemberIterator EraseMember(ConstMemberIterator pos) const { return value_.EraseMember(pos); }
- MemberIterator EraseMember(ConstMemberIterator first, ConstMemberIterator last) const { return value_.EraseMember(first, last); }
- bool EraseMember(const Ch* name) const { return value_.EraseMember(name); }
-#if RAPIDJSON_HAS_STDSTRING
- bool EraseMember(const std::basic_string<Ch>& name) const { return EraseMember(ValueType(StringRef(name))); }
-#endif
- template <typename SourceAllocator> bool EraseMember(const GenericValue<EncodingType, SourceAllocator>& name) const { return value_.EraseMember(name); }
-
-#if RAPIDJSON_HAS_CXX11_RANGE_FOR
- MemberIterator begin() const { return value_.MemberBegin(); }
- MemberIterator end() const { return value_.MemberEnd(); }
-#endif
-
-private:
- GenericObject();
- GenericObject(ValueType& value) : value_(value) {}
- ValueType& value_;
-};
-
-RAPIDJSON_NAMESPACE_END
-RAPIDJSON_DIAG_POP
-
-#endif // RAPIDJSON_DOCUMENT_H_
diff --git a/include/rapidjson/error/error.h b/include/rapidjson/error/error.h
deleted file mode 100644
index 95cb31a7..00000000
--- a/include/rapidjson/error/error.h
+++ /dev/null
@@ -1,155 +0,0 @@
-// Tencent is pleased to support the open source community by making RapidJSON available.
-//
-// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
-//
-// Licensed under the MIT License (the "License"); you may not use this file except
-// in compliance with the License. You may obtain a copy of the License at
-//
-// http://opensource.org/licenses/MIT
-//
-// Unless required by applicable law or agreed to in writing, software distributed
-// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
-// CONDITIONS OF ANY KIND, either express or implied. See the License for the
-// specific language governing permissions and limitations under the License.
-
-#ifndef RAPIDJSON_ERROR_ERROR_H_
-#define RAPIDJSON_ERROR_ERROR_H_
-
-#include "../rapidjson.h"
-
-#ifdef __clang__
-RAPIDJSON_DIAG_PUSH
-RAPIDJSON_DIAG_OFF(padded)
-#endif
-
-/*! \file error.h */
-
-/*! \defgroup RAPIDJSON_ERRORS RapidJSON error handling */
-
-///////////////////////////////////////////////////////////////////////////////
-// RAPIDJSON_ERROR_CHARTYPE
-
-//! Character type of error messages.
-/*! \ingroup RAPIDJSON_ERRORS
- The default character type is \c char.
- On Windows, user can define this macro as \c TCHAR for supporting both
- unicode/non-unicode settings.
-*/
-#ifndef RAPIDJSON_ERROR_CHARTYPE
-#define RAPIDJSON_ERROR_CHARTYPE char
-#endif
-
-///////////////////////////////////////////////////////////////////////////////
-// RAPIDJSON_ERROR_STRING
-
-//! Macro for converting string literial to \ref RAPIDJSON_ERROR_CHARTYPE[].
-/*! \ingroup RAPIDJSON_ERRORS
- By default this conversion macro does nothing.
- On Windows, user can define this macro as \c _T(x) for supporting both
- unicode/non-unicode settings.
-*/
-#ifndef RAPIDJSON_ERROR_STRING
-#define RAPIDJSON_ERROR_STRING(x) x
-#endif
-
-RAPIDJSON_NAMESPACE_BEGIN
-
-///////////////////////////////////////////////////////////////////////////////
-// ParseErrorCode
-
-//! Error code of parsing.
-/*! \ingroup RAPIDJSON_ERRORS
- \see GenericReader::Parse, GenericReader::GetParseErrorCode
-*/
-enum ParseErrorCode {
- kParseErrorNone = 0, //!< No error.
-
- kParseErrorDocumentEmpty, //!< The document is empty.
- kParseErrorDocumentRootNotSingular, //!< The document root must not follow by other values.
-
- kParseErrorValueInvalid, //!< Invalid value.
-
- kParseErrorObjectMissName, //!< Missing a name for object member.
- kParseErrorObjectMissColon, //!< Missing a colon after a name of object member.
- kParseErrorObjectMissCommaOrCurlyBracket, //!< Missing a comma or '}' after an object member.
-
- kParseErrorArrayMissCommaOrSquareBracket, //!< Missing a comma or ']' after an array element.
-
- kParseErrorStringUnicodeEscapeInvalidHex, //!< Incorrect hex digit after \\u escape in string.
- kParseErrorStringUnicodeSurrogateInvalid, //!< The surrogate pair in string is invalid.
- kParseErrorStringEscapeInvalid, //!< Invalid escape character in string.
- kParseErrorStringMissQuotationMark, //!< Missing a closing quotation mark in string.
- kParseErrorStringInvalidEncoding, //!< Invalid encoding in string.
-
- kParseErrorNumberTooBig, //!< Number too big to be stored in double.
- kParseErrorNumberMissFraction, //!< Miss fraction part in number.
- kParseErrorNumberMissExponent, //!< Miss exponent in number.
-
- kParseErrorTermination, //!< Parsing was terminated.
- kParseErrorUnspecificSyntaxError //!< Unspecific syntax error.
-};
-
-//! Result of parsing (wraps ParseErrorCode)
-/*!
- \ingroup RAPIDJSON_ERRORS
- \code
- Document doc;
- ParseResult ok = doc.Parse("[42]");
- if (!ok) {
- fprintf(stderr, "JSON parse error: %s (%u)",
- GetParseError_En(ok.Code()), ok.Offset());
- exit(EXIT_FAILURE);
- }
- \endcode
- \see GenericReader::Parse, GenericDocument::Parse
-*/
-struct ParseResult {
-public:
- //! Default constructor, no error.
- ParseResult() : code_(kParseErrorNone), offset_(0) {}
- //! Constructor to set an error.
- ParseResult(ParseErrorCode code, size_t offset) : code_(code), offset_(offset) {}
-
- //! Get the error code.
- ParseErrorCode Code() const { return code_; }
- //! Get the error offset, if \ref IsError(), 0 otherwise.
- size_t Offset() const { return offset_; }
-
- //! Conversion to \c bool, returns \c true, iff !\ref IsError().
- operator bool() const { return !IsError(); }
- //! Whether the result is an error.
- bool IsError() const { return code_ != kParseErrorNone; }
-
- bool operator==(const ParseResult& that) const { return code_ == that.code_; }
- bool operator==(ParseErrorCode code) const { return code_ == code; }
- friend bool operator==(ParseErrorCode code, const ParseResult & err) { return code == err.code_; }
-
- //! Reset error code.
- void Clear() { Set(kParseErrorNone); }
- //! Update error code and offset.
- void Set(ParseErrorCode code, size_t offset = 0) { code_ = code; offset_ = offset; }
-
-private:
- ParseErrorCode code_;
- size_t offset_;
-};
-
-//! Function pointer type of GetParseError().
-/*! \ingroup RAPIDJSON_ERRORS
-
- This is the prototype for \c GetParseError_X(), where \c X is a locale.
- User can dynamically change locale in runtime, e.g.:
-\code
- GetParseErrorFunc GetParseError = GetParseError_En; // or whatever
- const RAPIDJSON_ERROR_CHARTYPE* s = GetParseError(document.GetParseErrorCode());
-\endcode
-*/
-typedef const RAPIDJSON_ERROR_CHARTYPE* (*GetParseErrorFunc)(ParseErrorCode);
-
-RAPIDJSON_NAMESPACE_END
-
-#ifdef __clang__
-RAPIDJSON_DIAG_POP
-#endif
-
-#endif // RAPIDJSON_ERROR_ERROR_H_
diff --git a/include/rapidjson/internal/biginteger.h b/include/rapidjson/internal/biginteger.h
deleted file mode 100644
index 9d3e88c9..00000000
--- a/include/rapidjson/internal/biginteger.h
+++ /dev/null
@@ -1,290 +0,0 @@
-// Tencent is pleased to support the open source community by making RapidJSON available.
-//
-// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
-//
-// Licensed under the MIT License (the "License"); you may not use this file except
-// in compliance with the License. You may obtain a copy of the License at
-//
-// http://opensource.org/licenses/MIT
-//
-// Unless required by applicable law or agreed to in writing, software distributed
-// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
-// CONDITIONS OF ANY KIND, either express or implied. See the License for the
-// specific language governing permissions and limitations under the License.
-
-#ifndef RAPIDJSON_BIGINTEGER_H_
-#define RAPIDJSON_BIGINTEGER_H_
-
-#include "../rapidjson.h"
-
-#if defined(_MSC_VER) && defined(_M_AMD64)
-#include <intrin.h> // for _umul128
-#pragma intrinsic(_umul128)
-#endif
-
-RAPIDJSON_NAMESPACE_BEGIN
-namespace internal {
-
-class BigInteger {
-public:
- typedef uint64_t Type;
-
- BigInteger(const BigInteger& rhs) : count_(rhs.count_) {
- std::memcpy(digits_, rhs.digits_, count_ * sizeof(Type));
- }
-
- explicit BigInteger(uint64_t u) : count_(1) {
- digits_[0] = u;
- }
-
- BigInteger(const char* decimals, size_t length) : count_(1) {
- RAPIDJSON_ASSERT(length > 0);
- digits_[0] = 0;
- size_t i = 0;
- const size_t kMaxDigitPerIteration = 19; // 2^64 = 18446744073709551616 > 10^19
- while (length >= kMaxDigitPerIteration) {
- AppendDecimal64(decimals + i, decimals + i + kMaxDigitPerIteration);
- length -= kMaxDigitPerIteration;
- i += kMaxDigitPerIteration;
- }
-
- if (length > 0)
- AppendDecimal64(decimals + i, decimals + i + length);
- }
-
- BigInteger& operator=(const BigInteger &rhs)
- {
- if (this != &rhs) {
- count_ = rhs.count_;
- std::memcpy(digits_, rhs.digits_, count_ * sizeof(Type));
- }
- return *this;
- }
-
- BigInteger& operator=(uint64_t u) {
- digits_[0] = u;
- count_ = 1;
- return *this;
- }
-
- BigInteger& operator+=(uint64_t u) {
- Type backup = digits_[0];
- digits_[0] += u;
- for (size_t i = 0; i < count_ - 1; i++) {
- if (digits_[i] >= backup)
- return *this; // no carry
- backup = digits_[i + 1];
- digits_[i + 1] += 1;
- }
-
- // Last carry
- if (digits_[count_ - 1] < backup)
- PushBack(1);
-
- return *this;
- }
-
- BigInteger& operator*=(uint64_t u) {
- if (u == 0) return *this = 0;
- if (u == 1) return *this;
- if (*this == 1) return *this = u;
-
- uint64_t k = 0;
- for (size_t i = 0; i < count_; i++) {
- uint64_t hi;
- digits_[i] = MulAdd64(digits_[i], u, k, &hi);
- k = hi;
- }
-
- if (k > 0)
- PushBack(k);
-
- return *this;
- }
-
- BigInteger& operator*=(uint32_t u) {
- if (u == 0) return *this = 0;
- if (u == 1) return *this;
- if (*this == 1) return *this = u;
-
- uint64_t k = 0;
- for (size_t i = 0; i < count_; i++) {
- const uint64_t c = digits_[i] >> 32;
- const uint64_t d = digits_[i] & 0xFFFFFFFF;
- const uint64_t uc = u * c;
- const uint64_t ud = u * d;
- const uint64_t p0 = ud + k;
- const uint64_t p1 = uc + (p0 >> 32);
- digits_[i] = (p0 & 0xFFFFFFFF) | (p1 << 32);
- k = p1 >> 32;
- }
-
- if (k > 0)
- PushBack(k);
-
- return *this;
- }
-
- BigInteger& operator<<=(size_t shift) {
- if (IsZero() || shift == 0) return *this;
-
- size_t offset = shift / kTypeBit;
- size_t interShift = shift % kTypeBit;
- RAPIDJSON_ASSERT(count_ + offset <= kCapacity);
-
- if (interShift == 0) {
- std::memmove(&digits_[count_ - 1 + offset], &digits_[count_ - 1], count_ * sizeof(Type));
- count_ += offset;
- }
- else {
- digits_[count_] = 0;
- for (size_t i = count_; i > 0; i--)
- digits_[i + offset] = (digits_[i] << interShift) | (digits_[i - 1] >> (kTypeBit - interShift));
- digits_[offset] = digits_[0] << interShift;
- count_ += offset;
- if (digits_[count_])
- count_++;
- }
-
- std::memset(digits_, 0, offset * sizeof(Type));
-
- return *this;
- }
-
- bool operator==(const BigInteger& rhs) const {
- return count_ == rhs.count_ && std::memcmp(digits_, rhs.digits_, count_ * sizeof(Type)) == 0;
- }
-
- bool operator==(const Type rhs) const {
- return count_ == 1 && digits_[0] == rhs;
- }
-
- BigInteger& MultiplyPow5(unsigned exp) {
- static const uint32_t kPow5[12] = {
- 5,
- 5 * 5,
- 5 * 5 * 5,
- 5 * 5 * 5 * 5,
- 5 * 5 * 5 * 5 * 5,
- 5 * 5 * 5 * 5 * 5 * 5,
- 5 * 5 * 5 * 5 * 5 * 5 * 5,
- 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5,
- 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5,
- 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5,
- 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5,
- 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5
- };
- if (exp == 0) return *this;
- for (; exp >= 27; exp -= 27) *this *= RAPIDJSON_UINT64_C2(0X6765C793, 0XFA10079D); // 5^27
- for (; exp >= 13; exp -= 13) *this *= static_cast<uint32_t>(1220703125u); // 5^13
- if (exp > 0) *this *= kPow5[exp - 1];
- return *this;
- }
-
- // Compute absolute difference of this and rhs.
- // Assume this != rhs
- bool Difference(const BigInteger& rhs, BigInteger* out) const {
- int cmp = Compare(rhs);
- RAPIDJSON_ASSERT(cmp != 0);
- const BigInteger *a, *b; // Makes a > b
- bool ret;
- if (cmp < 0) { a = &rhs; b = this; ret = true; }
- else { a = this; b = &rhs; ret = false; }
-
- Type borrow = 0;
- for (size_t i = 0; i < a->count_; i++) {
- Type d = a->digits_[i] - borrow;
- if (i < b->count_)
- d -= b->digits_[i];
- borrow = (d > a->digits_[i]) ? 1 : 0;
- out->digits_[i] = d;
- if (d != 0)
- out->count_ = i + 1;
- }
-
- return ret;
- }
-
- int Compare(const BigInteger& rhs) const {
- if (count_ != rhs.count_)
- return count_ < rhs.count_ ? -1 : 1;
-
- for (size_t i = count_; i-- > 0;)
- if (digits_[i] != rhs.digits_[i])
- return digits_[i] < rhs.digits_[i] ? -1 : 1;
-
- return 0;
- }
-
- size_t GetCount() const { return count_; }
- Type GetDigit(size_t index) const { RAPIDJSON_ASSERT(index < count_); return digits_[index]; }
- bool IsZero() const { return count_ == 1 && digits_[0] == 0; }
-
-private:
- void AppendDecimal64(const char* begin, const char* end) {
- uint64_t u = ParseUint64(begin, end);
- if (IsZero())
- *this = u;
- else {
- unsigned exp = static_cast<unsigned>(end - begin);
- (MultiplyPow5(exp) <<= exp) += u; // *this = *this * 10^exp + u
- }
- }
-
- void PushBack(Type digit) {
- RAPIDJSON_ASSERT(count_ < kCapacity);
- digits_[count_++] = digit;
- }
-
- static uint64_t ParseUint64(const char* begin, const char* end) {
- uint64_t r = 0;
- for (const char* p = begin; p != end; ++p) {
- RAPIDJSON_ASSERT(*p >= '0' && *p <= '9');
- r = r * 10u + static_cast<unsigned>(*p - '0');
- }
- return r;
- }
-
- // Assume a * b + k < 2^128
- static uint64_t MulAdd64(uint64_t a, uint64_t b, uint64_t k, uint64_t* outHigh) {
-#if defined(_MSC_VER) && defined(_M_AMD64)
- uint64_t low = _umul128(a, b, outHigh) + k;
- if (low < k)
- (*outHigh)++;
- return low;
-#elif (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6)) && defined(__x86_64__)
- __extension__ typedef unsigned __int128 uint128;
- uint128 p = static_cast<uint128>(a) * static_cast<uint128>(b);
- p += k;
- *outHigh = static_cast<uint64_t>(p >> 64);
- return static_cast<uint64_t>(p);
-#else
- const uint64_t a0 = a & 0xFFFFFFFF, a1 = a >> 32, b0 = b & 0xFFFFFFFF, b1 = b >> 32;
- uint64_t x0 = a0 * b0, x1 = a0 * b1, x2 = a1 * b0, x3 = a1 * b1;
- x1 += (x0 >> 32); // can't give carry
- x1 += x2;
- if (x1 < x2)
- x3 += (static_cast<uint64_t>(1) << 32);
- uint64_t lo = (x1 << 32) + (x0 & 0xFFFFFFFF);
- uint64_t hi = x3 + (x1 >> 32);
-
- lo += k;
- if (lo < k)
- hi++;
- *outHigh = hi;
- return lo;
-#endif
- }
-
- static const size_t kBitCount = 3328; // 64bit * 54 > 10^1000
- static const size_t kCapacity = kBitCount / sizeof(Type);
- static const size_t kTypeBit = sizeof(Type) * 8;
-
- Type digits_[kCapacity];
- size_t count_;
-};
-
-} // namespace internal
-RAPIDJSON_NAMESPACE_END
-
-#endif // RAPIDJSON_BIGINTEGER_H_
diff --git a/include/rapidjson/internal/diyfp.h b/include/rapidjson/internal/diyfp.h
deleted file mode 100644
index c9fefdc6..00000000
--- a/include/rapidjson/internal/diyfp.h
+++ /dev/null
@@ -1,258 +0,0 @@
-// Tencent is pleased to support the open source community by making RapidJSON available.
-//
-// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
-//
-// Licensed under the MIT License (the "License"); you may not use this file except
-// in compliance with the License. You may obtain a copy of the License at
-//
-// http://opensource.org/licenses/MIT
-//
-// Unless required by applicable law or agreed to in writing, software distributed
-// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
-// CONDITIONS OF ANY KIND, either express or implied. See the License for the
-// specific language governing permissions and limitations under the License.
-
-// This is a C++ header-only implementation of Grisu2 algorithm from the publication:
-// Loitsch, Florian. "Printing floating-point numbers quickly and accurately with
-// integers." ACM Sigplan Notices 45.6 (2010): 233-243.
-
-#ifndef RAPIDJSON_DIYFP_H_
-#define RAPIDJSON_DIYFP_H_
-
-#include "../rapidjson.h"
-
-#if defined(_MSC_VER) && defined(_M_AMD64)
-#include <intrin.h>
-#pragma intrinsic(_BitScanReverse64)
-#pragma intrinsic(_umul128)
-#endif
-
-RAPIDJSON_NAMESPACE_BEGIN
-namespace internal {
-
-#ifdef __GNUC__
-RAPIDJSON_DIAG_PUSH
-RAPIDJSON_DIAG_OFF(effc++)
-#endif
-
-#ifdef __clang__
-RAPIDJSON_DIAG_PUSH
-RAPIDJSON_DIAG_OFF(padded)
-#endif
-
-struct DiyFp {
- DiyFp() : f(), e() {}
-
- DiyFp(uint64_t fp, int exp) : f(fp), e(exp) {}
-
- explicit DiyFp(double d) {
- union {
- double d;
- uint64_t u64;
- } u = { d };
-
- int biased_e = static_cast<int>((u.u64 & kDpExponentMask) >> kDpSignificandSize);
- uint64_t significand = (u.u64 & kDpSignificandMask);
- if (biased_e != 0) {
- f = significand + kDpHiddenBit;
- e = biased_e - kDpExponentBias;
- }
- else {
- f = significand;
- e = kDpMinExponent + 1;
- }
- }
-
- DiyFp operator-(const DiyFp& rhs) const {
- return DiyFp(f - rhs.f, e);
- }
-
- DiyFp operator*(const DiyFp& rhs) const {
-#if defined(_MSC_VER) && defined(_M_AMD64)
- uint64_t h;
- uint64_t l = _umul128(f, rhs.f, &h);
- if (l & (uint64_t(1) << 63)) // rounding
- h++;
- return DiyFp(h, e + rhs.e + 64);
-#elif (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6)) && defined(__x86_64__)
- __extension__ typedef unsigned __int128 uint128;
- uint128 p = static_cast<uint128>(f) * static_cast<uint128>(rhs.f);
- uint64_t h = static_cast<uint64_t>(p >> 64);
- uint64_t l = static_cast<uint64_t>(p);
- if (l & (uint64_t(1) << 63)) // rounding
- h++;
- return DiyFp(h, e + rhs.e + 64);
-#else
- const uint64_t M32 = 0xFFFFFFFF;
- const uint64_t a = f >> 32;
- const uint64_t b = f & M32;
- const uint64_t c = rhs.f >> 32;
- const uint64_t d = rhs.f & M32;
- const uint64_t ac = a * c;
- const uint64_t bc = b * c;
- const uint64_t ad = a * d;
- const uint64_t bd = b * d;
- uint64_t tmp = (bd >> 32) + (ad & M32) + (bc & M32);
- tmp += 1U << 31; /// mult_round
- return DiyFp(ac + (ad >> 32) + (bc >> 32) + (tmp >> 32), e + rhs.e + 64);
-#endif
- }
-
- DiyFp Normalize() const {
-#if defined(_MSC_VER) && defined(_M_AMD64)
- unsigned long index;
- _BitScanReverse64(&index, f);
- return DiyFp(f << (63 - index), e - (63 - index));
-#elif defined(__GNUC__) && __GNUC__ >= 4
- int s = __builtin_clzll(f);
- return DiyFp(f << s, e - s);
-#else
- DiyFp res = *this;
- while (!(res.f & (static_cast<uint64_t>(1) << 63))) {
- res.f <<= 1;
- res.e--;
- }
- return res;
-#endif
- }
-
- DiyFp NormalizeBoundary() const {
- DiyFp res = *this;
- while (!(res.f & (kDpHiddenBit << 1))) {
- res.f <<= 1;
- res.e--;
- }
- res.f <<= (kDiySignificandSize - kDpSignificandSize - 2);
- res.e = res.e - (kDiySignificandSize - kDpSignificandSize - 2);
- return res;
- }
-
- void NormalizedBoundaries(DiyFp* minus, DiyFp* plus) const {
- DiyFp pl = DiyFp((f << 1) + 1, e - 1).NormalizeBoundary();
- DiyFp mi = (f == kDpHiddenBit) ? DiyFp((f << 2) - 1, e - 2) : DiyFp((f << 1) - 1, e - 1);
- mi.f <<= mi.e - pl.e;
- mi.e = pl.e;
- *plus = pl;
- *minus = mi;
- }
-
- double ToDouble() const {
- union {
- double d;
- uint64_t u64;
- }u;
- const uint64_t be = (e == kDpDenormalExponent && (f & kDpHiddenBit) == 0) ? 0 :
- static_cast<uint64_t>(e + kDpExponentBias);
- u.u64 = (f & kDpSignificandMask) | (be << kDpSignificandSize);
- return u.d;
- }
-
- static const int kDiySignificandSize = 64;
- static const int kDpSignificandSize = 52;
- static const int kDpExponentBias = 0x3FF + kDpSignificandSize;
- static const int kDpMaxExponent = 0x7FF - kDpExponentBias;
- static const int kDpMinExponent = -kDpExponentBias;
- static const int kDpDenormalExponent = -kDpExponentBias + 1;
- static const uint64_t kDpExponentMask = RAPIDJSON_UINT64_C2(0x7FF00000, 0x00000000);
- static const uint64_t kDpSignificandMask = RAPIDJSON_UINT64_C2(0x000FFFFF, 0xFFFFFFFF);
- static const uint64_t kDpHiddenBit = RAPIDJSON_UINT64_C2(0x00100000, 0x00000000);
-
- uint64_t f;
- int e;
-};
-
-inline DiyFp GetCachedPowerByIndex(size_t index) {
- // 10^-348, 10^-340, ..., 10^340
- static const uint64_t kCachedPowers_F[] = {
- RAPIDJSON_UINT64_C2(0xfa8fd5a0, 0x081c0288), RAPIDJSON_UINT64_C2(0xbaaee17f, 0xa23ebf76),
- RAPIDJSON_UINT64_C2(0x8b16fb20, 0x3055ac76), RAPIDJSON_UINT64_C2(0xcf42894a, 0x5dce35ea),
- RAPIDJSON_UINT64_C2(0x9a6bb0aa, 0x55653b2d), RAPIDJSON_UINT64_C2(0xe61acf03, 0x3d1a45df),
- RAPIDJSON_UINT64_C2(0xab70fe17, 0xc79ac6ca), RAPIDJSON_UINT64_C2(0xff77b1fc, 0xbebcdc4f),
- RAPIDJSON_UINT64_C2(0xbe5691ef, 0x416bd60c), RAPIDJSON_UINT64_C2(0x8dd01fad, 0x907ffc3c),
- RAPIDJSON_UINT64_C2(0xd3515c28, 0x31559a83), RAPIDJSON_UINT64_C2(0x9d71ac8f, 0xada6c9b5),
- RAPIDJSON_UINT64_C2(0xea9c2277, 0x23ee8bcb), RAPIDJSON_UINT64_C2(0xaecc4991, 0x4078536d),
- RAPIDJSON_UINT64_C2(0x823c1279, 0x5db6ce57), RAPIDJSON_UINT64_C2(0xc2109436, 0x4dfb5637),
- RAPIDJSON_UINT64_C2(0x9096ea6f, 0x3848984f), RAPIDJSON_UINT64_C2(0xd77485cb, 0x25823ac7),
- RAPIDJSON_UINT64_C2(0xa086cfcd, 0x97bf97f4), RAPIDJSON_UINT64_C2(0xef340a98, 0x172aace5),
- RAPIDJSON_UINT64_C2(0xb23867fb, 0x2a35b28e), RAPIDJSON_UINT64_C2(0x84c8d4df, 0xd2c63f3b),
- RAPIDJSON_UINT64_C2(0xc5dd4427, 0x1ad3cdba), RAPIDJSON_UINT64_C2(0x936b9fce, 0xbb25c996),
- RAPIDJSON_UINT64_C2(0xdbac6c24, 0x7d62a584), RAPIDJSON_UINT64_C2(0xa3ab6658, 0x0d5fdaf6),
- RAPIDJSON_UINT64_C2(0xf3e2f893, 0xdec3f126), RAPIDJSON_UINT64_C2(0xb5b5ada8, 0xaaff80b8),
- RAPIDJSON_UINT64_C2(0x87625f05, 0x6c7c4a8b), RAPIDJSON_UINT64_C2(0xc9bcff60, 0x34c13053),
- RAPIDJSON_UINT64_C2(0x964e858c, 0x91ba2655), RAPIDJSON_UINT64_C2(0xdff97724, 0x70297ebd),
- RAPIDJSON_UINT64_C2(0xa6dfbd9f, 0xb8e5b88f), RAPIDJSON_UINT64_C2(0xf8a95fcf, 0x88747d94),
- RAPIDJSON_UINT64_C2(0xb9447093, 0x8fa89bcf), RAPIDJSON_UINT64_C2(0x8a08f0f8, 0xbf0f156b),
- RAPIDJSON_UINT64_C2(0xcdb02555, 0x653131b6), RAPIDJSON_UINT64_C2(0x993fe2c6, 0xd07b7fac),
- RAPIDJSON_UINT64_C2(0xe45c10c4, 0x2a2b3b06), RAPIDJSON_UINT64_C2(0xaa242499, 0x697392d3),
- RAPIDJSON_UINT64_C2(0xfd87b5f2, 0x8300ca0e), RAPIDJSON_UINT64_C2(0xbce50864, 0x92111aeb),
- RAPIDJSON_UINT64_C2(0x8cbccc09, 0x6f5088cc), RAPIDJSON_UINT64_C2(0xd1b71758, 0xe219652c),
- RAPIDJSON_UINT64_C2(0x9c400000, 0x00000000), RAPIDJSON_UINT64_C2(0xe8d4a510, 0x00000000),
- RAPIDJSON_UINT64_C2(0xad78ebc5, 0xac620000), RAPIDJSON_UINT64_C2(0x813f3978, 0xf8940984),
- RAPIDJSON_UINT64_C2(0xc097ce7b, 0xc90715b3), RAPIDJSON_UINT64_C2(0x8f7e32ce, 0x7bea5c70),
- RAPIDJSON_UINT64_C2(0xd5d238a4, 0xabe98068), RAPIDJSON_UINT64_C2(0x9f4f2726, 0x179a2245),
- RAPIDJSON_UINT64_C2(0xed63a231, 0xd4c4fb27), RAPIDJSON_UINT64_C2(0xb0de6538, 0x8cc8ada8),
- RAPIDJSON_UINT64_C2(0x83c7088e, 0x1aab65db), RAPIDJSON_UINT64_C2(0xc45d1df9, 0x42711d9a),
- RAPIDJSON_UINT64_C2(0x924d692c, 0xa61be758), RAPIDJSON_UINT64_C2(0xda01ee64, 0x1a708dea),
- RAPIDJSON_UINT64_C2(0xa26da399, 0x9aef774a), RAPIDJSON_UINT64_C2(0xf209787b, 0xb47d6b85),
- RAPIDJSON_UINT64_C2(0xb454e4a1, 0x79dd1877), RAPIDJSON_UINT64_C2(0x865b8692, 0x5b9bc5c2),
- RAPIDJSON_UINT64_C2(0xc83553c5, 0xc8965d3d), RAPIDJSON_UINT64_C2(0x952ab45c, 0xfa97a0b3),
- RAPIDJSON_UINT64_C2(0xde469fbd, 0x99a05fe3), RAPIDJSON_UINT64_C2(0xa59bc234, 0xdb398c25),
- RAPIDJSON_UINT64_C2(0xf6c69a72, 0xa3989f5c), RAPIDJSON_UINT64_C2(0xb7dcbf53, 0x54e9bece),
- RAPIDJSON_UINT64_C2(0x88fcf317, 0xf22241e2), RAPIDJSON_UINT64_C2(0xcc20ce9b, 0xd35c78a5),
- RAPIDJSON_UINT64_C2(0x98165af3, 0x7b2153df), RAPIDJSON_UINT64_C2(0xe2a0b5dc, 0x971f303a),
- RAPIDJSON_UINT64_C2(0xa8d9d153, 0x5ce3b396), RAPIDJSON_UINT64_C2(0xfb9b7cd9, 0xa4a7443c),
- RAPIDJSON_UINT64_C2(0xbb764c4c, 0xa7a44410), RAPIDJSON_UINT64_C2(0x8bab8eef, 0xb6409c1a),
- RAPIDJSON_UINT64_C2(0xd01fef10, 0xa657842c), RAPIDJSON_UINT64_C2(0x9b10a4e5, 0xe9913129),
- RAPIDJSON_UINT64_C2(0xe7109bfb, 0xa19c0c9d), RAPIDJSON_UINT64_C2(0xac2820d9, 0x623bf429),
- RAPIDJSON_UINT64_C2(0x80444b5e, 0x7aa7cf85), RAPIDJSON_UINT64_C2(0xbf21e440, 0x03acdd2d),
- RAPIDJSON_UINT64_C2(0x8e679c2f, 0x5e44ff8f), RAPIDJSON_UINT64_C2(0xd433179d, 0x9c8cb841),
- RAPIDJSON_UINT64_C2(0x9e19db92, 0xb4e31ba9), RAPIDJSON_UINT64_C2(0xeb96bf6e, 0xbadf77d9),
- RAPIDJSON_UINT64_C2(0xaf87023b, 0x9bf0ee6b)
- };
- static const int16_t kCachedPowers_E[] = {
- -1220, -1193, -1166, -1140, -1113, -1087, -1060, -1034, -1007, -980,
- -954, -927, -901, -874, -847, -821, -794, -768, -741, -715,
- -688, -661, -635, -608, -582, -555, -529, -502, -475, -449,
- -422, -396, -369, -343, -316, -289, -263, -236, -210, -183,
- -157, -130, -103, -77, -50, -24, 3, 30, 56, 83,
- 109, 136, 162, 189, 216, 242, 269, 295, 322, 348,
- 375, 402, 428, 455, 481, 508, 534, 561, 588, 614,
- 641, 667, 694, 720, 747, 774, 800, 827, 853, 880,
- 907, 933, 960, 986, 1013, 1039, 1066
- };
- return DiyFp(kCachedPowers_F[index], kCachedPowers_E[index]);
-}
-
-inline DiyFp GetCachedPower(int e, int* K) {
-
- //int k = static_cast<int>(ceil((-61 - e) * 0.30102999566398114)) + 374;
- double dk = (-61 - e) * 0.30102999566398114 + 347; // dk must be positive, so can do ceiling in positive
- int k = static_cast<int>(dk);
- if (dk - k > 0.0)
- k++;
-
- unsigned index = static_cast<unsigned>((k >> 3) + 1);
- *K = -(-348 + static_cast<int>(index << 3)); // decimal exponent no need lookup table
-
- return GetCachedPowerByIndex(index);
-}
-
-inline DiyFp GetCachedPower10(int exp, int *outExp) {
- unsigned index = (static_cast<unsigned>(exp) + 348u) / 8u;
- *outExp = -348 + static_cast<int>(index) * 8;
- return GetCachedPowerByIndex(index);
- }
-
-#ifdef __GNUC__
-RAPIDJSON_DIAG_POP
-#endif
-
-#ifdef __clang__
-RAPIDJSON_DIAG_POP
-RAPIDJSON_DIAG_OFF(padded)
-#endif
-
-} // namespace internal
-RAPIDJSON_NAMESPACE_END
-
-#endif // RAPIDJSON_DIYFP_H_
diff --git a/include/rapidjson/internal/ieee754.h b/include/rapidjson/internal/ieee754.h
deleted file mode 100644
index 82bb0b99..00000000
--- a/include/rapidjson/internal/ieee754.h
+++ /dev/null
@@ -1,78 +0,0 @@
-// Tencent is pleased to support the open source community by making RapidJSON available.
-//
-// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
-//
-// Licensed under the MIT License (the "License"); you may not use this file except
-// in compliance with the License. You may obtain a copy of the License at
-//
-// http://opensource.org/licenses/MIT
-//
-// Unless required by applicable law or agreed to in writing, software distributed
-// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
-// CONDITIONS OF ANY KIND, either express or implied. See the License for the
-// specific language governing permissions and limitations under the License.
-
-#ifndef RAPIDJSON_IEEE754_
-#define RAPIDJSON_IEEE754_
-
-#include "../rapidjson.h"
-
-RAPIDJSON_NAMESPACE_BEGIN
-namespace internal {
-
-class Double {
-public:
- Double() {}
- Double(double d) : d_(d) {}
- Double(uint64_t u) : u_(u) {}
-
- double Value() const { return d_; }
- uint64_t Uint64Value() const { return u_; }
-
- double NextPositiveDouble() const {
- RAPIDJSON_ASSERT(!Sign());
- return Double(u_ + 1).Value();
- }
-
- bool Sign() const { return (u_ & kSignMask) != 0; }
- uint64_t Significand() const { return u_ & kSignificandMask; }
- int Exponent() const { return static_cast<int>(((u_ & kExponentMask) >> kSignificandSize) - kExponentBias); }
-
- bool IsNan() const { return (u_ & kExponentMask) == kExponentMask && Significand() != 0; }
- bool IsInf() const { return (u_ & kExponentMask) == kExponentMask && Significand() == 0; }
- bool IsNanOrInf() const { return (u_ & kExponentMask) == kExponentMask; }
- bool IsNormal() const { return (u_ & kExponentMask) != 0 || Significand() == 0; }
- bool IsZero() const { return (u_ & (kExponentMask | kSignificandMask)) == 0; }
-
- uint64_t IntegerSignificand() const { return IsNormal() ? Significand() | kHiddenBit : Significand(); }
- int IntegerExponent() const { return (IsNormal() ? Exponent() : kDenormalExponent) - kSignificandSize; }
- uint64_t ToBias() const { return (u_ & kSignMask) ? ~u_ + 1 : u_ | kSignMask; }
-
- static unsigned EffectiveSignificandSize(int order) {
- if (order >= -1021)
- return 53;
- else if (order <= -1074)
- return 0;
- else
- return static_cast<unsigned>(order) + 1074;
- }
-
-private:
- static const int kSignificandSize = 52;
- static const int kExponentBias = 0x3FF;
- static const int kDenormalExponent = 1 - kExponentBias;
- static const uint64_t kSignMask = RAPIDJSON_UINT64_C2(0x80000000, 0x00000000);
- static const uint64_t kExponentMask = RAPIDJSON_UINT64_C2(0x7FF00000, 0x00000000);
- static const uint64_t kSignificandMask = RAPIDJSON_UINT64_C2(0x000FFFFF, 0xFFFFFFFF);
- static const uint64_t kHiddenBit = RAPIDJSON_UINT64_C2(0x00100000, 0x00000000);
-
- union {
- double d_;
- uint64_t u_;
- };
-};
-
-} // namespace internal
-RAPIDJSON_NAMESPACE_END
-
-#endif // RAPIDJSON_IEEE754_
diff --git a/include/rapidjson/internal/itoa.h b/include/rapidjson/internal/itoa.h
deleted file mode 100644
index 01a4e7e7..00000000
--- a/include/rapidjson/internal/itoa.h
+++ /dev/null
@@ -1,304 +0,0 @@
-// Tencent is pleased to support the open source community by making RapidJSON available.
-//
-// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
-//
-// Licensed under the MIT License (the "License"); you may not use this file except
-// in compliance with the License. You may obtain a copy of the License at
-//
-// http://opensource.org/licenses/MIT
-//
-// Unless required by applicable law or agreed to in writing, software distributed
-// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
-// CONDITIONS OF ANY KIND, either express or implied. See the License for the
-// specific language governing permissions and limitations under the License.
-
-#ifndef RAPIDJSON_ITOA_
-#define RAPIDJSON_ITOA_
-
-#include "../rapidjson.h"
-
-RAPIDJSON_NAMESPACE_BEGIN
-namespace internal {
-
-inline const char* GetDigitsLut() {
- static const char cDigitsLut[200] = {
- '0','0','0','1','0','2','0','3','0','4','0','5','0','6','0','7','0','8','0','9',
- '1','0','1','1','1','2','1','3','1','4','1','5','1','6','1','7','1','8','1','9',
- '2','0','2','1','2','2','2','3','2','4','2','5','2','6','2','7','2','8','2','9',
- '3','0','3','1','3','2','3','3','3','4','3','5','3','6','3','7','3','8','3','9',
- '4','0','4','1','4','2','4','3','4','4','4','5','4','6','4','7','4','8','4','9',
- '5','0','5','1','5','2','5','3','5','4','5','5','5','6','5','7','5','8','5','9',
- '6','0','6','1','6','2','6','3','6','4','6','5','6','6','6','7','6','8','6','9',
- '7','0','7','1','7','2','7','3','7','4','7','5','7','6','7','7','7','8','7','9',
- '8','0','8','1','8','2','8','3','8','4','8','5','8','6','8','7','8','8','8','9',
- '9','0','9','1','9','2','9','3','9','4','9','5','9','6','9','7','9','8','9','9'
- };
- return cDigitsLut;
-}
-
-inline char* u32toa(uint32_t value, char* buffer) {
- const char* cDigitsLut = GetDigitsLut();
-
- if (value < 10000) {
- const uint32_t d1 = (value / 100) << 1;
- const uint32_t d2 = (value % 100) << 1;
-
- if (value >= 1000)
- *buffer++ = cDigitsLut[d1];
- if (value >= 100)
- *buffer++ = cDigitsLut[d1 + 1];
- if (value >= 10)
- *buffer++ = cDigitsLut[d2];
- *buffer++ = cDigitsLut[d2 + 1];
- }
- else if (value < 100000000) {
- // value = bbbbcccc
- const uint32_t b = value / 10000;
- const uint32_t c = value % 10000;
-
- const uint32_t d1 = (b / 100) << 1;
- const uint32_t d2 = (b % 100) << 1;
-
- const uint32_t d3 = (c / 100) << 1;
- const uint32_t d4 = (c % 100) << 1;
-
- if (value >= 10000000)
- *buffer++ = cDigitsLut[d1];
- if (value >= 1000000)
- *buffer++ = cDigitsLut[d1 + 1];
- if (value >= 100000)
- *buffer++ = cDigitsLut[d2];
- *buffer++ = cDigitsLut[d2 + 1];
-
- *buffer++ = cDigitsLut[d3];
- *buffer++ = cDigitsLut[d3 + 1];
- *buffer++ = cDigitsLut[d4];
- *buffer++ = cDigitsLut[d4 + 1];
- }
- else {
- // value = aabbbbcccc in decimal
-
- const uint32_t a = value / 100000000; // 1 to 42
- value %= 100000000;
-
- if (a >= 10) {
- const unsigned i = a << 1;
- *buffer++ = cDigitsLut[i];
- *buffer++ = cDigitsLut[i + 1];
- }
- else
- *buffer++ = static_cast<char>('0' + static_cast<char>(a));
-
- const uint32_t b = value / 10000; // 0 to 9999
- const uint32_t c = value % 10000; // 0 to 9999
-
- const uint32_t d1 = (b / 100) << 1;
- const uint32_t d2 = (b % 100) << 1;
-
- const uint32_t d3 = (c / 100) << 1;
- const uint32_t d4 = (c % 100) << 1;
-
- *buffer++ = cDigitsLut[d1];
- *buffer++ = cDigitsLut[d1 + 1];
- *buffer++ = cDigitsLut[d2];
- *buffer++ = cDigitsLut[d2 + 1];
- *buffer++ = cDigitsLut[d3];
- *buffer++ = cDigitsLut[d3 + 1];
- *buffer++ = cDigitsLut[d4];
- *buffer++ = cDigitsLut[d4 + 1];
- }
- return buffer;
-}
-
-inline char* i32toa(int32_t value, char* buffer) {
- uint32_t u = static_cast<uint32_t>(value);
- if (value < 0) {
- *buffer++ = '-';
- u = ~u + 1;
- }
-
- return u32toa(u, buffer);
-}
-
-inline char* u64toa(uint64_t value, char* buffer) {
- const char* cDigitsLut = GetDigitsLut();
- const uint64_t kTen8 = 100000000;
- const uint64_t kTen9 = kTen8 * 10;
- const uint64_t kTen10 = kTen8 * 100;
- const uint64_t kTen11 = kTen8 * 1000;
- const uint64_t kTen12 = kTen8 * 10000;
- const uint64_t kTen13 = kTen8 * 100000;
- const uint64_t kTen14 = kTen8 * 1000000;
- const uint64_t kTen15 = kTen8 * 10000000;
- const uint64_t kTen16 = kTen8 * kTen8;
-
- if (value < kTen8) {
- uint32_t v = static_cast<uint32_t>(value);
- if (v < 10000) {
- const uint32_t d1 = (v / 100) << 1;
- const uint32_t d2 = (v % 100) << 1;
-
- if (v >= 1000)
- *buffer++ = cDigitsLut[d1];
- if (v >= 100)
- *buffer++ = cDigitsLut[d1 + 1];
- if (v >= 10)
- *buffer++ = cDigitsLut[d2];
- *buffer++ = cDigitsLut[d2 + 1];
- }
- else {
- // value = bbbbcccc
- const uint32_t b = v / 10000;
- const uint32_t c = v % 10000;
-
- const uint32_t d1 = (b / 100) << 1;
- const uint32_t d2 = (b % 100) << 1;
-
- const uint32_t d3 = (c / 100) << 1;
- const uint32_t d4 = (c % 100) << 1;
-
- if (value >= 10000000)
- *buffer++ = cDigitsLut[d1];
- if (value >= 1000000)
- *buffer++ = cDigitsLut[d1 + 1];
- if (value >= 100000)
- *buffer++ = cDigitsLut[d2];
- *buffer++ = cDigitsLut[d2 + 1];
-
- *buffer++ = cDigitsLut[d3];
- *buffer++ = cDigitsLut[d3 + 1];
- *buffer++ = cDigitsLut[d4];
- *buffer++ = cDigitsLut[d4 + 1];
- }
- }
- else if (value < kTen16) {
- const uint32_t v0 = static_cast<uint32_t>(value / kTen8);
- const uint32_t v1 = static_cast<uint32_t>(value % kTen8);
-
- const uint32_t b0 = v0 / 10000;
- const uint32_t c0 = v0 % 10000;
-
- const uint32_t d1 = (b0 / 100) << 1;
- const uint32_t d2 = (b0 % 100) << 1;
-
- const uint32_t d3 = (c0 / 100) << 1;
- const uint32_t d4 = (c0 % 100) << 1;
-
- const uint32_t b1 = v1 / 10000;
- const uint32_t c1 = v1 % 10000;
-
- const uint32_t d5 = (b1 / 100) << 1;
- const uint32_t d6 = (b1 % 100) << 1;
-
- const uint32_t d7 = (c1 / 100) << 1;
- const uint32_t d8 = (c1 % 100) << 1;
-
- if (value >= kTen15)
- *buffer++ = cDigitsLut[d1];
- if (value >= kTen14)
- *buffer++ = cDigitsLut[d1 + 1];
- if (value >= kTen13)
- *buffer++ = cDigitsLut[d2];
- if (value >= kTen12)
- *buffer++ = cDigitsLut[d2 + 1];
- if (value >= kTen11)
- *buffer++ = cDigitsLut[d3];
- if (value >= kTen10)
- *buffer++ = cDigitsLut[d3 + 1];
- if (value >= kTen9)
- *buffer++ = cDigitsLut[d4];
- if (value >= kTen8)
- *buffer++ = cDigitsLut[d4 + 1];
-
- *buffer++ = cDigitsLut[d5];
- *buffer++ = cDigitsLut[d5 + 1];
- *buffer++ = cDigitsLut[d6];
- *buffer++ = cDigitsLut[d6 + 1];
- *buffer++ = cDigitsLut[d7];
- *buffer++ = cDigitsLut[d7 + 1];
- *buffer++ = cDigitsLut[d8];
- *buffer++ = cDigitsLut[d8 + 1];
- }
- else {
- const uint32_t a = static_cast<uint32_t>(value / kTen16); // 1 to 1844
- value %= kTen16;
-
- if (a < 10)
- *buffer++ = static_cast<char>('0' + static_cast<char>(a));
- else if (a < 100) {
- const uint32_t i = a << 1;
- *buffer++ = cDigitsLut[i];
- *buffer++ = cDigitsLut[i + 1];
- }
- else if (a < 1000) {
- *buffer++ = static_cast<char>('0' + static_cast<char>(a / 100));
-
- const uint32_t i = (a % 100) << 1;
- *buffer++ = cDigitsLut[i];
- *buffer++ = cDigitsLut[i + 1];
- }
- else {
- const uint32_t i = (a / 100) << 1;
- const uint32_t j = (a % 100) << 1;
- *buffer++ = cDigitsLut[i];
- *buffer++ = cDigitsLut[i + 1];
- *buffer++ = cDigitsLut[j];
- *buffer++ = cDigitsLut[j + 1];
- }
-
- const uint32_t v0 = static_cast<uint32_t>(value / kTen8);
- const uint32_t v1 = static_cast<uint32_t>(value % kTen8);
-
- const uint32_t b0 = v0 / 10000;
- const uint32_t c0 = v0 % 10000;
-
- const uint32_t d1 = (b0 / 100) << 1;
- const uint32_t d2 = (b0 % 100) << 1;
-
- const uint32_t d3 = (c0 / 100) << 1;
- const uint32_t d4 = (c0 % 100) << 1;
-
- const uint32_t b1 = v1 / 10000;
- const uint32_t c1 = v1 % 10000;
-
- const uint32_t d5 = (b1 / 100) << 1;
- const uint32_t d6 = (b1 % 100) << 1;
-
- const uint32_t d7 = (c1 / 100) << 1;
- const uint32_t d8 = (c1 % 100) << 1;
-
- *buffer++ = cDigitsLut[d1];
- *buffer++ = cDigitsLut[d1 + 1];
- *buffer++ = cDigitsLut[d2];
- *buffer++ = cDigitsLut[d2 + 1];
- *buffer++ = cDigitsLut[d3];
- *buffer++ = cDigitsLut[d3 + 1];
- *buffer++ = cDigitsLut[d4];
- *buffer++ = cDigitsLut[d4 + 1];
- *buffer++ = cDigitsLut[d5];
- *buffer++ = cDigitsLut[d5 + 1];
- *buffer++ = cDigitsLut[d6];
- *buffer++ = cDigitsLut[d6 + 1];
- *buffer++ = cDigitsLut[d7];
- *buffer++ = cDigitsLut[d7 + 1];
- *buffer++ = cDigitsLut[d8];
- *buffer++ = cDigitsLut[d8 + 1];
- }
-
- return buffer;
-}
-
-inline char* i64toa(int64_t value, char* buffer) {
- uint64_t u = static_cast<uint64_t>(value);
- if (value < 0) {
- *buffer++ = '-';
- u = ~u + 1;
- }
-
- return u64toa(u, buffer);
-}
-
-} // namespace internal
-RAPIDJSON_NAMESPACE_END
-
-#endif // RAPIDJSON_ITOA_
diff --git a/include/rapidjson/internal/meta.h b/include/rapidjson/internal/meta.h
deleted file mode 100644
index 5a9aaa42..00000000
--- a/include/rapidjson/internal/meta.h
+++ /dev/null
@@ -1,181 +0,0 @@
-// Tencent is pleased to support the open source community by making RapidJSON available.
-//
-// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
-//
-// Licensed under the MIT License (the "License"); you may not use this file except
-// in compliance with the License. You may obtain a copy of the License at
-//
-// http://opensource.org/licenses/MIT
-//
-// Unless required by applicable law or agreed to in writing, software distributed
-// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
-// CONDITIONS OF ANY KIND, either express or implied. See the License for the
-// specific language governing permissions and limitations under the License.
-
-#ifndef RAPIDJSON_INTERNAL_META_H_
-#define RAPIDJSON_INTERNAL_META_H_
-
-#include "../rapidjson.h"
-
-#ifdef __GNUC__
-RAPIDJSON_DIAG_PUSH
-RAPIDJSON_DIAG_OFF(effc++)
-#endif
-#if defined(_MSC_VER)
-RAPIDJSON_DIAG_PUSH
-RAPIDJSON_DIAG_OFF(6334)
-#endif
-
-#if RAPIDJSON_HAS_CXX11_TYPETRAITS
-#include <type_traits>
-#endif
-
-//@cond RAPIDJSON_INTERNAL
-RAPIDJSON_NAMESPACE_BEGIN
-namespace internal {
-
-// Helper to wrap/convert arbitrary types to void, useful for arbitrary type matching
-template <typename T> struct Void { typedef void Type; };
-
-///////////////////////////////////////////////////////////////////////////////
-// BoolType, TrueType, FalseType
-//
-template <bool Cond> struct BoolType {
- static const bool Value = Cond;
- typedef BoolType Type;
-};
-typedef BoolType<true> TrueType;
-typedef BoolType<false> FalseType;
-
-
-///////////////////////////////////////////////////////////////////////////////
-// SelectIf, BoolExpr, NotExpr, AndExpr, OrExpr
-//
-
-template <bool C> struct SelectIfImpl { template <typename T1, typename T2> struct Apply { typedef T1 Type; }; };
-template <> struct SelectIfImpl<false> { template <typename T1, typename T2> struct Apply { typedef T2 Type; }; };
-template <bool C, typename T1, typename T2> struct SelectIfCond : SelectIfImpl<C>::template Apply<T1,T2> {};
-template <typename C, typename T1, typename T2> struct SelectIf : SelectIfCond<C::Value, T1, T2> {};
-
-template <bool Cond1, bool Cond2> struct AndExprCond : FalseType {};
-template <> struct AndExprCond<true, true> : TrueType {};
-template <bool Cond1, bool Cond2> struct OrExprCond : TrueType {};
-template <> struct OrExprCond<false, false> : FalseType {};
-
-template <typename C> struct BoolExpr : SelectIf<C,TrueType,FalseType>::Type {};
-template <typename C> struct NotExpr : SelectIf<C,FalseType,TrueType>::Type {};
-template <typename C1, typename C2> struct AndExpr : AndExprCond<C1::Value, C2::Value>::Type {};
-template <typename C1, typename C2> struct OrExpr : OrExprCond<C1::Value, C2::Value>::Type {};
-
-
-///////////////////////////////////////////////////////////////////////////////
-// AddConst, MaybeAddConst, RemoveConst
-template <typename T> struct AddConst { typedef const T Type; };
-template <bool Constify, typename T> struct MaybeAddConst : SelectIfCond<Constify, const T, T> {};
-template <typename T> struct RemoveConst { typedef T Type; };
-template <typename T> struct RemoveConst<const T> { typedef T Type; };
-
-
-///////////////////////////////////////////////////////////////////////////////
-// IsSame, IsConst, IsMoreConst, IsPointer
-//
-template <typename T, typename U> struct IsSame : FalseType {};
-template <typename T> struct IsSame<T, T> : TrueType {};
-
-template <typename T> struct IsConst : FalseType {};
-template <typename T> struct IsConst<const T> : TrueType {};
-
-template <typename CT, typename T>
-struct IsMoreConst
- : AndExpr<IsSame<typename RemoveConst<CT>::Type, typename RemoveConst<T>::Type>,
- BoolType<IsConst<CT>::Value >= IsConst<T>::Value> >::Type {};
-
-template <typename T> struct IsPointer : FalseType {};
-template <typename T> struct IsPointer<T*> : TrueType {};
-
-///////////////////////////////////////////////////////////////////////////////
-// IsBaseOf
-//
-#if RAPIDJSON_HAS_CXX11_TYPETRAITS
-
-template <typename B, typename D> struct IsBaseOf
- : BoolType< ::std::is_base_of<B,D>::value> {};
-
-#else // simplified version adopted from Boost
-
-template<typename B, typename D> struct IsBaseOfImpl {
- RAPIDJSON_STATIC_ASSERT(sizeof(B) != 0);
- RAPIDJSON_STATIC_ASSERT(sizeof(D) != 0);
-
- typedef char (&Yes)[1];
- typedef char (&No) [2];
-
- template <typename T>
- static Yes Check(const D*, T);
- static No Check(const B*, int);
-
- struct Host {
- operator const B*() const;
- operator const D*();
- };
-
- enum { Value = (sizeof(Check(Host(), 0)) == sizeof(Yes)) };
-};
-
-template <typename B, typename D> struct IsBaseOf
- : OrExpr<IsSame<B, D>, BoolExpr<IsBaseOfImpl<B, D> > >::Type {};
-
-#endif // RAPIDJSON_HAS_CXX11_TYPETRAITS
-
-
-//////////////////////////////////////////////////////////////////////////
-// EnableIf / DisableIf
-//
-template <bool Condition, typename T = void> struct EnableIfCond { typedef T Type; };
-template <typename T> struct EnableIfCond<false, T> { /* empty */ };
-
-template <bool Condition, typename T = void> struct DisableIfCond { typedef T Type; };
-template <typename T> struct DisableIfCond<true, T> { /* empty */ };
-
-template <typename Condition, typename T = void>
-struct EnableIf : EnableIfCond<Condition::Value, T> {};
-
-template <typename Condition, typename T = void>
-struct DisableIf : DisableIfCond<Condition::Value, T> {};
-
-// SFINAE helpers
-struct SfinaeTag {};
-template <typename T> struct RemoveSfinaeTag;
-template <typename T> struct RemoveSfinaeTag<SfinaeTag&(*)(T)> { typedef T Type; };
-
-#define RAPIDJSON_REMOVEFPTR_(type) \
- typename ::RAPIDJSON_NAMESPACE::internal::RemoveSfinaeTag \
- < ::RAPIDJSON_NAMESPACE::internal::SfinaeTag&(*) type>::Type
-
-#define RAPIDJSON_ENABLEIF(cond) \
- typename ::RAPIDJSON_NAMESPACE::internal::EnableIf \
- <RAPIDJSON_REMOVEFPTR_(cond)>::Type * = NULL
-
-#define RAPIDJSON_DISABLEIF(cond) \
- typename ::RAPIDJSON_NAMESPACE::internal::DisableIf \
- <RAPIDJSON_REMOVEFPTR_(cond)>::Type * = NULL
-
-#define RAPIDJSON_ENABLEIF_RETURN(cond,returntype) \
- typename ::RAPIDJSON_NAMESPACE::internal::EnableIf \
- <RAPIDJSON_REMOVEFPTR_(cond), \
- RAPIDJSON_REMOVEFPTR_(returntype)>::Type
-
-#define RAPIDJSON_DISABLEIF_RETURN(cond,returntype) \
- typename ::RAPIDJSON_NAMESPACE::internal::DisableIf \
- <RAPIDJSON_REMOVEFPTR_(cond), \
- RAPIDJSON_REMOVEFPTR_(returntype)>::Type
-
-} // namespace internal
-RAPIDJSON_NAMESPACE_END
-//@endcond
-
-#if defined(__GNUC__) || defined(_MSC_VER)
-RAPIDJSON_DIAG_POP
-#endif
-
-#endif // RAPIDJSON_INTERNAL_META_H_
diff --git a/include/rapidjson/internal/pow10.h b/include/rapidjson/internal/pow10.h
deleted file mode 100644
index 02f475d7..00000000
--- a/include/rapidjson/internal/pow10.h
+++ /dev/null
@@ -1,55 +0,0 @@
-// Tencent is pleased to support the open source community by making RapidJSON available.
-//
-// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
-//
-// Licensed under the MIT License (the "License"); you may not use this file except
-// in compliance with the License. You may obtain a copy of the License at
-//
-// http://opensource.org/licenses/MIT
-//
-// Unless required by applicable law or agreed to in writing, software distributed
-// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
-// CONDITIONS OF ANY KIND, either express or implied. See the License for the
-// specific language governing permissions and limitations under the License.
-
-#ifndef RAPIDJSON_POW10_
-#define RAPIDJSON_POW10_
-
-#include "../rapidjson.h"
-
-RAPIDJSON_NAMESPACE_BEGIN
-namespace internal {
-
-//! Computes integer powers of 10 in double (10.0^n).
-/*! This function uses lookup table for fast and accurate results.
- \param n non-negative exponent. Must <= 308.
- \return 10.0^n
-*/
-inline double Pow10(int n) {
- static const double e[] = { // 1e-0...1e308: 309 * 8 bytes = 2472 bytes
- 1e+0,
- 1e+1, 1e+2, 1e+3, 1e+4, 1e+5, 1e+6, 1e+7, 1e+8, 1e+9, 1e+10, 1e+11, 1e+12, 1e+13, 1e+14, 1e+15, 1e+16, 1e+17, 1e+18, 1e+19, 1e+20,
- 1e+21, 1e+22, 1e+23, 1e+24, 1e+25, 1e+26, 1e+27, 1e+28, 1e+29, 1e+30, 1e+31, 1e+32, 1e+33, 1e+34, 1e+35, 1e+36, 1e+37, 1e+38, 1e+39, 1e+40,
- 1e+41, 1e+42, 1e+43, 1e+44, 1e+45, 1e+46, 1e+47, 1e+48, 1e+49, 1e+50, 1e+51, 1e+52, 1e+53, 1e+54, 1e+55, 1e+56, 1e+57, 1e+58, 1e+59, 1e+60,
- 1e+61, 1e+62, 1e+63, 1e+64, 1e+65, 1e+66, 1e+67, 1e+68, 1e+69, 1e+70, 1e+71, 1e+72, 1e+73, 1e+74, 1e+75, 1e+76, 1e+77, 1e+78, 1e+79, 1e+80,
- 1e+81, 1e+82, 1e+83, 1e+84, 1e+85, 1e+86, 1e+87, 1e+88, 1e+89, 1e+90, 1e+91, 1e+92, 1e+93, 1e+94, 1e+95, 1e+96, 1e+97, 1e+98, 1e+99, 1e+100,
- 1e+101,1e+102,1e+103,1e+104,1e+105,1e+106,1e+107,1e+108,1e+109,1e+110,1e+111,1e+112,1e+113,1e+114,1e+115,1e+116,1e+117,1e+118,1e+119,1e+120,
- 1e+121,1e+122,1e+123,1e+124,1e+125,1e+126,1e+127,1e+128,1e+129,1e+130,1e+131,1e+132,1e+133,1e+134,1e+135,1e+136,1e+137,1e+138,1e+139,1e+140,
- 1e+141,1e+142,1e+143,1e+144,1e+145,1e+146,1e+147,1e+148,1e+149,1e+150,1e+151,1e+152,1e+153,1e+154,1e+155,1e+156,1e+157,1e+158,1e+159,1e+160,
- 1e+161,1e+162,1e+163,1e+164,1e+165,1e+166,1e+167,1e+168,1e+169,1e+170,1e+171,1e+172,1e+173,1e+174,1e+175,1e+176,1e+177,1e+178,1e+179,1e+180,
- 1e+181,1e+182,1e+183,1e+184,1e+185,1e+186,1e+187,1e+188,1e+189,1e+190,1e+191,1e+192,1e+193,1e+194,1e+195,1e+196,1e+197,1e+198,1e+199,1e+200,
- 1e+201,1e+202,1e+203,1e+204,1e+205,1e+206,1e+207,1e+208,1e+209,1e+210,1e+211,1e+212,1e+213,1e+214,1e+215,1e+216,1e+217,1e+218,1e+219,1e+220,
- 1e+221,1e+222,1e+223,1e+224,1e+225,1e+226,1e+227,1e+228,1e+229,1e+230,1e+231,1e+232,1e+233,1e+234,1e+235,1e+236,1e+237,1e+238,1e+239,1e+240,
- 1e+241,1e+242,1e+243,1e+244,1e+245,1e+246,1e+247,1e+248,1e+249,1e+250,1e+251,1e+252,1e+253,1e+254,1e+255,1e+256,1e+257,1e+258,1e+259,1e+260,
- 1e+261,1e+262,1e+263,1e+264,1e+265,1e+266,1e+267,1e+268,1e+269,1e+270,1e+271,1e+272,1e+273,1e+274,1e+275,1e+276,1e+277,1e+278,1e+279,1e+280,
- 1e+281,1e+282,1e+283,1e+284,1e+285,1e+286,1e+287,1e+288,1e+289,1e+290,1e+291,1e+292,1e+293,1e+294,1e+295,1e+296,1e+297,1e+298,1e+299,1e+300,
- 1e+301,1e+302,1e+303,1e+304,1e+305,1e+306,1e+307,1e+308
- };
- RAPIDJSON_ASSERT(n >= 0 && n <= 308);
- return e[n];
-}
-
-} // namespace internal
-RAPIDJSON_NAMESPACE_END
-
-#endif // RAPIDJSON_POW10_
diff --git a/include/rapidjson/internal/regex.h b/include/rapidjson/internal/regex.h
deleted file mode 100644
index 422a5240..00000000
--- a/include/rapidjson/internal/regex.h
+++ /dev/null
@@ -1,701 +0,0 @@
-// Tencent is pleased to support the open source community by making RapidJSON available.
-//
-// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
-//
-// Licensed under the MIT License (the "License"); you may not use this file except
-// in compliance with the License. You may obtain a copy of the License at
-//
-// http://opensource.org/licenses/MIT
-//
-// Unless required by applicable law or agreed to in writing, software distributed
-// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
-// CONDITIONS OF ANY KIND, either express or implied. See the License for the
-// specific language governing permissions and limitations under the License.
-
-#ifndef RAPIDJSON_INTERNAL_REGEX_H_
-#define RAPIDJSON_INTERNAL_REGEX_H_
-
-#include "../allocators.h"
-#include "../stream.h"
-#include "stack.h"
-
-#ifdef __clang__
-RAPIDJSON_DIAG_PUSH
-RAPIDJSON_DIAG_OFF(padded)
-RAPIDJSON_DIAG_OFF(switch-enum)
-RAPIDJSON_DIAG_OFF(implicit-fallthrough)
-#endif
-
-#ifdef __GNUC__
-RAPIDJSON_DIAG_PUSH
-RAPIDJSON_DIAG_OFF(effc++)
-#endif
-
-#ifdef _MSC_VER
-RAPIDJSON_DIAG_PUSH
-RAPIDJSON_DIAG_OFF(4512) // assignment operator could not be generated
-#endif
-
-#ifndef RAPIDJSON_REGEX_VERBOSE
-#define RAPIDJSON_REGEX_VERBOSE 0
-#endif
-
-RAPIDJSON_NAMESPACE_BEGIN
-namespace internal {
-
-///////////////////////////////////////////////////////////////////////////////
-// GenericRegex
-
-static const SizeType kRegexInvalidState = ~SizeType(0); //!< Represents an invalid index in GenericRegex::State::out, out1
-static const SizeType kRegexInvalidRange = ~SizeType(0);
-
-//! Regular expression engine with subset of ECMAscript grammar.
-/*!
- Supported regular expression syntax:
- - \c ab Concatenation
- - \c a|b Alternation
- - \c a? Zero or one
- - \c a* Zero or more
- - \c a+ One or more
- - \c a{3} Exactly 3 times
- - \c a{3,} At least 3 times
- - \c a{3,5} 3 to 5 times
- - \c (ab) Grouping
- - \c ^a At the beginning
- - \c a$ At the end
- - \c . Any character
- - \c [abc] Character classes
- - \c [a-c] Character class range
- - \c [a-z0-9_] Character class combination
- - \c [^abc] Negated character classes
- - \c [^a-c] Negated character class range
- - \c [\b] Backspace (U+0008)
- - \c \\| \\\\ ... Escape characters
- - \c \\f Form feed (U+000C)
- - \c \\n Line feed (U+000A)
- - \c \\r Carriage return (U+000D)
- - \c \\t Tab (U+0009)
- - \c \\v Vertical tab (U+000B)
-
- \note This is a Thompson NFA engine, implemented with reference to
- Cox, Russ. "Regular Expression Matching Can Be Simple And Fast (but is slow in Java, Perl, PHP, Python, Ruby,...).",
- https://swtch.com/~rsc/regexp/regexp1.html
-*/
-template <typename Encoding, typename Allocator = CrtAllocator>
-class GenericRegex {
-public:
- typedef typename Encoding::Ch Ch;
-
- GenericRegex(const Ch* source, Allocator* allocator = 0) :
- states_(allocator, 256), ranges_(allocator, 256), root_(kRegexInvalidState), stateCount_(), rangeCount_(),
- stateSet_(), state0_(allocator, 0), state1_(allocator, 0), anchorBegin_(), anchorEnd_()
- {
- GenericStringStream<Encoding> ss(source);
- DecodedStream<GenericStringStream<Encoding> > ds(ss);
- Parse(ds);
- }
-
- ~GenericRegex() {
- Allocator::Free(stateSet_);
- }
-
- bool IsValid() const {
- return root_ != kRegexInvalidState;
- }
-
- template <typename InputStream>
- bool Match(InputStream& is) const {
- return SearchWithAnchoring(is, true, true);
- }
-
- bool Match(const Ch* s) const {
- GenericStringStream<Encoding> is(s);
- return Match(is);
- }
-
- template <typename InputStream>
- bool Search(InputStream& is) const {
- return SearchWithAnchoring(is, anchorBegin_, anchorEnd_);
- }
-
- bool Search(const Ch* s) const {
- GenericStringStream<Encoding> is(s);
- return Search(is);
- }
-
-private:
- enum Operator {
- kZeroOrOne,
- kZeroOrMore,
- kOneOrMore,
- kConcatenation,
- kAlternation,
- kLeftParenthesis
- };
-
- static const unsigned kAnyCharacterClass = 0xFFFFFFFF; //!< For '.'
- static const unsigned kRangeCharacterClass = 0xFFFFFFFE;
- static const unsigned kRangeNegationFlag = 0x80000000;
-
- struct Range {
- unsigned start; //
- unsigned end;
- SizeType next;
- };
-
- struct State {
- SizeType out; //!< Equals to kInvalid for matching state
- SizeType out1; //!< Equals to non-kInvalid for split
- SizeType rangeStart;
- unsigned codepoint;
- };
-
- struct Frag {
- Frag(SizeType s, SizeType o, SizeType m) : start(s), out(o), minIndex(m) {}
- SizeType start;
- SizeType out; //!< link-list of all output states
- SizeType minIndex;
- };
-
- template <typename SourceStream>
- class DecodedStream {
- public:
- DecodedStream(SourceStream& ss) : ss_(ss), codepoint_() { Decode(); }
- unsigned Peek() { return codepoint_; }
- unsigned Take() {
- unsigned c = codepoint_;
- if (c) // No further decoding when '\0'
- Decode();
- return c;
- }
-
- private:
- void Decode() {
- if (!Encoding::Decode(ss_, &codepoint_))
- codepoint_ = 0;
- }
-
- SourceStream& ss_;
- unsigned codepoint_;
- };
-
- State& GetState(SizeType index) {
- RAPIDJSON_ASSERT(index < stateCount_);
- return states_.template Bottom<State>()[index];
- }
-
- const State& GetState(SizeType index) const {
- RAPIDJSON_ASSERT(index < stateCount_);
- return states_.template Bottom<State>()[index];
- }
-
- Range& GetRange(SizeType index) {
- RAPIDJSON_ASSERT(index < rangeCount_);
- return ranges_.template Bottom<Range>()[index];
- }
-
- const Range& GetRange(SizeType index) const {
- RAPIDJSON_ASSERT(index < rangeCount_);
- return ranges_.template Bottom<Range>()[index];
- }
-
- template <typename InputStream>
- void Parse(DecodedStream<InputStream>& ds) {
- Allocator allocator;
- Stack<Allocator> operandStack(&allocator, 256); // Frag
- Stack<Allocator> operatorStack(&allocator, 256); // Operator
- Stack<Allocator> atomCountStack(&allocator, 256); // unsigned (Atom per parenthesis)
-
- *atomCountStack.template Push<unsigned>() = 0;
-
- unsigned codepoint;
- while (ds.Peek() != 0) {
- switch (codepoint = ds.Take()) {
- case '^':
- anchorBegin_ = true;
- break;
-
- case '$':
- anchorEnd_ = true;
- break;
-
- case '|':
- while (!operatorStack.Empty() && *operatorStack.template Top<Operator>() < kAlternation)
- if (!Eval(operandStack, *operatorStack.template Pop<Operator>(1)))
- return;
- *operatorStack.template Push<Operator>() = kAlternation;
- *atomCountStack.template Top<unsigned>() = 0;
- break;
-
- case '(':
- *operatorStack.template Push<Operator>() = kLeftParenthesis;
- *atomCountStack.template Push<unsigned>() = 0;
- break;
-
- case ')':
- while (!operatorStack.Empty() && *operatorStack.template Top<Operator>() != kLeftParenthesis)
- if (!Eval(operandStack, *operatorStack.template Pop<Operator>(1)))
- return;
- if (operatorStack.Empty())
- return;
- operatorStack.template Pop<Operator>(1);
- atomCountStack.template Pop<unsigned>(1);
- ImplicitConcatenation(atomCountStack, operatorStack);
- break;
-
- case '?':
- if (!Eval(operandStack, kZeroOrOne))
- return;
- break;
-
- case '*':
- if (!Eval(operandStack, kZeroOrMore))
- return;
- break;
-
- case '+':
- if (!Eval(operandStack, kOneOrMore))
- return;
- break;
-
- case '{':
- {
- unsigned n, m;
- if (!ParseUnsigned(ds, &n))
- return;
-
- if (ds.Peek() == ',') {
- ds.Take();
- if (ds.Peek() == '}')
- m = kInfinityQuantifier;
- else if (!ParseUnsigned(ds, &m) || m < n)
- return;
- }
- else
- m = n;
-
- if (!EvalQuantifier(operandStack, n, m) || ds.Peek() != '}')
- return;
- ds.Take();
- }
- break;
-
- case '.':
- PushOperand(operandStack, kAnyCharacterClass);
- ImplicitConcatenation(atomCountStack, operatorStack);
- break;
-
- case '[':
- {
- SizeType range;
- if (!ParseRange(ds, &range))
- return;
- SizeType s = NewState(kRegexInvalidState, kRegexInvalidState, kRangeCharacterClass);
- GetState(s).rangeStart = range;
- *operandStack.template Push<Frag>() = Frag(s, s, s);
- }
- ImplicitConcatenation(atomCountStack, operatorStack);
- break;
-
- case '\\': // Escape character
- if (!CharacterEscape(ds, &codepoint))
- return; // Unsupported escape character
- // fall through to default
-
- default: // Pattern character
- PushOperand(operandStack, codepoint);
- ImplicitConcatenation(atomCountStack, operatorStack);
- }
- }
-
- while (!operatorStack.Empty())
- if (!Eval(operandStack, *operatorStack.template Pop<Operator>(1)))
- return;
-
- // Link the operand to matching state.
- if (operandStack.GetSize() == sizeof(Frag)) {
- Frag* e = operandStack.template Pop<Frag>(1);
- Patch(e->out, NewState(kRegexInvalidState, kRegexInvalidState, 0));
- root_ = e->start;
-
-#if RAPIDJSON_REGEX_VERBOSE
- printf("root: %d\n", root_);
- for (SizeType i = 0; i < stateCount_ ; i++) {
- State& s = GetState(i);
- printf("[%2d] out: %2d out1: %2d c: '%c'\n", i, s.out, s.out1, (char)s.codepoint);
- }
- printf("\n");
-#endif
- }
-
- // Preallocate buffer for SearchWithAnchoring()
- RAPIDJSON_ASSERT(stateSet_ == 0);
- if (stateCount_ > 0) {
- stateSet_ = static_cast<unsigned*>(states_.GetAllocator().Malloc(GetStateSetSize()));
- state0_.template Reserve<SizeType>(stateCount_);
- state1_.template Reserve<SizeType>(stateCount_);
- }
- }
-
- SizeType NewState(SizeType out, SizeType out1, unsigned codepoint) {
- State* s = states_.template Push<State>();
- s->out = out;
- s->out1 = out1;
- s->codepoint = codepoint;
- s->rangeStart = kRegexInvalidRange;
- return stateCount_++;
- }
-
- void PushOperand(Stack<Allocator>& operandStack, unsigned codepoint) {
- SizeType s = NewState(kRegexInvalidState, kRegexInvalidState, codepoint);
- *operandStack.template Push<Frag>() = Frag(s, s, s);
- }
-
- void ImplicitConcatenation(Stack<Allocator>& atomCountStack, Stack<Allocator>& operatorStack) {
- if (*atomCountStack.template Top<unsigned>())
- *operatorStack.template Push<Operator>() = kConcatenation;
- (*atomCountStack.template Top<unsigned>())++;
- }
-
- SizeType Append(SizeType l1, SizeType l2) {
- SizeType old = l1;
- while (GetState(l1).out != kRegexInvalidState)
- l1 = GetState(l1).out;
- GetState(l1).out = l2;
- return old;
- }
-
- void Patch(SizeType l, SizeType s) {
- for (SizeType next; l != kRegexInvalidState; l = next) {
- next = GetState(l).out;
- GetState(l).out = s;
- }
- }
-
- bool Eval(Stack<Allocator>& operandStack, Operator op) {
- switch (op) {
- case kConcatenation:
- RAPIDJSON_ASSERT(operandStack.GetSize() >= sizeof(Frag) * 2);
- {
- Frag e2 = *operandStack.template Pop<Frag>(1);
- Frag e1 = *operandStack.template Pop<Frag>(1);
- Patch(e1.out, e2.start);
- *operandStack.template Push<Frag>() = Frag(e1.start, e2.out, Min(e1.minIndex, e2.minIndex));
- }
- return true;
-
- case kAlternation:
- if (operandStack.GetSize() >= sizeof(Frag) * 2) {
- Frag e2 = *operandStack.template Pop<Frag>(1);
- Frag e1 = *operandStack.template Pop<Frag>(1);
- SizeType s = NewState(e1.start, e2.start, 0);
- *operandStack.template Push<Frag>() = Frag(s, Append(e1.out, e2.out), Min(e1.minIndex, e2.minIndex));
- return true;
- }
- return false;
-
- case kZeroOrOne:
- if (operandStack.GetSize() >= sizeof(Frag)) {
- Frag e = *operandStack.template Pop<Frag>(1);
- SizeType s = NewState(kRegexInvalidState, e.start, 0);
- *operandStack.template Push<Frag>() = Frag(s, Append(e.out, s), e.minIndex);
- return true;
- }
- return false;
-
- case kZeroOrMore:
- if (operandStack.GetSize() >= sizeof(Frag)) {
- Frag e = *operandStack.template Pop<Frag>(1);
- SizeType s = NewState(kRegexInvalidState, e.start, 0);
- Patch(e.out, s);
- *operandStack.template Push<Frag>() = Frag(s, s, e.minIndex);
- return true;
- }
- return false;
-
- default:
- RAPIDJSON_ASSERT(op == kOneOrMore);
- if (operandStack.GetSize() >= sizeof(Frag)) {
- Frag e = *operandStack.template Pop<Frag>(1);
- SizeType s = NewState(kRegexInvalidState, e.start, 0);
- Patch(e.out, s);
- *operandStack.template Push<Frag>() = Frag(e.start, s, e.minIndex);
- return true;
- }
- return false;
- }
- }
-
- bool EvalQuantifier(Stack<Allocator>& operandStack, unsigned n, unsigned m) {
- RAPIDJSON_ASSERT(n <= m);
- RAPIDJSON_ASSERT(operandStack.GetSize() >= sizeof(Frag));
-
- if (n == 0) {
- if (m == 0) // a{0} not support
- return false;
- else if (m == kInfinityQuantifier)
- Eval(operandStack, kZeroOrMore); // a{0,} -> a*
- else {
- Eval(operandStack, kZeroOrOne); // a{0,5} -> a?
- for (unsigned i = 0; i < m - 1; i++)
- CloneTopOperand(operandStack); // a{0,5} -> a? a? a? a? a?
- for (unsigned i = 0; i < m - 1; i++)
- Eval(operandStack, kConcatenation); // a{0,5} -> a?a?a?a?a?
- }
- return true;
- }
-
- for (unsigned i = 0; i < n - 1; i++) // a{3} -> a a a
- CloneTopOperand(operandStack);
-
- if (m == kInfinityQuantifier)
- Eval(operandStack, kOneOrMore); // a{3,} -> a a a+
- else if (m > n) {
- CloneTopOperand(operandStack); // a{3,5} -> a a a a
- Eval(operandStack, kZeroOrOne); // a{3,5} -> a a a a?
- for (unsigned i = n; i < m - 1; i++)
- CloneTopOperand(operandStack); // a{3,5} -> a a a a? a?
- for (unsigned i = n; i < m; i++)
- Eval(operandStack, kConcatenation); // a{3,5} -> a a aa?a?
- }
-
- for (unsigned i = 0; i < n - 1; i++)
- Eval(operandStack, kConcatenation); // a{3} -> aaa, a{3,} -> aaa+, a{3.5} -> aaaa?a?
-
- return true;
- }
-
- static SizeType Min(SizeType a, SizeType b) { return a < b ? a : b; }
-
- void CloneTopOperand(Stack<Allocator>& operandStack) {
- const Frag src = *operandStack.template Top<Frag>(); // Copy constructor to prevent invalidation
- SizeType count = stateCount_ - src.minIndex; // Assumes top operand contains states in [src->minIndex, stateCount_)
- State* s = states_.template Push<State>(count);
- memcpy(s, &GetState(src.minIndex), count * sizeof(State));
- for (SizeType j = 0; j < count; j++) {
- if (s[j].out != kRegexInvalidState)
- s[j].out += count;
- if (s[j].out1 != kRegexInvalidState)
- s[j].out1 += count;
- }
- *operandStack.template Push<Frag>() = Frag(src.start + count, src.out + count, src.minIndex + count);
- stateCount_ += count;
- }
-
- template <typename InputStream>
- bool ParseUnsigned(DecodedStream<InputStream>& ds, unsigned* u) {
- unsigned r = 0;
- if (ds.Peek() < '0' || ds.Peek() > '9')
- return false;
- while (ds.Peek() >= '0' && ds.Peek() <= '9') {
- if (r >= 429496729 && ds.Peek() > '5') // 2^32 - 1 = 4294967295
- return false; // overflow
- r = r * 10 + (ds.Take() - '0');
- }
- *u = r;
- return true;
- }
-
- template <typename InputStream>
- bool ParseRange(DecodedStream<InputStream>& ds, SizeType* range) {
- bool isBegin = true;
- bool negate = false;
- int step = 0;
- SizeType start = kRegexInvalidRange;
- SizeType current = kRegexInvalidRange;
- unsigned codepoint;
- while ((codepoint = ds.Take()) != 0) {
- if (isBegin) {
- isBegin = false;
- if (codepoint == '^') {
- negate = true;
- continue;
- }
- }
-
- switch (codepoint) {
- case ']':
- if (start == kRegexInvalidRange)
- return false; // Error: nothing inside []
- if (step == 2) { // Add trailing '-'
- SizeType r = NewRange('-');
- RAPIDJSON_ASSERT(current != kRegexInvalidRange);
- GetRange(current).next = r;
- }
- if (negate)
- GetRange(start).start |= kRangeNegationFlag;
- *range = start;
- return true;
-
- case '\\':
- if (ds.Peek() == 'b') {
- ds.Take();
- codepoint = 0x0008; // Escape backspace character
- }
- else if (!CharacterEscape(ds, &codepoint))
- return false;
- // fall through to default
-
- default:
- switch (step) {
- case 1:
- if (codepoint == '-') {
- step++;
- break;
- }
- // fall through to step 0 for other characters
-
- case 0:
- {
- SizeType r = NewRange(codepoint);
- if (current != kRegexInvalidRange)
- GetRange(current).next = r;
- if (start == kRegexInvalidRange)
- start = r;
- current = r;
- }
- step = 1;
- break;
-
- default:
- RAPIDJSON_ASSERT(step == 2);
- GetRange(current).end = codepoint;
- step = 0;
- }
- }
- }
- return false;
- }
-
- SizeType NewRange(unsigned codepoint) {
- Range* r = ranges_.template Push<Range>();
- r->start = r->end = codepoint;
- r->next = kRegexInvalidRange;
- return rangeCount_++;
- }
-
- template <typename InputStream>
- bool CharacterEscape(DecodedStream<InputStream>& ds, unsigned* escapedCodepoint) {
- unsigned codepoint;
- switch (codepoint = ds.Take()) {
- case '^':
- case '$':
- case '|':
- case '(':
- case ')':
- case '?':
- case '*':
- case '+':
- case '.':
- case '[':
- case ']':
- case '{':
- case '}':
- case '\\':
- *escapedCodepoint = codepoint; return true;
- case 'f': *escapedCodepoint = 0x000C; return true;
- case 'n': *escapedCodepoint = 0x000A; return true;
- case 'r': *escapedCodepoint = 0x000D; return true;
- case 't': *escapedCodepoint = 0x0009; return true;
- case 'v': *escapedCodepoint = 0x000B; return true;
- default:
- return false; // Unsupported escape character
- }
- }
-
- template <typename InputStream>
- bool SearchWithAnchoring(InputStream& is, bool anchorBegin, bool anchorEnd) const {
- RAPIDJSON_ASSERT(IsValid());
- DecodedStream<InputStream> ds(is);
-
- state0_.Clear();
- Stack<Allocator> *current = &state0_, *next = &state1_;
- const size_t stateSetSize = GetStateSetSize();
- std::memset(stateSet_, 0, stateSetSize);
-
- bool matched = AddState(*current, root_);
- unsigned codepoint;
- while (!current->Empty() && (codepoint = ds.Take()) != 0) {
- std::memset(stateSet_, 0, stateSetSize);
- next->Clear();
- matched = false;
- for (const SizeType* s = current->template Bottom<SizeType>(); s != current->template End<SizeType>(); ++s) {
- const State& sr = GetState(*s);
- if (sr.codepoint == codepoint ||
- sr.codepoint == kAnyCharacterClass ||
- (sr.codepoint == kRangeCharacterClass && MatchRange(sr.rangeStart, codepoint)))
- {
- matched = AddState(*next, sr.out) || matched;
- if (!anchorEnd && matched)
- return true;
- }
- if (!anchorBegin)
- AddState(*next, root_);
- }
- internal::Swap(current, next);
- }
-
- return matched;
- }
-
- size_t GetStateSetSize() const {
- return (stateCount_ + 31) / 32 * 4;
- }
-
- // Return whether the added states is a match state
- bool AddState(Stack<Allocator>& l, SizeType index) const {
- RAPIDJSON_ASSERT(index != kRegexInvalidState);
-
- const State& s = GetState(index);
- if (s.out1 != kRegexInvalidState) { // Split
- bool matched = AddState(l, s.out);
- return AddState(l, s.out1) || matched;
- }
- else if (!(stateSet_[index >> 5] & (1 << (index & 31)))) {
- stateSet_[index >> 5] |= (1 << (index & 31));
- *l.template PushUnsafe<SizeType>() = index;
- }
- return s.out == kRegexInvalidState; // by using PushUnsafe() above, we can ensure s is not validated due to reallocation.
- }
-
- bool MatchRange(SizeType rangeIndex, unsigned codepoint) const {
- bool yes = (GetRange(rangeIndex).start & kRangeNegationFlag) == 0;
- while (rangeIndex != kRegexInvalidRange) {
- const Range& r = GetRange(rangeIndex);
- if (codepoint >= (r.start & ~kRangeNegationFlag) && codepoint <= r.end)
- return yes;
- rangeIndex = r.next;
- }
- return !yes;
- }
-
- Stack<Allocator> states_;
- Stack<Allocator> ranges_;
- SizeType root_;
- SizeType stateCount_;
- SizeType rangeCount_;
-
- static const unsigned kInfinityQuantifier = ~0u;
-
- // For SearchWithAnchoring()
- uint32_t* stateSet_; // allocated by states_.GetAllocator()
- mutable Stack<Allocator> state0_;
- mutable Stack<Allocator> state1_;
- bool anchorBegin_;
- bool anchorEnd_;
-};
-
-typedef GenericRegex<UTF8<> > Regex;
-
-} // namespace internal
-RAPIDJSON_NAMESPACE_END
-
-#ifdef __clang__
-RAPIDJSON_DIAG_POP
-#endif
-
-#ifdef _MSC_VER
-RAPIDJSON_DIAG_POP
-#endif
-
-#endif // RAPIDJSON_INTERNAL_REGEX_H_
diff --git a/include/rapidjson/internal/stack.h b/include/rapidjson/internal/stack.h
deleted file mode 100644
index 022c9aab..00000000
--- a/include/rapidjson/internal/stack.h
+++ /dev/null
@@ -1,230 +0,0 @@
-// Tencent is pleased to support the open source community by making RapidJSON available.
-//
-// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
-//
-// Licensed under the MIT License (the "License"); you may not use this file except
-// in compliance with the License. You may obtain a copy of the License at
-//
-// http://opensource.org/licenses/MIT
-//
-// Unless required by applicable law or agreed to in writing, software distributed
-// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
-// CONDITIONS OF ANY KIND, either express or implied. See the License for the
-// specific language governing permissions and limitations under the License.
-
-#ifndef RAPIDJSON_INTERNAL_STACK_H_
-#define RAPIDJSON_INTERNAL_STACK_H_
-
-#include "../allocators.h"
-#include "swap.h"
-
-#if defined(__clang__)
-RAPIDJSON_DIAG_PUSH
-RAPIDJSON_DIAG_OFF(c++98-compat)
-#endif
-
-RAPIDJSON_NAMESPACE_BEGIN
-namespace internal {
-
-///////////////////////////////////////////////////////////////////////////////
-// Stack
-
-//! A type-unsafe stack for storing different types of data.
-/*! \tparam Allocator Allocator for allocating stack memory.
-*/
-template <typename Allocator>
-class Stack {
-public:
- // Optimization note: Do not allocate memory for stack_ in constructor.
- // Do it lazily when first Push() -> Expand() -> Resize().
- Stack(Allocator* allocator, size_t stackCapacity) : allocator_(allocator), ownAllocator_(0), stack_(0), stackTop_(0), stackEnd_(0), initialCapacity_(stackCapacity) {
- }
-
-#if RAPIDJSON_HAS_CXX11_RVALUE_REFS
- Stack(Stack&& rhs)
- : allocator_(rhs.allocator_),
- ownAllocator_(rhs.ownAllocator_),
- stack_(rhs.stack_),
- stackTop_(rhs.stackTop_),
- stackEnd_(rhs.stackEnd_),
- initialCapacity_(rhs.initialCapacity_)
- {
- rhs.allocator_ = 0;
- rhs.ownAllocator_ = 0;
- rhs.stack_ = 0;
- rhs.stackTop_ = 0;
- rhs.stackEnd_ = 0;
- rhs.initialCapacity_ = 0;
- }
-#endif
-
- ~Stack() {
- Destroy();
- }
-
-#if RAPIDJSON_HAS_CXX11_RVALUE_REFS
- Stack& operator=(Stack&& rhs) {
- if (&rhs != this)
- {
- Destroy();
-
- allocator_ = rhs.allocator_;
- ownAllocator_ = rhs.ownAllocator_;
- stack_ = rhs.stack_;
- stackTop_ = rhs.stackTop_;
- stackEnd_ = rhs.stackEnd_;
- initialCapacity_ = rhs.initialCapacity_;
-
- rhs.allocator_ = 0;
- rhs.ownAllocator_ = 0;
- rhs.stack_ = 0;
- rhs.stackTop_ = 0;
- rhs.stackEnd_ = 0;
- rhs.initialCapacity_ = 0;
- }
- return *this;
- }
-#endif
-
- void Swap(Stack& rhs) RAPIDJSON_NOEXCEPT {
- internal::Swap(allocator_, rhs.allocator_);
- internal::Swap(ownAllocator_, rhs.ownAllocator_);
- internal::Swap(stack_, rhs.stack_);
- internal::Swap(stackTop_, rhs.stackTop_);
- internal::Swap(stackEnd_, rhs.stackEnd_);
- internal::Swap(initialCapacity_, rhs.initialCapacity_);
- }
-
- void Clear() { stackTop_ = stack_; }
-
- void ShrinkToFit() {
- if (Empty()) {
- // If the stack is empty, completely deallocate the memory.
- Allocator::Free(stack_);
- stack_ = 0;
- stackTop_ = 0;
- stackEnd_ = 0;
- }
- else
- Resize(GetSize());
- }
-
- // Optimization note: try to minimize the size of this function for force inline.
- // Expansion is run very infrequently, so it is moved to another (probably non-inline) function.
- template<typename T>
- RAPIDJSON_FORCEINLINE void Reserve(size_t count = 1) {
- // Expand the stack if needed
- if (RAPIDJSON_UNLIKELY(stackTop_ + sizeof(T) * count > stackEnd_))
- Expand<T>(count);
- }
-
- template<typename T>
- RAPIDJSON_FORCEINLINE T* Push(size_t count = 1) {
- Reserve<T>(count);
- return PushUnsafe<T>(count);
- }
-
- template<typename T>
- RAPIDJSON_FORCEINLINE T* PushUnsafe(size_t count = 1) {
- RAPIDJSON_ASSERT(stackTop_ + sizeof(T) * count <= stackEnd_);
- T* ret = reinterpret_cast<T*>(stackTop_);
- stackTop_ += sizeof(T) * count;
- return ret;
- }
-
- template<typename T>
- T* Pop(size_t count) {
- RAPIDJSON_ASSERT(GetSize() >= count * sizeof(T));
- stackTop_ -= count * sizeof(T);
- return reinterpret_cast<T*>(stackTop_);
- }
-
- template<typename T>
- T* Top() {
- RAPIDJSON_ASSERT(GetSize() >= sizeof(T));
- return reinterpret_cast<T*>(stackTop_ - sizeof(T));
- }
-
- template<typename T>
- const T* Top() const {
- RAPIDJSON_ASSERT(GetSize() >= sizeof(T));
- return reinterpret_cast<T*>(stackTop_ - sizeof(T));
- }
-
- template<typename T>
- T* End() { return reinterpret_cast<T*>(stackTop_); }
-
- template<typename T>
- const T* End() const { return reinterpret_cast<T*>(stackTop_); }
-
- template<typename T>
- T* Bottom() { return reinterpret_cast<T*>(stack_); }
-
- template<typename T>
- const T* Bottom() const { return reinterpret_cast<T*>(stack_); }
-
- bool HasAllocator() const {
- return allocator_ != 0;
- }
-
- Allocator& GetAllocator() {
- RAPIDJSON_ASSERT(allocator_);
- return *allocator_;
- }
-
- bool Empty() const { return stackTop_ == stack_; }
- size_t GetSize() const { return static_cast<size_t>(stackTop_ - stack_); }
- size_t GetCapacity() const { return static_cast<size_t>(stackEnd_ - stack_); }
-
-private:
- template<typename T>
- void Expand(size_t count) {
- // Only expand the capacity if the current stack exists. Otherwise just create a stack with initial capacity.
- size_t newCapacity;
- if (stack_ == 0) {
- if (!allocator_)
- ownAllocator_ = allocator_ = RAPIDJSON_NEW(Allocator());
- newCapacity = initialCapacity_;
- } else {
- newCapacity = GetCapacity();
- newCapacity += (newCapacity + 1) / 2;
- }
- size_t newSize = GetSize() + sizeof(T) * count;
- if (newCapacity < newSize)
- newCapacity = newSize;
-
- Resize(newCapacity);
- }
-
- void Resize(size_t newCapacity) {
- const size_t size = GetSize(); // Backup the current size
- stack_ = static_cast<char*>(allocator_->Realloc(stack_, GetCapacity(), newCapacity));
- stackTop_ = stack_ + size;
- stackEnd_ = stack_ + newCapacity;
- }
-
- void Destroy() {
- Allocator::Free(stack_);
- RAPIDJSON_DELETE(ownAllocator_); // Only delete if it is owned by the stack
- }
-
- // Prohibit copy constructor & assignment operator.
- Stack(const Stack&);
- Stack& operator=(const Stack&);
-
- Allocator* allocator_;
- Allocator* ownAllocator_;
- char *stack_;
- char *stackTop_;
- char *stackEnd_;
- size_t initialCapacity_;
-};
-
-} // namespace internal
-RAPIDJSON_NAMESPACE_END
-
-#if defined(__clang__)
-RAPIDJSON_DIAG_POP
-#endif
-
-#endif // RAPIDJSON_STACK_H_
diff --git a/include/rapidjson/internal/strfunc.h b/include/rapidjson/internal/strfunc.h
deleted file mode 100644
index 2edfae52..00000000
--- a/include/rapidjson/internal/strfunc.h
+++ /dev/null
@@ -1,55 +0,0 @@
-// Tencent is pleased to support the open source community by making RapidJSON available.
-//
-// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
-//
-// Licensed under the MIT License (the "License"); you may not use this file except
-// in compliance with the License. You may obtain a copy of the License at
-//
-// http://opensource.org/licenses/MIT
-//
-// Unless required by applicable law or agreed to in writing, software distributed
-// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
-// CONDITIONS OF ANY KIND, either express or implied. See the License for the
-// specific language governing permissions and limitations under the License.
-
-#ifndef RAPIDJSON_INTERNAL_STRFUNC_H_
-#define RAPIDJSON_INTERNAL_STRFUNC_H_
-
-#include "../stream.h"
-
-RAPIDJSON_NAMESPACE_BEGIN
-namespace internal {
-
-//! Custom strlen() which works on different character types.
-/*! \tparam Ch Character type (e.g. char, wchar_t, short)
- \param s Null-terminated input string.
- \return Number of characters in the string.
- \note This has the same semantics as strlen(), the return value is not number of Unicode codepoints.
-*/
-template <typename Ch>
-inline SizeType StrLen(const Ch* s) {
- const Ch* p = s;
- while (*p) ++p;
- return SizeType(p - s);
-}
-
-//! Returns number of code points in a encoded string.
-template<typename Encoding>
-bool CountStringCodePoint(const typename Encoding::Ch* s, SizeType length, SizeType* outCount) {
- GenericStringStream<Encoding> is(s);
- const typename Encoding::Ch* end = s + length;
- SizeType count = 0;
- while (is.src_ < end) {
- unsigned codepoint;
- if (!Encoding::Decode(is, &codepoint))
- return false;
- count++;
- }
- *outCount = count;
- return true;
-}
-
-} // namespace internal
-RAPIDJSON_NAMESPACE_END
-
-#endif // RAPIDJSON_INTERNAL_STRFUNC_H_
diff --git a/include/rapidjson/memorybuffer.h b/include/rapidjson/memorybuffer.h
deleted file mode 100644
index 39bee1de..00000000
--- a/include/rapidjson/memorybuffer.h
+++ /dev/null
@@ -1,70 +0,0 @@
-// Tencent is pleased to support the open source community by making RapidJSON available.
-//
-// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
-//
-// Licensed under the MIT License (the "License"); you may not use this file except
-// in compliance with the License. You may obtain a copy of the License at
-//
-// http://opensource.org/licenses/MIT
-//
-// Unless required by applicable law or agreed to in writing, software distributed
-// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
-// CONDITIONS OF ANY KIND, either express or implied. See the License for the
-// specific language governing permissions and limitations under the License.
-
-#ifndef RAPIDJSON_MEMORYBUFFER_H_
-#define RAPIDJSON_MEMORYBUFFER_H_
-
-#include "stream.h"
-#include "internal/stack.h"
-
-RAPIDJSON_NAMESPACE_BEGIN
-
-//! Represents an in-memory output byte stream.
-/*!
- This class is mainly for being wrapped by EncodedOutputStream or AutoUTFOutputStream.
-
- It is similar to FileWriteBuffer but the destination is an in-memory buffer instead of a file.
-
- Differences between MemoryBuffer and StringBuffer:
- 1. StringBuffer has Encoding but MemoryBuffer is only a byte buffer.
- 2. StringBuffer::GetString() returns a null-terminated string. MemoryBuffer::GetBuffer() returns a buffer without terminator.
-
- \tparam Allocator type for allocating memory buffer.
- \note implements Stream concept
-*/
-template <typename Allocator = CrtAllocator>
-struct GenericMemoryBuffer {
- typedef char Ch; // byte
-
- GenericMemoryBuffer(Allocator* allocator = 0, size_t capacity = kDefaultCapacity) : stack_(allocator, capacity) {}
-
- void Put(Ch c) { *stack_.template Push<Ch>() = c; }
- void Flush() {}
-
- void Clear() { stack_.Clear(); }
- void ShrinkToFit() { stack_.ShrinkToFit(); }
- Ch* Push(size_t count) { return stack_.template Push<Ch>(count); }
- void Pop(size_t count) { stack_.template Pop<Ch>(count); }
-
- const Ch* GetBuffer() const {
- return stack_.template Bottom<Ch>();
- }
-
- size_t GetSize() const { return stack_.GetSize(); }
-
- static const size_t kDefaultCapacity = 256;
- mutable internal::Stack<Allocator> stack_;
-};
-
-typedef GenericMemoryBuffer<> MemoryBuffer;
-
-//! Implement specialized version of PutN() with memset() for better performance.
-template<>
-inline void PutN(MemoryBuffer& memoryBuffer, char c, size_t n) {
- std::memset(memoryBuffer.stack_.Push<char>(n), c, n * sizeof(c));
-}
-
-RAPIDJSON_NAMESPACE_END
-
-#endif // RAPIDJSON_MEMORYBUFFER_H_
diff --git a/include/rapidjson/pointer.h b/include/rapidjson/pointer.h
deleted file mode 100644
index 0206ac1c..00000000
--- a/include/rapidjson/pointer.h
+++ /dev/null
@@ -1,1358 +0,0 @@
-// Tencent is pleased to support the open source community by making RapidJSON available.
-//
-// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
-//
-// Licensed under the MIT License (the "License"); you may not use this file except
-// in compliance with the License. You may obtain a copy of the License at
-//
-// http://opensource.org/licenses/MIT
-//
-// Unless required by applicable law or agreed to in writing, software distributed
-// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
-// CONDITIONS OF ANY KIND, either express or implied. See the License for the
-// specific language governing permissions and limitations under the License.
-
-#ifndef RAPIDJSON_POINTER_H_
-#define RAPIDJSON_POINTER_H_
-
-#include "document.h"
-#include "internal/itoa.h"
-
-#ifdef __clang__
-RAPIDJSON_DIAG_PUSH
-RAPIDJSON_DIAG_OFF(switch-enum)
-#endif
-
-#ifdef _MSC_VER
-RAPIDJSON_DIAG_PUSH
-RAPIDJSON_DIAG_OFF(4512) // assignment operator could not be generated
-#endif
-
-RAPIDJSON_NAMESPACE_BEGIN
-
-static const SizeType kPointerInvalidIndex = ~SizeType(0); //!< Represents an invalid index in GenericPointer::Token
-
-//! Error code of parsing.
-/*! \ingroup RAPIDJSON_ERRORS
- \see GenericPointer::GenericPointer, GenericPointer::GetParseErrorCode
-*/
-enum PointerParseErrorCode {
- kPointerParseErrorNone = 0, //!< The parse is successful
-
- kPointerParseErrorTokenMustBeginWithSolidus, //!< A token must begin with a '/'
- kPointerParseErrorInvalidEscape, //!< Invalid escape
- kPointerParseErrorInvalidPercentEncoding, //!< Invalid percent encoding in URI fragment
- kPointerParseErrorCharacterMustPercentEncode //!< A character must percent encoded in URI fragment
-};
-
-///////////////////////////////////////////////////////////////////////////////
-// GenericPointer
-
-//! Represents a JSON Pointer. Use Pointer for UTF8 encoding and default allocator.
-/*!
- This class implements RFC 6901 "JavaScript Object Notation (JSON) Pointer"
- (https://tools.ietf.org/html/rfc6901).
-
- A JSON pointer is for identifying a specific value in a JSON document
- (GenericDocument). It can simplify coding of DOM tree manipulation, because it
- can access multiple-level depth of DOM tree with single API call.
-
- After it parses a string representation (e.g. "/foo/0" or URI fragment
- representation (e.g. "#/foo/0") into its internal representation (tokens),
- it can be used to resolve a specific value in multiple documents, or sub-tree
- of documents.
-
- Contrary to GenericValue, Pointer can be copy constructed and copy assigned.
- Apart from assignment, a Pointer cannot be modified after construction.
-
- Although Pointer is very convenient, please aware that constructing Pointer
- involves parsing and dynamic memory allocation. A special constructor with user-
- supplied tokens eliminates these.
-
- GenericPointer depends on GenericDocument and GenericValue.
-
- \tparam ValueType The value type of the DOM tree. E.g. GenericValue<UTF8<> >
- \tparam Allocator The allocator type for allocating memory for internal representation.
-
- \note GenericPointer uses same encoding of ValueType.
- However, Allocator of GenericPointer is independent of Allocator of Value.
-*/
-template <typename ValueType, typename Allocator = CrtAllocator>
-class GenericPointer {
-public:
- typedef typename ValueType::EncodingType EncodingType; //!< Encoding type from Value
- typedef typename ValueType::Ch Ch; //!< Character type from Value
-
- //! A token is the basic units of internal representation.
- /*!
- A JSON pointer string representation "/foo/123" is parsed to two tokens:
- "foo" and 123. 123 will be represented in both numeric form and string form.
- They are resolved according to the actual value type (object or array).
-
- For token that are not numbers, or the numeric value is out of bound
- (greater than limits of SizeType), they are only treated as string form
- (i.e. the token's index will be equal to kPointerInvalidIndex).
-
- This struct is public so that user can create a Pointer without parsing and
- allocation, using a special constructor.
- */
- struct Token {
- const Ch* name; //!< Name of the token. It has null character at the end but it can contain null character.
- SizeType length; //!< Length of the name.
- SizeType index; //!< A valid array index, if it is not equal to kPointerInvalidIndex.
- };
-
- //!@name Constructors and destructor.
- //@{
-
- //! Default constructor.
- GenericPointer(Allocator* allocator = 0) : allocator_(allocator), ownAllocator_(), nameBuffer_(), tokens_(), tokenCount_(), parseErrorOffset_(), parseErrorCode_(kPointerParseErrorNone) {}
-
- //! Constructor that parses a string or URI fragment representation.
- /*!
- \param source A null-terminated, string or URI fragment representation of JSON pointer.
- \param allocator User supplied allocator for this pointer. If no allocator is provided, it creates a self-owned one.
- */
- explicit GenericPointer(const Ch* source, Allocator* allocator = 0) : allocator_(allocator), ownAllocator_(), nameBuffer_(), tokens_(), tokenCount_(), parseErrorOffset_(), parseErrorCode_(kPointerParseErrorNone) {
- Parse(source, internal::StrLen(source));
- }
-
-#if RAPIDJSON_HAS_STDSTRING
- //! Constructor that parses a string or URI fragment representation.
- /*!
- \param source A string or URI fragment representation of JSON pointer.
- \param allocator User supplied allocator for this pointer. If no allocator is provided, it creates a self-owned one.
- \note Requires the definition of the preprocessor symbol \ref RAPIDJSON_HAS_STDSTRING.
- */
- explicit GenericPointer(const std::basic_string<Ch>& source, Allocator* allocator = 0) : allocator_(allocator), ownAllocator_(), nameBuffer_(), tokens_(), tokenCount_(), parseErrorOffset_(), parseErrorCode_(kPointerParseErrorNone) {
- Parse(source.c_str(), source.size());
- }
-#endif
-
- //! Constructor that parses a string or URI fragment representation, with length of the source string.
- /*!
- \param source A string or URI fragment representation of JSON pointer.
- \param length Length of source.
- \param allocator User supplied allocator for this pointer. If no allocator is provided, it creates a self-owned one.
- \note Slightly faster than the overload without length.
- */
- GenericPointer(const Ch* source, size_t length, Allocator* allocator = 0) : allocator_(allocator), ownAllocator_(), nameBuffer_(), tokens_(), tokenCount_(), parseErrorOffset_(), parseErrorCode_(kPointerParseErrorNone) {
- Parse(source, length);
- }
-
- //! Constructor with user-supplied tokens.
- /*!
- This constructor let user supplies const array of tokens.
- This prevents the parsing process and eliminates allocation.
- This is preferred for memory constrained environments.
-
- \param tokens An constant array of tokens representing the JSON pointer.
- \param tokenCount Number of tokens.
-
- \b Example
- \code
- #define NAME(s) { s, sizeof(s) / sizeof(s[0]) - 1, kPointerInvalidIndex }
- #define INDEX(i) { #i, sizeof(#i) - 1, i }
-
- static const Pointer::Token kTokens[] = { NAME("foo"), INDEX(123) };
- static const Pointer p(kTokens, sizeof(kTokens) / sizeof(kTokens[0]));
- // Equivalent to static const Pointer p("/foo/123");
-
- #undef NAME
- #undef INDEX
- \endcode
- */
- GenericPointer(const Token* tokens, size_t tokenCount) : allocator_(), ownAllocator_(), nameBuffer_(), tokens_(const_cast<Token*>(tokens)), tokenCount_(tokenCount), parseErrorOffset_(), parseErrorCode_(kPointerParseErrorNone) {}
-
- //! Copy constructor.
- GenericPointer(const GenericPointer& rhs, Allocator* allocator = 0) : allocator_(allocator), ownAllocator_(), nameBuffer_(), tokens_(), tokenCount_(), parseErrorOffset_(), parseErrorCode_(kPointerParseErrorNone) {
- *this = rhs;
- }
-
- //! Destructor.
- ~GenericPointer() {
- if (nameBuffer_) // If user-supplied tokens constructor is used, nameBuffer_ is nullptr and tokens_ are not deallocated.
- Allocator::Free(tokens_);
- RAPIDJSON_DELETE(ownAllocator_);
- }
-
- //! Assignment operator.
- GenericPointer& operator=(const GenericPointer& rhs) {
- if (this != &rhs) {
- // Do not delete ownAllcator
- if (nameBuffer_)
- Allocator::Free(tokens_);
-
- tokenCount_ = rhs.tokenCount_;
- parseErrorOffset_ = rhs.parseErrorOffset_;
- parseErrorCode_ = rhs.parseErrorCode_;
-
- if (rhs.nameBuffer_)
- CopyFromRaw(rhs); // Normally parsed tokens.
- else {
- tokens_ = rhs.tokens_; // User supplied const tokens.
- nameBuffer_ = 0;
- }
- }
- return *this;
- }
-
- //@}
-
- //!@name Append token
- //@{
-
- //! Append a token and return a new Pointer
- /*!
- \param token Token to be appended.
- \param allocator Allocator for the newly return Pointer.
- \return A new Pointer with appended token.
- */
- GenericPointer Append(const Token& token, Allocator* allocator = 0) const {
- GenericPointer r;
- r.allocator_ = allocator;
- Ch *p = r.CopyFromRaw(*this, 1, token.length + 1);
- std::memcpy(p, token.name, (token.length + 1) * sizeof(Ch));
- r.tokens_[tokenCount_].name = p;
- r.tokens_[tokenCount_].length = token.length;
- r.tokens_[tokenCount_].index = token.index;
- return r;
- }
-
- //! Append a name token with length, and return a new Pointer
- /*!
- \param name Name to be appended.
- \param length Length of name.
- \param allocator Allocator for the newly return Pointer.
- \return A new Pointer with appended token.
- */
- GenericPointer Append(const Ch* name, SizeType length, Allocator* allocator = 0) const {
- Token token = { name, length, kPointerInvalidIndex };
- return Append(token, allocator);
- }
-
- //! Append a name token without length, and return a new Pointer
- /*!
- \param name Name (const Ch*) to be appended.
- \param allocator Allocator for the newly return Pointer.
- \return A new Pointer with appended token.
- */
- template <typename T>
- RAPIDJSON_DISABLEIF_RETURN((internal::NotExpr<internal::IsSame<typename internal::RemoveConst<T>::Type, Ch> >), (GenericPointer))
- Append(T* name, Allocator* allocator = 0) const {
- return Append(name, StrLen(name), allocator);
- }
-
-#if RAPIDJSON_HAS_STDSTRING
- //! Append a name token, and return a new Pointer
- /*!
- \param name Name to be appended.
- \param allocator Allocator for the newly return Pointer.
- \return A new Pointer with appended token.
- */
- GenericPointer Append(const std::basic_string<Ch>& name, Allocator* allocator = 0) const {
- return Append(name.c_str(), static_cast<SizeType>(name.size()), allocator);
- }
-#endif
-
- //! Append a index token, and return a new Pointer
- /*!
- \param index Index to be appended.
- \param allocator Allocator for the newly return Pointer.
- \return A new Pointer with appended token.
- */
- GenericPointer Append(SizeType index, Allocator* allocator = 0) const {
- char buffer[21];
- char* end = sizeof(SizeType) == 4 ? internal::u32toa(index, buffer) : internal::u64toa(index, buffer);
- SizeType length = static_cast<SizeType>(end - buffer);
- buffer[length] = '\0';
-
- if (sizeof(Ch) == 1) {
- Token token = { reinterpret_cast<Ch*>(buffer), length, index };
- return Append(token, allocator);
- }
- else {
- Ch name[21];
- for (size_t i = 0; i <= length; i++)
- name[i] = buffer[i];
- Token token = { name, length, index };
- return Append(token, allocator);
- }
- }
-
- //! Append a token by value, and return a new Pointer
- /*!
- \param token token to be appended.
- \param allocator Allocator for the newly return Pointer.
- \return A new Pointer with appended token.
- */
- GenericPointer Append(const ValueType& token, Allocator* allocator = 0) const {
- if (token.IsString())
- return Append(token.GetString(), token.GetStringLength(), allocator);
- else {
- RAPIDJSON_ASSERT(token.IsUint64());
- RAPIDJSON_ASSERT(token.GetUint64() <= SizeType(~0));
- return Append(static_cast<SizeType>(token.GetUint64()), allocator);
- }
- }
-
- //!@name Handling Parse Error
- //@{
-
- //! Check whether this is a valid pointer.
- bool IsValid() const { return parseErrorCode_ == kPointerParseErrorNone; }
-
- //! Get the parsing error offset in code unit.
- size_t GetParseErrorOffset() const { return parseErrorOffset_; }
-
- //! Get the parsing error code.
- PointerParseErrorCode GetParseErrorCode() const { return parseErrorCode_; }
-
- //@}
-
- //! Get the allocator of this pointer.
- Allocator& GetAllocator() { return *allocator_; }
-
- //!@name Tokens
- //@{
-
- //! Get the token array (const version only).
- const Token* GetTokens() const { return tokens_; }
-
- //! Get the number of tokens.
- size_t GetTokenCount() const { return tokenCount_; }
-
- //@}
-
- //!@name Equality/inequality operators
- //@{
-
- //! Equality operator.
- /*!
- \note When any pointers are invalid, always returns false.
- */
- bool operator==(const GenericPointer& rhs) const {
- if (!IsValid() || !rhs.IsValid() || tokenCount_ != rhs.tokenCount_)
- return false;
-
- for (size_t i = 0; i < tokenCount_; i++) {
- if (tokens_[i].index != rhs.tokens_[i].index ||
- tokens_[i].length != rhs.tokens_[i].length ||
- (tokens_[i].length != 0 && std::memcmp(tokens_[i].name, rhs.tokens_[i].name, sizeof(Ch)* tokens_[i].length) != 0))
- {
- return false;
- }
- }
-
- return true;
- }
-
- //! Inequality operator.
- /*!
- \note When any pointers are invalid, always returns true.
- */
- bool operator!=(const GenericPointer& rhs) const { return !(*this == rhs); }
-
- //@}
-
- //!@name Stringify
- //@{
-
- //! Stringify the pointer into string representation.
- /*!
- \tparam OutputStream Type of output stream.
- \param os The output stream.
- */
- template<typename OutputStream>
- bool Stringify(OutputStream& os) const {
- return Stringify<false, OutputStream>(os);
- }
-
- //! Stringify the pointer into URI fragment representation.
- /*!
- \tparam OutputStream Type of output stream.
- \param os The output stream.
- */
- template<typename OutputStream>
- bool StringifyUriFragment(OutputStream& os) const {
- return Stringify<true, OutputStream>(os);
- }
-
- //@}
-
- //!@name Create value
- //@{
-
- //! Create a value in a subtree.
- /*!
- If the value is not exist, it creates all parent values and a JSON Null value.
- So it always succeed and return the newly created or existing value.
-
- Remind that it may change types of parents according to tokens, so it
- potentially removes previously stored values. For example, if a document
- was an array, and "/foo" is used to create a value, then the document
- will be changed to an object, and all existing array elements are lost.
-
- \param root Root value of a DOM subtree to be resolved. It can be any value other than document root.
- \param allocator Allocator for creating the values if the specified value or its parents are not exist.
- \param alreadyExist If non-null, it stores whether the resolved value is already exist.
- \return The resolved newly created (a JSON Null value), or already exists value.
- */
- ValueType& Create(ValueType& root, typename ValueType::AllocatorType& allocator, bool* alreadyExist = 0) const {
- RAPIDJSON_ASSERT(IsValid());
- ValueType* v = &root;
- bool exist = true;
- for (const Token *t = tokens_; t != tokens_ + tokenCount_; ++t) {
- if (v->IsArray() && t->name[0] == '-' && t->length == 1) {
- v->PushBack(ValueType().Move(), allocator);
- v = &((*v)[v->Size() - 1]);
- exist = false;
- }
- else {
- if (t->index == kPointerInvalidIndex) { // must be object name
- if (!v->IsObject())
- v->SetObject(); // Change to Object
- }
- else { // object name or array index
- if (!v->IsArray() && !v->IsObject())
- v->SetArray(); // Change to Array
- }
-
- if (v->IsArray()) {
- if (t->index >= v->Size()) {
- v->Reserve(t->index + 1, allocator);
- while (t->index >= v->Size())
- v->PushBack(ValueType().Move(), allocator);
- exist = false;
- }
- v = &((*v)[t->index]);
- }
- else {
- typename ValueType::MemberIterator m = v->FindMember(GenericStringRef<Ch>(t->name, t->length));
- if (m == v->MemberEnd()) {
- v->AddMember(ValueType(t->name, t->length, allocator).Move(), ValueType().Move(), allocator);
- v = &(--v->MemberEnd())->value; // Assumes AddMember() appends at the end
- exist = false;
- }
- else
- v = &m->value;
- }
- }
- }
-
- if (alreadyExist)
- *alreadyExist = exist;
-
- return *v;
- }
-
- //! Creates a value in a document.
- /*!
- \param document A document to be resolved.
- \param alreadyExist If non-null, it stores whether the resolved value is already exist.
- \return The resolved newly created, or already exists value.
- */
- template <typename stackAllocator>
- ValueType& Create(GenericDocument<EncodingType, typename ValueType::AllocatorType, stackAllocator>& document, bool* alreadyExist = 0) const {
- return Create(document, document.GetAllocator(), alreadyExist);
- }
-
- //@}
-
- //!@name Query value
- //@{
-
- //! Query a value in a subtree.
- /*!
- \param root Root value of a DOM sub-tree to be resolved. It can be any value other than document root.
- \param unresolvedTokenIndex If the pointer cannot resolve a token in the pointer, this parameter can obtain the index of unresolved token.
- \return Pointer to the value if it can be resolved. Otherwise null.
-
- \note
- There are only 3 situations when a value cannot be resolved:
- 1. A value in the path is not an array nor object.
- 2. An object value does not contain the token.
- 3. A token is out of range of an array value.
-
- Use unresolvedTokenIndex to retrieve the token index.
- */
- ValueType* Get(ValueType& root, size_t* unresolvedTokenIndex = 0) const {
- RAPIDJSON_ASSERT(IsValid());
- ValueType* v = &root;
- for (const Token *t = tokens_; t != tokens_ + tokenCount_; ++t) {
- switch (v->GetType()) {
- case kObjectType:
- {
- typename ValueType::MemberIterator m = v->FindMember(GenericStringRef<Ch>(t->name, t->length));
- if (m == v->MemberEnd())
- break;
- v = &m->value;
- }
- continue;
- case kArrayType:
- if (t->index == kPointerInvalidIndex || t->index >= v->Size())
- break;
- v = &((*v)[t->index]);
- continue;
- default:
- break;
- }
-
- // Error: unresolved token
- if (unresolvedTokenIndex)
- *unresolvedTokenIndex = static_cast<size_t>(t - tokens_);
- return 0;
- }
- return v;
- }
-
- //! Query a const value in a const subtree.
- /*!
- \param root Root value of a DOM sub-tree to be resolved. It can be any value other than document root.
- \return Pointer to the value if it can be resolved. Otherwise null.
- */
- const ValueType* Get(const ValueType& root, size_t* unresolvedTokenIndex = 0) const {
- return Get(const_cast<ValueType&>(root), unresolvedTokenIndex);
- }
-
- //@}
-
- //!@name Query a value with default
- //@{
-
- //! Query a value in a subtree with default value.
- /*!
- Similar to Get(), but if the specified value do not exists, it creates all parents and clone the default value.
- So that this function always succeed.
-
- \param root Root value of a DOM sub-tree to be resolved. It can be any value other than document root.
- \param defaultValue Default value to be cloned if the value was not exists.
- \param allocator Allocator for creating the values if the specified value or its parents are not exist.
- \see Create()
- */
- ValueType& GetWithDefault(ValueType& root, const ValueType& defaultValue, typename ValueType::AllocatorType& allocator) const {
- bool alreadyExist;
- Value& v = Create(root, allocator, &alreadyExist);
- return alreadyExist ? v : v.CopyFrom(defaultValue, allocator);
- }
-
- //! Query a value in a subtree with default null-terminated string.
- ValueType& GetWithDefault(ValueType& root, const Ch* defaultValue, typename ValueType::AllocatorType& allocator) const {
- bool alreadyExist;
- Value& v = Create(root, allocator, &alreadyExist);
- return alreadyExist ? v : v.SetString(defaultValue, allocator);
- }
-
-#if RAPIDJSON_HAS_STDSTRING
- //! Query a value in a subtree with default std::basic_string.
- ValueType& GetWithDefault(ValueType& root, const std::basic_string<Ch>& defaultValue, typename ValueType::AllocatorType& allocator) const {
- bool alreadyExist;
- Value& v = Create(root, allocator, &alreadyExist);
- return alreadyExist ? v : v.SetString(defaultValue, allocator);
- }
-#endif
-
- //! Query a value in a subtree with default primitive value.
- /*!
- \tparam T Either \ref Type, \c int, \c unsigned, \c int64_t, \c uint64_t, \c bool
- */
- template <typename T>
- RAPIDJSON_DISABLEIF_RETURN((internal::OrExpr<internal::IsPointer<T>, internal::IsGenericValue<T> >), (ValueType&))
- GetWithDefault(ValueType& root, T defaultValue, typename ValueType::AllocatorType& allocator) const {
- return GetWithDefault(root, ValueType(defaultValue).Move(), allocator);
- }
-
- //! Query a value in a document with default value.
- template <typename stackAllocator>
- ValueType& GetWithDefault(GenericDocument<EncodingType, typename ValueType::AllocatorType, stackAllocator>& document, const ValueType& defaultValue) const {
- return GetWithDefault(document, defaultValue, document.GetAllocator());
- }
-
- //! Query a value in a document with default null-terminated string.
- template <typename stackAllocator>
- ValueType& GetWithDefault(GenericDocument<EncodingType, typename ValueType::AllocatorType, stackAllocator>& document, const Ch* defaultValue) const {
- return GetWithDefault(document, defaultValue, document.GetAllocator());
- }
-
-#if RAPIDJSON_HAS_STDSTRING
- //! Query a value in a document with default std::basic_string.
- template <typename stackAllocator>
- ValueType& GetWithDefault(GenericDocument<EncodingType, typename ValueType::AllocatorType, stackAllocator>& document, const std::basic_string<Ch>& defaultValue) const {
- return GetWithDefault(document, defaultValue, document.GetAllocator());
- }
-#endif
-
- //! Query a value in a document with default primitive value.
- /*!
- \tparam T Either \ref Type, \c int, \c unsigned, \c int64_t, \c uint64_t, \c bool
- */
- template <typename T, typename stackAllocator>
- RAPIDJSON_DISABLEIF_RETURN((internal::OrExpr<internal::IsPointer<T>, internal::IsGenericValue<T> >), (ValueType&))
- GetWithDefault(GenericDocument<EncodingType, typename ValueType::AllocatorType, stackAllocator>& document, T defaultValue) const {
- return GetWithDefault(document, defaultValue, document.GetAllocator());
- }
-
- //@}
-
- //!@name Set a value
- //@{
-
- //! Set a value in a subtree, with move semantics.
- /*!
- It creates all parents if they are not exist or types are different to the tokens.
- So this function always succeeds but potentially remove existing values.
-
- \param root Root value of a DOM sub-tree to be resolved. It can be any value other than document root.
- \param value Value to be set.
- \param allocator Allocator for creating the values if the specified value or its parents are not exist.
- \see Create()
- */
- ValueType& Set(ValueType& root, ValueType& value, typename ValueType::AllocatorType& allocator) const {
- return Create(root, allocator) = value;
- }
-
- //! Set a value in a subtree, with copy semantics.
- ValueType& Set(ValueType& root, const ValueType& value, typename ValueType::AllocatorType& allocator) const {
- return Create(root, allocator).CopyFrom(value, allocator);
- }
-
- //! Set a null-terminated string in a subtree.
- ValueType& Set(ValueType& root, const Ch* value, typename ValueType::AllocatorType& allocator) const {
- return Create(root, allocator) = ValueType(value, allocator).Move();
- }
-
-#if RAPIDJSON_HAS_STDSTRING
- //! Set a std::basic_string in a subtree.
- ValueType& Set(ValueType& root, const std::basic_string<Ch>& value, typename ValueType::AllocatorType& allocator) const {
- return Create(root, allocator) = ValueType(value, allocator).Move();
- }
-#endif
-
- //! Set a primitive value in a subtree.
- /*!
- \tparam T Either \ref Type, \c int, \c unsigned, \c int64_t, \c uint64_t, \c bool
- */
- template <typename T>
- RAPIDJSON_DISABLEIF_RETURN((internal::OrExpr<internal::IsPointer<T>, internal::IsGenericValue<T> >), (ValueType&))
- Set(ValueType& root, T value, typename ValueType::AllocatorType& allocator) const {
- return Create(root, allocator) = ValueType(value).Move();
- }
-
- //! Set a value in a document, with move semantics.
- template <typename stackAllocator>
- ValueType& Set(GenericDocument<EncodingType, typename ValueType::AllocatorType, stackAllocator>& document, ValueType& value) const {
- return Create(document) = value;
- }
-
- //! Set a value in a document, with copy semantics.
- template <typename stackAllocator>
- ValueType& Set(GenericDocument<EncodingType, typename ValueType::AllocatorType, stackAllocator>& document, const ValueType& value) const {
- return Create(document).CopyFrom(value, document.GetAllocator());
- }
-
- //! Set a null-terminated string in a document.
- template <typename stackAllocator>
- ValueType& Set(GenericDocument<EncodingType, typename ValueType::AllocatorType, stackAllocator>& document, const Ch* value) const {
- return Create(document) = ValueType(value, document.GetAllocator()).Move();
- }
-
-#if RAPIDJSON_HAS_STDSTRING
- //! Sets a std::basic_string in a document.
- template <typename stackAllocator>
- ValueType& Set(GenericDocument<EncodingType, typename ValueType::AllocatorType, stackAllocator>& document, const std::basic_string<Ch>& value) const {
- return Create(document) = ValueType(value, document.GetAllocator()).Move();
- }
-#endif
-
- //! Set a primitive value in a document.
- /*!
- \tparam T Either \ref Type, \c int, \c unsigned, \c int64_t, \c uint64_t, \c bool
- */
- template <typename T, typename stackAllocator>
- RAPIDJSON_DISABLEIF_RETURN((internal::OrExpr<internal::IsPointer<T>, internal::IsGenericValue<T> >), (ValueType&))
- Set(GenericDocument<EncodingType, typename ValueType::AllocatorType, stackAllocator>& document, T value) const {
- return Create(document) = value;
- }
-
- //@}
-
- //!@name Swap a value
- //@{
-
- //! Swap a value with a value in a subtree.
- /*!
- It creates all parents if they are not exist or types are different to the tokens.
- So this function always succeeds but potentially remove existing values.
-
- \param root Root value of a DOM sub-tree to be resolved. It can be any value other than document root.
- \param value Value to be swapped.
- \param allocator Allocator for creating the values if the specified value or its parents are not exist.
- \see Create()
- */
- ValueType& Swap(ValueType& root, ValueType& value, typename ValueType::AllocatorType& allocator) const {
- return Create(root, allocator).Swap(value);
- }
-
- //! Swap a value with a value in a document.
- template <typename stackAllocator>
- ValueType& Swap(GenericDocument<EncodingType, typename ValueType::AllocatorType, stackAllocator>& document, ValueType& value) const {
- return Create(document).Swap(value);
- }
-
- //@}
-
- //! Erase a value in a subtree.
- /*!
- \param root Root value of a DOM sub-tree to be resolved. It can be any value other than document root.
- \return Whether the resolved value is found and erased.
-
- \note Erasing with an empty pointer \c Pointer(""), i.e. the root, always fail and return false.
- */
- bool Erase(ValueType& root) const {
- RAPIDJSON_ASSERT(IsValid());
- if (tokenCount_ == 0) // Cannot erase the root
- return false;
-
- ValueType* v = &root;
- const Token* last = tokens_ + (tokenCount_ - 1);
- for (const Token *t = tokens_; t != last; ++t) {
- switch (v->GetType()) {
- case kObjectType:
- {
- typename ValueType::MemberIterator m = v->FindMember(GenericStringRef<Ch>(t->name, t->length));
- if (m == v->MemberEnd())
- return false;
- v = &m->value;
- }
- break;
- case kArrayType:
- if (t->index == kPointerInvalidIndex || t->index >= v->Size())
- return false;
- v = &((*v)[t->index]);
- break;
- default:
- return false;
- }
- }
-
- switch (v->GetType()) {
- case kObjectType:
- return v->EraseMember(GenericStringRef<Ch>(last->name, last->length));
- case kArrayType:
- if (last->index == kPointerInvalidIndex || last->index >= v->Size())
- return false;
- v->Erase(v->Begin() + last->index);
- return true;
- default:
- return false;
- }
- }
-
-private:
- //! Clone the content from rhs to this.
- /*!
- \param rhs Source pointer.
- \param extraToken Extra tokens to be allocated.
- \param extraNameBufferSize Extra name buffer size (in number of Ch) to be allocated.
- \return Start of non-occupied name buffer, for storing extra names.
- */
- Ch* CopyFromRaw(const GenericPointer& rhs, size_t extraToken = 0, size_t extraNameBufferSize = 0) {
- if (!allocator_) // allocator is independently owned.
- ownAllocator_ = allocator_ = RAPIDJSON_NEW(Allocator());
-
- size_t nameBufferSize = rhs.tokenCount_; // null terminators for tokens
- for (Token *t = rhs.tokens_; t != rhs.tokens_ + rhs.tokenCount_; ++t)
- nameBufferSize += t->length;
-
- tokenCount_ = rhs.tokenCount_ + extraToken;
- tokens_ = static_cast<Token *>(allocator_->Malloc(tokenCount_ * sizeof(Token) + (nameBufferSize + extraNameBufferSize) * sizeof(Ch)));
- nameBuffer_ = reinterpret_cast<Ch *>(tokens_ + tokenCount_);
- if (rhs.tokenCount_ > 0) {
- std::memcpy(tokens_, rhs.tokens_, rhs.tokenCount_ * sizeof(Token));
- }
- if (nameBufferSize > 0) {
- std::memcpy(nameBuffer_, rhs.nameBuffer_, nameBufferSize * sizeof(Ch));
- }
-
- // Adjust pointers to name buffer
- std::ptrdiff_t diff = nameBuffer_ - rhs.nameBuffer_;
- for (Token *t = tokens_; t != tokens_ + rhs.tokenCount_; ++t)
- t->name += diff;
-
- return nameBuffer_ + nameBufferSize;
- }
-
- //! Check whether a character should be percent-encoded.
- /*!
- According to RFC 3986 2.3 Unreserved Characters.
- \param c The character (code unit) to be tested.
- */
- bool NeedPercentEncode(Ch c) const {
- return !((c >= '0' && c <= '9') || (c >= 'A' && c <='Z') || (c >= 'a' && c <= 'z') || c == '-' || c == '.' || c == '_' || c =='~');
- }
-
- //! Parse a JSON String or its URI fragment representation into tokens.
-#ifndef __clang__ // -Wdocumentation
- /*!
- \param source Either a JSON Pointer string, or its URI fragment representation. Not need to be null terminated.
- \param length Length of the source string.
- \note Source cannot be JSON String Representation of JSON Pointer, e.g. In "/\u0000", \u0000 will not be unescaped.
- */
-#endif
- void Parse(const Ch* source, size_t length) {
- RAPIDJSON_ASSERT(source != NULL);
- RAPIDJSON_ASSERT(nameBuffer_ == 0);
- RAPIDJSON_ASSERT(tokens_ == 0);
-
- // Create own allocator if user did not supply.
- if (!allocator_)
- ownAllocator_ = allocator_ = RAPIDJSON_NEW(Allocator());
-
- // Count number of '/' as tokenCount
- tokenCount_ = 0;
- for (const Ch* s = source; s != source + length; s++)
- if (*s == '/')
- tokenCount_++;
-
- Token* token = tokens_ = static_cast<Token *>(allocator_->Malloc(tokenCount_ * sizeof(Token) + length * sizeof(Ch)));
- Ch* name = nameBuffer_ = reinterpret_cast<Ch *>(tokens_ + tokenCount_);
- size_t i = 0;
-
- // Detect if it is a URI fragment
- bool uriFragment = false;
- if (source[i] == '#') {
- uriFragment = true;
- i++;
- }
-
- if (i != length && source[i] != '/') {
- parseErrorCode_ = kPointerParseErrorTokenMustBeginWithSolidus;
- goto error;
- }
-
- while (i < length) {
- RAPIDJSON_ASSERT(source[i] == '/');
- i++; // consumes '/'
-
- token->name = name;
- bool isNumber = true;
-
- while (i < length && source[i] != '/') {
- Ch c = source[i];
- if (uriFragment) {
- // Decoding percent-encoding for URI fragment
- if (c == '%') {
- PercentDecodeStream is(&source[i], source + length);
- GenericInsituStringStream<EncodingType> os(name);
- Ch* begin = os.PutBegin();
- if (!Transcoder<UTF8<>, EncodingType>().Validate(is, os) || !is.IsValid()) {
- parseErrorCode_ = kPointerParseErrorInvalidPercentEncoding;
- goto error;
- }
- size_t len = os.PutEnd(begin);
- i += is.Tell() - 1;
- if (len == 1)
- c = *name;
- else {
- name += len;
- isNumber = false;
- i++;
- continue;
- }
- }
- else if (NeedPercentEncode(c)) {
- parseErrorCode_ = kPointerParseErrorCharacterMustPercentEncode;
- goto error;
- }
- }
-
- i++;
-
- // Escaping "~0" -> '~', "~1" -> '/'
- if (c == '~') {
- if (i < length) {
- c = source[i];
- if (c == '0') c = '~';
- else if (c == '1') c = '/';
- else {
- parseErrorCode_ = kPointerParseErrorInvalidEscape;
- goto error;
- }
- i++;
- }
- else {
- parseErrorCode_ = kPointerParseErrorInvalidEscape;
- goto error;
- }
- }
-
- // First check for index: all of characters are digit
- if (c < '0' || c > '9')
- isNumber = false;
-
- *name++ = c;
- }
- token->length = static_cast<SizeType>(name - token->name);
- if (token->length == 0)
- isNumber = false;
- *name++ = '\0'; // Null terminator
-
- // Second check for index: more than one digit cannot have leading zero
- if (isNumber && token->length > 1 && token->name[0] == '0')
- isNumber = false;
-
- // String to SizeType conversion
- SizeType n = 0;
- if (isNumber) {
- for (size_t j = 0; j < token->length; j++) {
- SizeType m = n * 10 + static_cast<SizeType>(token->name[j] - '0');
- if (m < n) { // overflow detection
- isNumber = false;
- break;
- }
- n = m;
- }
- }
-
- token->index = isNumber ? n : kPointerInvalidIndex;
- token++;
- }
-
- RAPIDJSON_ASSERT(name <= nameBuffer_ + length); // Should not overflow buffer
- parseErrorCode_ = kPointerParseErrorNone;
- return;
-
- error:
- Allocator::Free(tokens_);
- nameBuffer_ = 0;
- tokens_ = 0;
- tokenCount_ = 0;
- parseErrorOffset_ = i;
- return;
- }
-
- //! Stringify to string or URI fragment representation.
- /*!
- \tparam uriFragment True for stringifying to URI fragment representation. False for string representation.
- \tparam OutputStream type of output stream.
- \param os The output stream.
- */
- template<bool uriFragment, typename OutputStream>
- bool Stringify(OutputStream& os) const {
- RAPIDJSON_ASSERT(IsValid());
-
- if (uriFragment)
- os.Put('#');
-
- for (Token *t = tokens_; t != tokens_ + tokenCount_; ++t) {
- os.Put('/');
- for (size_t j = 0; j < t->length; j++) {
- Ch c = t->name[j];
- if (c == '~') {
- os.Put('~');
- os.Put('0');
- }
- else if (c == '/') {
- os.Put('~');
- os.Put('1');
- }
- else if (uriFragment && NeedPercentEncode(c)) {
- // Transcode to UTF8 sequence
- GenericStringStream<typename ValueType::EncodingType> source(&t->name[j]);
- PercentEncodeStream<OutputStream> target(os);
- if (!Transcoder<EncodingType, UTF8<> >().Validate(source, target))
- return false;
- j += source.Tell() - 1;
- }
- else
- os.Put(c);
- }
- }
- return true;
- }
-
- //! A helper stream for decoding a percent-encoded sequence into code unit.
- /*!
- This stream decodes %XY triplet into code unit (0-255).
- If it encounters invalid characters, it sets output code unit as 0 and
- mark invalid, and to be checked by IsValid().
- */
- class PercentDecodeStream {
- public:
- typedef typename ValueType::Ch Ch;
-
- //! Constructor
- /*!
- \param source Start of the stream
- \param end Past-the-end of the stream.
- */
- PercentDecodeStream(const Ch* source, const Ch* end) : src_(source), head_(source), end_(end), valid_(true) {}
-
- Ch Take() {
- if (*src_ != '%' || src_ + 3 > end_) { // %XY triplet
- valid_ = false;
- return 0;
- }
- src_++;
- Ch c = 0;
- for (int j = 0; j < 2; j++) {
- c = static_cast<Ch>(c << 4);
- Ch h = *src_;
- if (h >= '0' && h <= '9') c = static_cast<Ch>(c + h - '0');
- else if (h >= 'A' && h <= 'F') c = static_cast<Ch>(c + h - 'A' + 10);
- else if (h >= 'a' && h <= 'f') c = static_cast<Ch>(c + h - 'a' + 10);
- else {
- valid_ = false;
- return 0;
- }
- src_++;
- }
- return c;
- }
-
- size_t Tell() const { return static_cast<size_t>(src_ - head_); }
- bool IsValid() const { return valid_; }
-
- private:
- const Ch* src_; //!< Current read position.
- const Ch* head_; //!< Original head of the string.
- const Ch* end_; //!< Past-the-end position.
- bool valid_; //!< Whether the parsing is valid.
- };
-
- //! A helper stream to encode character (UTF-8 code unit) into percent-encoded sequence.
- template <typename OutputStream>
- class PercentEncodeStream {
- public:
- PercentEncodeStream(OutputStream& os) : os_(os) {}
- void Put(char c) { // UTF-8 must be byte
- unsigned char u = static_cast<unsigned char>(c);
- static const char hexDigits[16] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' };
- os_.Put('%');
- os_.Put(hexDigits[u >> 4]);
- os_.Put(hexDigits[u & 15]);
- }
- private:
- OutputStream& os_;
- };
-
- Allocator* allocator_; //!< The current allocator. It is either user-supplied or equal to ownAllocator_.
- Allocator* ownAllocator_; //!< Allocator owned by this Pointer.
- Ch* nameBuffer_; //!< A buffer containing all names in tokens.
- Token* tokens_; //!< A list of tokens.
- size_t tokenCount_; //!< Number of tokens in tokens_.
- size_t parseErrorOffset_; //!< Offset in code unit when parsing fail.
- PointerParseErrorCode parseErrorCode_; //!< Parsing error code.
-};
-
-//! GenericPointer for Value (UTF-8, default allocator).
-typedef GenericPointer<Value> Pointer;
-
-//!@name Helper functions for GenericPointer
-//@{
-
-//////////////////////////////////////////////////////////////////////////////
-
-template <typename T>
-typename T::ValueType& CreateValueByPointer(T& root, const GenericPointer<typename T::ValueType>& pointer, typename T::AllocatorType& a) {
- return pointer.Create(root, a);
-}
-
-template <typename T, typename CharType, size_t N>
-typename T::ValueType& CreateValueByPointer(T& root, const CharType(&source)[N], typename T::AllocatorType& a) {
- return GenericPointer<typename T::ValueType>(source, N - 1).Create(root, a);
-}
-
-// No allocator parameter
-
-template <typename DocumentType>
-typename DocumentType::ValueType& CreateValueByPointer(DocumentType& document, const GenericPointer<typename DocumentType::ValueType>& pointer) {
- return pointer.Create(document);
-}
-
-template <typename DocumentType, typename CharType, size_t N>
-typename DocumentType::ValueType& CreateValueByPointer(DocumentType& document, const CharType(&source)[N]) {
- return GenericPointer<typename DocumentType::ValueType>(source, N - 1).Create(document);
-}
-
-//////////////////////////////////////////////////////////////////////////////
-
-template <typename T>
-typename T::ValueType* GetValueByPointer(T& root, const GenericPointer<typename T::ValueType>& pointer, size_t* unresolvedTokenIndex = 0) {
- return pointer.Get(root, unresolvedTokenIndex);
-}
-
-template <typename T>
-const typename T::ValueType* GetValueByPointer(const T& root, const GenericPointer<typename T::ValueType>& pointer, size_t* unresolvedTokenIndex = 0) {
- return pointer.Get(root, unresolvedTokenIndex);
-}
-
-template <typename T, typename CharType, size_t N>
-typename T::ValueType* GetValueByPointer(T& root, const CharType (&source)[N], size_t* unresolvedTokenIndex = 0) {
- return GenericPointer<typename T::ValueType>(source, N - 1).Get(root, unresolvedTokenIndex);
-}
-
-template <typename T, typename CharType, size_t N>
-const typename T::ValueType* GetValueByPointer(const T& root, const CharType(&source)[N], size_t* unresolvedTokenIndex = 0) {
- return GenericPointer<typename T::ValueType>(source, N - 1).Get(root, unresolvedTokenIndex);
-}
-
-//////////////////////////////////////////////////////////////////////////////
-
-template <typename T>
-typename T::ValueType& GetValueByPointerWithDefault(T& root, const GenericPointer<typename T::ValueType>& pointer, const typename T::ValueType& defaultValue, typename T::AllocatorType& a) {
- return pointer.GetWithDefault(root, defaultValue, a);
-}
-
-template <typename T>
-typename T::ValueType& GetValueByPointerWithDefault(T& root, const GenericPointer<typename T::ValueType>& pointer, const typename T::Ch* defaultValue, typename T::AllocatorType& a) {
- return pointer.GetWithDefault(root, defaultValue, a);
-}
-
-#if RAPIDJSON_HAS_STDSTRING
-template <typename T>
-typename T::ValueType& GetValueByPointerWithDefault(T& root, const GenericPointer<typename T::ValueType>& pointer, const std::basic_string<typename T::Ch>& defaultValue, typename T::AllocatorType& a) {
- return pointer.GetWithDefault(root, defaultValue, a);
-}
-#endif
-
-template <typename T, typename T2>
-RAPIDJSON_DISABLEIF_RETURN((internal::OrExpr<internal::IsPointer<T2>, internal::IsGenericValue<T2> >), (typename T::ValueType&))
-GetValueByPointerWithDefault(T& root, const GenericPointer<typename T::ValueType>& pointer, T2 defaultValue, typename T::AllocatorType& a) {
- return pointer.GetWithDefault(root, defaultValue, a);
-}
-
-template <typename T, typename CharType, size_t N>
-typename T::ValueType& GetValueByPointerWithDefault(T& root, const CharType(&source)[N], const typename T::ValueType& defaultValue, typename T::AllocatorType& a) {
- return GenericPointer<typename T::ValueType>(source, N - 1).GetWithDefault(root, defaultValue, a);
-}
-
-template <typename T, typename CharType, size_t N>
-typename T::ValueType& GetValueByPointerWithDefault(T& root, const CharType(&source)[N], const typename T::Ch* defaultValue, typename T::AllocatorType& a) {
- return GenericPointer<typename T::ValueType>(source, N - 1).GetWithDefault(root, defaultValue, a);
-}
-
-#if RAPIDJSON_HAS_STDSTRING
-template <typename T, typename CharType, size_t N>
-typename T::ValueType& GetValueByPointerWithDefault(T& root, const CharType(&source)[N], const std::basic_string<typename T::Ch>& defaultValue, typename T::AllocatorType& a) {
- return GenericPointer<typename T::ValueType>(source, N - 1).GetWithDefault(root, defaultValue, a);
-}
-#endif
-
-template <typename T, typename CharType, size_t N, typename T2>
-RAPIDJSON_DISABLEIF_RETURN((internal::OrExpr<internal::IsPointer<T2>, internal::IsGenericValue<T2> >), (typename T::ValueType&))
-GetValueByPointerWithDefault(T& root, const CharType(&source)[N], T2 defaultValue, typename T::AllocatorType& a) {
- return GenericPointer<typename T::ValueType>(source, N - 1).GetWithDefault(root, defaultValue, a);
-}
-
-// No allocator parameter
-
-template <typename DocumentType>
-typename DocumentType::ValueType& GetValueByPointerWithDefault(DocumentType& document, const GenericPointer<typename DocumentType::ValueType>& pointer, const typename DocumentType::ValueType& defaultValue) {
- return pointer.GetWithDefault(document, defaultValue);
-}
-
-template <typename DocumentType>
-typename DocumentType::ValueType& GetValueByPointerWithDefault(DocumentType& document, const GenericPointer<typename DocumentType::ValueType>& pointer, const typename DocumentType::Ch* defaultValue) {
- return pointer.GetWithDefault(document, defaultValue);
-}
-
-#if RAPIDJSON_HAS_STDSTRING
-template <typename DocumentType>
-typename DocumentType::ValueType& GetValueByPointerWithDefault(DocumentType& document, const GenericPointer<typename DocumentType::ValueType>& pointer, const std::basic_string<typename DocumentType::Ch>& defaultValue) {
- return pointer.GetWithDefault(document, defaultValue);
-}
-#endif
-
-template <typename DocumentType, typename T2>
-RAPIDJSON_DISABLEIF_RETURN((internal::OrExpr<internal::IsPointer<T2>, internal::IsGenericValue<T2> >), (typename DocumentType::ValueType&))
-GetValueByPointerWithDefault(DocumentType& document, const GenericPointer<typename DocumentType::ValueType>& pointer, T2 defaultValue) {
- return pointer.GetWithDefault(document, defaultValue);
-}
-
-template <typename DocumentType, typename CharType, size_t N>
-typename DocumentType::ValueType& GetValueByPointerWithDefault(DocumentType& document, const CharType(&source)[N], const typename DocumentType::ValueType& defaultValue) {
- return GenericPointer<typename DocumentType::ValueType>(source, N - 1).GetWithDefault(document, defaultValue);
-}
-
-template <typename DocumentType, typename CharType, size_t N>
-typename DocumentType::ValueType& GetValueByPointerWithDefault(DocumentType& document, const CharType(&source)[N], const typename DocumentType::Ch* defaultValue) {
- return GenericPointer<typename DocumentType::ValueType>(source, N - 1).GetWithDefault(document, defaultValue);
-}
-
-#if RAPIDJSON_HAS_STDSTRING
-template <typename DocumentType, typename CharType, size_t N>
-typename DocumentType::ValueType& GetValueByPointerWithDefault(DocumentType& document, const CharType(&source)[N], const std::basic_string<typename DocumentType::Ch>& defaultValue) {
- return GenericPointer<typename DocumentType::ValueType>(source, N - 1).GetWithDefault(document, defaultValue);
-}
-#endif
-
-template <typename DocumentType, typename CharType, size_t N, typename T2>
-RAPIDJSON_DISABLEIF_RETURN((internal::OrExpr<internal::IsPointer<T2>, internal::IsGenericValue<T2> >), (typename DocumentType::ValueType&))
-GetValueByPointerWithDefault(DocumentType& document, const CharType(&source)[N], T2 defaultValue) {
- return GenericPointer<typename DocumentType::ValueType>(source, N - 1).GetWithDefault(document, defaultValue);
-}
-
-//////////////////////////////////////////////////////////////////////////////
-
-template <typename T>
-typename T::ValueType& SetValueByPointer(T& root, const GenericPointer<typename T::ValueType>& pointer, typename T::ValueType& value, typename T::AllocatorType& a) {
- return pointer.Set(root, value, a);
-}
-
-template <typename T>
-typename T::ValueType& SetValueByPointer(T& root, const GenericPointer<typename T::ValueType>& pointer, const typename T::ValueType& value, typename T::AllocatorType& a) {
- return pointer.Set(root, value, a);
-}
-
-template <typename T>
-typename T::ValueType& SetValueByPointer(T& root, const GenericPointer<typename T::ValueType>& pointer, const typename T::Ch* value, typename T::AllocatorType& a) {
- return pointer.Set(root, value, a);
-}
-
-#if RAPIDJSON_HAS_STDSTRING
-template <typename T>
-typename T::ValueType& SetValueByPointer(T& root, const GenericPointer<typename T::ValueType>& pointer, const std::basic_string<typename T::Ch>& value, typename T::AllocatorType& a) {
- return pointer.Set(root, value, a);
-}
-#endif
-
-template <typename T, typename T2>
-RAPIDJSON_DISABLEIF_RETURN((internal::OrExpr<internal::IsPointer<T2>, internal::IsGenericValue<T2> >), (typename T::ValueType&))
-SetValueByPointer(T& root, const GenericPointer<typename T::ValueType>& pointer, T2 value, typename T::AllocatorType& a) {
- return pointer.Set(root, value, a);
-}
-
-template <typename T, typename CharType, size_t N>
-typename T::ValueType& SetValueByPointer(T& root, const CharType(&source)[N], typename T::ValueType& value, typename T::AllocatorType& a) {
- return GenericPointer<typename T::ValueType>(source, N - 1).Set(root, value, a);
-}
-
-template <typename T, typename CharType, size_t N>
-typename T::ValueType& SetValueByPointer(T& root, const CharType(&source)[N], const typename T::ValueType& value, typename T::AllocatorType& a) {
- return GenericPointer<typename T::ValueType>(source, N - 1).Set(root, value, a);
-}
-
-template <typename T, typename CharType, size_t N>
-typename T::ValueType& SetValueByPointer(T& root, const CharType(&source)[N], const typename T::Ch* value, typename T::AllocatorType& a) {
- return GenericPointer<typename T::ValueType>(source, N - 1).Set(root, value, a);
-}
-
-#if RAPIDJSON_HAS_STDSTRING
-template <typename T, typename CharType, size_t N>
-typename T::ValueType& SetValueByPointer(T& root, const CharType(&source)[N], const std::basic_string<typename T::Ch>& value, typename T::AllocatorType& a) {
- return GenericPointer<typename T::ValueType>(source, N - 1).Set(root, value, a);
-}
-#endif
-
-template <typename T, typename CharType, size_t N, typename T2>
-RAPIDJSON_DISABLEIF_RETURN((internal::OrExpr<internal::IsPointer<T2>, internal::IsGenericValue<T2> >), (typename T::ValueType&))
-SetValueByPointer(T& root, const CharType(&source)[N], T2 value, typename T::AllocatorType& a) {
- return GenericPointer<typename T::ValueType>(source, N - 1).Set(root, value, a);
-}
-
-// No allocator parameter
-
-template <typename DocumentType>
-typename DocumentType::ValueType& SetValueByPointer(DocumentType& document, const GenericPointer<typename DocumentType::ValueType>& pointer, typename DocumentType::ValueType& value) {
- return pointer.Set(document, value);
-}
-
-template <typename DocumentType>
-typename DocumentType::ValueType& SetValueByPointer(DocumentType& document, const GenericPointer<typename DocumentType::ValueType>& pointer, const typename DocumentType::ValueType& value) {
- return pointer.Set(document, value);
-}
-
-template <typename DocumentType>
-typename DocumentType::ValueType& SetValueByPointer(DocumentType& document, const GenericPointer<typename DocumentType::ValueType>& pointer, const typename DocumentType::Ch* value) {
- return pointer.Set(document, value);
-}
-
-#if RAPIDJSON_HAS_STDSTRING
-template <typename DocumentType>
-typename DocumentType::ValueType& SetValueByPointer(DocumentType& document, const GenericPointer<typename DocumentType::ValueType>& pointer, const std::basic_string<typename DocumentType::Ch>& value) {
- return pointer.Set(document, value);
-}
-#endif
-
-template <typename DocumentType, typename T2>
-RAPIDJSON_DISABLEIF_RETURN((internal::OrExpr<internal::IsPointer<T2>, internal::IsGenericValue<T2> >), (typename DocumentType::ValueType&))
-SetValueByPointer(DocumentType& document, const GenericPointer<typename DocumentType::ValueType>& pointer, T2 value) {
- return pointer.Set(document, value);
-}
-
-template <typename DocumentType, typename CharType, size_t N>
-typename DocumentType::ValueType& SetValueByPointer(DocumentType& document, const CharType(&source)[N], typename DocumentType::ValueType& value) {
- return GenericPointer<typename DocumentType::ValueType>(source, N - 1).Set(document, value);
-}
-
-template <typename DocumentType, typename CharType, size_t N>
-typename DocumentType::ValueType& SetValueByPointer(DocumentType& document, const CharType(&source)[N], const typename DocumentType::ValueType& value) {
- return GenericPointer<typename DocumentType::ValueType>(source, N - 1).Set(document, value);
-}
-
-template <typename DocumentType, typename CharType, size_t N>
-typename DocumentType::ValueType& SetValueByPointer(DocumentType& document, const CharType(&source)[N], const typename DocumentType::Ch* value) {
- return GenericPointer<typename DocumentType::ValueType>(source, N - 1).Set(document, value);
-}
-
-#if RAPIDJSON_HAS_STDSTRING
-template <typename DocumentType, typename CharType, size_t N>
-typename DocumentType::ValueType& SetValueByPointer(DocumentType& document, const CharType(&source)[N], const std::basic_string<typename DocumentType::Ch>& value) {
- return GenericPointer<typename DocumentType::ValueType>(source, N - 1).Set(document, value);
-}
-#endif
-
-template <typename DocumentType, typename CharType, size_t N, typename T2>
-RAPIDJSON_DISABLEIF_RETURN((internal::OrExpr<internal::IsPointer<T2>, internal::IsGenericValue<T2> >), (typename DocumentType::ValueType&))
-SetValueByPointer(DocumentType& document, const CharType(&source)[N], T2 value) {
- return GenericPointer<typename DocumentType::ValueType>(source, N - 1).Set(document, value);
-}
-
-//////////////////////////////////////////////////////////////////////////////
-
-template <typename T>
-typename T::ValueType& SwapValueByPointer(T& root, const GenericPointer<typename T::ValueType>& pointer, typename T::ValueType& value, typename T::AllocatorType& a) {
- return pointer.Swap(root, value, a);
-}
-
-template <typename T, typename CharType, size_t N>
-typename T::ValueType& SwapValueByPointer(T& root, const CharType(&source)[N], typename T::ValueType& value, typename T::AllocatorType& a) {
- return GenericPointer<typename T::ValueType>(source, N - 1).Swap(root, value, a);
-}
-
-template <typename DocumentType>
-typename DocumentType::ValueType& SwapValueByPointer(DocumentType& document, const GenericPointer<typename DocumentType::ValueType>& pointer, typename DocumentType::ValueType& value) {
- return pointer.Swap(document, value);
-}
-
-template <typename DocumentType, typename CharType, size_t N>
-typename DocumentType::ValueType& SwapValueByPointer(DocumentType& document, const CharType(&source)[N], typename DocumentType::ValueType& value) {
- return GenericPointer<typename DocumentType::ValueType>(source, N - 1).Swap(document, value);
-}
-
-//////////////////////////////////////////////////////////////////////////////
-
-template <typename T>
-bool EraseValueByPointer(T& root, const GenericPointer<typename T::ValueType>& pointer) {
- return pointer.Erase(root);
-}
-
-template <typename T, typename CharType, size_t N>
-bool EraseValueByPointer(T& root, const CharType(&source)[N]) {
- return GenericPointer<typename T::ValueType>(source, N - 1).Erase(root);
-}
-
-//@}
-
-RAPIDJSON_NAMESPACE_END
-
-#ifdef __clang__
-RAPIDJSON_DIAG_POP
-#endif
-
-#ifdef _MSC_VER
-RAPIDJSON_DIAG_POP
-#endif
-
-#endif // RAPIDJSON_POINTER_H_
diff --git a/include/rapidjson/reader.h b/include/rapidjson/reader.h
deleted file mode 100644
index 19f8849b..00000000
--- a/include/rapidjson/reader.h
+++ /dev/null
@@ -1,1879 +0,0 @@
-// Tencent is pleased to support the open source community by making RapidJSON available.
-//
-// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
-//
-// Licensed under the MIT License (the "License"); you may not use this file except
-// in compliance with the License. You may obtain a copy of the License at
-//
-// http://opensource.org/licenses/MIT
-//
-// Unless required by applicable law or agreed to in writing, software distributed
-// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
-// CONDITIONS OF ANY KIND, either express or implied. See the License for the
-// specific language governing permissions and limitations under the License.
-
-#ifndef RAPIDJSON_READER_H_
-#define RAPIDJSON_READER_H_
-
-/*! \file reader.h */
-
-#include "allocators.h"
-#include "stream.h"
-#include "encodedstream.h"
-#include "internal/meta.h"
-#include "internal/stack.h"
-#include "internal/strtod.h"
-#include <limits>
-
-#if defined(RAPIDJSON_SIMD) && defined(_MSC_VER)
-#include <intrin.h>
-#pragma intrinsic(_BitScanForward)
-#endif
-#ifdef RAPIDJSON_SSE42
-#include <nmmintrin.h>
-#elif defined(RAPIDJSON_SSE2)
-#include <emmintrin.h>
-#endif
-
-#ifdef _MSC_VER
-RAPIDJSON_DIAG_PUSH
-RAPIDJSON_DIAG_OFF(4127) // conditional expression is constant
-RAPIDJSON_DIAG_OFF(4702) // unreachable code
-#endif
-
-#ifdef __clang__
-RAPIDJSON_DIAG_PUSH
-RAPIDJSON_DIAG_OFF(old-style-cast)
-RAPIDJSON_DIAG_OFF(padded)
-RAPIDJSON_DIAG_OFF(switch-enum)
-#endif
-
-#ifdef __GNUC__
-RAPIDJSON_DIAG_PUSH
-RAPIDJSON_DIAG_OFF(effc++)
-#endif
-
-//!@cond RAPIDJSON_HIDDEN_FROM_DOXYGEN
-#define RAPIDJSON_NOTHING /* deliberately empty */
-#ifndef RAPIDJSON_PARSE_ERROR_EARLY_RETURN
-#define RAPIDJSON_PARSE_ERROR_EARLY_RETURN(value) \
- RAPIDJSON_MULTILINEMACRO_BEGIN \
- if (RAPIDJSON_UNLIKELY(HasParseError())) { return value; } \
- RAPIDJSON_MULTILINEMACRO_END
-#endif
-#define RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID \
- RAPIDJSON_PARSE_ERROR_EARLY_RETURN(RAPIDJSON_NOTHING)
-//!@endcond
-
-/*! \def RAPIDJSON_PARSE_ERROR_NORETURN
- \ingroup RAPIDJSON_ERRORS
- \brief Macro to indicate a parse error.
- \param parseErrorCode \ref rapidjson::ParseErrorCode of the error
- \param offset position of the error in JSON input (\c size_t)
-
- This macros can be used as a customization point for the internal
- error handling mechanism of RapidJSON.
-
- A common usage model is to throw an exception instead of requiring the
- caller to explicitly check the \ref rapidjson::GenericReader::Parse's
- return value:
-
- \code
- #define RAPIDJSON_PARSE_ERROR_NORETURN(parseErrorCode,offset) \
- throw ParseException(parseErrorCode, #parseErrorCode, offset)
-
- #include <stdexcept> // std::runtime_error
- #include "rapidjson/error/error.h" // rapidjson::ParseResult
-
- struct ParseException : std::runtime_error, rapidjson::ParseResult {
- ParseException(rapidjson::ParseErrorCode code, const char* msg, size_t offset)
- : std::runtime_error(msg), ParseResult(code, offset) {}
- };
-
- #include "rapidjson/reader.h"
- \endcode
-
- \see RAPIDJSON_PARSE_ERROR, rapidjson::GenericReader::Parse
- */
-#ifndef RAPIDJSON_PARSE_ERROR_NORETURN
-#define RAPIDJSON_PARSE_ERROR_NORETURN(parseErrorCode, offset) \
- RAPIDJSON_MULTILINEMACRO_BEGIN \
- RAPIDJSON_ASSERT(!HasParseError()); /* Error can only be assigned once */ \
- SetParseError(parseErrorCode, offset); \
- RAPIDJSON_MULTILINEMACRO_END
-#endif
-
-/*! \def RAPIDJSON_PARSE_ERROR
- \ingroup RAPIDJSON_ERRORS
- \brief (Internal) macro to indicate and handle a parse error.
- \param parseErrorCode \ref rapidjson::ParseErrorCode of the error
- \param offset position of the error in JSON input (\c size_t)
-
- Invokes RAPIDJSON_PARSE_ERROR_NORETURN and stops the parsing.
-
- \see RAPIDJSON_PARSE_ERROR_NORETURN
- \hideinitializer
- */
-#ifndef RAPIDJSON_PARSE_ERROR
-#define RAPIDJSON_PARSE_ERROR(parseErrorCode, offset) \
- RAPIDJSON_MULTILINEMACRO_BEGIN \
- RAPIDJSON_PARSE_ERROR_NORETURN(parseErrorCode, offset); \
- RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID; \
- RAPIDJSON_MULTILINEMACRO_END
-#endif
-
-#include "error/error.h" // ParseErrorCode, ParseResult
-
-RAPIDJSON_NAMESPACE_BEGIN
-
-///////////////////////////////////////////////////////////////////////////////
-// ParseFlag
-
-/*! \def RAPIDJSON_PARSE_DEFAULT_FLAGS
- \ingroup RAPIDJSON_CONFIG
- \brief User-defined kParseDefaultFlags definition.
-
- User can define this as any \c ParseFlag combinations.
-*/
-#ifndef RAPIDJSON_PARSE_DEFAULT_FLAGS
-#define RAPIDJSON_PARSE_DEFAULT_FLAGS kParseNoFlags
-#endif
-
-//! Combination of parseFlags
-/*! \see Reader::Parse, Document::Parse, Document::ParseInsitu, Document::ParseStream
- */
-enum ParseFlag {
- kParseNoFlags = 0, //!< No flags are set.
- kParseInsituFlag = 1, //!< In-situ(destructive) parsing.
- kParseValidateEncodingFlag = 2, //!< Validate encoding of JSON strings.
- kParseIterativeFlag = 4, //!< Iterative(constant complexity in terms of function call stack size) parsing.
- kParseStopWhenDoneFlag = 8, //!< After parsing a complete JSON root from stream, stop further processing the rest of stream. When this flag is used, parser will not generate kParseErrorDocumentRootNotSingular error.
- kParseFullPrecisionFlag = 16, //!< Parse number in full precision (but slower).
- kParseCommentsFlag = 32, //!< Allow one-line (//) and multi-line (/**/) comments.
- kParseNumbersAsStringsFlag = 64, //!< Parse all numbers (ints/doubles) as strings.
- kParseTrailingCommasFlag = 128, //!< Allow trailing commas at the end of objects and arrays.
- kParseNanAndInfFlag = 256, //!< Allow parsing NaN, Inf, Infinity, -Inf and -Infinity as doubles.
- kParseDefaultFlags = RAPIDJSON_PARSE_DEFAULT_FLAGS //!< Default parse flags. Can be customized by defining RAPIDJSON_PARSE_DEFAULT_FLAGS
-};
-
-///////////////////////////////////////////////////////////////////////////////
-// Handler
-
-/*! \class rapidjson::Handler
- \brief Concept for receiving events from GenericReader upon parsing.
- The functions return true if no error occurs. If they return false,
- the event publisher should terminate the process.
-\code
-concept Handler {
- typename Ch;
-
- bool Null();
- bool Bool(bool b);
- bool Int(int i);
- bool Uint(unsigned i);
- bool Int64(int64_t i);
- bool Uint64(uint64_t i);
- bool Double(double d);
- /// enabled via kParseNumbersAsStringsFlag, string is not null-terminated (use length)
- bool RawNumber(const Ch* str, SizeType length, bool copy);
- bool String(const Ch* str, SizeType length, bool copy);
- bool StartObject();
- bool Key(const Ch* str, SizeType length, bool copy);
- bool EndObject(SizeType memberCount);
- bool StartArray();
- bool EndArray(SizeType elementCount);
-};
-\endcode
-*/
-///////////////////////////////////////////////////////////////////////////////
-// BaseReaderHandler
-
-//! Default implementation of Handler.
-/*! This can be used as base class of any reader handler.
- \note implements Handler concept
-*/
-template<typename Encoding = UTF8<>, typename Derived = void>
-struct BaseReaderHandler {
- typedef typename Encoding::Ch Ch;
-
- typedef typename internal::SelectIf<internal::IsSame<Derived, void>, BaseReaderHandler, Derived>::Type Override;
-
- bool Default() { return true; }
- bool Null() { return static_cast<Override&>(*this).Default(); }
- bool Bool(bool) { return static_cast<Override&>(*this).Default(); }
- bool Int(int) { return static_cast<Override&>(*this).Default(); }
- bool Uint(unsigned) { return static_cast<Override&>(*this).Default(); }
- bool Int64(int64_t) { return static_cast<Override&>(*this).Default(); }
- bool Uint64(uint64_t) { return static_cast<Override&>(*this).Default(); }
- bool Double(double) { return static_cast<Override&>(*this).Default(); }
- /// enabled via kParseNumbersAsStringsFlag, string is not null-terminated (use length)
- bool RawNumber(const Ch* str, SizeType len, bool copy) { return static_cast<Override&>(*this).String(str, len, copy); }
- bool String(const Ch*, SizeType, bool) { return static_cast<Override&>(*this).Default(); }
- bool StartObject() { return static_cast<Override&>(*this).Default(); }
- bool Key(const Ch* str, SizeType len, bool copy) { return static_cast<Override&>(*this).String(str, len, copy); }
- bool EndObject(SizeType) { return static_cast<Override&>(*this).Default(); }
- bool StartArray() { return static_cast<Override&>(*this).Default(); }
- bool EndArray(SizeType) { return static_cast<Override&>(*this).Default(); }
-};
-
-///////////////////////////////////////////////////////////////////////////////
-// StreamLocalCopy
-
-namespace internal {
-
-template<typename Stream, int = StreamTraits<Stream>::copyOptimization>
-class StreamLocalCopy;
-
-//! Do copy optimization.
-template<typename Stream>
-class StreamLocalCopy<Stream, 1> {
-public:
- StreamLocalCopy(Stream& original) : s(original), original_(original) {}
- ~StreamLocalCopy() { original_ = s; }
-
- Stream s;
-
-private:
- StreamLocalCopy& operator=(const StreamLocalCopy&) /* = delete */;
-
- Stream& original_;
-};
-
-//! Keep reference.
-template<typename Stream>
-class StreamLocalCopy<Stream, 0> {
-public:
- StreamLocalCopy(Stream& original) : s(original) {}
-
- Stream& s;
-
-private:
- StreamLocalCopy& operator=(const StreamLocalCopy&) /* = delete */;
-};
-
-} // namespace internal
-
-///////////////////////////////////////////////////////////////////////////////
-// SkipWhitespace
-
-//! Skip the JSON white spaces in a stream.
-/*! \param is A input stream for skipping white spaces.
- \note This function has SSE2/SSE4.2 specialization.
-*/
-template<typename InputStream>
-void SkipWhitespace(InputStream& is) {
- internal::StreamLocalCopy<InputStream> copy(is);
- InputStream& s(copy.s);
-
- typename InputStream::Ch c;
- while ((c = s.Peek()) == ' ' || c == '\n' || c == '\r' || c == '\t')
- s.Take();
-}
-
-inline const char* SkipWhitespace(const char* p, const char* end) {
- while (p != end && (*p == ' ' || *p == '\n' || *p == '\r' || *p == '\t'))
- ++p;
- return p;
-}
-
-#ifdef RAPIDJSON_SSE42
-//! Skip whitespace with SSE 4.2 pcmpistrm instruction, testing 16 8-byte characters at once.
-inline const char *SkipWhitespace_SIMD(const char* p) {
- // Fast return for single non-whitespace
- if (*p == ' ' || *p == '\n' || *p == '\r' || *p == '\t')
- ++p;
- else
- return p;
-
- // 16-byte align to the next boundary
- const char* nextAligned = reinterpret_cast<const char*>((reinterpret_cast<size_t>(p) + 15) & static_cast<size_t>(~15));
- while (p != nextAligned)
- if (*p == ' ' || *p == '\n' || *p == '\r' || *p == '\t')
- ++p;
- else
- return p;
-
- // The rest of string using SIMD
- static const char whitespace[16] = " \n\r\t";
- const __m128i w = _mm_loadu_si128(reinterpret_cast<const __m128i *>(&whitespace[0]));
-
- for (;; p += 16) {
- const __m128i s = _mm_load_si128(reinterpret_cast<const __m128i *>(p));
- const int r = _mm_cvtsi128_si32(_mm_cmpistrm(w, s, _SIDD_UBYTE_OPS | _SIDD_CMP_EQUAL_ANY | _SIDD_BIT_MASK | _SIDD_NEGATIVE_POLARITY));
- if (r != 0) { // some of characters is non-whitespace
-#ifdef _MSC_VER // Find the index of first non-whitespace
- unsigned long offset;
- _BitScanForward(&offset, r);
- return p + offset;
-#else
- return p + __builtin_ffs(r) - 1;
-#endif
- }
- }
-}
-
-inline const char *SkipWhitespace_SIMD(const char* p, const char* end) {
- // Fast return for single non-whitespace
- if (p != end && (*p == ' ' || *p == '\n' || *p == '\r' || *p == '\t'))
- ++p;
- else
- return p;
-
- // The middle of string using SIMD
- static const char whitespace[16] = " \n\r\t";
- const __m128i w = _mm_loadu_si128(reinterpret_cast<const __m128i *>(&whitespace[0]));
-
- for (; p <= end - 16; p += 16) {
- const __m128i s = _mm_loadu_si128(reinterpret_cast<const __m128i *>(p));
- const int r = _mm_cvtsi128_si32(_mm_cmpistrm(w, s, _SIDD_UBYTE_OPS | _SIDD_CMP_EQUAL_ANY | _SIDD_BIT_MASK | _SIDD_NEGATIVE_POLARITY));
- if (r != 0) { // some of characters is non-whitespace
-#ifdef _MSC_VER // Find the index of first non-whitespace
- unsigned long offset;
- _BitScanForward(&offset, r);
- return p + offset;
-#else
- return p + __builtin_ffs(r) - 1;
-#endif
- }
- }
-
- return SkipWhitespace(p, end);
-}
-
-#elif defined(RAPIDJSON_SSE2)
-
-//! Skip whitespace with SSE2 instructions, testing 16 8-byte characters at once.
-inline const char *SkipWhitespace_SIMD(const char* p) {
- // Fast return for single non-whitespace
- if (*p == ' ' || *p == '\n' || *p == '\r' || *p == '\t')
- ++p;
- else
- return p;
-
- // 16-byte align to the next boundary
- const char* nextAligned = reinterpret_cast<const char*>((reinterpret_cast<size_t>(p) + 15) & static_cast<size_t>(~15));
- while (p != nextAligned)
- if (*p == ' ' || *p == '\n' || *p == '\r' || *p == '\t')
- ++p;
- else
- return p;
-
- // The rest of string
- #define C16(c) { c, c, c, c, c, c, c, c, c, c, c, c, c, c, c, c }
- static const char whitespaces[4][16] = { C16(' '), C16('\n'), C16('\r'), C16('\t') };
- #undef C16
-
- const __m128i w0 = _mm_loadu_si128(reinterpret_cast<const __m128i *>(&whitespaces[0][0]));
- const __m128i w1 = _mm_loadu_si128(reinterpret_cast<const __m128i *>(&whitespaces[1][0]));
- const __m128i w2 = _mm_loadu_si128(reinterpret_cast<const __m128i *>(&whitespaces[2][0]));
- const __m128i w3 = _mm_loadu_si128(reinterpret_cast<const __m128i *>(&whitespaces[3][0]));
-
- for (;; p += 16) {
- const __m128i s = _mm_load_si128(reinterpret_cast<const __m128i *>(p));
- __m128i x = _mm_cmpeq_epi8(s, w0);
- x = _mm_or_si128(x, _mm_cmpeq_epi8(s, w1));
- x = _mm_or_si128(x, _mm_cmpeq_epi8(s, w2));
- x = _mm_or_si128(x, _mm_cmpeq_epi8(s, w3));
- unsigned short r = static_cast<unsigned short>(~_mm_movemask_epi8(x));
- if (r != 0) { // some of characters may be non-whitespace
-#ifdef _MSC_VER // Find the index of first non-whitespace
- unsigned long offset;
- _BitScanForward(&offset, r);
- return p + offset;
-#else
- return p + __builtin_ffs(r) - 1;
-#endif
- }
- }
-}
-
-inline const char *SkipWhitespace_SIMD(const char* p, const char* end) {
- // Fast return for single non-whitespace
- if (p != end && (*p == ' ' || *p == '\n' || *p == '\r' || *p == '\t'))
- ++p;
- else
- return p;
-
- // The rest of string
- #define C16(c) { c, c, c, c, c, c, c, c, c, c, c, c, c, c, c, c }
- static const char whitespaces[4][16] = { C16(' '), C16('\n'), C16('\r'), C16('\t') };
- #undef C16
-
- const __m128i w0 = _mm_loadu_si128(reinterpret_cast<const __m128i *>(&whitespaces[0][0]));
- const __m128i w1 = _mm_loadu_si128(reinterpret_cast<const __m128i *>(&whitespaces[1][0]));
- const __m128i w2 = _mm_loadu_si128(reinterpret_cast<const __m128i *>(&whitespaces[2][0]));
- const __m128i w3 = _mm_loadu_si128(reinterpret_cast<const __m128i *>(&whitespaces[3][0]));
-
- for (; p <= end - 16; p += 16) {
- const __m128i s = _mm_loadu_si128(reinterpret_cast<const __m128i *>(p));
- __m128i x = _mm_cmpeq_epi8(s, w0);
- x = _mm_or_si128(x, _mm_cmpeq_epi8(s, w1));
- x = _mm_or_si128(x, _mm_cmpeq_epi8(s, w2));
- x = _mm_or_si128(x, _mm_cmpeq_epi8(s, w3));
- unsigned short r = static_cast<unsigned short>(~_mm_movemask_epi8(x));
- if (r != 0) { // some of characters may be non-whitespace
-#ifdef _MSC_VER // Find the index of first non-whitespace
- unsigned long offset;
- _BitScanForward(&offset, r);
- return p + offset;
-#else
- return p + __builtin_ffs(r) - 1;
-#endif
- }
- }
-
- return SkipWhitespace(p, end);
-}
-
-#endif // RAPIDJSON_SSE2
-
-#ifdef RAPIDJSON_SIMD
-//! Template function specialization for InsituStringStream
-template<> inline void SkipWhitespace(InsituStringStream& is) {
- is.src_ = const_cast<char*>(SkipWhitespace_SIMD(is.src_));
-}
-
-//! Template function specialization for StringStream
-template<> inline void SkipWhitespace(StringStream& is) {
- is.src_ = SkipWhitespace_SIMD(is.src_);
-}
-
-template<> inline void SkipWhitespace(EncodedInputStream<UTF8<>, MemoryStream>& is) {
- is.is_.src_ = SkipWhitespace_SIMD(is.is_.src_, is.is_.end_);
-}
-#endif // RAPIDJSON_SIMD
-
-///////////////////////////////////////////////////////////////////////////////
-// GenericReader
-
-//! SAX-style JSON parser. Use \ref Reader for UTF8 encoding and default allocator.
-/*! GenericReader parses JSON text from a stream, and send events synchronously to an
- object implementing Handler concept.
-
- It needs to allocate a stack for storing a single decoded string during
- non-destructive parsing.
-
- For in-situ parsing, the decoded string is directly written to the source
- text string, no temporary buffer is required.
-
- A GenericReader object can be reused for parsing multiple JSON text.
-
- \tparam SourceEncoding Encoding of the input stream.
- \tparam TargetEncoding Encoding of the parse output.
- \tparam StackAllocator Allocator type for stack.
-*/
-template <typename SourceEncoding, typename TargetEncoding, typename StackAllocator = CrtAllocator>
-class GenericReader {
-public:
- typedef typename SourceEncoding::Ch Ch; //!< SourceEncoding character type
-
- //! Constructor.
- /*! \param stackAllocator Optional allocator for allocating stack memory. (Only use for non-destructive parsing)
- \param stackCapacity stack capacity in bytes for storing a single decoded string. (Only use for non-destructive parsing)
- */
- GenericReader(StackAllocator* stackAllocator = 0, size_t stackCapacity = kDefaultStackCapacity) : stack_(stackAllocator, stackCapacity), parseResult_() {}
-
- //! Parse JSON text.
- /*! \tparam parseFlags Combination of \ref ParseFlag.
- \tparam InputStream Type of input stream, implementing Stream concept.
- \tparam Handler Type of handler, implementing Handler concept.
- \param is Input stream to be parsed.
- \param handler The handler to receive events.
- \return Whether the parsing is successful.
- */
- template <unsigned parseFlags, typename InputStream, typename Handler>
- ParseResult Parse(InputStream& is, Handler& handler) {
- if (parseFlags & kParseIterativeFlag)
- return IterativeParse<parseFlags>(is, handler);
-
- parseResult_.Clear();
-
- ClearStackOnExit scope(*this);
-
- SkipWhitespaceAndComments<parseFlags>(is);
- RAPIDJSON_PARSE_ERROR_EARLY_RETURN(parseResult_);
-
- if (RAPIDJSON_UNLIKELY(is.Peek() == '\0')) {
- RAPIDJSON_PARSE_ERROR_NORETURN(kParseErrorDocumentEmpty, is.Tell());
- RAPIDJSON_PARSE_ERROR_EARLY_RETURN(parseResult_);
- }
- else {
- ParseValue<parseFlags>(is, handler);
- RAPIDJSON_PARSE_ERROR_EARLY_RETURN(parseResult_);
-
- if (!(parseFlags & kParseStopWhenDoneFlag)) {
- SkipWhitespaceAndComments<parseFlags>(is);
- RAPIDJSON_PARSE_ERROR_EARLY_RETURN(parseResult_);
-
- if (RAPIDJSON_UNLIKELY(is.Peek() != '\0')) {
- RAPIDJSON_PARSE_ERROR_NORETURN(kParseErrorDocumentRootNotSingular, is.Tell());
- RAPIDJSON_PARSE_ERROR_EARLY_RETURN(parseResult_);
- }
- }
- }
-
- return parseResult_;
- }
-
- //! Parse JSON text (with \ref kParseDefaultFlags)
- /*! \tparam InputStream Type of input stream, implementing Stream concept
- \tparam Handler Type of handler, implementing Handler concept.
- \param is Input stream to be parsed.
- \param handler The handler to receive events.
- \return Whether the parsing is successful.
- */
- template <typename InputStream, typename Handler>
- ParseResult Parse(InputStream& is, Handler& handler) {
- return Parse<kParseDefaultFlags>(is, handler);
- }
-
- //! Whether a parse error has occured in the last parsing.
- bool HasParseError() const { return parseResult_.IsError(); }
-
- //! Get the \ref ParseErrorCode of last parsing.
- ParseErrorCode GetParseErrorCode() const { return parseResult_.Code(); }
-
- //! Get the position of last parsing error in input, 0 otherwise.
- size_t GetErrorOffset() const { return parseResult_.Offset(); }
-
-protected:
- void SetParseError(ParseErrorCode code, size_t offset) { parseResult_.Set(code, offset); }
-
-private:
- // Prohibit copy constructor & assignment operator.
- GenericReader(const GenericReader&);
- GenericReader& operator=(const GenericReader&);
-
- void ClearStack() { stack_.Clear(); }
-
- // clear stack on any exit from ParseStream, e.g. due to exception
- struct ClearStackOnExit {
- explicit ClearStackOnExit(GenericReader& r) : r_(r) {}
- ~ClearStackOnExit() { r_.ClearStack(); }
- private:
- GenericReader& r_;
- ClearStackOnExit(const ClearStackOnExit&);
- ClearStackOnExit& operator=(const ClearStackOnExit&);
- };
-
- template<unsigned parseFlags, typename InputStream>
- void SkipWhitespaceAndComments(InputStream& is) {
- SkipWhitespace(is);
-
- if (parseFlags & kParseCommentsFlag) {
- while (RAPIDJSON_UNLIKELY(Consume(is, '/'))) {
- if (Consume(is, '*')) {
- while (true) {
- if (RAPIDJSON_UNLIKELY(is.Peek() == '\0'))
- RAPIDJSON_PARSE_ERROR(kParseErrorUnspecificSyntaxError, is.Tell());
- else if (Consume(is, '*')) {
- if (Consume(is, '/'))
- break;
- }
- else
- is.Take();
- }
- }
- else if (RAPIDJSON_LIKELY(Consume(is, '/')))
- while (is.Peek() != '\0' && is.Take() != '\n');
- else
- RAPIDJSON_PARSE_ERROR(kParseErrorUnspecificSyntaxError, is.Tell());
-
- SkipWhitespace(is);
- }
- }
- }
-
- // Parse object: { string : value, ... }
- template<unsigned parseFlags, typename InputStream, typename Handler>
- void ParseObject(InputStream& is, Handler& handler) {
- RAPIDJSON_ASSERT(is.Peek() == '{');
- is.Take(); // Skip '{'
-
- if (RAPIDJSON_UNLIKELY(!handler.StartObject()))
- RAPIDJSON_PARSE_ERROR(kParseErrorTermination, is.Tell());
-
- SkipWhitespaceAndComments<parseFlags>(is);
- RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID;
-
- if (Consume(is, '}')) {
- if (RAPIDJSON_UNLIKELY(!handler.EndObject(0))) // empty object
- RAPIDJSON_PARSE_ERROR(kParseErrorTermination, is.Tell());
- return;
- }
-
- for (SizeType memberCount = 0;;) {
- if (RAPIDJSON_UNLIKELY(is.Peek() != '"'))
- RAPIDJSON_PARSE_ERROR(kParseErrorObjectMissName, is.Tell());
-
- ParseString<parseFlags>(is, handler, true);
- RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID;
-
- SkipWhitespaceAndComments<parseFlags>(is);
- RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID;
-
- if (RAPIDJSON_UNLIKELY(!Consume(is, ':')))
- RAPIDJSON_PARSE_ERROR(kParseErrorObjectMissColon, is.Tell());
-
- SkipWhitespaceAndComments<parseFlags>(is);
- RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID;
-
- ParseValue<parseFlags>(is, handler);
- RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID;
-
- SkipWhitespaceAndComments<parseFlags>(is);
- RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID;
-
- ++memberCount;
-
- switch (is.Peek()) {
- case ',':
- is.Take();
- SkipWhitespaceAndComments<parseFlags>(is);
- RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID;
- break;
- case '}':
- is.Take();
- if (RAPIDJSON_UNLIKELY(!handler.EndObject(memberCount)))
- RAPIDJSON_PARSE_ERROR(kParseErrorTermination, is.Tell());
- return;
- default:
- RAPIDJSON_PARSE_ERROR(kParseErrorObjectMissCommaOrCurlyBracket, is.Tell()); break; // This useless break is only for making warning and coverage happy
- }
-
- if (parseFlags & kParseTrailingCommasFlag) {
- if (is.Peek() == '}') {
- if (RAPIDJSON_UNLIKELY(!handler.EndObject(memberCount)))
- RAPIDJSON_PARSE_ERROR(kParseErrorTermination, is.Tell());
- is.Take();
- return;
- }
- }
- }
- }
-
- // Parse array: [ value, ... ]
- template<unsigned parseFlags, typename InputStream, typename Handler>
- void ParseArray(InputStream& is, Handler& handler) {
- RAPIDJSON_ASSERT(is.Peek() == '[');
- is.Take(); // Skip '['
-
- if (RAPIDJSON_UNLIKELY(!handler.StartArray()))
- RAPIDJSON_PARSE_ERROR(kParseErrorTermination, is.Tell());
-
- SkipWhitespaceAndComments<parseFlags>(is);
- RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID;
-
- if (Consume(is, ']')) {
- if (RAPIDJSON_UNLIKELY(!handler.EndArray(0))) // empty array
- RAPIDJSON_PARSE_ERROR(kParseErrorTermination, is.Tell());
- return;
- }
-
- for (SizeType elementCount = 0;;) {
- ParseValue<parseFlags>(is, handler);
- RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID;
-
- ++elementCount;
- SkipWhitespaceAndComments<parseFlags>(is);
- RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID;
-
- if (Consume(is, ',')) {
- SkipWhitespaceAndComments<parseFlags>(is);
- RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID;
- }
- else if (Consume(is, ']')) {
- if (RAPIDJSON_UNLIKELY(!handler.EndArray(elementCount)))
- RAPIDJSON_PARSE_ERROR(kParseErrorTermination, is.Tell());
- return;
- }
- else
- RAPIDJSON_PARSE_ERROR(kParseErrorArrayMissCommaOrSquareBracket, is.Tell());
-
- if (parseFlags & kParseTrailingCommasFlag) {
- if (is.Peek() == ']') {
- if (RAPIDJSON_UNLIKELY(!handler.EndArray(elementCount)))
- RAPIDJSON_PARSE_ERROR(kParseErrorTermination, is.Tell());
- is.Take();
- return;
- }
- }
- }
- }
-
- template<unsigned parseFlags, typename InputStream, typename Handler>
- void ParseNull(InputStream& is, Handler& handler) {
- RAPIDJSON_ASSERT(is.Peek() == 'n');
- is.Take();
-
- if (RAPIDJSON_LIKELY(Consume(is, 'u') && Consume(is, 'l') && Consume(is, 'l'))) {
- if (RAPIDJSON_UNLIKELY(!handler.Null()))
- RAPIDJSON_PARSE_ERROR(kParseErrorTermination, is.Tell());
- }
- else
- RAPIDJSON_PARSE_ERROR(kParseErrorValueInvalid, is.Tell());
- }
-
- template<unsigned parseFlags, typename InputStream, typename Handler>
- void ParseTrue(InputStream& is, Handler& handler) {
- RAPIDJSON_ASSERT(is.Peek() == 't');
- is.Take();
-
- if (RAPIDJSON_LIKELY(Consume(is, 'r') && Consume(is, 'u') && Consume(is, 'e'))) {
- if (RAPIDJSON_UNLIKELY(!handler.Bool(true)))
- RAPIDJSON_PARSE_ERROR(kParseErrorTermination, is.Tell());
- }
- else
- RAPIDJSON_PARSE_ERROR(kParseErrorValueInvalid, is.Tell());
- }
-
- template<unsigned parseFlags, typename InputStream, typename Handler>
- void ParseFalse(InputStream& is, Handler& handler) {
- RAPIDJSON_ASSERT(is.Peek() == 'f');
- is.Take();
-
- if (RAPIDJSON_LIKELY(Consume(is, 'a') && Consume(is, 'l') && Consume(is, 's') && Consume(is, 'e'))) {
- if (RAPIDJSON_UNLIKELY(!handler.Bool(false)))
- RAPIDJSON_PARSE_ERROR(kParseErrorTermination, is.Tell());
- }
- else
- RAPIDJSON_PARSE_ERROR(kParseErrorValueInvalid, is.Tell());
- }
-
- template<typename InputStream>
- RAPIDJSON_FORCEINLINE static bool Consume(InputStream& is, typename InputStream::Ch expect) {
- if (RAPIDJSON_LIKELY(is.Peek() == expect)) {
- is.Take();
- return true;
- }
- else
- return false;
- }
-
- // Helper function to parse four hexidecimal digits in \uXXXX in ParseString().
- template<typename InputStream>
- unsigned ParseHex4(InputStream& is, size_t escapeOffset) {
- unsigned codepoint = 0;
- for (int i = 0; i < 4; i++) {
- Ch c = is.Peek();
- codepoint <<= 4;
- codepoint += static_cast<unsigned>(c);
- if (c >= '0' && c <= '9')
- codepoint -= '0';
- else if (c >= 'A' && c <= 'F')
- codepoint -= 'A' - 10;
- else if (c >= 'a' && c <= 'f')
- codepoint -= 'a' - 10;
- else {
- RAPIDJSON_PARSE_ERROR_NORETURN(kParseErrorStringUnicodeEscapeInvalidHex, escapeOffset);
- RAPIDJSON_PARSE_ERROR_EARLY_RETURN(0);
- }
- is.Take();
- }
- return codepoint;
- }
-
- template <typename CharType>
- class StackStream {
- public:
- typedef CharType Ch;
-
- StackStream(internal::Stack<StackAllocator>& stack) : stack_(stack), length_(0) {}
- RAPIDJSON_FORCEINLINE void Put(Ch c) {
- *stack_.template Push<Ch>() = c;
- ++length_;
- }
-
- RAPIDJSON_FORCEINLINE void* Push(SizeType count) {
- length_ += count;
- return stack_.template Push<Ch>(count);
- }
-
- size_t Length() const { return length_; }
-
- Ch* Pop() {
- return stack_.template Pop<Ch>(length_);
- }
-
- private:
- StackStream(const StackStream&);
- StackStream& operator=(const StackStream&);
-
- internal::Stack<StackAllocator>& stack_;
- SizeType length_;
- };
-
- // Parse string and generate String event. Different code paths for kParseInsituFlag.
- template<unsigned parseFlags, typename InputStream, typename Handler>
- void ParseString(InputStream& is, Handler& handler, bool isKey = false) {
- internal::StreamLocalCopy<InputStream> copy(is);
- InputStream& s(copy.s);
-
- RAPIDJSON_ASSERT(s.Peek() == '\"');
- s.Take(); // Skip '\"'
-
- bool success = false;
- if (parseFlags & kParseInsituFlag) {
- typename InputStream::Ch *head = s.PutBegin();
- ParseStringToStream<parseFlags, SourceEncoding, SourceEncoding>(s, s);
- RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID;
- size_t length = s.PutEnd(head) - 1;
- RAPIDJSON_ASSERT(length <= 0xFFFFFFFF);
- const typename TargetEncoding::Ch* const str = reinterpret_cast<typename TargetEncoding::Ch*>(head);
- success = (isKey ? handler.Key(str, SizeType(length), false) : handler.String(str, SizeType(length), false));
- }
- else {
- StackStream<typename TargetEncoding::Ch> stackStream(stack_);
- ParseStringToStream<parseFlags, SourceEncoding, TargetEncoding>(s, stackStream);
- RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID;
- SizeType length = static_cast<SizeType>(stackStream.Length()) - 1;
- const typename TargetEncoding::Ch* const str = stackStream.Pop();
- success = (isKey ? handler.Key(str, length, true) : handler.String(str, length, true));
- }
- if (RAPIDJSON_UNLIKELY(!success))
- RAPIDJSON_PARSE_ERROR(kParseErrorTermination, s.Tell());
- }
-
- // Parse string to an output is
- // This function handles the prefix/suffix double quotes, escaping, and optional encoding validation.
- template<unsigned parseFlags, typename SEncoding, typename TEncoding, typename InputStream, typename OutputStream>
- RAPIDJSON_FORCEINLINE void ParseStringToStream(InputStream& is, OutputStream& os) {
-//!@cond RAPIDJSON_HIDDEN_FROM_DOXYGEN
-#define Z16 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
- static const char escape[256] = {
- Z16, Z16, 0, 0,'\"', 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,'/',
- Z16, Z16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,'\\', 0, 0, 0,
- 0, 0,'\b', 0, 0, 0,'\f', 0, 0, 0, 0, 0, 0, 0,'\n', 0,
- 0, 0,'\r', 0,'\t', 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- Z16, Z16, Z16, Z16, Z16, Z16, Z16, Z16
- };
-#undef Z16
-//!@endcond
-
- for (;;) {
- // Scan and copy string before "\\\"" or < 0x20. This is an optional optimzation.
- if (!(parseFlags & kParseValidateEncodingFlag))
- ScanCopyUnescapedString(is, os);
-
- Ch c = is.Peek();
- if (RAPIDJSON_UNLIKELY(c == '\\')) { // Escape
- size_t escapeOffset = is.Tell(); // For invalid escaping, report the inital '\\' as error offset
- is.Take();
- Ch e = is.Peek();
- if ((sizeof(Ch) == 1 || unsigned(e) < 256) && RAPIDJSON_LIKELY(escape[static_cast<unsigned char>(e)])) {
- is.Take();
- os.Put(static_cast<typename TEncoding::Ch>(escape[static_cast<unsigned char>(e)]));
- }
- else if (RAPIDJSON_LIKELY(e == 'u')) { // Unicode
- is.Take();
- unsigned codepoint = ParseHex4(is, escapeOffset);
- RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID;
- if (RAPIDJSON_UNLIKELY(codepoint >= 0xD800 && codepoint <= 0xDBFF)) {
- // Handle UTF-16 surrogate pair
- if (RAPIDJSON_UNLIKELY(!Consume(is, '\\') || !Consume(is, 'u')))
- RAPIDJSON_PARSE_ERROR(kParseErrorStringUnicodeSurrogateInvalid, escapeOffset);
- unsigned codepoint2 = ParseHex4(is, escapeOffset);
- RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID;
- if (RAPIDJSON_UNLIKELY(codepoint2 < 0xDC00 || codepoint2 > 0xDFFF))
- RAPIDJSON_PARSE_ERROR(kParseErrorStringUnicodeSurrogateInvalid, escapeOffset);
- codepoint = (((codepoint - 0xD800) << 10) | (codepoint2 - 0xDC00)) + 0x10000;
- }
- TEncoding::Encode(os, codepoint);
- }
- else
- RAPIDJSON_PARSE_ERROR(kParseErrorStringEscapeInvalid, escapeOffset);
- }
- else if (RAPIDJSON_UNLIKELY(c == '"')) { // Closing double quote
- is.Take();
- os.Put('\0'); // null-terminate the string
- return;
- }
- else if (RAPIDJSON_UNLIKELY(static_cast<unsigned>(c) < 0x20)) { // RFC 4627: unescaped = %x20-21 / %x23-5B / %x5D-10FFFF
- if (c == '\0')
- RAPIDJSON_PARSE_ERROR(kParseErrorStringMissQuotationMark, is.Tell());
- else
- RAPIDJSON_PARSE_ERROR(kParseErrorStringEscapeInvalid, is.Tell());
- }
- else {
- size_t offset = is.Tell();
- if (RAPIDJSON_UNLIKELY((parseFlags & kParseValidateEncodingFlag ?
- !Transcoder<SEncoding, TEncoding>::Validate(is, os) :
- !Transcoder<SEncoding, TEncoding>::Transcode(is, os))))
- RAPIDJSON_PARSE_ERROR(kParseErrorStringInvalidEncoding, offset);
- }
- }
- }
-
- template<typename InputStream, typename OutputStream>
- static RAPIDJSON_FORCEINLINE void ScanCopyUnescapedString(InputStream&, OutputStream&) {
- // Do nothing for generic version
- }
-
-#if defined(RAPIDJSON_SSE2) || defined(RAPIDJSON_SSE42)
- // StringStream -> StackStream<char>
- static RAPIDJSON_FORCEINLINE void ScanCopyUnescapedString(StringStream& is, StackStream<char>& os) {
- const char* p = is.src_;
-
- // Scan one by one until alignment (unaligned load may cross page boundary and cause crash)
- const char* nextAligned = reinterpret_cast<const char*>((reinterpret_cast<size_t>(p) + 15) & static_cast<size_t>(~15));
- while (p != nextAligned)
- if (RAPIDJSON_UNLIKELY(*p == '\"') || RAPIDJSON_UNLIKELY(*p == '\\') || RAPIDJSON_UNLIKELY(static_cast<unsigned>(*p) < 0x20)) {
- is.src_ = p;
- return;
- }
- else
- os.Put(*p++);
-
- // The rest of string using SIMD
- static const char dquote[16] = { '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"' };
- static const char bslash[16] = { '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\' };
- static const char space[16] = { 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19 };
- const __m128i dq = _mm_loadu_si128(reinterpret_cast<const __m128i *>(&dquote[0]));
- const __m128i bs = _mm_loadu_si128(reinterpret_cast<const __m128i *>(&bslash[0]));
- const __m128i sp = _mm_loadu_si128(reinterpret_cast<const __m128i *>(&space[0]));
-
- for (;; p += 16) {
- const __m128i s = _mm_load_si128(reinterpret_cast<const __m128i *>(p));
- const __m128i t1 = _mm_cmpeq_epi8(s, dq);
- const __m128i t2 = _mm_cmpeq_epi8(s, bs);
- const __m128i t3 = _mm_cmpeq_epi8(_mm_max_epu8(s, sp), sp); // s < 0x20 <=> max(s, 0x19) == 0x19
- const __m128i x = _mm_or_si128(_mm_or_si128(t1, t2), t3);
- unsigned short r = static_cast<unsigned short>(_mm_movemask_epi8(x));
- if (RAPIDJSON_UNLIKELY(r != 0)) { // some of characters is escaped
- SizeType length;
- #ifdef _MSC_VER // Find the index of first escaped
- unsigned long offset;
- _BitScanForward(&offset, r);
- length = offset;
- #else
- length = static_cast<SizeType>(__builtin_ffs(r) - 1);
- #endif
- char* q = reinterpret_cast<char*>(os.Push(length));
- for (size_t i = 0; i < length; i++)
- q[i] = p[i];
-
- p += length;
- break;
- }
- _mm_storeu_si128(reinterpret_cast<__m128i *>(os.Push(16)), s);
- }
-
- is.src_ = p;
- }
-
- // InsituStringStream -> InsituStringStream
- static RAPIDJSON_FORCEINLINE void ScanCopyUnescapedString(InsituStringStream& is, InsituStringStream& os) {
- RAPIDJSON_ASSERT(&is == &os);
- (void)os;
-
- if (is.src_ == is.dst_) {
- SkipUnescapedString(is);
- return;
- }
-
- char* p = is.src_;
- char *q = is.dst_;
-
- // Scan one by one until alignment (unaligned load may cross page boundary and cause crash)
- const char* nextAligned = reinterpret_cast<const char*>((reinterpret_cast<size_t>(p) + 15) & static_cast<size_t>(~15));
- while (p != nextAligned)
- if (RAPIDJSON_UNLIKELY(*p == '\"') || RAPIDJSON_UNLIKELY(*p == '\\') || RAPIDJSON_UNLIKELY(static_cast<unsigned>(*p) < 0x20)) {
- is.src_ = p;
- is.dst_ = q;
- return;
- }
- else
- *q++ = *p++;
-
- // The rest of string using SIMD
- static const char dquote[16] = { '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"' };
- static const char bslash[16] = { '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\' };
- static const char space[16] = { 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19 };
- const __m128i dq = _mm_loadu_si128(reinterpret_cast<const __m128i *>(&dquote[0]));
- const __m128i bs = _mm_loadu_si128(reinterpret_cast<const __m128i *>(&bslash[0]));
- const __m128i sp = _mm_loadu_si128(reinterpret_cast<const __m128i *>(&space[0]));
-
- for (;; p += 16, q += 16) {
- const __m128i s = _mm_load_si128(reinterpret_cast<const __m128i *>(p));
- const __m128i t1 = _mm_cmpeq_epi8(s, dq);
- const __m128i t2 = _mm_cmpeq_epi8(s, bs);
- const __m128i t3 = _mm_cmpeq_epi8(_mm_max_epu8(s, sp), sp); // s < 0x20 <=> max(s, 0x19) == 0x19
- const __m128i x = _mm_or_si128(_mm_or_si128(t1, t2), t3);
- unsigned short r = static_cast<unsigned short>(_mm_movemask_epi8(x));
- if (RAPIDJSON_UNLIKELY(r != 0)) { // some of characters is escaped
- size_t length;
-#ifdef _MSC_VER // Find the index of first escaped
- unsigned long offset;
- _BitScanForward(&offset, r);
- length = offset;
-#else
- length = static_cast<size_t>(__builtin_ffs(r) - 1);
-#endif
- for (const char* pend = p + length; p != pend; )
- *q++ = *p++;
- break;
- }
- _mm_storeu_si128(reinterpret_cast<__m128i *>(q), s);
- }
-
- is.src_ = p;
- is.dst_ = q;
- }
-
- // When read/write pointers are the same for insitu stream, just skip unescaped characters
- static RAPIDJSON_FORCEINLINE void SkipUnescapedString(InsituStringStream& is) {
- RAPIDJSON_ASSERT(is.src_ == is.dst_);
- char* p = is.src_;
-
- // Scan one by one until alignment (unaligned load may cross page boundary and cause crash)
- const char* nextAligned = reinterpret_cast<const char*>((reinterpret_cast<size_t>(p) + 15) & static_cast<size_t>(~15));
- for (; p != nextAligned; p++)
- if (RAPIDJSON_UNLIKELY(*p == '\"') || RAPIDJSON_UNLIKELY(*p == '\\') || RAPIDJSON_UNLIKELY(static_cast<unsigned>(*p) < 0x20)) {
- is.src_ = is.dst_ = p;
- return;
- }
-
- // The rest of string using SIMD
- static const char dquote[16] = { '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"' };
- static const char bslash[16] = { '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\' };
- static const char space[16] = { 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19 };
- const __m128i dq = _mm_loadu_si128(reinterpret_cast<const __m128i *>(&dquote[0]));
- const __m128i bs = _mm_loadu_si128(reinterpret_cast<const __m128i *>(&bslash[0]));
- const __m128i sp = _mm_loadu_si128(reinterpret_cast<const __m128i *>(&space[0]));
-
- for (;; p += 16) {
- const __m128i s = _mm_load_si128(reinterpret_cast<const __m128i *>(p));
- const __m128i t1 = _mm_cmpeq_epi8(s, dq);
- const __m128i t2 = _mm_cmpeq_epi8(s, bs);
- const __m128i t3 = _mm_cmpeq_epi8(_mm_max_epu8(s, sp), sp); // s < 0x20 <=> max(s, 0x19) == 0x19
- const __m128i x = _mm_or_si128(_mm_or_si128(t1, t2), t3);
- unsigned short r = static_cast<unsigned short>(_mm_movemask_epi8(x));
- if (RAPIDJSON_UNLIKELY(r != 0)) { // some of characters is escaped
- size_t length;
-#ifdef _MSC_VER // Find the index of first escaped
- unsigned long offset;
- _BitScanForward(&offset, r);
- length = offset;
-#else
- length = static_cast<size_t>(__builtin_ffs(r) - 1);
-#endif
- p += length;
- break;
- }
- }
-
- is.src_ = is.dst_ = p;
- }
-#endif
-
- template<typename InputStream, bool backup, bool pushOnTake>
- class NumberStream;
-
- template<typename InputStream>
- class NumberStream<InputStream, false, false> {
- public:
- typedef typename InputStream::Ch Ch;
-
- NumberStream(GenericReader& reader, InputStream& s) : is(s) { (void)reader; }
- ~NumberStream() {}
-
- RAPIDJSON_FORCEINLINE Ch Peek() const { return is.Peek(); }
- RAPIDJSON_FORCEINLINE Ch TakePush() { return is.Take(); }
- RAPIDJSON_FORCEINLINE Ch Take() { return is.Take(); }
- RAPIDJSON_FORCEINLINE void Push(char) {}
-
- size_t Tell() { return is.Tell(); }
- size_t Length() { return 0; }
- const char* Pop() { return 0; }
-
- protected:
- NumberStream& operator=(const NumberStream&);
-
- InputStream& is;
- };
-
- template<typename InputStream>
- class NumberStream<InputStream, true, false> : public NumberStream<InputStream, false, false> {
- typedef NumberStream<InputStream, false, false> Base;
- public:
- NumberStream(GenericReader& reader, InputStream& is) : Base(reader, is), stackStream(reader.stack_) {}
- ~NumberStream() {}
-
- RAPIDJSON_FORCEINLINE Ch TakePush() {
- stackStream.Put(static_cast<char>(Base::is.Peek()));
- return Base::is.Take();
- }
-
- RAPIDJSON_FORCEINLINE void Push(char c) {
- stackStream.Put(c);
- }
-
- size_t Length() { return stackStream.Length(); }
-
- const char* Pop() {
- stackStream.Put('\0');
- return stackStream.Pop();
- }
-
- private:
- StackStream<char> stackStream;
- };
-
- template<typename InputStream>
- class NumberStream<InputStream, true, true> : public NumberStream<InputStream, true, false> {
- typedef NumberStream<InputStream, true, false> Base;
- public:
- NumberStream(GenericReader& reader, InputStream& is) : Base(reader, is) {}
- ~NumberStream() {}
-
- RAPIDJSON_FORCEINLINE Ch Take() { return Base::TakePush(); }
- };
-
- template<unsigned parseFlags, typename InputStream, typename Handler>
- void ParseNumber(InputStream& is, Handler& handler) {
- internal::StreamLocalCopy<InputStream> copy(is);
- NumberStream<InputStream,
- ((parseFlags & kParseNumbersAsStringsFlag) != 0) ?
- ((parseFlags & kParseInsituFlag) == 0) :
- ((parseFlags & kParseFullPrecisionFlag) != 0),
- (parseFlags & kParseNumbersAsStringsFlag) != 0 &&
- (parseFlags & kParseInsituFlag) == 0> s(*this, copy.s);
-
- size_t startOffset = s.Tell();
- double d = 0.0;
- bool useNanOrInf = false;
-
- // Parse minus
- bool minus = Consume(s, '-');
-
- // Parse int: zero / ( digit1-9 *DIGIT )
- unsigned i = 0;
- uint64_t i64 = 0;
- bool use64bit = false;
- int significandDigit = 0;
- if (RAPIDJSON_UNLIKELY(s.Peek() == '0')) {
- i = 0;
- s.TakePush();
- }
- else if (RAPIDJSON_LIKELY(s.Peek() >= '1' && s.Peek() <= '9')) {
- i = static_cast<unsigned>(s.TakePush() - '0');
-
- if (minus)
- while (RAPIDJSON_LIKELY(s.Peek() >= '0' && s.Peek() <= '9')) {
- if (RAPIDJSON_UNLIKELY(i >= 214748364)) { // 2^31 = 2147483648
- if (RAPIDJSON_LIKELY(i != 214748364 || s.Peek() > '8')) {
- i64 = i;
- use64bit = true;
- break;
- }
- }
- i = i * 10 + static_cast<unsigned>(s.TakePush() - '0');
- significandDigit++;
- }
- else
- while (RAPIDJSON_LIKELY(s.Peek() >= '0' && s.Peek() <= '9')) {
- if (RAPIDJSON_UNLIKELY(i >= 429496729)) { // 2^32 - 1 = 4294967295
- if (RAPIDJSON_LIKELY(i != 429496729 || s.Peek() > '5')) {
- i64 = i;
- use64bit = true;
- break;
- }
- }
- i = i * 10 + static_cast<unsigned>(s.TakePush() - '0');
- significandDigit++;
- }
- }
- // Parse NaN or Infinity here
- else if ((parseFlags & kParseNanAndInfFlag) && RAPIDJSON_LIKELY((s.Peek() == 'I' || s.Peek() == 'N'))) {
- useNanOrInf = true;
- if (RAPIDJSON_LIKELY(Consume(s, 'N') && Consume(s, 'a') && Consume(s, 'N'))) {
- d = std::numeric_limits<double>::quiet_NaN();
- }
- else if (RAPIDJSON_LIKELY(Consume(s, 'I') && Consume(s, 'n') && Consume(s, 'f'))) {
- d = (minus ? -std::numeric_limits<double>::infinity() : std::numeric_limits<double>::infinity());
- if (RAPIDJSON_UNLIKELY(s.Peek() == 'i' && !(Consume(s, 'i') && Consume(s, 'n')
- && Consume(s, 'i') && Consume(s, 't') && Consume(s, 'y'))))
- RAPIDJSON_PARSE_ERROR(kParseErrorValueInvalid, s.Tell());
- }
- else
- RAPIDJSON_PARSE_ERROR(kParseErrorValueInvalid, s.Tell());
- }
- else
- RAPIDJSON_PARSE_ERROR(kParseErrorValueInvalid, s.Tell());
-
- // Parse 64bit int
- bool useDouble = false;
- if (use64bit) {
- if (minus)
- while (RAPIDJSON_LIKELY(s.Peek() >= '0' && s.Peek() <= '9')) {
- if (RAPIDJSON_UNLIKELY(i64 >= RAPIDJSON_UINT64_C2(0x0CCCCCCC, 0xCCCCCCCC))) // 2^63 = 9223372036854775808
- if (RAPIDJSON_LIKELY(i64 != RAPIDJSON_UINT64_C2(0x0CCCCCCC, 0xCCCCCCCC) || s.Peek() > '8')) {
- d = static_cast<double>(i64);
- useDouble = true;
- break;
- }
- i64 = i64 * 10 + static_cast<unsigned>(s.TakePush() - '0');
- significandDigit++;
- }
- else
- while (RAPIDJSON_LIKELY(s.Peek() >= '0' && s.Peek() <= '9')) {
- if (RAPIDJSON_UNLIKELY(i64 >= RAPIDJSON_UINT64_C2(0x19999999, 0x99999999))) // 2^64 - 1 = 18446744073709551615
- if (RAPIDJSON_LIKELY(i64 != RAPIDJSON_UINT64_C2(0x19999999, 0x99999999) || s.Peek() > '5')) {
- d = static_cast<double>(i64);
- useDouble = true;
- break;
- }
- i64 = i64 * 10 + static_cast<unsigned>(s.TakePush() - '0');
- significandDigit++;
- }
- }
-
- // Force double for big integer
- if (useDouble) {
- while (RAPIDJSON_LIKELY(s.Peek() >= '0' && s.Peek() <= '9')) {
- if (RAPIDJSON_UNLIKELY(d >= 1.7976931348623157e307)) // DBL_MAX / 10.0
- RAPIDJSON_PARSE_ERROR(kParseErrorNumberTooBig, startOffset);
- d = d * 10 + (s.TakePush() - '0');
- }
- }
-
- // Parse frac = decimal-point 1*DIGIT
- int expFrac = 0;
- size_t decimalPosition;
- if (Consume(s, '.')) {
- decimalPosition = s.Length();
-
- if (RAPIDJSON_UNLIKELY(!(s.Peek() >= '0' && s.Peek() <= '9')))
- RAPIDJSON_PARSE_ERROR(kParseErrorNumberMissFraction, s.Tell());
-
- if (!useDouble) {
-#if RAPIDJSON_64BIT
- // Use i64 to store significand in 64-bit architecture
- if (!use64bit)
- i64 = i;
-
- while (RAPIDJSON_LIKELY(s.Peek() >= '0' && s.Peek() <= '9')) {
- if (i64 > RAPIDJSON_UINT64_C2(0x1FFFFF, 0xFFFFFFFF)) // 2^53 - 1 for fast path
- break;
- else {
- i64 = i64 * 10 + static_cast<unsigned>(s.TakePush() - '0');
- --expFrac;
- if (i64 != 0)
- significandDigit++;
- }
- }
-
- d = static_cast<double>(i64);
-#else
- // Use double to store significand in 32-bit architecture
- d = static_cast<double>(use64bit ? i64 : i);
-#endif
- useDouble = true;
- }
-
- while (RAPIDJSON_LIKELY(s.Peek() >= '0' && s.Peek() <= '9')) {
- if (significandDigit < 17) {
- d = d * 10.0 + (s.TakePush() - '0');
- --expFrac;
- if (RAPIDJSON_LIKELY(d > 0.0))
- significandDigit++;
- }
- else
- s.TakePush();
- }
- }
- else
- decimalPosition = s.Length(); // decimal position at the end of integer.
-
- // Parse exp = e [ minus / plus ] 1*DIGIT
- int exp = 0;
- if (Consume(s, 'e') || Consume(s, 'E')) {
- if (!useDouble) {
- d = static_cast<double>(use64bit ? i64 : i);
- useDouble = true;
- }
-
- bool expMinus = false;
- if (Consume(s, '+'))
- ;
- else if (Consume(s, '-'))
- expMinus = true;
-
- if (RAPIDJSON_LIKELY(s.Peek() >= '0' && s.Peek() <= '9')) {
- exp = static_cast<int>(s.Take() - '0');
- if (expMinus) {
- while (RAPIDJSON_LIKELY(s.Peek() >= '0' && s.Peek() <= '9')) {
- exp = exp * 10 + static_cast<int>(s.Take() - '0');
- if (exp >= 214748364) { // Issue #313: prevent overflow exponent
- while (RAPIDJSON_UNLIKELY(s.Peek() >= '0' && s.Peek() <= '9')) // Consume the rest of exponent
- s.Take();
- }
- }
- }
- else { // positive exp
- int maxExp = 308 - expFrac;
- while (RAPIDJSON_LIKELY(s.Peek() >= '0' && s.Peek() <= '9')) {
- exp = exp * 10 + static_cast<int>(s.Take() - '0');
- if (RAPIDJSON_UNLIKELY(exp > maxExp))
- RAPIDJSON_PARSE_ERROR(kParseErrorNumberTooBig, startOffset);
- }
- }
- }
- else
- RAPIDJSON_PARSE_ERROR(kParseErrorNumberMissExponent, s.Tell());
-
- if (expMinus)
- exp = -exp;
- }
-
- // Finish parsing, call event according to the type of number.
- bool cont = true;
-
- if (parseFlags & kParseNumbersAsStringsFlag) {
- if (parseFlags & kParseInsituFlag) {
- s.Pop(); // Pop stack no matter if it will be used or not.
- typename InputStream::Ch* head = is.PutBegin();
- const size_t length = s.Tell() - startOffset;
- RAPIDJSON_ASSERT(length <= 0xFFFFFFFF);
- // unable to insert the \0 character here, it will erase the comma after this number
- const typename TargetEncoding::Ch* const str = reinterpret_cast<typename TargetEncoding::Ch*>(head);
- cont = handler.RawNumber(str, SizeType(length), false);
- }
- else {
- SizeType numCharsToCopy = static_cast<SizeType>(s.Length());
- StringStream srcStream(s.Pop());
- StackStream<typename TargetEncoding::Ch> dstStream(stack_);
- while (numCharsToCopy--) {
- Transcoder<UTF8<>, TargetEncoding>::Transcode(srcStream, dstStream);
- }
- dstStream.Put('\0');
- const typename TargetEncoding::Ch* str = dstStream.Pop();
- const SizeType length = static_cast<SizeType>(dstStream.Length()) - 1;
- cont = handler.RawNumber(str, SizeType(length), true);
- }
- }
- else {
- size_t length = s.Length();
- const char* decimal = s.Pop(); // Pop stack no matter if it will be used or not.
-
- if (useDouble) {
- int p = exp + expFrac;
- if (parseFlags & kParseFullPrecisionFlag)
- d = internal::StrtodFullPrecision(d, p, decimal, length, decimalPosition, exp);
- else
- d = internal::StrtodNormalPrecision(d, p);
-
- cont = handler.Double(minus ? -d : d);
- }
- else if (useNanOrInf) {
- cont = handler.Double(d);
- }
- else {
- if (use64bit) {
- if (minus)
- cont = handler.Int64(static_cast<int64_t>(~i64 + 1));
- else
- cont = handler.Uint64(i64);
- }
- else {
- if (minus)
- cont = handler.Int(static_cast<int32_t>(~i + 1));
- else
- cont = handler.Uint(i);
- }
- }
- }
- if (RAPIDJSON_UNLIKELY(!cont))
- RAPIDJSON_PARSE_ERROR(kParseErrorTermination, startOffset);
- }
-
- // Parse any JSON value
- template<unsigned parseFlags, typename InputStream, typename Handler>
- void ParseValue(InputStream& is, Handler& handler) {
- switch (is.Peek()) {
- case 'n': ParseNull <parseFlags>(is, handler); break;
- case 't': ParseTrue <parseFlags>(is, handler); break;
- case 'f': ParseFalse <parseFlags>(is, handler); break;
- case '"': ParseString<parseFlags>(is, handler); break;
- case '{': ParseObject<parseFlags>(is, handler); break;
- case '[': ParseArray <parseFlags>(is, handler); break;
- default :
- ParseNumber<parseFlags>(is, handler);
- break;
-
- }
- }
-
- // Iterative Parsing
-
- // States
- enum IterativeParsingState {
- IterativeParsingStartState = 0,
- IterativeParsingFinishState,
- IterativeParsingErrorState,
-
- // Object states
- IterativeParsingObjectInitialState,
- IterativeParsingMemberKeyState,
- IterativeParsingKeyValueDelimiterState,
- IterativeParsingMemberValueState,
- IterativeParsingMemberDelimiterState,
- IterativeParsingObjectFinishState,
-
- // Array states
- IterativeParsingArrayInitialState,
- IterativeParsingElementState,
- IterativeParsingElementDelimiterState,
- IterativeParsingArrayFinishState,
-
- // Single value state
- IterativeParsingValueState
- };
-
- enum { cIterativeParsingStateCount = IterativeParsingValueState + 1 };
-
- // Tokens
- enum Token {
- LeftBracketToken = 0,
- RightBracketToken,
-
- LeftCurlyBracketToken,
- RightCurlyBracketToken,
-
- CommaToken,
- ColonToken,
-
- StringToken,
- FalseToken,
- TrueToken,
- NullToken,
- NumberToken,
-
- kTokenCount
- };
-
- RAPIDJSON_FORCEINLINE Token Tokenize(Ch c) {
-
-//!@cond RAPIDJSON_HIDDEN_FROM_DOXYGEN
-#define N NumberToken
-#define N16 N,N,N,N,N,N,N,N,N,N,N,N,N,N,N,N
- // Maps from ASCII to Token
- static const unsigned char tokenMap[256] = {
- N16, // 00~0F
- N16, // 10~1F
- N, N, StringToken, N, N, N, N, N, N, N, N, N, CommaToken, N, N, N, // 20~2F
- N, N, N, N, N, N, N, N, N, N, ColonToken, N, N, N, N, N, // 30~3F
- N16, // 40~4F
- N, N, N, N, N, N, N, N, N, N, N, LeftBracketToken, N, RightBracketToken, N, N, // 50~5F
- N, N, N, N, N, N, FalseToken, N, N, N, N, N, N, N, NullToken, N, // 60~6F
- N, N, N, N, TrueToken, N, N, N, N, N, N, LeftCurlyBracketToken, N, RightCurlyBracketToken, N, N, // 70~7F
- N16, N16, N16, N16, N16, N16, N16, N16 // 80~FF
- };
-#undef N
-#undef N16
-//!@endcond
-
- if (sizeof(Ch) == 1 || static_cast<unsigned>(c) < 256)
- return static_cast<Token>(tokenMap[static_cast<unsigned char>(c)]);
- else
- return NumberToken;
- }
-
- RAPIDJSON_FORCEINLINE IterativeParsingState Predict(IterativeParsingState state, Token token) {
- // current state x one lookahead token -> new state
- static const char G[cIterativeParsingStateCount][kTokenCount] = {
- // Start
- {
- IterativeParsingArrayInitialState, // Left bracket
- IterativeParsingErrorState, // Right bracket
- IterativeParsingObjectInitialState, // Left curly bracket
- IterativeParsingErrorState, // Right curly bracket
- IterativeParsingErrorState, // Comma
- IterativeParsingErrorState, // Colon
- IterativeParsingValueState, // String
- IterativeParsingValueState, // False
- IterativeParsingValueState, // True
- IterativeParsingValueState, // Null
- IterativeParsingValueState // Number
- },
- // Finish(sink state)
- {
- IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState,
- IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState,
- IterativeParsingErrorState
- },
- // Error(sink state)
- {
- IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState,
- IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState,
- IterativeParsingErrorState
- },
- // ObjectInitial
- {
- IterativeParsingErrorState, // Left bracket
- IterativeParsingErrorState, // Right bracket
- IterativeParsingErrorState, // Left curly bracket
- IterativeParsingObjectFinishState, // Right curly bracket
- IterativeParsingErrorState, // Comma
- IterativeParsingErrorState, // Colon
- IterativeParsingMemberKeyState, // String
- IterativeParsingErrorState, // False
- IterativeParsingErrorState, // True
- IterativeParsingErrorState, // Null
- IterativeParsingErrorState // Number
- },
- // MemberKey
- {
- IterativeParsingErrorState, // Left bracket
- IterativeParsingErrorState, // Right bracket
- IterativeParsingErrorState, // Left curly bracket
- IterativeParsingErrorState, // Right curly bracket
- IterativeParsingErrorState, // Comma
- IterativeParsingKeyValueDelimiterState, // Colon
- IterativeParsingErrorState, // String
- IterativeParsingErrorState, // False
- IterativeParsingErrorState, // True
- IterativeParsingErrorState, // Null
- IterativeParsingErrorState // Number
- },
- // KeyValueDelimiter
- {
- IterativeParsingArrayInitialState, // Left bracket(push MemberValue state)
- IterativeParsingErrorState, // Right bracket
- IterativeParsingObjectInitialState, // Left curly bracket(push MemberValue state)
- IterativeParsingErrorState, // Right curly bracket
- IterativeParsingErrorState, // Comma
- IterativeParsingErrorState, // Colon
- IterativeParsingMemberValueState, // String
- IterativeParsingMemberValueState, // False
- IterativeParsingMemberValueState, // True
- IterativeParsingMemberValueState, // Null
- IterativeParsingMemberValueState // Number
- },
- // MemberValue
- {
- IterativeParsingErrorState, // Left bracket
- IterativeParsingErrorState, // Right bracket
- IterativeParsingErrorState, // Left curly bracket
- IterativeParsingObjectFinishState, // Right curly bracket
- IterativeParsingMemberDelimiterState, // Comma
- IterativeParsingErrorState, // Colon
- IterativeParsingErrorState, // String
- IterativeParsingErrorState, // False
- IterativeParsingErrorState, // True
- IterativeParsingErrorState, // Null
- IterativeParsingErrorState // Number
- },
- // MemberDelimiter
- {
- IterativeParsingErrorState, // Left bracket
- IterativeParsingErrorState, // Right bracket
- IterativeParsingErrorState, // Left curly bracket
- IterativeParsingObjectFinishState, // Right curly bracket
- IterativeParsingErrorState, // Comma
- IterativeParsingErrorState, // Colon
- IterativeParsingMemberKeyState, // String
- IterativeParsingErrorState, // False
- IterativeParsingErrorState, // True
- IterativeParsingErrorState, // Null
- IterativeParsingErrorState // Number
- },
- // ObjectFinish(sink state)
- {
- IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState,
- IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState,
- IterativeParsingErrorState
- },
- // ArrayInitial
- {
- IterativeParsingArrayInitialState, // Left bracket(push Element state)
- IterativeParsingArrayFinishState, // Right bracket
- IterativeParsingObjectInitialState, // Left curly bracket(push Element state)
- IterativeParsingErrorState, // Right curly bracket
- IterativeParsingErrorState, // Comma
- IterativeParsingErrorState, // Colon
- IterativeParsingElementState, // String
- IterativeParsingElementState, // False
- IterativeParsingElementState, // True
- IterativeParsingElementState, // Null
- IterativeParsingElementState // Number
- },
- // Element
- {
- IterativeParsingErrorState, // Left bracket
- IterativeParsingArrayFinishState, // Right bracket
- IterativeParsingErrorState, // Left curly bracket
- IterativeParsingErrorState, // Right curly bracket
- IterativeParsingElementDelimiterState, // Comma
- IterativeParsingErrorState, // Colon
- IterativeParsingErrorState, // String
- IterativeParsingErrorState, // False
- IterativeParsingErrorState, // True
- IterativeParsingErrorState, // Null
- IterativeParsingErrorState // Number
- },
- // ElementDelimiter
- {
- IterativeParsingArrayInitialState, // Left bracket(push Element state)
- IterativeParsingArrayFinishState, // Right bracket
- IterativeParsingObjectInitialState, // Left curly bracket(push Element state)
- IterativeParsingErrorState, // Right curly bracket
- IterativeParsingErrorState, // Comma
- IterativeParsingErrorState, // Colon
- IterativeParsingElementState, // String
- IterativeParsingElementState, // False
- IterativeParsingElementState, // True
- IterativeParsingElementState, // Null
- IterativeParsingElementState // Number
- },
- // ArrayFinish(sink state)
- {
- IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState,
- IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState,
- IterativeParsingErrorState
- },
- // Single Value (sink state)
- {
- IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState,
- IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState, IterativeParsingErrorState,
- IterativeParsingErrorState
- }
- }; // End of G
-
- return static_cast<IterativeParsingState>(G[state][token]);
- }
-
- // Make an advance in the token stream and state based on the candidate destination state which was returned by Transit().
- // May return a new state on state pop.
- template <unsigned parseFlags, typename InputStream, typename Handler>
- RAPIDJSON_FORCEINLINE IterativeParsingState Transit(IterativeParsingState src, Token token, IterativeParsingState dst, InputStream& is, Handler& handler) {
- (void)token;
-
- switch (dst) {
- case IterativeParsingErrorState:
- return dst;
-
- case IterativeParsingObjectInitialState:
- case IterativeParsingArrayInitialState:
- {
- // Push the state(Element or MemeberValue) if we are nested in another array or value of member.
- // In this way we can get the correct state on ObjectFinish or ArrayFinish by frame pop.
- IterativeParsingState n = src;
- if (src == IterativeParsingArrayInitialState || src == IterativeParsingElementDelimiterState)
- n = IterativeParsingElementState;
- else if (src == IterativeParsingKeyValueDelimiterState)
- n = IterativeParsingMemberValueState;
- // Push current state.
- *stack_.template Push<SizeType>(1) = n;
- // Initialize and push the member/element count.
- *stack_.template Push<SizeType>(1) = 0;
- // Call handler
- bool hr = (dst == IterativeParsingObjectInitialState) ? handler.StartObject() : handler.StartArray();
- // On handler short circuits the parsing.
- if (!hr) {
- RAPIDJSON_PARSE_ERROR_NORETURN(kParseErrorTermination, is.Tell());
- return IterativeParsingErrorState;
- }
- else {
- is.Take();
- return dst;
- }
- }
-
- case IterativeParsingMemberKeyState:
- ParseString<parseFlags>(is, handler, true);
- if (HasParseError())
- return IterativeParsingErrorState;
- else
- return dst;
-
- case IterativeParsingKeyValueDelimiterState:
- RAPIDJSON_ASSERT(token == ColonToken);
- is.Take();
- return dst;
-
- case IterativeParsingMemberValueState:
- // Must be non-compound value. Or it would be ObjectInitial or ArrayInitial state.
- ParseValue<parseFlags>(is, handler);
- if (HasParseError()) {
- return IterativeParsingErrorState;
- }
- return dst;
-
- case IterativeParsingElementState:
- // Must be non-compound value. Or it would be ObjectInitial or ArrayInitial state.
- ParseValue<parseFlags>(is, handler);
- if (HasParseError()) {
- return IterativeParsingErrorState;
- }
- return dst;
-
- case IterativeParsingMemberDelimiterState:
- case IterativeParsingElementDelimiterState:
- is.Take();
- // Update member/element count.
- *stack_.template Top<SizeType>() = *stack_.template Top<SizeType>() + 1;
- return dst;
-
- case IterativeParsingObjectFinishState:
- {
- // Transit from delimiter is only allowed when trailing commas are enabled
- if (!(parseFlags & kParseTrailingCommasFlag) && src == IterativeParsingMemberDelimiterState) {
- RAPIDJSON_PARSE_ERROR_NORETURN(kParseErrorObjectMissName, is.Tell());
- return IterativeParsingErrorState;
- }
- // Get member count.
- SizeType c = *stack_.template Pop<SizeType>(1);
- // If the object is not empty, count the last member.
- if (src == IterativeParsingMemberValueState)
- ++c;
- // Restore the state.
- IterativeParsingState n = static_cast<IterativeParsingState>(*stack_.template Pop<SizeType>(1));
- // Transit to Finish state if this is the topmost scope.
- if (n == IterativeParsingStartState)
- n = IterativeParsingFinishState;
- // Call handler
- bool hr = handler.EndObject(c);
- // On handler short circuits the parsing.
- if (!hr) {
- RAPIDJSON_PARSE_ERROR_NORETURN(kParseErrorTermination, is.Tell());
- return IterativeParsingErrorState;
- }
- else {
- is.Take();
- return n;
- }
- }
-
- case IterativeParsingArrayFinishState:
- {
- // Transit from delimiter is only allowed when trailing commas are enabled
- if (!(parseFlags & kParseTrailingCommasFlag) && src == IterativeParsingElementDelimiterState) {
- RAPIDJSON_PARSE_ERROR_NORETURN(kParseErrorValueInvalid, is.Tell());
- return IterativeParsingErrorState;
- }
- // Get element count.
- SizeType c = *stack_.template Pop<SizeType>(1);
- // If the array is not empty, count the last element.
- if (src == IterativeParsingElementState)
- ++c;
- // Restore the state.
- IterativeParsingState n = static_cast<IterativeParsingState>(*stack_.template Pop<SizeType>(1));
- // Transit to Finish state if this is the topmost scope.
- if (n == IterativeParsingStartState)
- n = IterativeParsingFinishState;
- // Call handler
- bool hr = handler.EndArray(c);
- // On handler short circuits the parsing.
- if (!hr) {
- RAPIDJSON_PARSE_ERROR_NORETURN(kParseErrorTermination, is.Tell());
- return IterativeParsingErrorState;
- }
- else {
- is.Take();
- return n;
- }
- }
-
- default:
- // This branch is for IterativeParsingValueState actually.
- // Use `default:` rather than
- // `case IterativeParsingValueState:` is for code coverage.
-
- // The IterativeParsingStartState is not enumerated in this switch-case.
- // It is impossible for that case. And it can be caught by following assertion.
-
- // The IterativeParsingFinishState is not enumerated in this switch-case either.
- // It is a "derivative" state which cannot triggered from Predict() directly.
- // Therefore it cannot happen here. And it can be caught by following assertion.
- RAPIDJSON_ASSERT(dst == IterativeParsingValueState);
-
- // Must be non-compound value. Or it would be ObjectInitial or ArrayInitial state.
- ParseValue<parseFlags>(is, handler);
- if (HasParseError()) {
- return IterativeParsingErrorState;
- }
- return IterativeParsingFinishState;
- }
- }
-
- template <typename InputStream>
- void HandleError(IterativeParsingState src, InputStream& is) {
- if (HasParseError()) {
- // Error flag has been set.
- return;
- }
-
- switch (src) {
- case IterativeParsingStartState: RAPIDJSON_PARSE_ERROR(kParseErrorDocumentEmpty, is.Tell()); return;
- case IterativeParsingFinishState: RAPIDJSON_PARSE_ERROR(kParseErrorDocumentRootNotSingular, is.Tell()); return;
- case IterativeParsingObjectInitialState:
- case IterativeParsingMemberDelimiterState: RAPIDJSON_PARSE_ERROR(kParseErrorObjectMissName, is.Tell()); return;
- case IterativeParsingMemberKeyState: RAPIDJSON_PARSE_ERROR(kParseErrorObjectMissColon, is.Tell()); return;
- case IterativeParsingMemberValueState: RAPIDJSON_PARSE_ERROR(kParseErrorObjectMissCommaOrCurlyBracket, is.Tell()); return;
- case IterativeParsingKeyValueDelimiterState:
- case IterativeParsingArrayInitialState:
- case IterativeParsingElementDelimiterState: RAPIDJSON_PARSE_ERROR(kParseErrorValueInvalid, is.Tell()); return;
- default: RAPIDJSON_ASSERT(src == IterativeParsingElementState); RAPIDJSON_PARSE_ERROR(kParseErrorArrayMissCommaOrSquareBracket, is.Tell()); return;
- }
- }
-
- template <unsigned parseFlags, typename InputStream, typename Handler>
- ParseResult IterativeParse(InputStream& is, Handler& handler) {
- parseResult_.Clear();
- ClearStackOnExit scope(*this);
- IterativeParsingState state = IterativeParsingStartState;
-
- SkipWhitespaceAndComments<parseFlags>(is);
- RAPIDJSON_PARSE_ERROR_EARLY_RETURN(parseResult_);
- while (is.Peek() != '\0') {
- Token t = Tokenize(is.Peek());
- IterativeParsingState n = Predict(state, t);
- IterativeParsingState d = Transit<parseFlags>(state, t, n, is, handler);
-
- if (d == IterativeParsingErrorState) {
- HandleError(state, is);
- break;
- }
-
- state = d;
-
- // Do not further consume streams if a root JSON has been parsed.
- if ((parseFlags & kParseStopWhenDoneFlag) && state == IterativeParsingFinishState)
- break;
-
- SkipWhitespaceAndComments<parseFlags>(is);
- RAPIDJSON_PARSE_ERROR_EARLY_RETURN(parseResult_);
- }
-
- // Handle the end of file.
- if (state != IterativeParsingFinishState)
- HandleError(state, is);
-
- return parseResult_;
- }
-
- static const size_t kDefaultStackCapacity = 256; //!< Default stack capacity in bytes for storing a single decoded string.
- internal::Stack<StackAllocator> stack_; //!< A stack for storing decoded string temporarily during non-destructive parsing.
- ParseResult parseResult_;
-}; // class GenericReader
-
-//! Reader with UTF8 encoding and default allocator.
-typedef GenericReader<UTF8<>, UTF8<> > Reader;
-
-RAPIDJSON_NAMESPACE_END
-
-#ifdef __clang__
-RAPIDJSON_DIAG_POP
-#endif
-
-
-#ifdef __GNUC__
-RAPIDJSON_DIAG_POP
-#endif
-
-#ifdef _MSC_VER
-RAPIDJSON_DIAG_POP
-#endif
-
-#endif // RAPIDJSON_READER_H_
diff --git a/include/rapidjson/schema.h b/include/rapidjson/schema.h
deleted file mode 100644
index b182aa27..00000000
--- a/include/rapidjson/schema.h
+++ /dev/null
@@ -1,2006 +0,0 @@
-// Tencent is pleased to support the open source community by making RapidJSON available->
-//
-// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip-> All rights reserved->
-//
-// Licensed under the MIT License (the "License"); you may not use this file except
-// in compliance with the License-> You may obtain a copy of the License at
-//
-// http://opensource->org/licenses/MIT
-//
-// Unless required by applicable law or agreed to in writing, software distributed
-// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
-// CONDITIONS OF ANY KIND, either express or implied-> See the License for the
-// specific language governing permissions and limitations under the License->
-
-#ifndef RAPIDJSON_SCHEMA_H_
-#define RAPIDJSON_SCHEMA_H_
-
-#include "document.h"
-#include "pointer.h"
-#include <cmath> // abs, floor
-
-#if !defined(RAPIDJSON_SCHEMA_USE_INTERNALREGEX)
-#define RAPIDJSON_SCHEMA_USE_INTERNALREGEX 1
-#else
-#define RAPIDJSON_SCHEMA_USE_INTERNALREGEX 0
-#endif
-
-#if !RAPIDJSON_SCHEMA_USE_INTERNALREGEX && !defined(RAPIDJSON_SCHEMA_USE_STDREGEX) && (__cplusplus >=201103L || (defined(_MSC_VER) && _MSC_VER >= 1800))
-#define RAPIDJSON_SCHEMA_USE_STDREGEX 1
-#else
-#define RAPIDJSON_SCHEMA_USE_STDREGEX 0
-#endif
-
-#if RAPIDJSON_SCHEMA_USE_INTERNALREGEX
-#include "internal/regex.h"
-#elif RAPIDJSON_SCHEMA_USE_STDREGEX
-#include <regex>
-#endif
-
-#if RAPIDJSON_SCHEMA_USE_INTERNALREGEX || RAPIDJSON_SCHEMA_USE_STDREGEX
-#define RAPIDJSON_SCHEMA_HAS_REGEX 1
-#else
-#define RAPIDJSON_SCHEMA_HAS_REGEX 0
-#endif
-
-#ifndef RAPIDJSON_SCHEMA_VERBOSE
-#define RAPIDJSON_SCHEMA_VERBOSE 0
-#endif
-
-#if RAPIDJSON_SCHEMA_VERBOSE
-#include "stringbuffer.h"
-#endif
-
-RAPIDJSON_DIAG_PUSH
-
-#if defined(__GNUC__)
-RAPIDJSON_DIAG_OFF(effc++)
-#endif
-
-#ifdef __clang__
-RAPIDJSON_DIAG_OFF(weak-vtables)
-RAPIDJSON_DIAG_OFF(exit-time-destructors)
-RAPIDJSON_DIAG_OFF(c++98-compat-pedantic)
-RAPIDJSON_DIAG_OFF(variadic-macros)
-#endif
-
-#ifdef _MSC_VER
-RAPIDJSON_DIAG_OFF(4512) // assignment operator could not be generated
-#endif
-
-RAPIDJSON_NAMESPACE_BEGIN
-
-///////////////////////////////////////////////////////////////////////////////
-// Verbose Utilities
-
-#if RAPIDJSON_SCHEMA_VERBOSE
-
-namespace internal {
-
-inline void PrintInvalidKeyword(const char* keyword) {
- printf("Fail keyword: %s\n", keyword);
-}
-
-inline void PrintInvalidKeyword(const wchar_t* keyword) {
- wprintf(L"Fail keyword: %ls\n", keyword);
-}
-
-inline void PrintInvalidDocument(const char* document) {
- printf("Fail document: %s\n\n", document);
-}
-
-inline void PrintInvalidDocument(const wchar_t* document) {
- wprintf(L"Fail document: %ls\n\n", document);
-}
-
-inline void PrintValidatorPointers(unsigned depth, const char* s, const char* d) {
- printf("S: %*s%s\nD: %*s%s\n\n", depth * 4, " ", s, depth * 4, " ", d);
-}
-
-inline void PrintValidatorPointers(unsigned depth, const wchar_t* s, const wchar_t* d) {
- wprintf(L"S: %*ls%ls\nD: %*ls%ls\n\n", depth * 4, L" ", s, depth * 4, L" ", d);
-}
-
-} // namespace internal
-
-#endif // RAPIDJSON_SCHEMA_VERBOSE
-
-///////////////////////////////////////////////////////////////////////////////
-// RAPIDJSON_INVALID_KEYWORD_RETURN
-
-#if RAPIDJSON_SCHEMA_VERBOSE
-#define RAPIDJSON_INVALID_KEYWORD_VERBOSE(keyword) internal::PrintInvalidKeyword(keyword)
-#else
-#define RAPIDJSON_INVALID_KEYWORD_VERBOSE(keyword)
-#endif
-
-#define RAPIDJSON_INVALID_KEYWORD_RETURN(keyword)\
-RAPIDJSON_MULTILINEMACRO_BEGIN\
- context.invalidKeyword = keyword.GetString();\
- RAPIDJSON_INVALID_KEYWORD_VERBOSE(keyword.GetString());\
- return false;\
-RAPIDJSON_MULTILINEMACRO_END
-
-///////////////////////////////////////////////////////////////////////////////
-// Forward declarations
-
-template <typename ValueType, typename Allocator>
-class GenericSchemaDocument;
-
-namespace internal {
-
-template <typename SchemaDocumentType>
-class Schema;
-
-///////////////////////////////////////////////////////////////////////////////
-// ISchemaValidator
-
-class ISchemaValidator {
-public:
- virtual ~ISchemaValidator() {}
- virtual bool IsValid() const = 0;
-};
-
-///////////////////////////////////////////////////////////////////////////////
-// ISchemaStateFactory
-
-template <typename SchemaType>
-class ISchemaStateFactory {
-public:
- virtual ~ISchemaStateFactory() {}
- virtual ISchemaValidator* CreateSchemaValidator(const SchemaType&) = 0;
- virtual void DestroySchemaValidator(ISchemaValidator* validator) = 0;
- virtual void* CreateHasher() = 0;
- virtual uint64_t GetHashCode(void* hasher) = 0;
- virtual void DestroryHasher(void* hasher) = 0;
- virtual void* MallocState(size_t size) = 0;
- virtual void FreeState(void* p) = 0;
-};
-
-///////////////////////////////////////////////////////////////////////////////
-// Hasher
-
-// For comparison of compound value
-template<typename Encoding, typename Allocator>
-class Hasher {
-public:
- typedef typename Encoding::Ch Ch;
-
- Hasher(Allocator* allocator = 0, size_t stackCapacity = kDefaultSize) : stack_(allocator, stackCapacity) {}
-
- bool Null() { return WriteType(kNullType); }
- bool Bool(bool b) { return WriteType(b ? kTrueType : kFalseType); }
- bool Int(int i) { Number n; n.u.i = i; n.d = static_cast<double>(i); return WriteNumber(n); }
- bool Uint(unsigned u) { Number n; n.u.u = u; n.d = static_cast<double>(u); return WriteNumber(n); }
- bool Int64(int64_t i) { Number n; n.u.i = i; n.d = static_cast<double>(i); return WriteNumber(n); }
- bool Uint64(uint64_t u) { Number n; n.u.u = u; n.d = static_cast<double>(u); return WriteNumber(n); }
- bool Double(double d) {
- Number n;
- if (d < 0) n.u.i = static_cast<int64_t>(d);
- else n.u.u = static_cast<uint64_t>(d);
- n.d = d;
- return WriteNumber(n);
- }
-
- bool RawNumber(const Ch* str, SizeType len, bool) {
- WriteBuffer(kNumberType, str, len * sizeof(Ch));
- return true;
- }
-
- bool String(const Ch* str, SizeType len, bool) {
- WriteBuffer(kStringType, str, len * sizeof(Ch));
- return true;
- }
-
- bool StartObject() { return true; }
- bool Key(const Ch* str, SizeType len, bool copy) { return String(str, len, copy); }
- bool EndObject(SizeType memberCount) {
- uint64_t h = Hash(0, kObjectType);
- uint64_t* kv = stack_.template Pop<uint64_t>(memberCount * 2);
- for (SizeType i = 0; i < memberCount; i++)
- h ^= Hash(kv[i * 2], kv[i * 2 + 1]); // Use xor to achieve member order insensitive
- *stack_.template Push<uint64_t>() = h;
- return true;
- }
-
- bool StartArray() { return true; }
- bool EndArray(SizeType elementCount) {
- uint64_t h = Hash(0, kArrayType);
- uint64_t* e = stack_.template Pop<uint64_t>(elementCount);
- for (SizeType i = 0; i < elementCount; i++)
- h = Hash(h, e[i]); // Use hash to achieve element order sensitive
- *stack_.template Push<uint64_t>() = h;
- return true;
- }
-
- bool IsValid() const { return stack_.GetSize() == sizeof(uint64_t); }
-
- uint64_t GetHashCode() const {
- RAPIDJSON_ASSERT(IsValid());
- return *stack_.template Top<uint64_t>();
- }
-
-private:
- static const size_t kDefaultSize = 256;
- struct Number {
- union U {
- uint64_t u;
- int64_t i;
- }u;
- double d;
- };
-
- bool WriteType(Type type) { return WriteBuffer(type, 0, 0); }
-
- bool WriteNumber(const Number& n) { return WriteBuffer(kNumberType, &n, sizeof(n)); }
-
- bool WriteBuffer(Type type, const void* data, size_t len) {
- // FNV-1a from http://isthe.com/chongo/tech/comp/fnv/
- uint64_t h = Hash(RAPIDJSON_UINT64_C2(0x84222325, 0xcbf29ce4), type);
- const unsigned char* d = static_cast<const unsigned char*>(data);
- for (size_t i = 0; i < len; i++)
- h = Hash(h, d[i]);
- *stack_.template Push<uint64_t>() = h;
- return true;
- }
-
- static uint64_t Hash(uint64_t h, uint64_t d) {
- static const uint64_t kPrime = RAPIDJSON_UINT64_C2(0x00000100, 0x000001b3);
- h ^= d;
- h *= kPrime;
- return h;
- }
-
- Stack<Allocator> stack_;
-};
-
-///////////////////////////////////////////////////////////////////////////////
-// SchemaValidationContext
-
-template <typename SchemaDocumentType>
-struct SchemaValidationContext {
- typedef Schema<SchemaDocumentType> SchemaType;
- typedef ISchemaStateFactory<SchemaType> SchemaValidatorFactoryType;
- typedef typename SchemaType::ValueType ValueType;
- typedef typename ValueType::Ch Ch;
-
- enum PatternValidatorType {
- kPatternValidatorOnly,
- kPatternValidatorWithProperty,
- kPatternValidatorWithAdditionalProperty
- };
-
- SchemaValidationContext(SchemaValidatorFactoryType& f, const SchemaType* s) :
- factory(f),
- schema(s),
- valueSchema(),
- invalidKeyword(),
- hasher(),
- arrayElementHashCodes(),
- validators(),
- validatorCount(),
- patternPropertiesValidators(),
- patternPropertiesValidatorCount(),
- patternPropertiesSchemas(),
- patternPropertiesSchemaCount(),
- valuePatternValidatorType(kPatternValidatorOnly),
- propertyExist(),
- inArray(false),
- valueUniqueness(false),
- arrayUniqueness(false)
- {
- }
-
- ~SchemaValidationContext() {
- if (hasher)
- factory.DestroryHasher(hasher);
- if (validators) {
- for (SizeType i = 0; i < validatorCount; i++)
- factory.DestroySchemaValidator(validators[i]);
- factory.FreeState(validators);
- }
- if (patternPropertiesValidators) {
- for (SizeType i = 0; i < patternPropertiesValidatorCount; i++)
- factory.DestroySchemaValidator(patternPropertiesValidators[i]);
- factory.FreeState(patternPropertiesValidators);
- }
- if (patternPropertiesSchemas)
- factory.FreeState(patternPropertiesSchemas);
- if (propertyExist)
- factory.FreeState(propertyExist);
- }
-
- SchemaValidatorFactoryType& factory;
- const SchemaType* schema;
- const SchemaType* valueSchema;
- const Ch* invalidKeyword;
- void* hasher; // Only validator access
- void* arrayElementHashCodes; // Only validator access this
- ISchemaValidator** validators;
- SizeType validatorCount;
- ISchemaValidator** patternPropertiesValidators;
- SizeType patternPropertiesValidatorCount;
- const SchemaType** patternPropertiesSchemas;
- SizeType patternPropertiesSchemaCount;
- PatternValidatorType valuePatternValidatorType;
- PatternValidatorType objectPatternValidatorType;
- SizeType arrayElementIndex;
- bool* propertyExist;
- bool inArray;
- bool valueUniqueness;
- bool arrayUniqueness;
-};
-
-///////////////////////////////////////////////////////////////////////////////
-// Schema
-
-template <typename SchemaDocumentType>
-class Schema {
-public:
- typedef typename SchemaDocumentType::ValueType ValueType;
- typedef typename SchemaDocumentType::AllocatorType AllocatorType;
- typedef typename SchemaDocumentType::PointerType PointerType;
- typedef typename ValueType::EncodingType EncodingType;
- typedef typename EncodingType::Ch Ch;
- typedef SchemaValidationContext<SchemaDocumentType> Context;
- typedef Schema<SchemaDocumentType> SchemaType;
- typedef GenericValue<EncodingType, AllocatorType> SValue;
- friend class GenericSchemaDocument<ValueType, AllocatorType>;
-
- Schema(SchemaDocumentType* schemaDocument, const PointerType& p, const ValueType& value, const ValueType& document, AllocatorType* allocator) :
- allocator_(allocator),
- enum_(),
- enumCount_(),
- not_(),
- type_((1 << kTotalSchemaType) - 1), // typeless
- validatorCount_(),
- properties_(),
- additionalPropertiesSchema_(),
- patternProperties_(),
- patternPropertyCount_(),
- propertyCount_(),
- minProperties_(),
- maxProperties_(SizeType(~0)),
- additionalProperties_(true),
- hasDependencies_(),
- hasRequired_(),
- hasSchemaDependencies_(),
- additionalItemsSchema_(),
- itemsList_(),
- itemsTuple_(),
- itemsTupleCount_(),
- minItems_(),
- maxItems_(SizeType(~0)),
- additionalItems_(true),
- uniqueItems_(false),
- pattern_(),
- minLength_(0),
- maxLength_(~SizeType(0)),
- exclusiveMinimum_(false),
- exclusiveMaximum_(false)
- {
- typedef typename SchemaDocumentType::ValueType ValueType;
- typedef typename ValueType::ConstValueIterator ConstValueIterator;
- typedef typename ValueType::ConstMemberIterator ConstMemberIterator;
-
- if (!value.IsObject())
- return;
-
- if (const ValueType* v = GetMember(value, GetTypeString())) {
- type_ = 0;
- if (v->IsString())
- AddType(*v);
- else if (v->IsArray())
- for (ConstValueIterator itr = v->Begin(); itr != v->End(); ++itr)
- AddType(*itr);
- }
-
- if (const ValueType* v = GetMember(value, GetEnumString()))
- if (v->IsArray() && v->Size() > 0) {
- enum_ = static_cast<uint64_t*>(allocator_->Malloc(sizeof(uint64_t) * v->Size()));
- for (ConstValueIterator itr = v->Begin(); itr != v->End(); ++itr) {
- typedef Hasher<EncodingType, MemoryPoolAllocator<> > EnumHasherType;
- char buffer[256 + 24];
- MemoryPoolAllocator<> hasherAllocator(buffer, sizeof(buffer));
- EnumHasherType h(&hasherAllocator, 256);
- itr->Accept(h);
- enum_[enumCount_++] = h.GetHashCode();
- }
- }
-
- if (schemaDocument) {
- AssignIfExist(allOf_, *schemaDocument, p, value, GetAllOfString(), document);
- AssignIfExist(anyOf_, *schemaDocument, p, value, GetAnyOfString(), document);
- AssignIfExist(oneOf_, *schemaDocument, p, value, GetOneOfString(), document);
- }
-
- if (const ValueType* v = GetMember(value, GetNotString())) {
- schemaDocument->CreateSchema(&not_, p.Append(GetNotString(), allocator_), *v, document);
- notValidatorIndex_ = validatorCount_;
- validatorCount_++;
- }
-
- // Object
-
- const ValueType* properties = GetMember(value, GetPropertiesString());
- const ValueType* required = GetMember(value, GetRequiredString());
- const ValueType* dependencies = GetMember(value, GetDependenciesString());
- {
- // Gather properties from properties/required/dependencies
- SValue allProperties(kArrayType);
-
- if (properties && properties->IsObject())
- for (ConstMemberIterator itr = properties->MemberBegin(); itr != properties->MemberEnd(); ++itr)
- AddUniqueElement(allProperties, itr->name);
-
- if (required && required->IsArray())
- for (ConstValueIterator itr = required->Begin(); itr != required->End(); ++itr)
- if (itr->IsString())
- AddUniqueElement(allProperties, *itr);
-
- if (dependencies && dependencies->IsObject())
- for (ConstMemberIterator itr = dependencies->MemberBegin(); itr != dependencies->MemberEnd(); ++itr) {
- AddUniqueElement(allProperties, itr->name);
- if (itr->value.IsArray())
- for (ConstValueIterator i = itr->value.Begin(); i != itr->value.End(); ++i)
- if (i->IsString())
- AddUniqueElement(allProperties, *i);
- }
-
- if (allProperties.Size() > 0) {
- propertyCount_ = allProperties.Size();
- properties_ = static_cast<Property*>(allocator_->Malloc(sizeof(Property) * propertyCount_));
- for (SizeType i = 0; i < propertyCount_; i++) {
- new (&properties_[i]) Property();
- properties_[i].name = allProperties[i];
- properties_[i].schema = GetTypeless();
- }
- }
- }
-
- if (properties && properties->IsObject()) {
- PointerType q = p.Append(GetPropertiesString(), allocator_);
- for (ConstMemberIterator itr = properties->MemberBegin(); itr != properties->MemberEnd(); ++itr) {
- SizeType index;
- if (FindPropertyIndex(itr->name, &index))
- schemaDocument->CreateSchema(&properties_[index].schema, q.Append(itr->name, allocator_), itr->value, document);
- }
- }
-
- if (const ValueType* v = GetMember(value, GetPatternPropertiesString())) {
- PointerType q = p.Append(GetPatternPropertiesString(), allocator_);
- patternProperties_ = static_cast<PatternProperty*>(allocator_->Malloc(sizeof(PatternProperty) * v->MemberCount()));
- patternPropertyCount_ = 0;
-
- for (ConstMemberIterator itr = v->MemberBegin(); itr != v->MemberEnd(); ++itr) {
- new (&patternProperties_[patternPropertyCount_]) PatternProperty();
- patternProperties_[patternPropertyCount_].pattern = CreatePattern(itr->name);
- schemaDocument->CreateSchema(&patternProperties_[patternPropertyCount_].schema, q.Append(itr->name, allocator_), itr->value, document);
- patternPropertyCount_++;
- }
- }
-
- if (required && required->IsArray())
- for (ConstValueIterator itr = required->Begin(); itr != required->End(); ++itr)
- if (itr->IsString()) {
- SizeType index;
- if (FindPropertyIndex(*itr, &index)) {
- properties_[index].required = true;
- hasRequired_ = true;
- }
- }
-
- if (dependencies && dependencies->IsObject()) {
- PointerType q = p.Append(GetDependenciesString(), allocator_);
- hasDependencies_ = true;
- for (ConstMemberIterator itr = dependencies->MemberBegin(); itr != dependencies->MemberEnd(); ++itr) {
- SizeType sourceIndex;
- if (FindPropertyIndex(itr->name, &sourceIndex)) {
- if (itr->value.IsArray()) {
- properties_[sourceIndex].dependencies = static_cast<bool*>(allocator_->Malloc(sizeof(bool) * propertyCount_));
- std::memset(properties_[sourceIndex].dependencies, 0, sizeof(bool)* propertyCount_);
- for (ConstValueIterator targetItr = itr->value.Begin(); targetItr != itr->value.End(); ++targetItr) {
- SizeType targetIndex;
- if (FindPropertyIndex(*targetItr, &targetIndex))
- properties_[sourceIndex].dependencies[targetIndex] = true;
- }
- }
- else if (itr->value.IsObject()) {
- hasSchemaDependencies_ = true;
- schemaDocument->CreateSchema(&properties_[sourceIndex].dependenciesSchema, q.Append(itr->name, allocator_), itr->value, document);
- properties_[sourceIndex].dependenciesValidatorIndex = validatorCount_;
- validatorCount_++;
- }
- }
- }
- }
-
- if (const ValueType* v = GetMember(value, GetAdditionalPropertiesString())) {
- if (v->IsBool())
- additionalProperties_ = v->GetBool();
- else if (v->IsObject())
- schemaDocument->CreateSchema(&additionalPropertiesSchema_, p.Append(GetAdditionalPropertiesString(), allocator_), *v, document);
- }
-
- AssignIfExist(minProperties_, value, GetMinPropertiesString());
- AssignIfExist(maxProperties_, value, GetMaxPropertiesString());
-
- // Array
- if (const ValueType* v = GetMember(value, GetItemsString())) {
- PointerType q = p.Append(GetItemsString(), allocator_);
- if (v->IsObject()) // List validation
- schemaDocument->CreateSchema(&itemsList_, q, *v, document);
- else if (v->IsArray()) { // Tuple validation
- itemsTuple_ = static_cast<const Schema**>(allocator_->Malloc(sizeof(const Schema*) * v->Size()));
- SizeType index = 0;
- for (ConstValueIterator itr = v->Begin(); itr != v->End(); ++itr, index++)
- schemaDocument->CreateSchema(&itemsTuple_[itemsTupleCount_++], q.Append(index, allocator_), *itr, document);
- }
- }
-
- AssignIfExist(minItems_, value, GetMinItemsString());
- AssignIfExist(maxItems_, value, GetMaxItemsString());
-
- if (const ValueType* v = GetMember(value, GetAdditionalItemsString())) {
- if (v->IsBool())
- additionalItems_ = v->GetBool();
- else if (v->IsObject())
- schemaDocument->CreateSchema(&additionalItemsSchema_, p.Append(GetAdditionalItemsString(), allocator_), *v, document);
- }
-
- AssignIfExist(uniqueItems_, value, GetUniqueItemsString());
-
- // String
- AssignIfExist(minLength_, value, GetMinLengthString());
- AssignIfExist(maxLength_, value, GetMaxLengthString());
-
- if (const ValueType* v = GetMember(value, GetPatternString()))
- pattern_ = CreatePattern(*v);
-
- // Number
- if (const ValueType* v = GetMember(value, GetMinimumString()))
- if (v->IsNumber())
- minimum_.CopyFrom(*v, *allocator_);
-
- if (const ValueType* v = GetMember(value, GetMaximumString()))
- if (v->IsNumber())
- maximum_.CopyFrom(*v, *allocator_);
-
- AssignIfExist(exclusiveMinimum_, value, GetExclusiveMinimumString());
- AssignIfExist(exclusiveMaximum_, value, GetExclusiveMaximumString());
-
- if (const ValueType* v = GetMember(value, GetMultipleOfString()))
- if (v->IsNumber() && v->GetDouble() > 0.0)
- multipleOf_.CopyFrom(*v, *allocator_);
- }
-
- ~Schema() {
- if (allocator_) {
- allocator_->Free(enum_);
- }
- if (properties_) {
- for (SizeType i = 0; i < propertyCount_; i++)
- properties_[i].~Property();
- AllocatorType::Free(properties_);
- }
- if (patternProperties_) {
- for (SizeType i = 0; i < patternPropertyCount_; i++)
- patternProperties_[i].~PatternProperty();
- AllocatorType::Free(patternProperties_);
- }
- AllocatorType::Free(itemsTuple_);
-#if RAPIDJSON_SCHEMA_HAS_REGEX
- if (pattern_) {
- pattern_->~RegexType();
- allocator_->Free(pattern_);
- }
-#endif
- }
-
- bool BeginValue(Context& context) const {
- if (context.inArray) {
- if (uniqueItems_)
- context.valueUniqueness = true;
-
- if (itemsList_)
- context.valueSchema = itemsList_;
- else if (itemsTuple_) {
- if (context.arrayElementIndex < itemsTupleCount_)
- context.valueSchema = itemsTuple_[context.arrayElementIndex];
- else if (additionalItemsSchema_)
- context.valueSchema = additionalItemsSchema_;
- else if (additionalItems_)
- context.valueSchema = GetTypeless();
- else
- RAPIDJSON_INVALID_KEYWORD_RETURN(GetItemsString());
- }
- else
- context.valueSchema = GetTypeless();
-
- context.arrayElementIndex++;
- }
- return true;
- }
-
- RAPIDJSON_FORCEINLINE bool EndValue(Context& context) const {
- if (context.patternPropertiesValidatorCount > 0) {
- bool otherValid = false;
- SizeType count = context.patternPropertiesValidatorCount;
- if (context.objectPatternValidatorType != Context::kPatternValidatorOnly)
- otherValid = context.patternPropertiesValidators[--count]->IsValid();
-
- bool patternValid = true;
- for (SizeType i = 0; i < count; i++)
- if (!context.patternPropertiesValidators[i]->IsValid()) {
- patternValid = false;
- break;
- }
-
- if (context.objectPatternValidatorType == Context::kPatternValidatorOnly) {
- if (!patternValid)
- RAPIDJSON_INVALID_KEYWORD_RETURN(GetPatternPropertiesString());
- }
- else if (context.objectPatternValidatorType == Context::kPatternValidatorWithProperty) {
- if (!patternValid || !otherValid)
- RAPIDJSON_INVALID_KEYWORD_RETURN(GetPatternPropertiesString());
- }
- else if (!patternValid && !otherValid) // kPatternValidatorWithAdditionalProperty)
- RAPIDJSON_INVALID_KEYWORD_RETURN(GetPatternPropertiesString());
- }
-
- if (enum_) {
- const uint64_t h = context.factory.GetHashCode(context.hasher);
- for (SizeType i = 0; i < enumCount_; i++)
- if (enum_[i] == h)
- goto foundEnum;
- RAPIDJSON_INVALID_KEYWORD_RETURN(GetEnumString());
- foundEnum:;
- }
-
- if (allOf_.schemas)
- for (SizeType i = allOf_.begin; i < allOf_.begin + allOf_.count; i++)
- if (!context.validators[i]->IsValid())
- RAPIDJSON_INVALID_KEYWORD_RETURN(GetAllOfString());
-
- if (anyOf_.schemas) {
- for (SizeType i = anyOf_.begin; i < anyOf_.begin + anyOf_.count; i++)
- if (context.validators[i]->IsValid())
- goto foundAny;
- RAPIDJSON_INVALID_KEYWORD_RETURN(GetAnyOfString());
- foundAny:;
- }
-
- if (oneOf_.schemas) {
- bool oneValid = false;
- for (SizeType i = oneOf_.begin; i < oneOf_.begin + oneOf_.count; i++)
- if (context.validators[i]->IsValid()) {
- if (oneValid)
- RAPIDJSON_INVALID_KEYWORD_RETURN(GetOneOfString());
- else
- oneValid = true;
- }
- if (!oneValid)
- RAPIDJSON_INVALID_KEYWORD_RETURN(GetOneOfString());
- }
-
- if (not_ && context.validators[notValidatorIndex_]->IsValid())
- RAPIDJSON_INVALID_KEYWORD_RETURN(GetNotString());
-
- return true;
- }
-
- bool Null(Context& context) const {
- if (!(type_ & (1 << kNullSchemaType)))
- RAPIDJSON_INVALID_KEYWORD_RETURN(GetTypeString());
- return CreateParallelValidator(context);
- }
-
- bool Bool(Context& context, bool) const {
- if (!(type_ & (1 << kBooleanSchemaType)))
- RAPIDJSON_INVALID_KEYWORD_RETURN(GetTypeString());
- return CreateParallelValidator(context);
- }
-
- bool Int(Context& context, int i) const {
- if (!CheckInt(context, i))
- return false;
- return CreateParallelValidator(context);
- }
-
- bool Uint(Context& context, unsigned u) const {
- if (!CheckUint(context, u))
- return false;
- return CreateParallelValidator(context);
- }
-
- bool Int64(Context& context, int64_t i) const {
- if (!CheckInt(context, i))
- return false;
- return CreateParallelValidator(context);
- }
-
- bool Uint64(Context& context, uint64_t u) const {
- if (!CheckUint(context, u))
- return false;
- return CreateParallelValidator(context);
- }
-
- bool Double(Context& context, double d) const {
- if (!(type_ & (1 << kNumberSchemaType)))
- RAPIDJSON_INVALID_KEYWORD_RETURN(GetTypeString());
-
- if (!minimum_.IsNull() && !CheckDoubleMinimum(context, d))
- return false;
-
- if (!maximum_.IsNull() && !CheckDoubleMaximum(context, d))
- return false;
-
- if (!multipleOf_.IsNull() && !CheckDoubleMultipleOf(context, d))
- return false;
-
- return CreateParallelValidator(context);
- }
-
- bool String(Context& context, const Ch* str, SizeType length, bool) const {
- if (!(type_ & (1 << kStringSchemaType)))
- RAPIDJSON_INVALID_KEYWORD_RETURN(GetTypeString());
-
- if (minLength_ != 0 || maxLength_ != SizeType(~0)) {
- SizeType count;
- if (internal::CountStringCodePoint<EncodingType>(str, length, &count)) {
- if (count < minLength_)
- RAPIDJSON_INVALID_KEYWORD_RETURN(GetMinLengthString());
- if (count > maxLength_)
- RAPIDJSON_INVALID_KEYWORD_RETURN(GetMaxLengthString());
- }
- }
-
- if (pattern_ && !IsPatternMatch(pattern_, str, length))
- RAPIDJSON_INVALID_KEYWORD_RETURN(GetPatternString());
-
- return CreateParallelValidator(context);
- }
-
- bool StartObject(Context& context) const {
- if (!(type_ & (1 << kObjectSchemaType)))
- RAPIDJSON_INVALID_KEYWORD_RETURN(GetTypeString());
-
- if (hasDependencies_ || hasRequired_) {
- context.propertyExist = static_cast<bool*>(context.factory.MallocState(sizeof(bool) * propertyCount_));
- std::memset(context.propertyExist, 0, sizeof(bool) * propertyCount_);
- }
-
- if (patternProperties_) { // pre-allocate schema array
- SizeType count = patternPropertyCount_ + 1; // extra for valuePatternValidatorType
- context.patternPropertiesSchemas = static_cast<const SchemaType**>(context.factory.MallocState(sizeof(const SchemaType*) * count));
- context.patternPropertiesSchemaCount = 0;
- std::memset(context.patternPropertiesSchemas, 0, sizeof(SchemaType*) * count);
- }
-
- return CreateParallelValidator(context);
- }
-
- bool Key(Context& context, const Ch* str, SizeType len, bool) const {
- if (patternProperties_) {
- context.patternPropertiesSchemaCount = 0;
- for (SizeType i = 0; i < patternPropertyCount_; i++)
- if (patternProperties_[i].pattern && IsPatternMatch(patternProperties_[i].pattern, str, len))
- context.patternPropertiesSchemas[context.patternPropertiesSchemaCount++] = patternProperties_[i].schema;
- }
-
- SizeType index;
- if (FindPropertyIndex(ValueType(str, len).Move(), &index)) {
- if (context.patternPropertiesSchemaCount > 0) {
- context.patternPropertiesSchemas[context.patternPropertiesSchemaCount++] = properties_[index].schema;
- context.valueSchema = GetTypeless();
- context.valuePatternValidatorType = Context::kPatternValidatorWithProperty;
- }
- else
- context.valueSchema = properties_[index].schema;
-
- if (context.propertyExist)
- context.propertyExist[index] = true;
-
- return true;
- }
-
- if (additionalPropertiesSchema_) {
- if (additionalPropertiesSchema_ && context.patternPropertiesSchemaCount > 0) {
- context.patternPropertiesSchemas[context.patternPropertiesSchemaCount++] = additionalPropertiesSchema_;
- context.valueSchema = GetTypeless();
- context.valuePatternValidatorType = Context::kPatternValidatorWithAdditionalProperty;
- }
- else
- context.valueSchema = additionalPropertiesSchema_;
- return true;
- }
- else if (additionalProperties_) {
- context.valueSchema = GetTypeless();
- return true;
- }
-
- if (context.patternPropertiesSchemaCount == 0) // patternProperties are not additional properties
- RAPIDJSON_INVALID_KEYWORD_RETURN(GetAdditionalPropertiesString());
-
- return true;
- }
-
- bool EndObject(Context& context, SizeType memberCount) const {
- if (hasRequired_)
- for (SizeType index = 0; index < propertyCount_; index++)
- if (properties_[index].required)
- if (!context.propertyExist[index])
- RAPIDJSON_INVALID_KEYWORD_RETURN(GetRequiredString());
-
- if (memberCount < minProperties_)
- RAPIDJSON_INVALID_KEYWORD_RETURN(GetMinPropertiesString());
-
- if (memberCount > maxProperties_)
- RAPIDJSON_INVALID_KEYWORD_RETURN(GetMaxPropertiesString());
-
- if (hasDependencies_) {
- for (SizeType sourceIndex = 0; sourceIndex < propertyCount_; sourceIndex++)
- if (context.propertyExist[sourceIndex]) {
- if (properties_[sourceIndex].dependencies) {
- for (SizeType targetIndex = 0; targetIndex < propertyCount_; targetIndex++)
- if (properties_[sourceIndex].dependencies[targetIndex] && !context.propertyExist[targetIndex])
- RAPIDJSON_INVALID_KEYWORD_RETURN(GetDependenciesString());
- }
- else if (properties_[sourceIndex].dependenciesSchema)
- if (!context.validators[properties_[sourceIndex].dependenciesValidatorIndex]->IsValid())
- RAPIDJSON_INVALID_KEYWORD_RETURN(GetDependenciesString());
- }
- }
-
- return true;
- }
-
- bool StartArray(Context& context) const {
- if (!(type_ & (1 << kArraySchemaType)))
- RAPIDJSON_INVALID_KEYWORD_RETURN(GetTypeString());
-
- context.arrayElementIndex = 0;
- context.inArray = true;
-
- return CreateParallelValidator(context);
- }
-
- bool EndArray(Context& context, SizeType elementCount) const {
- context.inArray = false;
-
- if (elementCount < minItems_)
- RAPIDJSON_INVALID_KEYWORD_RETURN(GetMinItemsString());
-
- if (elementCount > maxItems_)
- RAPIDJSON_INVALID_KEYWORD_RETURN(GetMaxItemsString());
-
- return true;
- }
-
- // Generate functions for string literal according to Ch
-#define RAPIDJSON_STRING_(name, ...) \
- static const ValueType& Get##name##String() {\
- static const Ch s[] = { __VA_ARGS__, '\0' };\
- static const ValueType v(s, sizeof(s) / sizeof(Ch) - 1);\
- return v;\
- }
-
- RAPIDJSON_STRING_(Null, 'n', 'u', 'l', 'l')
- RAPIDJSON_STRING_(Boolean, 'b', 'o', 'o', 'l', 'e', 'a', 'n')
- RAPIDJSON_STRING_(Object, 'o', 'b', 'j', 'e', 'c', 't')
- RAPIDJSON_STRING_(Array, 'a', 'r', 'r', 'a', 'y')
- RAPIDJSON_STRING_(String, 's', 't', 'r', 'i', 'n', 'g')
- RAPIDJSON_STRING_(Number, 'n', 'u', 'm', 'b', 'e', 'r')
- RAPIDJSON_STRING_(Integer, 'i', 'n', 't', 'e', 'g', 'e', 'r')
- RAPIDJSON_STRING_(Type, 't', 'y', 'p', 'e')
- RAPIDJSON_STRING_(Enum, 'e', 'n', 'u', 'm')
- RAPIDJSON_STRING_(AllOf, 'a', 'l', 'l', 'O', 'f')
- RAPIDJSON_STRING_(AnyOf, 'a', 'n', 'y', 'O', 'f')
- RAPIDJSON_STRING_(OneOf, 'o', 'n', 'e', 'O', 'f')
- RAPIDJSON_STRING_(Not, 'n', 'o', 't')
- RAPIDJSON_STRING_(Properties, 'p', 'r', 'o', 'p', 'e', 'r', 't', 'i', 'e', 's')
- RAPIDJSON_STRING_(Required, 'r', 'e', 'q', 'u', 'i', 'r', 'e', 'd')
- RAPIDJSON_STRING_(Dependencies, 'd', 'e', 'p', 'e', 'n', 'd', 'e', 'n', 'c', 'i', 'e', 's')
- RAPIDJSON_STRING_(PatternProperties, 'p', 'a', 't', 't', 'e', 'r', 'n', 'P', 'r', 'o', 'p', 'e', 'r', 't', 'i', 'e', 's')
- RAPIDJSON_STRING_(AdditionalProperties, 'a', 'd', 'd', 'i', 't', 'i', 'o', 'n', 'a', 'l', 'P', 'r', 'o', 'p', 'e', 'r', 't', 'i', 'e', 's')
- RAPIDJSON_STRING_(MinProperties, 'm', 'i', 'n', 'P', 'r', 'o', 'p', 'e', 'r', 't', 'i', 'e', 's')
- RAPIDJSON_STRING_(MaxProperties, 'm', 'a', 'x', 'P', 'r', 'o', 'p', 'e', 'r', 't', 'i', 'e', 's')
- RAPIDJSON_STRING_(Items, 'i', 't', 'e', 'm', 's')
- RAPIDJSON_STRING_(MinItems, 'm', 'i', 'n', 'I', 't', 'e', 'm', 's')
- RAPIDJSON_STRING_(MaxItems, 'm', 'a', 'x', 'I', 't', 'e', 'm', 's')
- RAPIDJSON_STRING_(AdditionalItems, 'a', 'd', 'd', 'i', 't', 'i', 'o', 'n', 'a', 'l', 'I', 't', 'e', 'm', 's')
- RAPIDJSON_STRING_(UniqueItems, 'u', 'n', 'i', 'q', 'u', 'e', 'I', 't', 'e', 'm', 's')
- RAPIDJSON_STRING_(MinLength, 'm', 'i', 'n', 'L', 'e', 'n', 'g', 't', 'h')
- RAPIDJSON_STRING_(MaxLength, 'm', 'a', 'x', 'L', 'e', 'n', 'g', 't', 'h')
- RAPIDJSON_STRING_(Pattern, 'p', 'a', 't', 't', 'e', 'r', 'n')
- RAPIDJSON_STRING_(Minimum, 'm', 'i', 'n', 'i', 'm', 'u', 'm')
- RAPIDJSON_STRING_(Maximum, 'm', 'a', 'x', 'i', 'm', 'u', 'm')
- RAPIDJSON_STRING_(ExclusiveMinimum, 'e', 'x', 'c', 'l', 'u', 's', 'i', 'v', 'e', 'M', 'i', 'n', 'i', 'm', 'u', 'm')
- RAPIDJSON_STRING_(ExclusiveMaximum, 'e', 'x', 'c', 'l', 'u', 's', 'i', 'v', 'e', 'M', 'a', 'x', 'i', 'm', 'u', 'm')
- RAPIDJSON_STRING_(MultipleOf, 'm', 'u', 'l', 't', 'i', 'p', 'l', 'e', 'O', 'f')
-
-#undef RAPIDJSON_STRING_
-
-private:
- enum SchemaValueType {
- kNullSchemaType,
- kBooleanSchemaType,
- kObjectSchemaType,
- kArraySchemaType,
- kStringSchemaType,
- kNumberSchemaType,
- kIntegerSchemaType,
- kTotalSchemaType
- };
-
-#if RAPIDJSON_SCHEMA_USE_INTERNALREGEX
- typedef internal::GenericRegex<EncodingType> RegexType;
-#elif RAPIDJSON_SCHEMA_USE_STDREGEX
- typedef std::basic_regex<Ch> RegexType;
-#else
- typedef char RegexType;
-#endif
-
- struct SchemaArray {
- SchemaArray() : schemas(), count() {}
- ~SchemaArray() { AllocatorType::Free(schemas); }
- const SchemaType** schemas;
- SizeType begin; // begin index of context.validators
- SizeType count;
- };
-
- static const SchemaType* GetTypeless() {
- static SchemaType typeless(0, PointerType(), ValueType(kObjectType).Move(), ValueType(kObjectType).Move(), 0);
- return &typeless;
- }
-
- template <typename V1, typename V2>
- void AddUniqueElement(V1& a, const V2& v) {
- for (typename V1::ConstValueIterator itr = a.Begin(); itr != a.End(); ++itr)
- if (*itr == v)
- return;
- V1 c(v, *allocator_);
- a.PushBack(c, *allocator_);
- }
-
- static const ValueType* GetMember(const ValueType& value, const ValueType& name) {
- typename ValueType::ConstMemberIterator itr = value.FindMember(name);
- return itr != value.MemberEnd() ? &(itr->value) : 0;
- }
-
- static void AssignIfExist(bool& out, const ValueType& value, const ValueType& name) {
- if (const ValueType* v = GetMember(value, name))
- if (v->IsBool())
- out = v->GetBool();
- }
-
- static void AssignIfExist(SizeType& out, const ValueType& value, const ValueType& name) {
- if (const ValueType* v = GetMember(value, name))
- if (v->IsUint64() && v->GetUint64() <= SizeType(~0))
- out = static_cast<SizeType>(v->GetUint64());
- }
-
- void AssignIfExist(SchemaArray& out, SchemaDocumentType& schemaDocument, const PointerType& p, const ValueType& value, const ValueType& name, const ValueType& document) {
- if (const ValueType* v = GetMember(value, name)) {
- if (v->IsArray() && v->Size() > 0) {
- PointerType q = p.Append(name, allocator_);
- out.count = v->Size();
- out.schemas = static_cast<const Schema**>(allocator_->Malloc(out.count * sizeof(const Schema*)));
- memset(out.schemas, 0, sizeof(Schema*)* out.count);
- for (SizeType i = 0; i < out.count; i++)
- schemaDocument.CreateSchema(&out.schemas[i], q.Append(i, allocator_), (*v)[i], document);
- out.begin = validatorCount_;
- validatorCount_ += out.count;
- }
- }
- }
-
-#if RAPIDJSON_SCHEMA_USE_INTERNALREGEX
- template <typename ValueType>
- RegexType* CreatePattern(const ValueType& value) {
- if (value.IsString()) {
- RegexType* r = new (allocator_->Malloc(sizeof(RegexType))) RegexType(value.GetString());
- if (!r->IsValid()) {
- r->~RegexType();
- AllocatorType::Free(r);
- r = 0;
- }
- return r;
- }
- return 0;
- }
-
- static bool IsPatternMatch(const RegexType* pattern, const Ch *str, SizeType) {
- return pattern->Search(str);
- }
-#elif RAPIDJSON_SCHEMA_USE_STDREGEX
- template <typename ValueType>
- RegexType* CreatePattern(const ValueType& value) {
- if (value.IsString())
- try {
- return new (allocator_->Malloc(sizeof(RegexType))) RegexType(value.GetString(), std::size_t(value.GetStringLength()), std::regex_constants::ECMAScript);
- }
- catch (const std::regex_error&) {
- }
- return 0;
- }
-
- static bool IsPatternMatch(const RegexType* pattern, const Ch *str, SizeType length) {
- std::match_results<const Ch*> r;
- return std::regex_search(str, str + length, r, *pattern);
- }
-#else
- template <typename ValueType>
- RegexType* CreatePattern(const ValueType&) { return 0; }
-
- static bool IsPatternMatch(const RegexType*, const Ch *, SizeType) { return true; }
-#endif // RAPIDJSON_SCHEMA_USE_STDREGEX
-
- void AddType(const ValueType& type) {
- if (type == GetNullString() ) type_ |= 1 << kNullSchemaType;
- else if (type == GetBooleanString()) type_ |= 1 << kBooleanSchemaType;
- else if (type == GetObjectString() ) type_ |= 1 << kObjectSchemaType;
- else if (type == GetArrayString() ) type_ |= 1 << kArraySchemaType;
- else if (type == GetStringString() ) type_ |= 1 << kStringSchemaType;
- else if (type == GetIntegerString()) type_ |= 1 << kIntegerSchemaType;
- else if (type == GetNumberString() ) type_ |= (1 << kNumberSchemaType) | (1 << kIntegerSchemaType);
- }
-
- bool CreateParallelValidator(Context& context) const {
- if (enum_ || context.arrayUniqueness)
- context.hasher = context.factory.CreateHasher();
-
- if (validatorCount_) {
- RAPIDJSON_ASSERT(context.validators == 0);
- context.validators = static_cast<ISchemaValidator**>(context.factory.MallocState(sizeof(ISchemaValidator*) * validatorCount_));
- context.validatorCount = validatorCount_;
-
- if (allOf_.schemas)
- CreateSchemaValidators(context, allOf_);
-
- if (anyOf_.schemas)
- CreateSchemaValidators(context, anyOf_);
-
- if (oneOf_.schemas)
- CreateSchemaValidators(context, oneOf_);
-
- if (not_)
- context.validators[notValidatorIndex_] = context.factory.CreateSchemaValidator(*not_);
-
- if (hasSchemaDependencies_) {
- for (SizeType i = 0; i < propertyCount_; i++)
- if (properties_[i].dependenciesSchema)
- context.validators[properties_[i].dependenciesValidatorIndex] = context.factory.CreateSchemaValidator(*properties_[i].dependenciesSchema);
- }
- }
-
- return true;
- }
-
- void CreateSchemaValidators(Context& context, const SchemaArray& schemas) const {
- for (SizeType i = 0; i < schemas.count; i++)
- context.validators[schemas.begin + i] = context.factory.CreateSchemaValidator(*schemas.schemas[i]);
- }
-
- // O(n)
- bool FindPropertyIndex(const ValueType& name, SizeType* outIndex) const {
- SizeType len = name.GetStringLength();
- const Ch* str = name.GetString();
- for (SizeType index = 0; index < propertyCount_; index++)
- if (properties_[index].name.GetStringLength() == len &&
- (std::memcmp(properties_[index].name.GetString(), str, sizeof(Ch) * len) == 0))
- {
- *outIndex = index;
- return true;
- }
- return false;
- }
-
- bool CheckInt(Context& context, int64_t i) const {
- if (!(type_ & ((1 << kIntegerSchemaType) | (1 << kNumberSchemaType))))
- RAPIDJSON_INVALID_KEYWORD_RETURN(GetTypeString());
-
- if (!minimum_.IsNull()) {
- if (minimum_.IsInt64()) {
- if (exclusiveMinimum_ ? i <= minimum_.GetInt64() : i < minimum_.GetInt64())
- RAPIDJSON_INVALID_KEYWORD_RETURN(GetMinimumString());
- }
- else if (minimum_.IsUint64()) {
- RAPIDJSON_INVALID_KEYWORD_RETURN(GetMinimumString()); // i <= max(int64_t) < minimum.GetUint64()
- }
- else if (!CheckDoubleMinimum(context, static_cast<double>(i)))
- return false;
- }
-
- if (!maximum_.IsNull()) {
- if (maximum_.IsInt64()) {
- if (exclusiveMaximum_ ? i >= maximum_.GetInt64() : i > maximum_.GetInt64())
- RAPIDJSON_INVALID_KEYWORD_RETURN(GetMaximumString());
- }
- else if (maximum_.IsUint64())
- /* do nothing */; // i <= max(int64_t) < maximum_.GetUint64()
- else if (!CheckDoubleMaximum(context, static_cast<double>(i)))
- return false;
- }
-
- if (!multipleOf_.IsNull()) {
- if (multipleOf_.IsUint64()) {
- if (static_cast<uint64_t>(i >= 0 ? i : -i) % multipleOf_.GetUint64() != 0)
- RAPIDJSON_INVALID_KEYWORD_RETURN(GetMultipleOfString());
- }
- else if (!CheckDoubleMultipleOf(context, static_cast<double>(i)))
- return false;
- }
-
- return true;
- }
-
- bool CheckUint(Context& context, uint64_t i) const {
- if (!(type_ & ((1 << kIntegerSchemaType) | (1 << kNumberSchemaType))))
- RAPIDJSON_INVALID_KEYWORD_RETURN(GetTypeString());
-
- if (!minimum_.IsNull()) {
- if (minimum_.IsUint64()) {
- if (exclusiveMinimum_ ? i <= minimum_.GetUint64() : i < minimum_.GetUint64())
- RAPIDJSON_INVALID_KEYWORD_RETURN(GetMinimumString());
- }
- else if (minimum_.IsInt64())
- /* do nothing */; // i >= 0 > minimum.Getint64()
- else if (!CheckDoubleMinimum(context, static_cast<double>(i)))
- return false;
- }
-
- if (!maximum_.IsNull()) {
- if (maximum_.IsUint64()) {
- if (exclusiveMaximum_ ? i >= maximum_.GetUint64() : i > maximum_.GetUint64())
- RAPIDJSON_INVALID_KEYWORD_RETURN(GetMaximumString());
- }
- else if (maximum_.IsInt64())
- RAPIDJSON_INVALID_KEYWORD_RETURN(GetMaximumString()); // i >= 0 > maximum_
- else if (!CheckDoubleMaximum(context, static_cast<double>(i)))
- return false;
- }
-
- if (!multipleOf_.IsNull()) {
- if (multipleOf_.IsUint64()) {
- if (i % multipleOf_.GetUint64() != 0)
- RAPIDJSON_INVALID_KEYWORD_RETURN(GetMultipleOfString());
- }
- else if (!CheckDoubleMultipleOf(context, static_cast<double>(i)))
- return false;
- }
-
- return true;
- }
-
- bool CheckDoubleMinimum(Context& context, double d) const {
- if (exclusiveMinimum_ ? d <= minimum_.GetDouble() : d < minimum_.GetDouble())
- RAPIDJSON_INVALID_KEYWORD_RETURN(GetMinimumString());
- return true;
- }
-
- bool CheckDoubleMaximum(Context& context, double d) const {
- if (exclusiveMaximum_ ? d >= maximum_.GetDouble() : d > maximum_.GetDouble())
- RAPIDJSON_INVALID_KEYWORD_RETURN(GetMaximumString());
- return true;
- }
-
- bool CheckDoubleMultipleOf(Context& context, double d) const {
- double a = std::abs(d), b = std::abs(multipleOf_.GetDouble());
- double q = std::floor(a / b);
- double r = a - q * b;
- if (r > 0.0)
- RAPIDJSON_INVALID_KEYWORD_RETURN(GetMultipleOfString());
- return true;
- }
-
- struct Property {
- Property() : schema(), dependenciesSchema(), dependenciesValidatorIndex(), dependencies(), required(false) {}
- ~Property() { AllocatorType::Free(dependencies); }
- SValue name;
- const SchemaType* schema;
- const SchemaType* dependenciesSchema;
- SizeType dependenciesValidatorIndex;
- bool* dependencies;
- bool required;
- };
-
- struct PatternProperty {
- PatternProperty() : schema(), pattern() {}
- ~PatternProperty() {
- if (pattern) {
- pattern->~RegexType();
- AllocatorType::Free(pattern);
- }
- }
- const SchemaType* schema;
- RegexType* pattern;
- };
-
- AllocatorType* allocator_;
- uint64_t* enum_;
- SizeType enumCount_;
- SchemaArray allOf_;
- SchemaArray anyOf_;
- SchemaArray oneOf_;
- const SchemaType* not_;
- unsigned type_; // bitmask of kSchemaType
- SizeType validatorCount_;
- SizeType notValidatorIndex_;
-
- Property* properties_;
- const SchemaType* additionalPropertiesSchema_;
- PatternProperty* patternProperties_;
- SizeType patternPropertyCount_;
- SizeType propertyCount_;
- SizeType minProperties_;
- SizeType maxProperties_;
- bool additionalProperties_;
- bool hasDependencies_;
- bool hasRequired_;
- bool hasSchemaDependencies_;
-
- const SchemaType* additionalItemsSchema_;
- const SchemaType* itemsList_;
- const SchemaType** itemsTuple_;
- SizeType itemsTupleCount_;
- SizeType minItems_;
- SizeType maxItems_;
- bool additionalItems_;
- bool uniqueItems_;
-
- RegexType* pattern_;
- SizeType minLength_;
- SizeType maxLength_;
-
- SValue minimum_;
- SValue maximum_;
- SValue multipleOf_;
- bool exclusiveMinimum_;
- bool exclusiveMaximum_;
-};
-
-template<typename Stack, typename Ch>
-struct TokenHelper {
- RAPIDJSON_FORCEINLINE static void AppendIndexToken(Stack& documentStack, SizeType index) {
- *documentStack.template Push<Ch>() = '/';
- char buffer[21];
- size_t length = static_cast<size_t>((sizeof(SizeType) == 4 ? u32toa(index, buffer) : u64toa(index, buffer)) - buffer);
- for (size_t i = 0; i < length; i++)
- *documentStack.template Push<Ch>() = buffer[i];
- }
-};
-
-// Partial specialized version for char to prevent buffer copying.
-template <typename Stack>
-struct TokenHelper<Stack, char> {
- RAPIDJSON_FORCEINLINE static void AppendIndexToken(Stack& documentStack, SizeType index) {
- if (sizeof(SizeType) == 4) {
- char *buffer = documentStack.template Push<char>(1 + 10); // '/' + uint
- *buffer++ = '/';
- const char* end = internal::u32toa(index, buffer);
- documentStack.template Pop<char>(static_cast<size_t>(10 - (end - buffer)));
- }
- else {
- char *buffer = documentStack.template Push<char>(1 + 20); // '/' + uint64
- *buffer++ = '/';
- const char* end = internal::u64toa(index, buffer);
- documentStack.template Pop<char>(static_cast<size_t>(20 - (end - buffer)));
- }
- }
-};
-
-} // namespace internal
-
-///////////////////////////////////////////////////////////////////////////////
-// IGenericRemoteSchemaDocumentProvider
-
-template <typename SchemaDocumentType>
-class IGenericRemoteSchemaDocumentProvider {
-public:
- typedef typename SchemaDocumentType::Ch Ch;
-
- virtual ~IGenericRemoteSchemaDocumentProvider() {}
- virtual const SchemaDocumentType* GetRemoteDocument(const Ch* uri, SizeType length) = 0;
-};
-
-///////////////////////////////////////////////////////////////////////////////
-// GenericSchemaDocument
-
-//! JSON schema document.
-/*!
- A JSON schema document is a compiled version of a JSON schema.
- It is basically a tree of internal::Schema.
-
- \note This is an immutable class (i.e. its instance cannot be modified after construction).
- \tparam ValueT Type of JSON value (e.g. \c Value ), which also determine the encoding.
- \tparam Allocator Allocator type for allocating memory of this document.
-*/
-template <typename ValueT, typename Allocator = CrtAllocator>
-class GenericSchemaDocument {
-public:
- typedef ValueT ValueType;
- typedef IGenericRemoteSchemaDocumentProvider<GenericSchemaDocument> IRemoteSchemaDocumentProviderType;
- typedef Allocator AllocatorType;
- typedef typename ValueType::EncodingType EncodingType;
- typedef typename EncodingType::Ch Ch;
- typedef internal::Schema<GenericSchemaDocument> SchemaType;
- typedef GenericPointer<ValueType, Allocator> PointerType;
- friend class internal::Schema<GenericSchemaDocument>;
- template <typename, typename, typename>
- friend class GenericSchemaValidator;
-
- //! Constructor.
- /*!
- Compile a JSON document into schema document.
-
- \param document A JSON document as source.
- \param remoteProvider An optional remote schema document provider for resolving remote reference. Can be null.
- \param allocator An optional allocator instance for allocating memory. Can be null.
- */
- explicit GenericSchemaDocument(const ValueType& document, IRemoteSchemaDocumentProviderType* remoteProvider = 0, Allocator* allocator = 0) :
- remoteProvider_(remoteProvider),
- allocator_(allocator),
- ownAllocator_(),
- root_(),
- schemaMap_(allocator, kInitialSchemaMapSize),
- schemaRef_(allocator, kInitialSchemaRefSize)
- {
- if (!allocator_)
- ownAllocator_ = allocator_ = RAPIDJSON_NEW(Allocator());
-
- // Generate root schema, it will call CreateSchema() to create sub-schemas,
- // And call AddRefSchema() if there are $ref.
- CreateSchemaRecursive(&root_, PointerType(), document, document);
-
- // Resolve $ref
- while (!schemaRef_.Empty()) {
- SchemaRefEntry* refEntry = schemaRef_.template Pop<SchemaRefEntry>(1);
- if (const SchemaType* s = GetSchema(refEntry->target)) {
- if (refEntry->schema)
- *refEntry->schema = s;
-
- // Create entry in map if not exist
- if (!GetSchema(refEntry->source)) {
- new (schemaMap_.template Push<SchemaEntry>()) SchemaEntry(refEntry->source, const_cast<SchemaType*>(s), false, allocator_);
- }
- }
- refEntry->~SchemaRefEntry();
- }
-
- RAPIDJSON_ASSERT(root_ != 0);
-
- schemaRef_.ShrinkToFit(); // Deallocate all memory for ref
- }
-
-#if RAPIDJSON_HAS_CXX11_RVALUE_REFS
- //! Move constructor in C++11
- GenericSchemaDocument(GenericSchemaDocument&& rhs) RAPIDJSON_NOEXCEPT :
- remoteProvider_(rhs.remoteProvider_),
- allocator_(rhs.allocator_),
- ownAllocator_(rhs.ownAllocator_),
- root_(rhs.root_),
- schemaMap_(std::move(rhs.schemaMap_)),
- schemaRef_(std::move(rhs.schemaRef_))
- {
- rhs.remoteProvider_ = 0;
- rhs.allocator_ = 0;
- rhs.ownAllocator_ = 0;
- }
-#endif
-
- //! Destructor
- ~GenericSchemaDocument() {
- while (!schemaMap_.Empty())
- schemaMap_.template Pop<SchemaEntry>(1)->~SchemaEntry();
-
- RAPIDJSON_DELETE(ownAllocator_);
- }
-
- //! Get the root schema.
- const SchemaType& GetRoot() const { return *root_; }
-
-private:
- //! Prohibit copying
- GenericSchemaDocument(const GenericSchemaDocument&);
- //! Prohibit assignment
- GenericSchemaDocument& operator=(const GenericSchemaDocument&);
-
- struct SchemaRefEntry {
- SchemaRefEntry(const PointerType& s, const PointerType& t, const SchemaType** outSchema, Allocator *allocator) : source(s, allocator), target(t, allocator), schema(outSchema) {}
- PointerType source;
- PointerType target;
- const SchemaType** schema;
- };
-
- struct SchemaEntry {
- SchemaEntry(const PointerType& p, SchemaType* s, bool o, Allocator* allocator) : pointer(p, allocator), schema(s), owned(o) {}
- ~SchemaEntry() {
- if (owned) {
- schema->~SchemaType();
- Allocator::Free(schema);
- }
- }
- PointerType pointer;
- SchemaType* schema;
- bool owned;
- };
-
- void CreateSchemaRecursive(const SchemaType** schema, const PointerType& pointer, const ValueType& v, const ValueType& document) {
- if (schema)
- *schema = SchemaType::GetTypeless();
-
- if (v.GetType() == kObjectType) {
- const SchemaType* s = GetSchema(pointer);
- if (!s)
- CreateSchema(schema, pointer, v, document);
-
- for (typename ValueType::ConstMemberIterator itr = v.MemberBegin(); itr != v.MemberEnd(); ++itr)
- CreateSchemaRecursive(0, pointer.Append(itr->name, allocator_), itr->value, document);
- }
- else if (v.GetType() == kArrayType)
- for (SizeType i = 0; i < v.Size(); i++)
- CreateSchemaRecursive(0, pointer.Append(i, allocator_), v[i], document);
- }
-
- void CreateSchema(const SchemaType** schema, const PointerType& pointer, const ValueType& v, const ValueType& document) {
- RAPIDJSON_ASSERT(pointer.IsValid());
- if (v.IsObject()) {
- if (!HandleRefSchema(pointer, schema, v, document)) {
- SchemaType* s = new (allocator_->Malloc(sizeof(SchemaType))) SchemaType(this, pointer, v, document, allocator_);
- new (schemaMap_.template Push<SchemaEntry>()) SchemaEntry(pointer, s, true, allocator_);
- if (schema)
- *schema = s;
- }
- }
- }
-
- bool HandleRefSchema(const PointerType& source, const SchemaType** schema, const ValueType& v, const ValueType& document) {
- static const Ch kRefString[] = { '$', 'r', 'e', 'f', '\0' };
- static const ValueType kRefValue(kRefString, 4);
-
- typename ValueType::ConstMemberIterator itr = v.FindMember(kRefValue);
- if (itr == v.MemberEnd())
- return false;
-
- if (itr->value.IsString()) {
- SizeType len = itr->value.GetStringLength();
- if (len > 0) {
- const Ch* s = itr->value.GetString();
- SizeType i = 0;
- while (i < len && s[i] != '#') // Find the first #
- i++;
-
- if (i > 0) { // Remote reference, resolve immediately
- if (remoteProvider_) {
- if (const GenericSchemaDocument* remoteDocument = remoteProvider_->GetRemoteDocument(s, i - 1)) {
- PointerType pointer(&s[i], len - i, allocator_);
- if (pointer.IsValid()) {
- if (const SchemaType* sc = remoteDocument->GetSchema(pointer)) {
- if (schema)
- *schema = sc;
- return true;
- }
- }
- }
- }
- }
- else if (s[i] == '#') { // Local reference, defer resolution
- PointerType pointer(&s[i], len - i, allocator_);
- if (pointer.IsValid()) {
- if (const ValueType* nv = pointer.Get(document))
- if (HandleRefSchema(source, schema, *nv, document))
- return true;
-
- new (schemaRef_.template Push<SchemaRefEntry>()) SchemaRefEntry(source, pointer, schema, allocator_);
- return true;
- }
- }
- }
- }
- return false;
- }
-
- const SchemaType* GetSchema(const PointerType& pointer) const {
- for (const SchemaEntry* target = schemaMap_.template Bottom<SchemaEntry>(); target != schemaMap_.template End<SchemaEntry>(); ++target)
- if (pointer == target->pointer)
- return target->schema;
- return 0;
- }
-
- PointerType GetPointer(const SchemaType* schema) const {
- for (const SchemaEntry* target = schemaMap_.template Bottom<SchemaEntry>(); target != schemaMap_.template End<SchemaEntry>(); ++target)
- if (schema == target->schema)
- return target->pointer;
- return PointerType();
- }
-
- static const size_t kInitialSchemaMapSize = 64;
- static const size_t kInitialSchemaRefSize = 64;
-
- IRemoteSchemaDocumentProviderType* remoteProvider_;
- Allocator *allocator_;
- Allocator *ownAllocator_;
- const SchemaType* root_; //!< Root schema.
- internal::Stack<Allocator> schemaMap_; // Stores created Pointer -> Schemas
- internal::Stack<Allocator> schemaRef_; // Stores Pointer from $ref and schema which holds the $ref
-};
-
-//! GenericSchemaDocument using Value type.
-typedef GenericSchemaDocument<Value> SchemaDocument;
-//! IGenericRemoteSchemaDocumentProvider using SchemaDocument.
-typedef IGenericRemoteSchemaDocumentProvider<SchemaDocument> IRemoteSchemaDocumentProvider;
-
-///////////////////////////////////////////////////////////////////////////////
-// GenericSchemaValidator
-
-//! JSON Schema Validator.
-/*!
- A SAX style JSON schema validator.
- It uses a \c GenericSchemaDocument to validate SAX events.
- It delegates the incoming SAX events to an output handler.
- The default output handler does nothing.
- It can be reused multiple times by calling \c Reset().
-
- \tparam SchemaDocumentType Type of schema document.
- \tparam OutputHandler Type of output handler. Default handler does nothing.
- \tparam StateAllocator Allocator for storing the internal validation states.
-*/
-template <
- typename SchemaDocumentType,
- typename OutputHandler = BaseReaderHandler<typename SchemaDocumentType::SchemaType::EncodingType>,
- typename StateAllocator = CrtAllocator>
-class GenericSchemaValidator :
- public internal::ISchemaStateFactory<typename SchemaDocumentType::SchemaType>,
- public internal::ISchemaValidator
-{
-public:
- typedef typename SchemaDocumentType::SchemaType SchemaType;
- typedef typename SchemaDocumentType::PointerType PointerType;
- typedef typename SchemaType::EncodingType EncodingType;
- typedef typename EncodingType::Ch Ch;
-
- //! Constructor without output handler.
- /*!
- \param schemaDocument The schema document to conform to.
- \param allocator Optional allocator for storing internal validation states.
- \param schemaStackCapacity Optional initial capacity of schema path stack.
- \param documentStackCapacity Optional initial capacity of document path stack.
- */
- GenericSchemaValidator(
- const SchemaDocumentType& schemaDocument,
- StateAllocator* allocator = 0,
- size_t schemaStackCapacity = kDefaultSchemaStackCapacity,
- size_t documentStackCapacity = kDefaultDocumentStackCapacity)
- :
- schemaDocument_(&schemaDocument),
- root_(schemaDocument.GetRoot()),
- outputHandler_(GetNullHandler()),
- stateAllocator_(allocator),
- ownStateAllocator_(0),
- schemaStack_(allocator, schemaStackCapacity),
- documentStack_(allocator, documentStackCapacity),
- valid_(true)
-#if RAPIDJSON_SCHEMA_VERBOSE
- , depth_(0)
-#endif
- {
- }
-
- //! Constructor with output handler.
- /*!
- \param schemaDocument The schema document to conform to.
- \param allocator Optional allocator for storing internal validation states.
- \param schemaStackCapacity Optional initial capacity of schema path stack.
- \param documentStackCapacity Optional initial capacity of document path stack.
- */
- GenericSchemaValidator(
- const SchemaDocumentType& schemaDocument,
- OutputHandler& outputHandler,
- StateAllocator* allocator = 0,
- size_t schemaStackCapacity = kDefaultSchemaStackCapacity,
- size_t documentStackCapacity = kDefaultDocumentStackCapacity)
- :
- schemaDocument_(&schemaDocument),
- root_(schemaDocument.GetRoot()),
- outputHandler_(outputHandler),
- stateAllocator_(allocator),
- ownStateAllocator_(0),
- schemaStack_(allocator, schemaStackCapacity),
- documentStack_(allocator, documentStackCapacity),
- valid_(true)
-#if RAPIDJSON_SCHEMA_VERBOSE
- , depth_(0)
-#endif
- {
- }
-
- //! Destructor.
- ~GenericSchemaValidator() {
- Reset();
- RAPIDJSON_DELETE(ownStateAllocator_);
- }
-
- //! Reset the internal states.
- void Reset() {
- while (!schemaStack_.Empty())
- PopSchema();
- documentStack_.Clear();
- valid_ = true;
- }
-
- //! Checks whether the current state is valid.
- // Implementation of ISchemaValidator
- virtual bool IsValid() const { return valid_; }
-
- //! Gets the JSON pointer pointed to the invalid schema.
- PointerType GetInvalidSchemaPointer() const {
- return schemaStack_.Empty() ? PointerType() : schemaDocument_->GetPointer(&CurrentSchema());
- }
-
- //! Gets the keyword of invalid schema.
- const Ch* GetInvalidSchemaKeyword() const {
- return schemaStack_.Empty() ? 0 : CurrentContext().invalidKeyword;
- }
-
- //! Gets the JSON pointer pointed to the invalid value.
- PointerType GetInvalidDocumentPointer() const {
- return documentStack_.Empty() ? PointerType() : PointerType(documentStack_.template Bottom<Ch>(), documentStack_.GetSize() / sizeof(Ch));
- }
-
-#if RAPIDJSON_SCHEMA_VERBOSE
-#define RAPIDJSON_SCHEMA_HANDLE_BEGIN_VERBOSE_() \
-RAPIDJSON_MULTILINEMACRO_BEGIN\
- *documentStack_.template Push<Ch>() = '\0';\
- documentStack_.template Pop<Ch>(1);\
- internal::PrintInvalidDocument(documentStack_.template Bottom<Ch>());\
-RAPIDJSON_MULTILINEMACRO_END
-#else
-#define RAPIDJSON_SCHEMA_HANDLE_BEGIN_VERBOSE_()
-#endif
-
-#define RAPIDJSON_SCHEMA_HANDLE_BEGIN_(method, arg1)\
- if (!valid_) return false; \
- if (!BeginValue() || !CurrentSchema().method arg1) {\
- RAPIDJSON_SCHEMA_HANDLE_BEGIN_VERBOSE_();\
- return valid_ = false;\
- }
-
-#define RAPIDJSON_SCHEMA_HANDLE_PARALLEL_(method, arg2)\
- for (Context* context = schemaStack_.template Bottom<Context>(); context != schemaStack_.template End<Context>(); context++) {\
- if (context->hasher)\
- static_cast<HasherType*>(context->hasher)->method arg2;\
- if (context->validators)\
- for (SizeType i_ = 0; i_ < context->validatorCount; i_++)\
- static_cast<GenericSchemaValidator*>(context->validators[i_])->method arg2;\
- if (context->patternPropertiesValidators)\
- for (SizeType i_ = 0; i_ < context->patternPropertiesValidatorCount; i_++)\
- static_cast<GenericSchemaValidator*>(context->patternPropertiesValidators[i_])->method arg2;\
- }
-
-#define RAPIDJSON_SCHEMA_HANDLE_END_(method, arg2)\
- return valid_ = EndValue() && outputHandler_.method arg2
-
-#define RAPIDJSON_SCHEMA_HANDLE_VALUE_(method, arg1, arg2) \
- RAPIDJSON_SCHEMA_HANDLE_BEGIN_ (method, arg1);\
- RAPIDJSON_SCHEMA_HANDLE_PARALLEL_(method, arg2);\
- RAPIDJSON_SCHEMA_HANDLE_END_ (method, arg2)
-
- bool Null() { RAPIDJSON_SCHEMA_HANDLE_VALUE_(Null, (CurrentContext() ), ( )); }
- bool Bool(bool b) { RAPIDJSON_SCHEMA_HANDLE_VALUE_(Bool, (CurrentContext(), b), (b)); }
- bool Int(int i) { RAPIDJSON_SCHEMA_HANDLE_VALUE_(Int, (CurrentContext(), i), (i)); }
- bool Uint(unsigned u) { RAPIDJSON_SCHEMA_HANDLE_VALUE_(Uint, (CurrentContext(), u), (u)); }
- bool Int64(int64_t i) { RAPIDJSON_SCHEMA_HANDLE_VALUE_(Int64, (CurrentContext(), i), (i)); }
- bool Uint64(uint64_t u) { RAPIDJSON_SCHEMA_HANDLE_VALUE_(Uint64, (CurrentContext(), u), (u)); }
- bool Double(double d) { RAPIDJSON_SCHEMA_HANDLE_VALUE_(Double, (CurrentContext(), d), (d)); }
- bool RawNumber(const Ch* str, SizeType length, bool copy)
- { RAPIDJSON_SCHEMA_HANDLE_VALUE_(String, (CurrentContext(), str, length, copy), (str, length, copy)); }
- bool String(const Ch* str, SizeType length, bool copy)
- { RAPIDJSON_SCHEMA_HANDLE_VALUE_(String, (CurrentContext(), str, length, copy), (str, length, copy)); }
-
- bool StartObject() {
- RAPIDJSON_SCHEMA_HANDLE_BEGIN_(StartObject, (CurrentContext()));
- RAPIDJSON_SCHEMA_HANDLE_PARALLEL_(StartObject, ());
- return valid_ = outputHandler_.StartObject();
- }
-
- bool Key(const Ch* str, SizeType len, bool copy) {
- if (!valid_) return false;
- AppendToken(str, len);
- if (!CurrentSchema().Key(CurrentContext(), str, len, copy)) return valid_ = false;
- RAPIDJSON_SCHEMA_HANDLE_PARALLEL_(Key, (str, len, copy));
- return valid_ = outputHandler_.Key(str, len, copy);
- }
-
- bool EndObject(SizeType memberCount) {
- if (!valid_) return false;
- RAPIDJSON_SCHEMA_HANDLE_PARALLEL_(EndObject, (memberCount));
- if (!CurrentSchema().EndObject(CurrentContext(), memberCount)) return valid_ = false;
- RAPIDJSON_SCHEMA_HANDLE_END_(EndObject, (memberCount));
- }
-
- bool StartArray() {
- RAPIDJSON_SCHEMA_HANDLE_BEGIN_(StartArray, (CurrentContext()));
- RAPIDJSON_SCHEMA_HANDLE_PARALLEL_(StartArray, ());
- return valid_ = outputHandler_.StartArray();
- }
-
- bool EndArray(SizeType elementCount) {
- if (!valid_) return false;
- RAPIDJSON_SCHEMA_HANDLE_PARALLEL_(EndArray, (elementCount));
- if (!CurrentSchema().EndArray(CurrentContext(), elementCount)) return valid_ = false;
- RAPIDJSON_SCHEMA_HANDLE_END_(EndArray, (elementCount));
- }
-
-#undef RAPIDJSON_SCHEMA_HANDLE_BEGIN_VERBOSE_
-#undef RAPIDJSON_SCHEMA_HANDLE_BEGIN_
-#undef RAPIDJSON_SCHEMA_HANDLE_PARALLEL_
-#undef RAPIDJSON_SCHEMA_HANDLE_VALUE_
-
- // Implementation of ISchemaStateFactory<SchemaType>
- virtual ISchemaValidator* CreateSchemaValidator(const SchemaType& root) {
- return new (GetStateAllocator().Malloc(sizeof(GenericSchemaValidator))) GenericSchemaValidator(*schemaDocument_, root,
-#if RAPIDJSON_SCHEMA_VERBOSE
- depth_ + 1,
-#endif
- &GetStateAllocator());
- }
-
- virtual void DestroySchemaValidator(ISchemaValidator* validator) {
- GenericSchemaValidator* v = static_cast<GenericSchemaValidator*>(validator);
- v->~GenericSchemaValidator();
- StateAllocator::Free(v);
- }
-
- virtual void* CreateHasher() {
- return new (GetStateAllocator().Malloc(sizeof(HasherType))) HasherType(&GetStateAllocator());
- }
-
- virtual uint64_t GetHashCode(void* hasher) {
- return static_cast<HasherType*>(hasher)->GetHashCode();
- }
-
- virtual void DestroryHasher(void* hasher) {
- HasherType* h = static_cast<HasherType*>(hasher);
- h->~HasherType();
- StateAllocator::Free(h);
- }
-
- virtual void* MallocState(size_t size) {
- return GetStateAllocator().Malloc(size);
- }
-
- virtual void FreeState(void* p) {
- return StateAllocator::Free(p);
- }
-
-private:
- typedef typename SchemaType::Context Context;
- typedef GenericValue<UTF8<>, StateAllocator> HashCodeArray;
- typedef internal::Hasher<EncodingType, StateAllocator> HasherType;
-
- GenericSchemaValidator(
- const SchemaDocumentType& schemaDocument,
- const SchemaType& root,
-#if RAPIDJSON_SCHEMA_VERBOSE
- unsigned depth,
-#endif
- StateAllocator* allocator = 0,
- size_t schemaStackCapacity = kDefaultSchemaStackCapacity,
- size_t documentStackCapacity = kDefaultDocumentStackCapacity)
- :
- schemaDocument_(&schemaDocument),
- root_(root),
- outputHandler_(GetNullHandler()),
- stateAllocator_(allocator),
- ownStateAllocator_(0),
- schemaStack_(allocator, schemaStackCapacity),
- documentStack_(allocator, documentStackCapacity),
- valid_(true)
-#if RAPIDJSON_SCHEMA_VERBOSE
- , depth_(depth)
-#endif
- {
- }
-
- StateAllocator& GetStateAllocator() {
- if (!stateAllocator_)
- stateAllocator_ = ownStateAllocator_ = RAPIDJSON_NEW(StateAllocator());
- return *stateAllocator_;
- }
-
- bool BeginValue() {
- if (schemaStack_.Empty())
- PushSchema(root_);
- else {
- if (CurrentContext().inArray)
- internal::TokenHelper<internal::Stack<StateAllocator>, Ch>::AppendIndexToken(documentStack_, CurrentContext().arrayElementIndex);
-
- if (!CurrentSchema().BeginValue(CurrentContext()))
- return false;
-
- SizeType count = CurrentContext().patternPropertiesSchemaCount;
- const SchemaType** sa = CurrentContext().patternPropertiesSchemas;
- typename Context::PatternValidatorType patternValidatorType = CurrentContext().valuePatternValidatorType;
- bool valueUniqueness = CurrentContext().valueUniqueness;
- if (CurrentContext().valueSchema)
- PushSchema(*CurrentContext().valueSchema);
-
- if (count > 0) {
- CurrentContext().objectPatternValidatorType = patternValidatorType;
- ISchemaValidator**& va = CurrentContext().patternPropertiesValidators;
- SizeType& validatorCount = CurrentContext().patternPropertiesValidatorCount;
- va = static_cast<ISchemaValidator**>(MallocState(sizeof(ISchemaValidator*) * count));
- for (SizeType i = 0; i < count; i++)
- va[validatorCount++] = CreateSchemaValidator(*sa[i]);
- }
-
- CurrentContext().arrayUniqueness = valueUniqueness;
- }
- return true;
- }
-
- bool EndValue() {
- if (!CurrentSchema().EndValue(CurrentContext()))
- return false;
-
-#if RAPIDJSON_SCHEMA_VERBOSE
- GenericStringBuffer<EncodingType> sb;
- schemaDocument_->GetPointer(&CurrentSchema()).Stringify(sb);
-
- *documentStack_.template Push<Ch>() = '\0';
- documentStack_.template Pop<Ch>(1);
- internal::PrintValidatorPointers(depth_, sb.GetString(), documentStack_.template Bottom<Ch>());
-#endif
-
- uint64_t h = CurrentContext().arrayUniqueness ? static_cast<HasherType*>(CurrentContext().hasher)->GetHashCode() : 0;
-
- PopSchema();
-
- if (!schemaStack_.Empty()) {
- Context& context = CurrentContext();
- if (context.valueUniqueness) {
- HashCodeArray* a = static_cast<HashCodeArray*>(context.arrayElementHashCodes);
- if (!a)
- CurrentContext().arrayElementHashCodes = a = new (GetStateAllocator().Malloc(sizeof(HashCodeArray))) HashCodeArray(kArrayType);
- for (typename HashCodeArray::ConstValueIterator itr = a->Begin(); itr != a->End(); ++itr)
- if (itr->GetUint64() == h)
- RAPIDJSON_INVALID_KEYWORD_RETURN(SchemaType::GetUniqueItemsString());
- a->PushBack(h, GetStateAllocator());
- }
- }
-
- // Remove the last token of document pointer
- while (!documentStack_.Empty() && *documentStack_.template Pop<Ch>(1) != '/')
- ;
-
- return true;
- }
-
- void AppendToken(const Ch* str, SizeType len) {
- documentStack_.template Reserve<Ch>(1 + len * 2); // worst case all characters are escaped as two characters
- *documentStack_.template PushUnsafe<Ch>() = '/';
- for (SizeType i = 0; i < len; i++) {
- if (str[i] == '~') {
- *documentStack_.template PushUnsafe<Ch>() = '~';
- *documentStack_.template PushUnsafe<Ch>() = '0';
- }
- else if (str[i] == '/') {
- *documentStack_.template PushUnsafe<Ch>() = '~';
- *documentStack_.template PushUnsafe<Ch>() = '1';
- }
- else
- *documentStack_.template PushUnsafe<Ch>() = str[i];
- }
- }
-
- RAPIDJSON_FORCEINLINE void PushSchema(const SchemaType& schema) { new (schemaStack_.template Push<Context>()) Context(*this, &schema); }
-
- RAPIDJSON_FORCEINLINE void PopSchema() {
- Context* c = schemaStack_.template Pop<Context>(1);
- if (HashCodeArray* a = static_cast<HashCodeArray*>(c->arrayElementHashCodes)) {
- a->~HashCodeArray();
- StateAllocator::Free(a);
- }
- c->~Context();
- }
-
- const SchemaType& CurrentSchema() const { return *schemaStack_.template Top<Context>()->schema; }
- Context& CurrentContext() { return *schemaStack_.template Top<Context>(); }
- const Context& CurrentContext() const { return *schemaStack_.template Top<Context>(); }
-
- static OutputHandler& GetNullHandler() {
- static OutputHandler nullHandler;
- return nullHandler;
- }
-
- static const size_t kDefaultSchemaStackCapacity = 1024;
- static const size_t kDefaultDocumentStackCapacity = 256;
- const SchemaDocumentType* schemaDocument_;
- const SchemaType& root_;
- OutputHandler& outputHandler_;
- StateAllocator* stateAllocator_;
- StateAllocator* ownStateAllocator_;
- internal::Stack<StateAllocator> schemaStack_; //!< stack to store the current path of schema (BaseSchemaType *)
- internal::Stack<StateAllocator> documentStack_; //!< stack to store the current path of validating document (Ch)
- bool valid_;
-#if RAPIDJSON_SCHEMA_VERBOSE
- unsigned depth_;
-#endif
-};
-
-typedef GenericSchemaValidator<SchemaDocument> SchemaValidator;
-
-///////////////////////////////////////////////////////////////////////////////
-// SchemaValidatingReader
-
-//! A helper class for parsing with validation.
-/*!
- This helper class is a functor, designed as a parameter of \ref GenericDocument::Populate().
-
- \tparam parseFlags Combination of \ref ParseFlag.
- \tparam InputStream Type of input stream, implementing Stream concept.
- \tparam SourceEncoding Encoding of the input stream.
- \tparam SchemaDocumentType Type of schema document.
- \tparam StackAllocator Allocator type for stack.
-*/
-template <
- unsigned parseFlags,
- typename InputStream,
- typename SourceEncoding,
- typename SchemaDocumentType = SchemaDocument,
- typename StackAllocator = CrtAllocator>
-class SchemaValidatingReader {
-public:
- typedef typename SchemaDocumentType::PointerType PointerType;
- typedef typename InputStream::Ch Ch;
-
- //! Constructor
- /*!
- \param is Input stream.
- \param sd Schema document.
- */
- SchemaValidatingReader(InputStream& is, const SchemaDocumentType& sd) : is_(is), sd_(sd), invalidSchemaKeyword_(), isValid_(true) {}
-
- template <typename Handler>
- bool operator()(Handler& handler) {
- GenericReader<SourceEncoding, typename SchemaDocumentType::EncodingType, StackAllocator> reader;
- GenericSchemaValidator<SchemaDocumentType, Handler> validator(sd_, handler);
- parseResult_ = reader.template Parse<parseFlags>(is_, validator);
-
- isValid_ = validator.IsValid();
- if (isValid_) {
- invalidSchemaPointer_ = PointerType();
- invalidSchemaKeyword_ = 0;
- invalidDocumentPointer_ = PointerType();
- }
- else {
- invalidSchemaPointer_ = validator.GetInvalidSchemaPointer();
- invalidSchemaKeyword_ = validator.GetInvalidSchemaKeyword();
- invalidDocumentPointer_ = validator.GetInvalidDocumentPointer();
- }
-
- return parseResult_;
- }
-
- const ParseResult& GetParseResult() const { return parseResult_; }
- bool IsValid() const { return isValid_; }
- const PointerType& GetInvalidSchemaPointer() const { return invalidSchemaPointer_; }
- const Ch* GetInvalidSchemaKeyword() const { return invalidSchemaKeyword_; }
- const PointerType& GetInvalidDocumentPointer() const { return invalidDocumentPointer_; }
-
-private:
- InputStream& is_;
- const SchemaDocumentType& sd_;
-
- ParseResult parseResult_;
- PointerType invalidSchemaPointer_;
- const Ch* invalidSchemaKeyword_;
- PointerType invalidDocumentPointer_;
- bool isValid_;
-};
-
-RAPIDJSON_NAMESPACE_END
-RAPIDJSON_DIAG_POP
-
-#endif // RAPIDJSON_SCHEMA_H_
diff --git a/include/rapidjson/stringbuffer.h b/include/rapidjson/stringbuffer.h
deleted file mode 100644
index 78f34d20..00000000
--- a/include/rapidjson/stringbuffer.h
+++ /dev/null
@@ -1,117 +0,0 @@
-// Tencent is pleased to support the open source community by making RapidJSON available.
-//
-// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
-//
-// Licensed under the MIT License (the "License"); you may not use this file except
-// in compliance with the License. You may obtain a copy of the License at
-//
-// http://opensource.org/licenses/MIT
-//
-// Unless required by applicable law or agreed to in writing, software distributed
-// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
-// CONDITIONS OF ANY KIND, either express or implied. See the License for the
-// specific language governing permissions and limitations under the License.
-
-#ifndef RAPIDJSON_STRINGBUFFER_H_
-#define RAPIDJSON_STRINGBUFFER_H_
-
-#include "stream.h"
-#include "internal/stack.h"
-
-#if RAPIDJSON_HAS_CXX11_RVALUE_REFS
-#include <utility> // std::move
-#endif
-
-#include "internal/stack.h"
-
-#if defined(__clang__)
-RAPIDJSON_DIAG_PUSH
-RAPIDJSON_DIAG_OFF(c++98-compat)
-#endif
-
-RAPIDJSON_NAMESPACE_BEGIN
-
-//! Represents an in-memory output stream.
-/*!
- \tparam Encoding Encoding of the stream.
- \tparam Allocator type for allocating memory buffer.
- \note implements Stream concept
-*/
-template <typename Encoding, typename Allocator = CrtAllocator>
-class GenericStringBuffer {
-public:
- typedef typename Encoding::Ch Ch;
-
- GenericStringBuffer(Allocator* allocator = 0, size_t capacity = kDefaultCapacity) : stack_(allocator, capacity) {}
-
-#if RAPIDJSON_HAS_CXX11_RVALUE_REFS
- GenericStringBuffer(GenericStringBuffer&& rhs) : stack_(std::move(rhs.stack_)) {}
- GenericStringBuffer& operator=(GenericStringBuffer&& rhs) {
- if (&rhs != this)
- stack_ = std::move(rhs.stack_);
- return *this;
- }
-#endif
-
- void Put(Ch c) { *stack_.template Push<Ch>() = c; }
- void PutUnsafe(Ch c) { *stack_.template PushUnsafe<Ch>() = c; }
- void Flush() {}
-
- void Clear() { stack_.Clear(); }
- void ShrinkToFit() {
- // Push and pop a null terminator. This is safe.
- *stack_.template Push<Ch>() = '\0';
- stack_.ShrinkToFit();
- stack_.template Pop<Ch>(1);
- }
-
- void Reserve(size_t count) { stack_.template Reserve<Ch>(count); }
- Ch* Push(size_t count) { return stack_.template Push<Ch>(count); }
- Ch* PushUnsafe(size_t count) { return stack_.template PushUnsafe<Ch>(count); }
- void Pop(size_t count) { stack_.template Pop<Ch>(count); }
-
- const Ch* GetString() const {
- // Push and pop a null terminator. This is safe.
- *stack_.template Push<Ch>() = '\0';
- stack_.template Pop<Ch>(1);
-
- return stack_.template Bottom<Ch>();
- }
-
- size_t GetSize() const { return stack_.GetSize(); }
-
- static const size_t kDefaultCapacity = 256;
- mutable internal::Stack<Allocator> stack_;
-
-private:
- // Prohibit copy constructor & assignment operator.
- GenericStringBuffer(const GenericStringBuffer&);
- GenericStringBuffer& operator=(const GenericStringBuffer&);
-};
-
-//! String buffer with UTF8 encoding
-typedef GenericStringBuffer<UTF8<> > StringBuffer;
-
-template<typename Encoding, typename Allocator>
-inline void PutReserve(GenericStringBuffer<Encoding, Allocator>& stream, size_t count) {
- stream.Reserve(count);
-}
-
-template<typename Encoding, typename Allocator>
-inline void PutUnsafe(GenericStringBuffer<Encoding, Allocator>& stream, typename Encoding::Ch c) {
- stream.PutUnsafe(c);
-}
-
-//! Implement specialized version of PutN() with memset() for better performance.
-template<>
-inline void PutN(GenericStringBuffer<UTF8<> >& stream, char c, size_t n) {
- std::memset(stream.stack_.Push<char>(n), c, n * sizeof(c));
-}
-
-RAPIDJSON_NAMESPACE_END
-
-#if defined(__clang__)
-RAPIDJSON_DIAG_POP
-#endif
-
-#endif // RAPIDJSON_STRINGBUFFER_H_
diff --git a/include/rapidjson/writer.h b/include/rapidjson/writer.h
deleted file mode 100644
index 94f22dd5..00000000
--- a/include/rapidjson/writer.h
+++ /dev/null
@@ -1,610 +0,0 @@
-// Tencent is pleased to support the open source community by making RapidJSON available.
-//
-// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
-//
-// Licensed under the MIT License (the "License"); you may not use this file except
-// in compliance with the License. You may obtain a copy of the License at
-//
-// http://opensource.org/licenses/MIT
-//
-// Unless required by applicable law or agreed to in writing, software distributed
-// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
-// CONDITIONS OF ANY KIND, either express or implied. See the License for the
-// specific language governing permissions and limitations under the License.
-
-#ifndef RAPIDJSON_WRITER_H_
-#define RAPIDJSON_WRITER_H_
-
-#include "stream.h"
-#include "internal/stack.h"
-#include "internal/strfunc.h"
-#include "internal/dtoa.h"
-#include "internal/itoa.h"
-#include "stringbuffer.h"
-#include <new> // placement new
-
-#if defined(RAPIDJSON_SIMD) && defined(_MSC_VER)
-#include <intrin.h>
-#pragma intrinsic(_BitScanForward)
-#endif
-#ifdef RAPIDJSON_SSE42
-#include <nmmintrin.h>
-#elif defined(RAPIDJSON_SSE2)
-#include <emmintrin.h>
-#endif
-
-#ifdef _MSC_VER
-RAPIDJSON_DIAG_PUSH
-RAPIDJSON_DIAG_OFF(4127) // conditional expression is constant
-#endif
-
-#ifdef __clang__
-RAPIDJSON_DIAG_PUSH
-RAPIDJSON_DIAG_OFF(padded)
-RAPIDJSON_DIAG_OFF(unreachable-code)
-#endif
-
-RAPIDJSON_NAMESPACE_BEGIN
-
-///////////////////////////////////////////////////////////////////////////////
-// WriteFlag
-
-/*! \def RAPIDJSON_WRITE_DEFAULT_FLAGS
- \ingroup RAPIDJSON_CONFIG
- \brief User-defined kWriteDefaultFlags definition.
-
- User can define this as any \c WriteFlag combinations.
-*/
-#ifndef RAPIDJSON_WRITE_DEFAULT_FLAGS
-#define RAPIDJSON_WRITE_DEFAULT_FLAGS kWriteNoFlags
-#endif
-
-//! Combination of writeFlags
-enum WriteFlag {
- kWriteNoFlags = 0, //!< No flags are set.
- kWriteValidateEncodingFlag = 1, //!< Validate encoding of JSON strings.
- kWriteNanAndInfFlag = 2, //!< Allow writing of Infinity, -Infinity and NaN.
- kWriteDefaultFlags = RAPIDJSON_WRITE_DEFAULT_FLAGS //!< Default write flags. Can be customized by defining RAPIDJSON_WRITE_DEFAULT_FLAGS
-};
-
-//! JSON writer
-/*! Writer implements the concept Handler.
- It generates JSON text by events to an output os.
-
- User may programmatically calls the functions of a writer to generate JSON text.
-
- On the other side, a writer can also be passed to objects that generates events,
-
- for example Reader::Parse() and Document::Accept().
-
- \tparam OutputStream Type of output stream.
- \tparam SourceEncoding Encoding of source string.
- \tparam TargetEncoding Encoding of output stream.
- \tparam StackAllocator Type of allocator for allocating memory of stack.
- \note implements Handler concept
-*/
-template<typename OutputStream, typename SourceEncoding = UTF8<>, typename TargetEncoding = UTF8<>, typename StackAllocator = CrtAllocator, unsigned writeFlags = kWriteDefaultFlags>
-class Writer {
-public:
- typedef typename SourceEncoding::Ch Ch;
-
- static const int kDefaultMaxDecimalPlaces = 324;
-
- //! Constructor
- /*! \param os Output stream.
- \param stackAllocator User supplied allocator. If it is null, it will create a private one.
- \param levelDepth Initial capacity of stack.
- */
- explicit
- Writer(OutputStream& os, StackAllocator* stackAllocator = 0, size_t levelDepth = kDefaultLevelDepth) :
- os_(&os), level_stack_(stackAllocator, levelDepth * sizeof(Level)), maxDecimalPlaces_(kDefaultMaxDecimalPlaces), hasRoot_(false) {}
-
- explicit
- Writer(StackAllocator* allocator = 0, size_t levelDepth = kDefaultLevelDepth) :
- os_(0), level_stack_(allocator, levelDepth * sizeof(Level)), maxDecimalPlaces_(kDefaultMaxDecimalPlaces), hasRoot_(false) {}
-
- //! Reset the writer with a new stream.
- /*!
- This function reset the writer with a new stream and default settings,
- in order to make a Writer object reusable for output multiple JSONs.
-
- \param os New output stream.
- \code
- Writer<OutputStream> writer(os1);
- writer.StartObject();
- // ...
- writer.EndObject();
-
- writer.Reset(os2);
- writer.StartObject();
- // ...
- writer.EndObject();
- \endcode
- */
- void Reset(OutputStream& os) {
- os_ = &os;
- hasRoot_ = false;
- level_stack_.Clear();
- }
-
- //! Checks whether the output is a complete JSON.
- /*!
- A complete JSON has a complete root object or array.
- */
- bool IsComplete() const {
- return hasRoot_ && level_stack_.Empty();
- }
-
- int GetMaxDecimalPlaces() const {
- return maxDecimalPlaces_;
- }
-
- //! Sets the maximum number of decimal places for double output.
- /*!
- This setting truncates the output with specified number of decimal places.
-
- For example,
-
- \code
- writer.SetMaxDecimalPlaces(3);
- writer.StartArray();
- writer.Double(0.12345); // "0.123"
- writer.Double(0.0001); // "0.0"
- writer.Double(1.234567890123456e30); // "1.234567890123456e30" (do not truncate significand for positive exponent)
- writer.Double(1.23e-4); // "0.0" (do truncate significand for negative exponent)
- writer.EndArray();
- \endcode
-
- The default setting does not truncate any decimal places. You can restore to this setting by calling
- \code
- writer.SetMaxDecimalPlaces(Writer::kDefaultMaxDecimalPlaces);
- \endcode
- */
- void SetMaxDecimalPlaces(int maxDecimalPlaces) {
- maxDecimalPlaces_ = maxDecimalPlaces;
- }
-
- /*!@name Implementation of Handler
- \see Handler
- */
- //@{
-
- bool Null() { Prefix(kNullType); return EndValue(WriteNull()); }
- bool Bool(bool b) { Prefix(b ? kTrueType : kFalseType); return EndValue(WriteBool(b)); }
- bool Int(int i) { Prefix(kNumberType); return EndValue(WriteInt(i)); }
- bool Uint(unsigned u) { Prefix(kNumberType); return EndValue(WriteUint(u)); }
- bool Int64(int64_t i64) { Prefix(kNumberType); return EndValue(WriteInt64(i64)); }
- bool Uint64(uint64_t u64) { Prefix(kNumberType); return EndValue(WriteUint64(u64)); }
-
- //! Writes the given \c double value to the stream
- /*!
- \param d The value to be written.
- \return Whether it is succeed.
- */
- bool Double(double d) { Prefix(kNumberType); return EndValue(WriteDouble(d)); }
-
- bool RawNumber(const Ch* str, SizeType length, bool copy = false) {
- (void)copy;
- Prefix(kNumberType);
- return EndValue(WriteString(str, length));
- }
-
- bool String(const Ch* str, SizeType length, bool copy = false) {
- (void)copy;
- Prefix(kStringType);
- return EndValue(WriteString(str, length));
- }
-
-#if RAPIDJSON_HAS_STDSTRING
- bool String(const std::basic_string<Ch>& str) {
- return String(str.data(), SizeType(str.size()));
- }
-#endif
-
- bool StartObject() {
- Prefix(kObjectType);
- new (level_stack_.template Push<Level>()) Level(false);
- return WriteStartObject();
- }
-
- bool Key(const Ch* str, SizeType length, bool copy = false) { return String(str, length, copy); }
-
- bool EndObject(SizeType memberCount = 0) {
- (void)memberCount;
- RAPIDJSON_ASSERT(level_stack_.GetSize() >= sizeof(Level));
- RAPIDJSON_ASSERT(!level_stack_.template Top<Level>()->inArray);
- level_stack_.template Pop<Level>(1);
- return EndValue(WriteEndObject());
- }
-
- bool StartArray() {
- Prefix(kArrayType);
- new (level_stack_.template Push<Level>()) Level(true);
- return WriteStartArray();
- }
-
- bool EndArray(SizeType elementCount = 0) {
- (void)elementCount;
- RAPIDJSON_ASSERT(level_stack_.GetSize() >= sizeof(Level));
- RAPIDJSON_ASSERT(level_stack_.template Top<Level>()->inArray);
- level_stack_.template Pop<Level>(1);
- return EndValue(WriteEndArray());
- }
- //@}
-
- /*! @name Convenience extensions */
- //@{
-
- //! Simpler but slower overload.
- bool String(const Ch* str) { return String(str, internal::StrLen(str)); }
- bool Key(const Ch* str) { return Key(str, internal::StrLen(str)); }
-
- //@}
-
- //! Write a raw JSON value.
- /*!
- For user to write a stringified JSON as a value.
-
- \param json A well-formed JSON value. It should not contain null character within [0, length - 1] range.
- \param length Length of the json.
- \param type Type of the root of json.
- */
- bool RawValue(const Ch* json, size_t length, Type type) { Prefix(type); return EndValue(WriteRawValue(json, length)); }
-
-protected:
- //! Information for each nested level
- struct Level {
- Level(bool inArray_) : valueCount(0), inArray(inArray_) {}
- size_t valueCount; //!< number of values in this level
- bool inArray; //!< true if in array, otherwise in object
- };
-
- static const size_t kDefaultLevelDepth = 32;
-
- bool WriteNull() {
- PutReserve(*os_, 4);
- PutUnsafe(*os_, 'n'); PutUnsafe(*os_, 'u'); PutUnsafe(*os_, 'l'); PutUnsafe(*os_, 'l'); return true;
- }
-
- bool WriteBool(bool b) {
- if (b) {
- PutReserve(*os_, 4);
- PutUnsafe(*os_, 't'); PutUnsafe(*os_, 'r'); PutUnsafe(*os_, 'u'); PutUnsafe(*os_, 'e');
- }
- else {
- PutReserve(*os_, 5);
- PutUnsafe(*os_, 'f'); PutUnsafe(*os_, 'a'); PutUnsafe(*os_, 'l'); PutUnsafe(*os_, 's'); PutUnsafe(*os_, 'e');
- }
- return true;
- }
-
- bool WriteInt(int i) {
- char buffer[11];
- const char* end = internal::i32toa(i, buffer);
- PutReserve(*os_, static_cast<size_t>(end - buffer));
- for (const char* p = buffer; p != end; ++p)
- PutUnsafe(*os_, static_cast<typename TargetEncoding::Ch>(*p));
- return true;
- }
-
- bool WriteUint(unsigned u) {
- char buffer[10];
- const char* end = internal::u32toa(u, buffer);
- PutReserve(*os_, static_cast<size_t>(end - buffer));
- for (const char* p = buffer; p != end; ++p)
- PutUnsafe(*os_, static_cast<typename TargetEncoding::Ch>(*p));
- return true;
- }
-
- bool WriteInt64(int64_t i64) {
- char buffer[21];
- const char* end = internal::i64toa(i64, buffer);
- PutReserve(*os_, static_cast<size_t>(end - buffer));
- for (const char* p = buffer; p != end; ++p)
- PutUnsafe(*os_, static_cast<typename TargetEncoding::Ch>(*p));
- return true;
- }
-
- bool WriteUint64(uint64_t u64) {
- char buffer[20];
- char* end = internal::u64toa(u64, buffer);
- PutReserve(*os_, static_cast<size_t>(end - buffer));
- for (char* p = buffer; p != end; ++p)
- PutUnsafe(*os_, static_cast<typename TargetEncoding::Ch>(*p));
- return true;
- }
-
- bool WriteDouble(double d) {
- if (internal::Double(d).IsNanOrInf()) {
- if (!(writeFlags & kWriteNanAndInfFlag))
- return false;
- if (internal::Double(d).IsNan()) {
- PutReserve(*os_, 3);
- PutUnsafe(*os_, 'N'); PutUnsafe(*os_, 'a'); PutUnsafe(*os_, 'N');
- return true;
- }
- if (internal::Double(d).Sign()) {
- PutReserve(*os_, 9);
- PutUnsafe(*os_, '-');
- }
- else
- PutReserve(*os_, 8);
- PutUnsafe(*os_, 'I'); PutUnsafe(*os_, 'n'); PutUnsafe(*os_, 'f');
- PutUnsafe(*os_, 'i'); PutUnsafe(*os_, 'n'); PutUnsafe(*os_, 'i'); PutUnsafe(*os_, 't'); PutUnsafe(*os_, 'y');
- return true;
- }
-
- char buffer[25];
- char* end = internal::dtoa(d, buffer, maxDecimalPlaces_);
- PutReserve(*os_, static_cast<size_t>(end - buffer));
- for (char* p = buffer; p != end; ++p)
- PutUnsafe(*os_, static_cast<typename TargetEncoding::Ch>(*p));
- return true;
- }
-
- bool WriteString(const Ch* str, SizeType length) {
- static const typename TargetEncoding::Ch hexDigits[16] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' };
- static const char escape[256] = {
-#define Z16 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
- //0 1 2 3 4 5 6 7 8 9 A B C D E F
- 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'b', 't', 'n', 'u', 'f', 'r', 'u', 'u', // 00
- 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', // 10
- 0, 0, '"', 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 20
- Z16, Z16, // 30~4F
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,'\\', 0, 0, 0, // 50
- Z16, Z16, Z16, Z16, Z16, Z16, Z16, Z16, Z16, Z16 // 60~FF
-#undef Z16
- };
-
- if (TargetEncoding::supportUnicode)
- PutReserve(*os_, 2 + length * 6); // "\uxxxx..."
- else
- PutReserve(*os_, 2 + length * 12); // "\uxxxx\uyyyy..."
-
- PutUnsafe(*os_, '\"');
- GenericStringStream<SourceEncoding> is(str);
- while (ScanWriteUnescapedString(is, length)) {
- const Ch c = is.Peek();
- if (!TargetEncoding::supportUnicode && static_cast<unsigned>(c) >= 0x80) {
- // Unicode escaping
- unsigned codepoint;
- if (RAPIDJSON_UNLIKELY(!SourceEncoding::Decode(is, &codepoint)))
- return false;
- PutUnsafe(*os_, '\\');
- PutUnsafe(*os_, 'u');
- if (codepoint <= 0xD7FF || (codepoint >= 0xE000 && codepoint <= 0xFFFF)) {
- PutUnsafe(*os_, hexDigits[(codepoint >> 12) & 15]);
- PutUnsafe(*os_, hexDigits[(codepoint >> 8) & 15]);
- PutUnsafe(*os_, hexDigits[(codepoint >> 4) & 15]);
- PutUnsafe(*os_, hexDigits[(codepoint ) & 15]);
- }
- else {
- RAPIDJSON_ASSERT(codepoint >= 0x010000 && codepoint <= 0x10FFFF);
- // Surrogate pair
- unsigned s = codepoint - 0x010000;
- unsigned lead = (s >> 10) + 0xD800;
- unsigned trail = (s & 0x3FF) + 0xDC00;
- PutUnsafe(*os_, hexDigits[(lead >> 12) & 15]);
- PutUnsafe(*os_, hexDigits[(lead >> 8) & 15]);
- PutUnsafe(*os_, hexDigits[(lead >> 4) & 15]);
- PutUnsafe(*os_, hexDigits[(lead ) & 15]);
- PutUnsafe(*os_, '\\');
- PutUnsafe(*os_, 'u');
- PutUnsafe(*os_, hexDigits[(trail >> 12) & 15]);
- PutUnsafe(*os_, hexDigits[(trail >> 8) & 15]);
- PutUnsafe(*os_, hexDigits[(trail >> 4) & 15]);
- PutUnsafe(*os_, hexDigits[(trail ) & 15]);
- }
- }
- else if ((sizeof(Ch) == 1 || static_cast<unsigned>(c) < 256) && RAPIDJSON_UNLIKELY(escape[static_cast<unsigned char>(c)])) {
- is.Take();
- PutUnsafe(*os_, '\\');
- PutUnsafe(*os_, static_cast<typename TargetEncoding::Ch>(escape[static_cast<unsigned char>(c)]));
- if (escape[static_cast<unsigned char>(c)] == 'u') {
- PutUnsafe(*os_, '0');
- PutUnsafe(*os_, '0');
- PutUnsafe(*os_, hexDigits[static_cast<unsigned char>(c) >> 4]);
- PutUnsafe(*os_, hexDigits[static_cast<unsigned char>(c) & 0xF]);
- }
- }
- else if (RAPIDJSON_UNLIKELY(!(writeFlags & kWriteValidateEncodingFlag ?
- Transcoder<SourceEncoding, TargetEncoding>::Validate(is, *os_) :
- Transcoder<SourceEncoding, TargetEncoding>::TranscodeUnsafe(is, *os_))))
- return false;
- }
- PutUnsafe(*os_, '\"');
- return true;
- }
-
- bool ScanWriteUnescapedString(GenericStringStream<SourceEncoding>& is, size_t length) {
- return RAPIDJSON_LIKELY(is.Tell() < length);
- }
-
- bool WriteStartObject() { os_->Put('{'); return true; }
- bool WriteEndObject() { os_->Put('}'); return true; }
- bool WriteStartArray() { os_->Put('['); return true; }
- bool WriteEndArray() { os_->Put(']'); return true; }
-
- bool WriteRawValue(const Ch* json, size_t length) {
- PutReserve(*os_, length);
- for (size_t i = 0; i < length; i++) {
- RAPIDJSON_ASSERT(json[i] != '\0');
- PutUnsafe(*os_, json[i]);
- }
- return true;
- }
-
- void Prefix(Type type) {
- (void)type;
- if (RAPIDJSON_LIKELY(level_stack_.GetSize() != 0)) { // this value is not at root
- Level* level = level_stack_.template Top<Level>();
- if (level->valueCount > 0) {
- if (level->inArray)
- os_->Put(','); // add comma if it is not the first element in array
- else // in object
- os_->Put((level->valueCount % 2 == 0) ? ',' : ':');
- }
- if (!level->inArray && level->valueCount % 2 == 0)
- RAPIDJSON_ASSERT(type == kStringType); // if it's in object, then even number should be a name
- level->valueCount++;
- }
- else {
- RAPIDJSON_ASSERT(!hasRoot_); // Should only has one and only one root.
- hasRoot_ = true;
- }
- }
-
- // Flush the value if it is the top level one.
- bool EndValue(bool ret) {
- if (RAPIDJSON_UNLIKELY(level_stack_.Empty())) // end of json text
- os_->Flush();
- return ret;
- }
-
- OutputStream* os_;
- internal::Stack<StackAllocator> level_stack_;
- int maxDecimalPlaces_;
- bool hasRoot_;
-
-private:
- // Prohibit copy constructor & assignment operator.
- Writer(const Writer&);
- Writer& operator=(const Writer&);
-};
-
-// Full specialization for StringStream to prevent memory copying
-
-template<>
-inline bool Writer<StringBuffer>::WriteInt(int i) {
- char *buffer = os_->Push(11);
- const char* end = internal::i32toa(i, buffer);
- os_->Pop(static_cast<size_t>(11 - (end - buffer)));
- return true;
-}
-
-template<>
-inline bool Writer<StringBuffer>::WriteUint(unsigned u) {
- char *buffer = os_->Push(10);
- const char* end = internal::u32toa(u, buffer);
- os_->Pop(static_cast<size_t>(10 - (end - buffer)));
- return true;
-}
-
-template<>
-inline bool Writer<StringBuffer>::WriteInt64(int64_t i64) {
- char *buffer = os_->Push(21);
- const char* end = internal::i64toa(i64, buffer);
- os_->Pop(static_cast<size_t>(21 - (end - buffer)));
- return true;
-}
-
-template<>
-inline bool Writer<StringBuffer>::WriteUint64(uint64_t u) {
- char *buffer = os_->Push(20);
- const char* end = internal::u64toa(u, buffer);
- os_->Pop(static_cast<size_t>(20 - (end - buffer)));
- return true;
-}
-
-template<>
-inline bool Writer<StringBuffer>::WriteDouble(double d) {
- if (internal::Double(d).IsNanOrInf()) {
- // Note: This code path can only be reached if (RAPIDJSON_WRITE_DEFAULT_FLAGS & kWriteNanAndInfFlag).
- if (!(kWriteDefaultFlags & kWriteNanAndInfFlag))
- return false;
- if (internal::Double(d).IsNan()) {
- PutReserve(*os_, 3);
- PutUnsafe(*os_, 'N'); PutUnsafe(*os_, 'a'); PutUnsafe(*os_, 'N');
- return true;
- }
- if (internal::Double(d).Sign()) {
- PutReserve(*os_, 9);
- PutUnsafe(*os_, '-');
- }
- else
- PutReserve(*os_, 8);
- PutUnsafe(*os_, 'I'); PutUnsafe(*os_, 'n'); PutUnsafe(*os_, 'f');
- PutUnsafe(*os_, 'i'); PutUnsafe(*os_, 'n'); PutUnsafe(*os_, 'i'); PutUnsafe(*os_, 't'); PutUnsafe(*os_, 'y');
- return true;
- }
-
- char *buffer = os_->Push(25);
- char* end = internal::dtoa(d, buffer, maxDecimalPlaces_);
- os_->Pop(static_cast<size_t>(25 - (end - buffer)));
- return true;
-}
-
-#if defined(RAPIDJSON_SSE2) || defined(RAPIDJSON_SSE42)
-template<>
-inline bool Writer<StringBuffer>::ScanWriteUnescapedString(StringStream& is, size_t length) {
- if (length < 16)
- return RAPIDJSON_LIKELY(is.Tell() < length);
-
- if (!RAPIDJSON_LIKELY(is.Tell() < length))
- return false;
-
- const char* p = is.src_;
- const char* end = is.head_ + length;
- const char* nextAligned = reinterpret_cast<const char*>((reinterpret_cast<size_t>(p) + 15) & static_cast<size_t>(~15));
- const char* endAligned = reinterpret_cast<const char*>(reinterpret_cast<size_t>(end) & static_cast<size_t>(~15));
- if (nextAligned > end)
- return true;
-
- while (p != nextAligned)
- if (*p < 0x20 || *p == '\"' || *p == '\\') {
- is.src_ = p;
- return RAPIDJSON_LIKELY(is.Tell() < length);
- }
- else
- os_->PutUnsafe(*p++);
-
- // The rest of string using SIMD
- static const char dquote[16] = { '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"', '\"' };
- static const char bslash[16] = { '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\', '\\' };
- static const char space[16] = { 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19, 0x19 };
- const __m128i dq = _mm_loadu_si128(reinterpret_cast<const __m128i *>(&dquote[0]));
- const __m128i bs = _mm_loadu_si128(reinterpret_cast<const __m128i *>(&bslash[0]));
- const __m128i sp = _mm_loadu_si128(reinterpret_cast<const __m128i *>(&space[0]));
-
- for (; p != endAligned; p += 16) {
- const __m128i s = _mm_load_si128(reinterpret_cast<const __m128i *>(p));
- const __m128i t1 = _mm_cmpeq_epi8(s, dq);
- const __m128i t2 = _mm_cmpeq_epi8(s, bs);
- const __m128i t3 = _mm_cmpeq_epi8(_mm_max_epu8(s, sp), sp); // s < 0x20 <=> max(s, 0x19) == 0x19
- const __m128i x = _mm_or_si128(_mm_or_si128(t1, t2), t3);
- unsigned short r = static_cast<unsigned short>(_mm_movemask_epi8(x));
- if (RAPIDJSON_UNLIKELY(r != 0)) { // some of characters is escaped
- SizeType len;
-#ifdef _MSC_VER // Find the index of first escaped
- unsigned long offset;
- _BitScanForward(&offset, r);
- len = offset;
-#else
- len = static_cast<SizeType>(__builtin_ffs(r) - 1);
-#endif
- char* q = reinterpret_cast<char*>(os_->PushUnsafe(len));
- for (size_t i = 0; i < len; i++)
- q[i] = p[i];
-
- p += len;
- break;
- }
- _mm_storeu_si128(reinterpret_cast<__m128i *>(os_->PushUnsafe(16)), s);
- }
-
- is.src_ = p;
- return RAPIDJSON_LIKELY(is.Tell() < length);
-}
-#endif // defined(RAPIDJSON_SSE2) || defined(RAPIDJSON_SSE42)
-
-RAPIDJSON_NAMESPACE_END
-
-#ifdef _MSC_VER
-RAPIDJSON_DIAG_POP
-#endif
-
-#ifdef __clang__
-RAPIDJSON_DIAG_POP
-#endif
-
-#endif // RAPIDJSON_RAPIDJSON_H_
diff --git a/include/ui/KeyMgmt.h b/include/ui/KeyMgmt.h
deleted file mode 100755
index d96d6aba..00000000
--- a/include/ui/KeyMgmt.h
+++ /dev/null
@@ -1,108 +0,0 @@
-/**
- * This file is part of GPGFrontend.
- *
- * GPGFrontend is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * Foobar is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with Foobar. If not, see <https://www.gnu.org/licenses/>.
- *
- * The initial version of the source code is inherited from gpg4usb-team.
- * Their source code version also complies with GNU General Public License.
- *
- * The source code version of this software was modified and released
- * by Saturneric<[email protected]> starting on May 12, 2021.
- *
- */
-
-#ifndef __KEYMGMT_H__
-#define __KEYMGMT_H__
-
-#include "ui/widgets/KeyList.h"
-#include "ui/keypair_details/KeyDetailsDialog.h"
-#include "KeyImportDetailDialog.h"
-#include "KeyServerImportDialog.h"
-#include "ui/keygen/KeygenDialog.h"
-
-
-class KeyMgmt : public QMainWindow {
-Q_OBJECT
-
-public:
- explicit KeyMgmt(GpgFrontend::GpgContext *ctx, QWidget *parent = nullptr);
-
- QAction *importKeyFromClipboardAct{};
- QAction *importKeyFromFileAct{};
- QAction *importKeyFromKeyServerAct{};
-
- QAction *generateKeyPairAct{};
- QAction *generateSubKeyAct{};
-
-public slots:
-
- void slotGenerateSubKey();
-
- void slotImportKeyFromFile();
-
- void slotImportKeyFromClipboard();
-
- void slotImportKeyFromKeyServer();
-
- void slotImportKeys(QByteArray inBuffer);
-
- void slotExportKeyToFile();
-
- void slotExportKeyToClipboard();
-
- void slotDeleteSelectedKeys();
-
- void slotDeleteCheckedKeys();
-
- void slotGenerateKeyDialog();
-
- void slotShowKeyDetails();
-
-signals:
-
- void signalStatusBarChanged(QString);
-
-private:
- void createMenus();
-
- void createActions();
-
- void createToolBars();
-
- void deleteKeysWithWarning(QStringList *uidList);
-
- QString appPath;
- QSettings settings;
-
- KeyList *mKeyList;
- GpgFrontend::GpgContext *mCtx;
- QMenu *fileMenu{};
- QMenu *keyMenu{};
- QMenu *generateKeyMenu{};
- QMenu *importKeyMenu{};
- QAction *openKeyFileAct{};
- QAction *exportKeyToFileAct{};
- QAction *exportKeyToClipboardAct{};
- QAction *deleteCheckedKeysAct{};
- QAction *deleteSelectedKeysAct{};
- QAction *generateKeyDialogAct{};
- QAction *closeAct{};
- QAction *showKeyDetailsAct{};
- KeyServerImportDialog *importDialog{};
-
-protected:
- void closeEvent(QCloseEvent *event) override;
-};
-
-#endif // __KEYMGMT_H__
diff --git a/include/ui/KeyServerImportDialog.h b/include/ui/KeyServerImportDialog.h
deleted file mode 100644
index 46227481..00000000
--- a/include/ui/KeyServerImportDialog.h
+++ /dev/null
@@ -1,93 +0,0 @@
-/**
- * This file is part of GPGFrontend.
- *
- * GPGFrontend is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * Foobar is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with Foobar. If not, see <https://www.gnu.org/licenses/>.
- *
- * The initial version of the source code is inherited from gpg4usb-team.
- * Their source code version also complies with GNU General Public License.
- *
- * The source code version of this software was modified and released
- * by Saturneric<[email protected]> starting on May 12, 2021.
- *
- */
-
-#ifndef __KEYSERVERIMPORTDIALOG_H__
-#define __KEYSERVERIMPORTDIALOG_H__
-
-#include "gpg/GpgContext.h"
-#include "KeyImportDetailDialog.h"
-#include "ui/widgets/KeyList.h"
-
-
-class KeyServerImportDialog : public QDialog {
-Q_OBJECT
-
-public:
- KeyServerImportDialog(GpgFrontend::GpgContext *ctx, KeyList *keyList, bool automatic,
- QWidget *parent);
-
- KeyServerImportDialog(GpgFrontend::GpgContext *ctx, QWidget *parent);
-
- void slotImport(const QStringList& keyIds);
-
- void slotImport(const QStringList& keyIds, const QUrl& keyserverUrl);
-
- void slotImportKey(const QVector<GpgKey>& keys);
-
-private slots:
-
- void slotImport();
-
- void slotSearchFinished();
-
- void slotImportFinished();
-
- void slotSearch();
-
-private:
- void createKeysTable();
-
- void setMessage(const QString &text, bool error);
-
- void importKeys(QByteArray inBuffer);
-
- void setLoading(bool status);
-
- QPushButton *createButton(const QString &text, const char *member);
-
- QComboBox *createComboBox();
-
- bool mAutomatic;
-
- QString appPath;
- QSettings settings;
-
- GpgFrontend::GpgContext *mCtx;
- KeyList *mKeyList{};
- QLineEdit *searchLineEdit{};
- QComboBox *keyServerComboBox{};
- QProgressBar *waitingBar;
- QLabel *searchLabel{};
- QLabel *keyServerLabel{};
- QLabel *message{};
- QLabel *icon{};
- QPushButton *closeButton{};
- QPushButton *importButton{};
- QPushButton *searchButton{};
- QTableWidget *keysTable{};
- QNetworkAccessManager *qnam{};
-
-};
-
-#endif // __KEYSERVERIMPORTDIALOG_H__
diff --git a/include/ui/SendMailDialog.h b/include/ui/SendMailDialog.h
deleted file mode 100644
index e01802d3..00000000
--- a/include/ui/SendMailDialog.h
+++ /dev/null
@@ -1,66 +0,0 @@
-/**
- * This file is part of GPGFrontend.
- *
- * GPGFrontend is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * Foobar is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with Foobar. If not, see <https://www.gnu.org/licenses/>.
- *
- * The initial version of the source code is inherited from gpg4usb-team.
- * Their source code version also complies with GNU General Public License.
- *
- * The source code version of this software was modified and released
- * by Saturneric<[email protected]> starting on May 12, 2021.
- *
- */
-
-#ifndef GPGFRONTEND_SENDMAILDIALOG_H
-#define GPGFRONTEND_SENDMAILDIALOG_H
-
-#include "GpgFrontend.h"
-
-class SendMailDialog : public QDialog {
-Q_OBJECT
-public:
- explicit SendMailDialog(QString text, QWidget *parent = nullptr);
-
-private slots:
-
- void slotConfirm();
-
-private:
-
- QString appPath;
- QSettings settings;
-
- QLineEdit *senderEdit;
- QTextEdit *recipientEdit;
- QLineEdit *subjectEdit;
- QPushButton *confirmButton;
-
- QLabel *errorLabel;
- QString mText;
-
- QString smtpAddress = settings.value("sendMail/smtpAddress", QString()).toString();
- QString username = settings.value("sendMail/username", QString()).toString();
- QString password = settings.value("sendMail/password", QString()).toString();
- QString defaultSender = settings.value("sendMail/defaultSender", QString()).toString();
- QString connectionTypeSettings = settings.value("sendMail/connectionType", QString()).toString();
- int port = settings.value("sendMail/port", QString()).toInt();
-
- QRegularExpression re_email{
- R"((?:[a-z0-9!#$%&'*+/=?^_`{|}~-]+(?:\.[a-z0-9!#$%&'*+/=?^_`{|}~-]+)*|"(?:[\x01-\x08\x0b\x0c\x0e-\x1f\x21\x23-\x5b\x5d-\x7f]|\\[\x01-\x09\x0b\x0c\x0e-\x7f])*")@(?:(?:[a-z0-9](?:[a-z0-9-]*[a-z0-9])?\.)+[a-z0-9](?:[a-z0-9-]*[a-z0-9])?|\[(?:(?:(2(5[0-5]|[0-4][0-9])|1[0-9][0-9]|[1-9]?[0-9]))\.){3}(?:(2(5[0-5]|[0-4][0-9])|1[0-9][0-9]|[1-9]?[0-9])|[a-z0-9-]*[a-z0-9]:(?:[\x01-\x08\x0b\x0c\x0e-\x1f\x21-\x5a\x53-\x7f]|\\[\x01-\x09\x0b\x0c\x0e-\x7f])+)\]))"};
-
- bool check_email_address(const QString &str);
-};
-
-
-#endif //GPGFRONTEND_SENDMAILDIALOG_H
diff --git a/include/ui/SettingsDialog.h b/include/ui/SettingsDialog.h
deleted file mode 100755
index 6e102053..00000000
--- a/include/ui/SettingsDialog.h
+++ /dev/null
@@ -1,263 +0,0 @@
-/**
- * This file is part of GPGFrontend.
- *
- * GPGFrontend is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * Foobar is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with Foobar. If not, see <https://www.gnu.org/licenses/>.
- *
- * The initial version of the source code is inherited from gpg4usb-team.
- * Their source code version also complies with GNU General Public License.
- *
- * The source code version of this software was modified and released
- * by Saturneric<[email protected]> starting on May 12, 2021.
- *
- */
-
-#ifndef __SETTINGSDIALOG_H__
-#define __SETTINGSDIALOG_H__
-
-#include "ui/widgets/KeyList.h"
-
-class GeneralTab : public QWidget {
-Q_OBJECT
-
-public:
- explicit GeneralTab(GpgFrontend::GpgContext *ctx, QWidget *parent = nullptr);
-
- void setSettings();
-
- void applySettings();
-
-private:
-
- QString appPath;
- QSettings settings;
-
- QComboBox *serverSelectBox;
- QCheckBox *saveCheckedKeysCheckBox;
- QCheckBox *importConfirmationCheckBox;
- QComboBox *langSelectBox;
- QComboBox *ownKeySelectBox;
- QPushButton *getServiceTokenButton;
- QLabel *serviceTokenLabel;
- QHash<QString, QString> lang;
- QHash<QString, QString> keyIds;
- QVector<QString> keyIdsList;
- QString serviceToken;
- KeyList *mKeyList;
- GpgFrontend::GpgContext *mCtx;
-
-private slots:
-
- void slotOwnKeyIdChanged();
-
- void slotLanguageChanged();
-
- void slotGetServiceToken();
-
-signals:
-
- void signalRestartNeeded(bool needed);
-
-};
-
-class SendMailTab : public QWidget {
-Q_OBJECT
-
-public:
- explicit SendMailTab(QWidget *parent = nullptr);
-
- void setSettings();
-
- void applySettings();
-
-private slots:
-
- void slotCheckConnection();
-
- void slotCheckBoxSetEnableDisable(int state);
-
-private:
-
- QString appPath;
- QSettings settings;
-
- QCheckBox *enableCheckBox;
-
- QLineEdit *smtpAddress;
- QLineEdit *username;
- QLineEdit *password;
- QSpinBox *portSpin;
- QComboBox *connectionTypeComboBox;
- QLineEdit *defaultSender;
-
- QPushButton *checkConnectionButton;
-
-signals:
-
- void signalRestartNeeded(bool needed);
-
-};
-
-class AppearanceTab : public QWidget {
-Q_OBJECT
-
-public:
- //void setSettings();
- explicit AppearanceTab(QWidget *parent = nullptr);
-
- void setSettings();
-
- void applySettings();
-
-private:
-
- QString appPath;
- QSettings settings;
-
- QButtonGroup *iconStyleGroup;
- QRadioButton *iconSizeSmall;
- QRadioButton *iconSizeMedium;
- QRadioButton *iconSizeLarge;
- QButtonGroup *iconSizeGroup;
- QRadioButton *iconTextButton;
- QRadioButton *iconIconsButton;
- QRadioButton *iconAllButton;
- QSpinBox *infoBoardFontSizeSpin;
- QCheckBox *windowSizeCheckBox;
-
-signals:
-
- void signalRestartNeeded(bool needed);
-
-};
-
-class KeyserverTab : public QWidget {
-Q_OBJECT
-
-public:
- explicit KeyserverTab(QWidget *parent = nullptr);
-
- void setSettings();
-
- void applySettings();
-
-private:
-
- QString appPath;
- QSettings settings;
- QComboBox *comboBox;
- QLineEdit *newKeyServerEdit;
- QTableWidget *keyServerTable;
- QStringList keyServerStrList;
-
-private slots:
-
- void addKeyServer();
-
- void refreshTable();
-
-signals:
-
- void signalRestartNeeded(bool needed);
-
-};
-
-class AdvancedTab : public QWidget {
-Q_OBJECT
-
-public:
- explicit AdvancedTab(QWidget *parent = nullptr);
-
- void setSettings();
-
- void applySettings();
-
-private:
-
- QString appPath;
- QSettings settings;
-
- QCheckBox *steganoCheckBox;
- QCheckBox *autoPubkeyExchangeCheckBox;
-
-signals:
-
- void signalRestartNeeded(bool needed);
-
-};
-
-class GpgPathsTab : public QWidget {
-Q_OBJECT
-public:
- explicit GpgPathsTab(QWidget *parent = nullptr);
-
- void applySettings();
-
-private:
- static QString getRelativePath(const QString &dir1, const QString &dir2);
-
- QString appPath;
- QSettings settings;
-
- QString defKeydbPath; /** The default keydb path used by gpg4usb */
- QString accKeydbPath; /** The currently used keydb path */
- QLabel *keydbLabel;
-
- void setSettings();
-
-private slots:
-
- QString chooseKeydbDir();
-
- void setKeydbPathToDefault();
-
-};
-
-class SettingsDialog : public QDialog {
-Q_OBJECT
-
-public:
- explicit SettingsDialog(GpgFrontend::GpgContext *ctx, QWidget *parent = nullptr);
-
- GeneralTab *generalTab;
- SendMailTab *sendMailTab;
- AppearanceTab *appearanceTab;
- KeyserverTab *keyserverTab;
- AdvancedTab *advancedTab;
- GpgPathsTab *gpgPathsTab;
-
- static QHash<QString, QString> listLanguages();
-
-public slots:
-
- void slotAccept();
-
-signals:
-
- void signalRestartNeeded(bool needed);
-
-private:
- QTabWidget *tabWidget;
- QDialogButtonBox *buttonBox;
- GpgFrontend::GpgContext *mCtx; /** The current gpg context */
- bool restartNeeded{};
-
- bool getRestartNeeded() const;
-
-private slots:
-
- void slotSetRestartNeeded(bool needed);
-
-};
-
-#endif // __SETTINGSDIALOG_H__
diff --git a/include/ui/Wizard.h b/include/ui/Wizard.h
deleted file mode 100644
index e38bc560..00000000
--- a/include/ui/Wizard.h
+++ /dev/null
@@ -1,124 +0,0 @@
-/**
- * This file is part of GPGFrontend.
- *
- * GPGFrontend is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * Foobar is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with Foobar. If not, see <https://www.gnu.org/licenses/>.
- *
- * The initial version of the source code is inherited from gpg4usb-team.
- * Their source code version also complies with GNU General Public License.
- *
- * The source code version of this software was modified and released
- * by Saturneric<[email protected]> starting on May 12, 2021.
- *
- */
-
-#ifndef WIZARD_H
-#define WIZARD_H
-
-#include "ui/keygen/KeygenDialog.h"
-#include "ui/KeyMgmt.h"
-#include "gpg/GpgConstants.h"
-#include "SettingsDialog.h"
-
-class Wizard : public QWizard {
-Q_OBJECT
- Q_ENUMS(WizardPages)
-
-public:
- enum WizardPages {
- Page_Intro, Page_Choose, Page_ImportFromGpg4usb, Page_ImportFromGnupg, Page_GenKey,
- Page_Conclusion
- };
-
- Wizard(GpgFrontend::GpgContext *ctx, KeyMgmt *keyMgmt, QWidget *parent = nullptr);
-
-private:
- GpgFrontend::GpgContext *mCtx;
- KeyMgmt *mKeyMgmt;
- QString appPath;
- QSettings settings;
-
-private slots:
-
- void slotWizardAccepted();
-
-signals:
-
- void signalOpenHelp(QString page);
-};
-
-class IntroPage : public QWizardPage {
-Q_OBJECT
-
-public:
- explicit IntroPage(QWidget *parent = nullptr);
-
- QHash<QString, QString> languages;
-
- [[nodiscard]] int nextId() const override;
-
-private:
- QString appPath;
- QSettings settings;
-
-private slots:
-
- void slotLangChange(const QString& lang);
-};
-
-class ChoosePage : public QWizardPage {
-Q_OBJECT
-
-public:
- explicit ChoosePage(QWidget *parent = nullptr);
-
-private slots:
-
- void slotJumpPage(const QString &page);
-
-private:
- [[nodiscard]] int nextId() const override;
-
- int nextPage;
-};
-
-class KeyGenPage : public QWizardPage {
-Q_OBJECT
-
-public:
- explicit KeyGenPage(GpgFrontend::GpgContext *ctx, QWidget *parent = nullptr);
-
- [[nodiscard]] int nextId() const override;
-
-private slots:
-
- void slotGenerateKeyDialog();
-
-private:
- GpgFrontend::GpgContext *mCtx;
-};
-
-class ConclusionPage : public QWizardPage {
-Q_OBJECT
-
-public:
- explicit ConclusionPage(QWidget *parent = nullptr);
-
- [[nodiscard]] int nextId() const override;
-
-private:
- QCheckBox *dontShowWizardCheckBox;
- QCheckBox *openHelpCheckBox;
-};
-
-#endif
diff --git a/include/ui/keygen/KeygenDialog.h b/include/ui/keygen/KeygenDialog.h
deleted file mode 100644
index 84c734f1..00000000
--- a/include/ui/keygen/KeygenDialog.h
+++ /dev/null
@@ -1,109 +0,0 @@
-/**
- * This file is part of GPGFrontend.
- *
- * GPGFrontend is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * Foobar is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with Foobar. If not, see <https://www.gnu.org/licenses/>.
- *
- * The initial version of the source code is inherited from gpg4usb-team.
- * Their source code version also complies with GNU General Public License.
- *
- * The source code version of this software was modified and released
- * by Saturneric<[email protected]><[email protected]> starting on May 12, 2021.
- *
- */
-
-#ifndef __KEYGENDIALOG_H__
-#define __KEYGENDIALOG_H__
-
-#include "gpg/GpgContext.h"
-
-class KeyGenDialog : public QDialog {
-Q_OBJECT
-
-
-public:
-
- /**
- * @details Constructor of this class
- *
- * @param ctx The current GpgME context
- * @param key The key to show details of
- * @param parent The parent of this widget
- */
- explicit KeyGenDialog(GpgFrontend::GpgContext *ctx, QWidget *parent = nullptr);
-
-private:
-
- QGroupBox *create_key_usage_group_box();
-
- QGroupBox *create_basic_info_group_box();
-
- QRegularExpression re_email{
- R"((?:[a-z0-9!#$%&'*+/=?^_`{|}~-]+(?:\.[a-z0-9!#$%&'*+/=?^_`{|}~-]+)*|"(?:[\x01-\x08\x0b\x0c\x0e-\x1f\x21\x23-\x5b\x5d-\x7f]|\\[\x01-\x09\x0b\x0c\x0e-\x7f])*")@(?:(?:[a-z0-9](?:[a-z0-9-]*[a-z0-9])?\.)+[a-z0-9](?:[a-z0-9-]*[a-z0-9])?|\[(?:(?:(2(5[0-5]|[0-4][0-9])|1[0-9][0-9]|[1-9]?[0-9]))\.){3}(?:(2(5[0-5]|[0-4][0-9])|1[0-9][0-9]|[1-9]?[0-9])|[a-z0-9-]*[a-z0-9]:(?:[\x01-\x08\x0b\x0c\x0e-\x1f\x21-\x5a\x53-\x7f]|\\[\x01-\x09\x0b\x0c\x0e-\x7f])+)\]))"};
-
- GpgFrontend::GpgContext *mCtx; /** The current gpg context */
- QStringList errorMessages; /** List of errors occuring when checking entries of lineedits */
- GenKeyInfo genKeyInfo{};
-
- QDialogButtonBox *buttonBox; /** Box for standardbuttons */
- QLabel *errorLabel{}; /** Label containing error message */
- QLineEdit *nameEdit{}; /** Lineedit for the keys name */
- QLineEdit *emailEdit{}; /** Lineedit for the keys email */
- QLineEdit *commentEdit{}; /** Lineedit for the keys comment */
- QSpinBox *keySizeSpinBox{}; /** Spinbox for the keys size (in bit) */
- QComboBox *keyTypeComboBox{}; /** Combobox for Keytpe */
- QDateTimeEdit *dateEdit{}; /** Dateedit for expiration date */
- QCheckBox *expireCheckBox{}; /** Checkbox, if key should expire */
- QCheckBox *noPassPhraseCheckBox{};
-
- QGroupBox *keyUsageGroupBox{}; /** Group of Widgets detecting the usage of the Key **/
-
-// ENCR, SIGN, CERT, AUTH
- std::vector<QCheckBox *> keyUsageCheckBoxes;
-
- void generateKeyDialog();
-
- /**
- * @details Refresh widgets state by GenKeyInfo
- */
- void refresh_widgets_state();
-
- void set_signal_slot();
-
- bool check_email_address(const QString &str);
-
-private slots:
-
- /**
- * @details when expirebox was checked/unchecked, enable/disable the expiration date box
- */
- void slotExpireBoxChanged();
-
- /**
- * @details check all lineedits for false entries. Show error, when there is one, otherwise generate the key
- */
- void slotKeyGenAccept();
-
- void slotEncryptionBoxChanged(int state);
-
- void slotSigningBoxChanged(int state);
-
- void slotCertificationBoxChanged(int state);
-
- void slotAuthenticationBoxChanged(int state);
-
- void slotActivatedKeyType(int index);
-
-};
-
-#endif // __KEYGENDIALOG_H__
diff --git a/include/ui/keygen/SubkeyGenerateDialog.h b/include/ui/keygen/SubkeyGenerateDialog.h
deleted file mode 100644
index bbc99a9f..00000000
--- a/include/ui/keygen/SubkeyGenerateDialog.h
+++ /dev/null
@@ -1,91 +0,0 @@
-/**
- * This file is part of GPGFrontend.
- *
- * GPGFrontend is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * Foobar is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with Foobar. If not, see <https://www.gnu.org/licenses/>.
- *
- * The initial version of the source code is inherited from gpg4usb-team.
- * Their source code version also complies with GNU General Public License.
- *
- * The source code version of this software was modified and released
- * by Saturneric<[email protected]><[email protected]> starting on May 12, 2021.
- *
- */
-
-#ifndef GPGFRONTEND_SUBKEYGENERATEDIALOG_H
-#define GPGFRONTEND_SUBKEYGENERATEDIALOG_H
-
-#include "gpg/GpgContext.h"
-
-class SubkeyGenerateDialog : public QDialog {
-Q_OBJECT
-
-public:
-
- explicit SubkeyGenerateDialog(GpgFrontend::GpgContext *ctx, const GpgKey &key, QWidget *parent = nullptr);
-
-private:
-
- GpgFrontend::GpgContext *mCtx; /** The current gpg context */
- const GpgKey &mKey;
-
- GenKeyInfo genKeyInfo{};
-
- QGroupBox *keyUsageGroupBox{};
- QDialogButtonBox *buttonBox; /** Box for standardbuttons */
- QLabel *errorLabel{}; /** Label containing error message */
- QSpinBox *keySizeSpinBox{}; /** Spinbox for the keys size (in bit) */
- QComboBox *keyTypeComboBox{}; /** Combobox for Keytpe */
- QDateTimeEdit *dateEdit{}; /** Dateedit for expiration date */
- QCheckBox *expireCheckBox{}; /** Checkbox, if key should expire */
-
- // ENCR, SIGN, CERT, AUTH
- std::vector<QCheckBox *> keyUsageCheckBoxes;
-
- QGroupBox *create_key_usage_group_box();
-
- QGroupBox *create_basic_info_group_box();
-
- void set_signal_slot();
-
- /**
- * @details Refresh widgets state by GenKeyInfo
- */
- void refresh_widgets_state();
-
-private slots:
-
- /**
- * @details when expirebox was checked/unchecked, enable/disable the expiration date box
- */
- void slotExpireBoxChanged();
-
- /**
- * @details check all lineedits for false entries. Show error, when there is one, otherwise generate the key
- */
- void slotKeyGenAccept();
-
- void slotEncryptionBoxChanged(int state);
-
- void slotSigningBoxChanged(int state);
-
- void slotCertificationBoxChanged(int state);
-
- void slotAuthenticationBoxChanged(int state);
-
- void slotActivatedKeyType(int index);
-
-};
-
-
-#endif //GPGFRONTEND_SUBKEYGENERATEDIALOG_H
diff --git a/include/ui/keypair_details/KeyPairDetailTab.h b/include/ui/keypair_details/KeyPairDetailTab.h
deleted file mode 100644
index 0ea50788..00000000
--- a/include/ui/keypair_details/KeyPairDetailTab.h
+++ /dev/null
@@ -1,101 +0,0 @@
-/**
- * This file is part of GPGFrontend.
- *
- * GPGFrontend is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * Foobar is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with Foobar. If not, see <https://www.gnu.org/licenses/>.
- *
- * The initial version of the source code is inherited from gpg4usb-team.
- * Their source code version also complies with GNU General Public License.
- *
- * The source code version of this software was modified and released
- * by Saturneric<[email protected]><[email protected]> starting on May 12, 2021.
- *
- */
-
-#ifndef GPGFRONTEND_KEYPAIRDETAILTAB_H
-#define GPGFRONTEND_KEYPAIRDETAILTAB_H
-
-#include "GpgFrontend.h"
-#include "gpg/GpgContext.h"
-
-#include "ui/KeyUploadDialog.h"
-#include "ui/KeyServerImportDialog.h"
-#include "KeySetExpireDateDialog.h"
-
-class KeyPairDetailTab : public QWidget {
-Q_OBJECT
-
- /**
- * @details Return QString with a space inserted at every fourth character
- *
- * @param fingerprint The fingerprint to be beautified
- */
- static QString beautifyFingerprint(QString fingerprint);
-
- void createKeyServerOperaMenu();
-
-private slots:
-
- /**
- * @details Export the key to a file, which is choosen in a file dialog
- */
- void slotExportPrivateKey();
-
- /**
- * @details Copy the fingerprint to clipboard
- */
- void slotCopyFingerprint();
-
- void slotModifyEditDatetime();
-
- void slotRefreshKeyInfo();
-
- void slotUploadKeyToServer();
-
- void slotUpdateKeyToServer();
-
- void slotGenRevokeCert();
-
-private:
-
- QString *keyid; /** The id of the key the details should be shown for */
-
- GpgFrontend::GpgContext *mCtx; /** The current gpg-context */
- const GpgKey &mKey;
-
- QGroupBox *ownerBox; /** Groupbox containing owner information */
- QGroupBox *keyBox; /** Groupbox containing key information */
- QGroupBox *fingerprintBox; /** Groupbox containing fingerprint information */
- QGroupBox *additionalUidBox; /** Groupbox containing information about additional uids */
-
- QLabel *nameVarLabel; /** Label containng the keys name */
- QLabel *emailVarLabel; /** Label containng the keys email */
- QLabel *commentVarLabel; /** Label containng the keys commment */
- QLabel *keySizeVarLabel; /** Label containng the keys keysize */
- QLabel *expireVarLabel; /** Label containng the keys expiration date */
- QLabel *createdVarLabel; /** Label containng the keys creation date */
- QLabel *algorithmVarLabel; /** Label containng the keys algorithm */
- QLabel *keyidVarLabel; /** Label containng the keys keyid */
- QLabel *fingerPrintVarLabel; /** Label containng the keys fingerprint */
- QLabel *usageVarLabel;
- QLabel *actualUsageVarLabel;
- QLabel *masterKeyExistVarLabel;
-
- QMenu *keyServerOperaMenu;
-
-public:
- explicit KeyPairDetailTab(GpgFrontend::GpgContext *ctx, const GpgKey &mKey, QWidget *parent = nullptr);
-};
-
-
-#endif //GPGFRONTEND_KEYPAIRDETAILTAB_H
diff --git a/include/ui/keypair_details/KeyPairSubkeyTab.h b/include/ui/keypair_details/KeyPairSubkeyTab.h
deleted file mode 100644
index ae8b0893..00000000
--- a/include/ui/keypair_details/KeyPairSubkeyTab.h
+++ /dev/null
@@ -1,90 +0,0 @@
-/**
- * This file is part of GPGFrontend.
- *
- * GPGFrontend is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * Foobar is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with Foobar. If not, see <https://www.gnu.org/licenses/>.
- *
- * The initial version of the source code is inherited from gpg4usb-team.
- * Their source code version also complies with GNU General Public License.
- *
- * The source code version of this software was modified and released
- * by Saturneric<[email protected]> starting on May 12, 2021.
- *
- */
-
-#ifndef GPGFRONTEND_KEYPAIRSUBKEYTAB_H
-#define GPGFRONTEND_KEYPAIRSUBKEYTAB_H
-
-#include "GpgFrontend.h"
-
-#include "gpg/GpgContext.h"
-#include "ui/keygen/SubkeyGenerateDialog.h"
-#include "KeySetExpireDateDialog.h"
-
-class KeyPairSubkeyTab : public QWidget {
-Q_OBJECT
-
-public:
-
- KeyPairSubkeyTab(GpgFrontend::GpgContext *ctx, const GpgKey &key, QWidget *parent);
-
-private:
-
- void createSubkeyList();
-
- void createSubkeyOperaMenu();
-
- const GpgSubKey *getSelectedSubkey();
-
- GpgFrontend::GpgContext *mCtx;
- const GpgKey &mKey;
- QTableWidget *subkeyList;
- QVector<const GpgSubKey *> buffered_subkeys;
-
- QGroupBox *listBox;
- QGroupBox *detailBox;
-
- QMenu *subkeyOperaMenu;
-
-
- QLabel *keySizeVarLabel; /** Label containng the keys keysize */
- QLabel *expireVarLabel; /** Label containng the keys expiration date */
- QLabel *createdVarLabel; /** Label containng the keys creation date */
- QLabel *algorithmVarLabel; /** Label containng the keys algorithm */
- QLabel *keyidVarLabel; /** Label containng the keys keyid */
- QLabel *fingerPrintVarLabel; /** Label containng the keys fingerprint */
- QLabel *usageVarLabel;
- QLabel *masterKeyExistVarLabel;
-
-
-private slots:
-
- void slotAddSubkey();
-
- void slotRefreshSubkeyList();
-
- void slotRefreshSubkeyDetail();
-
- void slotEditSubkey();
-
- void slotRevokeSubkey();
-
-protected:
-
- void contextMenuEvent(QContextMenuEvent *event) override;
-
-
-};
-
-
-#endif //GPGFRONTEND_KEYPAIRSUBKEYTAB_H
diff --git a/include/ui/widgets/EditorPage.h b/include/ui/widgets/EditorPage.h
deleted file mode 100644
index 720f60c3..00000000
--- a/include/ui/widgets/EditorPage.h
+++ /dev/null
@@ -1,108 +0,0 @@
-/**
- * This file is part of GPGFrontend.
- *
- * GPGFrontend is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * Foobar is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with Foobar. If not, see <https://www.gnu.org/licenses/>.
- *
- * The initial version of the source code is inherited from gpg4usb-team.
- * Their source code version also complies with GNU General Public License.
- *
- * The source code version of this software was modified and released
- * by Saturneric<[email protected]> starting on May 12, 2021.
- *
- */
-
-#ifndef __EDITORPAGE_H__
-#define __EDITORPAGE_H__
-
-#include <GpgFrontend.h>
-
-#include "gpg/GpgConstants.h"
-
-
-QT_BEGIN_NAMESPACE
-class QVBoxLayout;
-
-class QHBoxLayout;
-
-class QString;
-
-class QLabel;
-
-QT_END_NAMESPACE
-
-/**
- * @brief Class for handling a single tab of the tabwidget
- *
- */
-class EditorPage : public QWidget {
-Q_OBJECT
-public:
- /**
- * @details Add layout and add plaintextedit
- *
- * @param filePath Path of the file handled in this tab
- * @param parent Pointer to the parent widget
- */
- explicit EditorPage(QString filePath = "", QWidget *parent = nullptr);
-
- /**
- * @details Get the filepath of the currently activated tab.
- */
- const QString &getFilePath() const;
-
- /**
- * @details Set filepath of currently activated tab.
- *
- * @param filePath The path to be set
- */
- void setFilePath(const QString &filePath);
-
- /**
- * @details Return pointer tp the textedit of the currently activated tab.
- */
- QTextEdit *getTextPage();
-
- /**
- * @details Show additional widget at buttom of currently active tab
- *
- * @param widget The widget to be added
- * @param className The name to handle the added widget
- */
- void showNotificationWidget(QWidget *widget, const char *className);
-
- /**
- * @details Hide all widgets with the given className
- *
- * @param className The classname of the widgets to hide
- */
- void closeNoteByClass(const char *className);
-
-
- const QString uuid = QUuid::createUuid().toString();
-
-private:
- QTextEdit *textPage; /** The textedit of the tab */
- QVBoxLayout *mainLayout; /** The layout for the tab */
- QString fullFilePath; /** The path to the file handled in the tab */
- bool signMarked{}; /** true, if the signed header is marked, false if not */
-
-private slots:
-
- /**
- * @details Format the gpg header in another font-style
- */
- void slotFormatGpgHeader();
-};
-
-#endif // __EDITORPAGE_H__
diff --git a/include/ui/widgets/FilePage.h b/include/ui/widgets/FilePage.h
deleted file mode 100644
index 45d638fa..00000000
--- a/include/ui/widgets/FilePage.h
+++ /dev/null
@@ -1,88 +0,0 @@
-/**
- * This file is part of GPGFrontend.
- *
- * GPGFrontend is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * Foobar is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with Foobar. If not, see <https://www.gnu.org/licenses/>.
- *
- * The initial version of the source code is inherited from gpg4usb-team.
- * Their source code version also complies with GNU General Public License.
- *
- * The source code version of this software was modified and released
- * by Saturneric<[email protected]> starting on May 12, 2021.
- *
- */
-
-#ifndef GPGFRONTEND_FILEPAGE_H
-#define GPGFRONTEND_FILEPAGE_H
-
-#include "GpgFrontend.h"
-
-class FilePage : public QWidget {
-Q_OBJECT
-public:
-
- explicit FilePage(QWidget* parent = nullptr);
-
- [[nodiscard]] QString getSelected() const;
-
- void createPopupMenu();
-
-signals:
- void pathChanged(const QString &path);
-
-private slots:
-
- void fileTreeViewItemClicked(const QModelIndex &index);
- void fileTreeViewItemDoubleClicked(const QModelIndex &index);
-
- void slotUpLevel();
- void slotGoPath();
-
- void slotOpenItem();
- void slotDeleteItem();
- void slotEncryptItem();
- void slotDecryptItem();
- void slotSignItem();
- void slotVerifyItem();
-
- void onCustomContextMenu(const QPoint &point);
-
-protected:
-
- void keyPressEvent(QKeyEvent *event) override;
-
-
-private:
-
- QFileSystemModel *dirModel;
- QTreeView *dirTreeView;
- QLineEdit *pathEdit;
- QString mPath;
- QString selectedPath;
-
- QPushButton *upLevelButton;
- QPushButton *goPathButton;
- QPushButton *refreshButton;
-
- QMenu *popUpMenu{};
- QAction *encryptItemAct{};
- QAction *decryptItemAct{};
- QAction *signItemAct{};
- QAction *verifyItemAct{};
-
- QWidget *firstParent;
-
-};
-
-
-#endif //GPGFRONTEND_FILEPAGE_H
diff --git a/include/ui/widgets/InfoBoardWidget.h b/include/ui/widgets/InfoBoardWidget.h
deleted file mode 100644
index 82c38f65..00000000
--- a/include/ui/widgets/InfoBoardWidget.h
+++ /dev/null
@@ -1,119 +0,0 @@
-/**
- * This file is part of GPGFrontend.
- *
- * GPGFrontend is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * Foobar is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with Foobar. If not, see <https://www.gnu.org/licenses/>.
- *
- * The initial version of the source code is inherited from gpg4usb-team.
- * Their source code version also complies with GNU General Public License.
- *
- * The source code version of this software was modified and released
- * by Saturneric<[email protected]> starting on May 12, 2021.
- *
- */
-
-#ifndef __VERIFYNOTIFICATION_H__
-#define __VERIFYNOTIFICATION_H__
-
-#include "EditorPage.h"
-#include "FilePage.h"
-#include "ui/VerifyDetailsDialog.h"
-#include "gpg/result_analyse/VerifyResultAnalyse.h"
-
-/**
- * @details Enumeration for the status of Verifylabel
- */
-typedef enum {
- INFO_ERROR_OK = 0,
- INFO_ERROR_WARN = 1,
- INFO_ERROR_CRITICAL = 2,
- INFO_ERROR_NEUTRAL = 3,
-} InfoBoardStatus;
-
-/**
- * @brief Class for handling the verifylabel shown at buttom of a textedit-page
- */
-class InfoBoardWidget : public QWidget {
-Q_OBJECT
-public:
- /**
- * @brief
- *
- * @param ctx The GPGme-Context
- * @param parent The parent widget
- */
- explicit InfoBoardWidget(QWidget *parent, GpgFrontend::GpgContext *ctx, KeyList *keyList);
-
-
- void associateTextEdit(QTextEdit *edit);
-
- void associateFileTreeView(FilePage *treeView);
-
- void associateTabWidget(QTabWidget *tab);
-
- void addOptionalAction(const QString& name, const std::function<void()>& action);
-
- void resetOptionActionsMenu();
-
-
-
- /**
- * @details Set the text and background-color of verify notification.
- *
- * @param text The text to be set.
- * @param verifyLabelStatus The status of label to set the specified color.
- */
- void setInfoBoard(const QString& text, InfoBoardStatus verifyLabelStatus);
-
-
- QStringList *keysNotInList; /** List with keys, which are in signature but not in keylist */
-
-
-public slots:
-
- /**
- * @details Import the keys contained in keysNotInList from keyserver
- *
- */
- void slotImportFromKeyserver();
-
- void slotReset();
-
- /**
- * @details Refresh the contents of dialog.
- */
- void slotRefresh(const QString &text, InfoBoardStatus status);
-
-private:
-
- QString appPath;
- QSettings settings;
-
- QMenu *detailMenu; /** Menu for te Button in verfiyNotification */
- QAction *importFromKeyserverAct; /** Action for importing keys from keyserver which are notin keylist */
- QTextEdit *infoBoard;
- GpgFrontend::GpgContext *mCtx; /** GpgME Context */
- KeyList *mKeyList; /** Table holding the keys */
-
- QTextEdit *mTextPage{ nullptr }; /** TextEdit associated to the notification */
- FilePage *mFileTreeView{nullptr }; /** TreeView associated to the notification */
- QTabWidget *mTabWidget{ nullptr }; /** TreeView associated to the notification */
-
- QHBoxLayout *actionButtonLayout;
-
- void deleteWidgetsInLayout(QLayout* layout, int start_index = 0);
-
-
-};
-
-#endif // __VERIFYNOTIFICATION_H__ \ No newline at end of file
diff --git a/include/ui/widgets/KeyList.h b/include/ui/widgets/KeyList.h
deleted file mode 100644
index c1a26931..00000000
--- a/include/ui/widgets/KeyList.h
+++ /dev/null
@@ -1,135 +0,0 @@
-/**
- * This file is part of GPGFrontend.
- *
- * GPGFrontend is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * Foobar is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with Foobar. If not, see <https://www.gnu.org/licenses/>.
- *
- * The initial version of the source code is inherited from gpg4usb-team.
- * Their source code version also complies with GNU General Public License.
- *
- * The source code version of this software was modified and released
- * by Saturneric<[email protected]> starting on May 12, 2021.
- *
- */
-
-#ifndef __KEYLIST_H__
-#define __KEYLIST_H__
-
-#include "gpg/GpgContext.h"
-#include "ui/KeyImportDetailDialog.h"
-
-
-struct KeyListRow {
-
- using KeyType = unsigned int;
-
- static const KeyType SECRET_OR_PUBLIC_KEY = 0;
- static const KeyType ONLY_SECRET_KEY = 1;
-
-};
-
-struct KeyListColumn {
-
- using InfoType = unsigned int;
-
- static constexpr InfoType ALL = ~0;
- static constexpr InfoType TYPE = 1 << 0;
- static constexpr InfoType NAME = 1 << 1;
- static constexpr InfoType EmailAddress = 1 << 2;
- static constexpr InfoType Usage = 1 << 3;
- static constexpr InfoType Validity = 1 << 4;
- static constexpr InfoType FingerPrint = 1 << 5;
-
-};
-
-
-class KeyList : public QWidget {
-Q_OBJECT
-
-public:
-
- explicit KeyList(GpgFrontend::GpgContext *ctx,
- KeyListRow::KeyType selectType = KeyListRow::SECRET_OR_PUBLIC_KEY,
- KeyListColumn::InfoType infoType = KeyListColumn::ALL,
- QWidget *parent = nullptr);
-
- void setExcludeKeys(std::initializer_list<QString> key_ids);
-
- void setFilter(std::function<bool(const GpgKey&)> filter);
-
- void setDoubleClickedAction(std::function<void(const GpgKey&, QWidget *)> action);
-
- void setColumnWidth(int row, int size);
-
- void addMenuAction(QAction *act);
-
- void addSeparator();
-
- QStringList *getChecked();
-
- void getCheckedKeys(QVector<GpgKey> &keys);
-
- QStringList *getPrivateChecked();
-
- void getPrivateCheckedKeys(QVector<GpgKey> &keys);
-
- QStringList *getAllPrivateKeys();
-
- void setChecked(QStringList *keyIds);
-
- QStringList *getSelected();
-
- GpgKey getSelectedKey();
-
- [[maybe_unused]] static void markKeys(QStringList *keyIds);
-
- [[maybe_unused]] bool containsPrivateKeys();
-
-public slots:
-
- void slotRefresh();
-
-private:
-
- void importKeys(QByteArray inBuffer);
-
- QString appPath;
- QSettings settings;
-
- GpgFrontend::GpgContext *mCtx;
- QTableWidget *mKeyList;
- QMenu *popupMenu;
- QNetworkAccessManager *qnam{};
- QVector<GpgKey> buffered_keys;
- KeyListRow::KeyType mSelectType;
- KeyListColumn::InfoType mInfoType;
- QVector<QString> excluded_key_ids;
-
- std::function<bool(const GpgKey &)> mFilter = nullptr;
- std::function<void(const GpgKey &, QWidget *)> mAction = nullptr;
-
-
-private slots:
-
- void slotDoubleClicked(const QModelIndex &index);
-
-protected:
-
- void contextMenuEvent(QContextMenuEvent *event) override;
-
- void dragEnterEvent(QDragEnterEvent *event) override;
-
- void dropEvent(QDropEvent *event) override;
-};
-
-#endif // __KEYLIST_H__
diff --git a/include/ui/widgets/TextEdit.h b/include/ui/widgets/TextEdit.h
deleted file mode 100644
index 92bf4dfa..00000000
--- a/include/ui/widgets/TextEdit.h
+++ /dev/null
@@ -1,298 +0,0 @@
-/**
- * This file is part of GPGFrontend.
- *
- * GPGFrontend is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * Foobar is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with Foobar. If not, see <https://www.gnu.org/licenses/>.
- *
- * The initial version of the source code is inherited from gpg4usb-team.
- * Their source code version also complies with GNU General Public License.
- *
- * The source code version of this software was modified and released
- * by Saturneric<[email protected]> starting on May 12, 2021.
- *
- */
-
-#ifndef __TEXTEDIT_H__
-#define __TEXTEDIT_H__
-
-#include "ui/widgets/EditorPage.h"
-#include "ui/widgets/HelpPage.h"
-#include "ui/widgets/FilePage.h"
-#include "ui/QuitDialog.h"
-
-
-/**
- * @brief TextEdit class
- */
-class TextEdit : public QWidget {
-Q_OBJECT
-public:
- /**
- * @brief
- */
- TextEdit(QWidget *parent);
-
- /**
- * @details Load the content of file into the current textpage
- *
- * @param fileName QString containing the filename to load
- * @return nothing
- */
- void loadFile(const QString &fileName);
-
-
- /**
- * @details Checks if there are unsaved documents in any tab,
- * which may need to be saved. Call this function before
- * closing the programme or all tabs.
- * @return \li false, if the close event should be aborted.
- * \li true, otherwise
- */
- bool maybeSaveAnyTab();
-
- [[nodiscard]] int tabCount() const;
-
- /**
- * @details textpage of the currently activated tab
- * @return \li reference to QTextEdit if tab has one
- * \li 0 otherwise (e.g. if helppage)
- */
- [[nodiscard]] QTextEdit *curTextPage() const;
-
- [[nodiscard]] FilePage * curFilePage() const;
-
- /**
- * @details List of currently unsaved tabs.
- * @returns QHash<int, QString> Hash of tabindexes and title of unsaved tabs.
- */
- [[nodiscard]] QHash<int, QString> unsavedDocuments() const;
-
- QTabWidget *tabWidget; /** Widget containing the tabs of the editor */
-
-public slots:
-
- /**
- * @details Return pointer to the currently activated text edit tab page.
- *
- */
- [[nodiscard]] EditorPage *slotCurPageTextEdit() const;
-
- /**
- * @details Return pointer to the currently activated file treeview tab page.
- *
- */
- [[nodiscard]] FilePage *slotCurPageFileTreeView() const;
-
- /**
- * @details Insert a ">" at the begining of every line of current textedit.
- */
- void slotQuote() const;
-
- /**
- * @details replace the text of currently active textedit with given text.
- * @param text to fill on.
- */
- void slotFillTextEditWithText(const QString& text) const;
-
- /**
- * @details Saves the content of the current tab, if it has a filepath
- * otherwise it calls saveAs for the current tab
- */
- void slotSave();
-
- /**
- * @details Opens a savefiledialog and calls saveFile with the choosen filename.
- *
- * @return Return the return value of the savefile method
- */
- bool slotSaveAs();
-
- /**
- * @details Show an OpenFileDoalog and open the file in a new tab.
- * Shows an error dialog, if the open fails.
- * Set the focus to the tab of the opened file.
- */
- void slotOpen();
-
- /**
- * @details Open a print-dialog for the current tab
- */
- void slotPrint();
-
- /**
- * @details Adds a new tab with the title "untitled"+countpage+".txt"
- * Sets the focus to the new tab. Increase Tab-Count by one
- */
- void slotNewTab();
-
- /**
- * @details Adds a new tab with opening file by path
- */
- void slotOpenFile(QString &path);
-
- /**
- * @details Adds a new tab with the given title and opens given html file.
- * Increase Tab-Count by one
- * @param title title for the tab
- * @param path path for html file to show
- */
- void slotNewHelpTab(const QString& title, const QString& path) const;
-
- /**
- * New File Tab to do file operation
- */
- void slotNewFileTab() const;
-
- /**
- * @details put a * in front of current tabs title, if current textedit is modified
- */
- void slotShowModified() const;
-
- /**
- * @details close the current tab and decrease TabWidget->count by \a 1
- *
- */
- void slotCloseTab();
-
- /**
- * @details Switch to the next tab.
- *
- */
- void slotSwitchTabUp() const;
-
- /**
- * @details Switch to the previous tab.
- *
- */
- void slotSwitchTabDown() const;
-
- /**
- * @details Insert text in target Text Edit
- */
- void slotInsertTargetTextPage(const QString &pagePtr, const QString &text);
-
- void slotReadTargetTextPageStart(const QString &pageStr);
-
- void slotReadTargetTextPageDone(const QString &pagePtr);
-
-signals:
-
- void readTargetTextPageStart(const QString &pagePtr);
-
- void insertTargetTextPage(const QString &pagePtr, const QString &text);
-
- void readTargetTextPageDone(const QString &pagePtr);
-
-private:
- /**
- * @details return just a filename stripped of a whole path
- *
- * @param a filename path
- * @return QString containing the filename
- */
- static QString strippedName(const QString &fullFileName);
-
- /**
- * @brief
- *
- * @param askToSave
- */
- bool maybeSaveCurrentTab(bool askToSave);
-
- /****************************************************************************************
- * Name: countPage
- * Description: int cotaining the number of added tabs
- */
- int countPage; /* TODO */
-
- QHash<const QString, QWidget *> pagesHashMap;
-
-private slots:
-
- void slotFilePagePathChanged(const QString& path);
-
- /**
- * @details Remove the tab with given index
- *
- * @param index Tab-number to remove
- */
- void removeTab(int index);
-
- /**
- * @details Cut selected text in current textpage.
- */
- void slotCut() const;
-
- /**
- * @details Copy selected text of current textpage to clipboard.
- */
- void slotCopy() const;
-
- /**
- * @details Paste text from clipboard to current textpage.
- */
- void slotPaste() const;
-
- /**
- * @details Undo last change in current textpage.
- *
- */
- void slotUndo() const;
- /****************************************************************************************
- * Name: redo
- * Description: redo last change in current textpage
- * Parameters: none
- * Return Values: none
- * Change on members: none
- */
- /**
- * @brief
- *
- */
- void slotRedo() const;
-
- void slotZoomIn() const;
-
- void slotZoomOut() const;
- /****************************************************************************************
- * Name: selectAll
- * Description: select all in current textpage
- * Parameters: none
- * Return Values: none
- * Change on members: none
- */
- /**
- * @brief
- *
- */
- void slotSelectAll() const;
-
-protected:
-
- /****************************************************************************************
- * Name: saveFile
- * Description: Saves the content of currentTab to the file filename
- * Parameters: QString filename contains the full path of the file to save
- * Return Values: true, if the file was saved succesfully
- * false, if parameter filename is empty or the saving failed
- * Change on members: sets isModified of the current tab to false
- */
- /**
- * @brief
- *
- * @param fileName
- */
- bool saveFile(const QString &fileName);
-};
-
-#endif // __TEXTEDIT_H__
diff --git a/src/MainWindow.cpp b/src/MainWindow.cpp
deleted file mode 100644
index d2c306ef..00000000
--- a/src/MainWindow.cpp
+++ /dev/null
@@ -1,245 +0,0 @@
-/**
- * This file is part of GPGFrontend.
- *
- * GPGFrontend is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * Foobar is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with Foobar. If not, see <https://www.gnu.org/licenses/>.
- *
- * The initial version of the source code is inherited from gpg4usb-team.
- * Their source code version also complies with GNU General Public License.
- *
- * The source code version of this software was modified and released
- * by Saturneric<[email protected]> starting on May 12, 2021.
- *
- */
-
-#include "MainWindow.h"
-#include "ui/help/VersionCheckThread.h"
-
-MainWindow::MainWindow()
- : appPath(qApp->applicationDirPath()),
- settings(RESOURCE_DIR(appPath) + "/conf/gpgfrontend.ini",
- QSettings::IniFormat) {
-
- networkAccessManager = new QNetworkAccessManager(this);
-
- auto waitingDialog = new WaitingDialog(tr("Loading Gnupg"), this);
-
- // Init Gnupg
- auto ctx_thread = QThread::create([&]() { mCtx = new GpgFrontend::GpgContext(); });
- ctx_thread->start();
- while (ctx_thread->isRunning())
- QApplication::processEvents();
- waitingDialog->close();
- ctx_thread->deleteLater();
-
- QString baseUrl = "https://api.github.com/repos/saturneric/gpgfrontend/releases/latest";
-
- QNetworkRequest request;
- request.setUrl(QUrl(baseUrl));
-
- QNetworkReply *replay = networkAccessManager->get(request);
-
- auto version_thread = new VersionCheckThread(replay);
-
- connect(version_thread, SIGNAL(finished()), version_thread, SLOT(deleteLater()));
- connect(version_thread, SIGNAL(upgradeVersion(const QString &, const QString &)), this, SLOT(slotVersionUpgrade(const QString &, const QString &)));
-
- version_thread->start();
-
- // Check Context Status
- if (!mCtx->isGood()) {
- QMessageBox::critical(
- nullptr, tr("ENV Loading Failed"),
- tr("Gnupg is not installed correctly, please follow the ReadME "
- "instructions to install gnupg and then open GPGFrontend."));
- QCoreApplication::quit();
- exit(0);
- }
-
- /* get path were app was started */
- setCorner(Qt::BottomLeftCorner, Qt::LeftDockWidgetArea);
- setCorner(Qt::BottomRightCorner, Qt::RightDockWidgetArea);
-
- edit = new TextEdit(this);
- setCentralWidget(edit);
-
- /* the list of Keys available*/
- mKeyList = new KeyList(mCtx, KeyListRow::SECRET_OR_PUBLIC_KEY,
- KeyListColumn::TYPE | KeyListColumn::NAME |
- KeyListColumn::EmailAddress |
- KeyListColumn::Usage | KeyListColumn::Validity,
- this);
- mKeyList->setFilter([](const GpgKey &key) -> bool {
- if (key.revoked || key.disabled || key.expired)
- return false;
- else
- return true;
- });
- mKeyList->slotRefresh();
-
- infoBoard = new InfoBoardWidget(this, mCtx, mKeyList);
-
- /* List of binary Attachments */
- attachmentDockCreated = false;
-
- /* Variable containing if restart is needed */
- this->slotSetRestartNeeded(false);
-
- keyMgmt = new KeyMgmt(mCtx, this);
- keyMgmt->hide();
- /* test attachmentdir for files alll 15s */
- auto *timer = new QTimer(this);
- connect(timer, SIGNAL(timeout()), this, SLOT(slotCheckAttachmentFolder()));
- timer->start(5000);
-
- createActions();
- createMenus();
- createToolBars();
- createStatusBar();
- createDockWindows();
-
- connect(edit->tabWidget, SIGNAL(currentChanged(int)), this,
- SLOT(slotDisableTabActions(int)));
-
- mKeyList->addMenuAction(appendSelectedKeysAct);
- mKeyList->addMenuAction(copyMailAddressToClipboardAct);
- mKeyList->addMenuAction(showKeyDetailsAct);
- mKeyList->addSeparator();
- mKeyList->addMenuAction(refreshKeysFromKeyserverAct);
- mKeyList->addMenuAction(uploadKeyToServerAct);
-
- restoreSettings();
-
- // open filename if provided as first command line parameter
- QStringList args = qApp->arguments();
- if (args.size() > 1) {
- if (!args[1].startsWith("-")) {
- if (QFile::exists(args[1]))
- edit->loadFile(args[1]);
- }
- }
- edit->curTextPage()->setFocus();
- this->setMinimumSize(1200, 700);
- this->setWindowTitle(qApp->applicationName());
- this->show();
-
- // Show wizard, if the don't show wizard message box wasn't checked
- // and keylist doesn't contain a private key
- qDebug() << "wizard/showWizard"
- << settings.value("wizard/showWizard", true).toBool();
- qDebug() << "wizard/nextPage" << settings.value("wizard/nextPage").isNull();
- if (settings.value("wizard/showWizard", true).toBool() ||
- !settings.value("wizard/nextPage").isNull()) {
- slotStartWizard();
- }
-
-}
-
-void MainWindow::restoreSettings() {
- // state sets pos & size of dock-widgets
- this->restoreState(settings.value("window/windowState").toByteArray());
-
- // Restore window size & location
- if (settings.value("window/windowSave").toBool()) {
- QPoint pos = settings.value("window/pos", QPoint(100, 100)).toPoint();
- QSize size = settings.value("window/size", QSize(800, 450)).toSize();
- this->resize(size);
- this->move(pos);
- } else {
- this->resize(QSize(800, 450));
- this->move(QPoint(100, 100));
- }
-
- // Iconsize
- QSize iconSize = settings.value("toolbar/iconsize", QSize(24, 24)).toSize();
- this->setIconSize(iconSize);
-
- importButton->setIconSize(iconSize);
- fileEncButton->setIconSize(iconSize);
- // set list of keyserver if not defined
- QStringList *keyServerDefaultList;
- keyServerDefaultList = new QStringList("http://keys.gnupg.net");
- keyServerDefaultList->append("https://keyserver.ubuntu.com");
- keyServerDefaultList->append("http://pool.sks-keyservers.net");
-
- QStringList keyServerList =
- settings.value("keyserver/keyServerList", *keyServerDefaultList)
- .toStringList();
- settings.setValue("keyserver/keyServerList", keyServerList);
-
- // set default keyserver, if it's not set
- QString defaultKeyServer = settings
- .value("keyserver/defaultKeyServer",
- QString("https://keyserver.ubuntu.com"))
- .toString();
- settings.setValue("keyserver/defaultKeyServer", defaultKeyServer);
-
- // Iconstyle
- Qt::ToolButtonStyle buttonStyle = static_cast<Qt::ToolButtonStyle>(
- settings.value("toolbar/iconstyle", Qt::ToolButtonTextUnderIcon)
- .toUInt());
- this->setToolButtonStyle(buttonStyle);
- importButton->setToolButtonStyle(buttonStyle);
- fileEncButton->setToolButtonStyle(buttonStyle);
-
- // Checked Keys
- if (settings.value("keys/saveKeyChecked").toBool()) {
- QStringList keyIds =
- settings.value("keys/savedCheckedKeyList").toStringList();
- mKeyList->setChecked(&keyIds);
- }
-}
-
-void MainWindow::saveSettings() {
- // window position and size
- settings.setValue("window/windowState", saveState());
- settings.setValue("window/pos", pos());
- settings.setValue("window/size", size());
-
- // keyid-list of private checked keys
- if (settings.value("keys/saveKeyChecked").toBool()) {
- QStringList *keyIds = mKeyList->getChecked();
- if (!keyIds->isEmpty()) {
- settings.setValue("keys/savedCheckedKeyList", *keyIds);
- } else {
- settings.setValue("keys/savedCheckedKeyList", "");
- }
- } else {
- settings.remove("keys/savedCheckedKeyList");
- }
-}
-
-void MainWindow::closeAttachmentDock() {
- if (!attachmentDockCreated) {
- return;
- }
- attachmentDock->close();
- attachmentDock->deleteLater();
- attachmentDockCreated = false;
-}
-
-void MainWindow::closeEvent(QCloseEvent *event) {
- /*
- * ask to save changes, if there are
- * modified documents in any tab
- */
- if (edit->maybeSaveAnyTab()) {
- saveSettings();
- event->accept();
- } else {
- event->ignore();
- }
-
- // clear password from memory
- mCtx->clearPasswordCache();
-}
diff --git a/src/MainWindow.h b/src/MainWindow.h
deleted file mode 100644
index 34a3130a..00000000
--- a/src/MainWindow.h
+++ /dev/null
@@ -1,415 +0,0 @@
-/**
- * This file is part of GPGFrontend.
- *
- * GPGFrontend is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * Foobar is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with Foobar. If not, see <https://www.gnu.org/licenses/>.
- *
- * The initial version of the source code is inherited from gpg4usb-team.
- * Their source code version also complies with GNU General Public License.
- *
- * The source code version of this software was modified and released
- * by Saturneric<[email protected]> starting on May 12, 2021.
- *
- */
-
-#ifndef __GPGWIN_H__
-#define __GPGWIN_H__
-
-#include "gpg/GpgConstants.h"
-#include "ui/KeyMgmt.h"
-#include "ui/widgets/TextEdit.h"
-#include "ui/FileEncryptionDialog.h"
-#include "ui/SettingsDialog.h"
-#include "ui/help/AboutDialog.h"
-#include "ui/widgets/InfoBoardWidget.h"
-#include "ui/FindWidget.h"
-#include "ui/Wizard.h"
-#include "ui/KeyUploadDialog.h"
-#include "ui/WaitingDialog.h"
-
-#include "gpg/result_analyse/SignResultAnalyse.h"
-#include "gpg/result_analyse/EncryptResultAnalyse.h"
-#include "gpg/result_analyse/DecryptResultAnalyse.h"
-
-#include "gpg/GpgFileOpera.h"
-
-
-/**
- * @brief
- *
- */
-class MainWindow : public QMainWindow {
-Q_OBJECT
-
-public:
- /**
- * @brief
- *
- */
- MainWindow();
-
-public slots:
-
- void slotSetStatusBarText(const QString& text);
-
-protected:
- /**
- * @details Close event shows a save dialog, if there are unsaved documents on exit.
- * @param event
- */
- void closeEvent(QCloseEvent *event) override;
-
-public slots:
-
- /**
- * @details Open a new tab for path
- */
- void slotOpenFile(QString &path);
-
- /**
- * @details Open dialog for encrypting file.
- */
- void slotFileEncrypt();
-
- /**
- * @details Open dialog for decrypting file.
- */
- void slotFileDecrypt();
-
- /**
- * @details Open dialog for signing file.
- */
- void slotFileSign();
-
- /**
- * @details Open dialog for verifying file.
- */
- void slotFileVerify();
-
- /**
- * @details Open dialog for signing file.
- */
- void slotFileEncryptSign();
-
- /**
- * @details Open dialog for verifying file.
- */
- void slotFileDecryptVerify();
-
-
-private slots:
-
- /**
- * @details encrypt the text of currently active textedit-page
- * with the currently checked keys
- */
- void slotEncrypt();
-
- /**
- * @details encrypt and sign the text of currently active textedit-page
- * with the currently checked keys
- */
- void slotEncryptSign();
-
- /**
- * @details Show a passphrase dialog and decrypt the text of currently active tab.
- */
- void slotDecrypt();
-
- /**
- * @details Sign the text of currently active tab with the checked private keys
- */
- void slotSign();
-
- /**
- * @details Verify the text of currently active tab and show verify information.
- * If document is signed with a key, which is not in keylist, show import missing
- * key from keyserver in Menu of verifynotification.
- */
- void slotVerify();
-
- /**
- * @details decrypt and verify the text of currently active textedit-page
- * with the currently checked keys
- */
- void slotDecryptVerify();
-
- /**
- * @details Open dialog for encrypting file.
- */
- void slotFileEncryptCustom();
-
- /**
- * @details Open dialog for decrypting file.
- */
- void slotFileDecryptCustom();
-
- /**
- * @details Open dialog for signing file.
- */
- void slotFileSignCustom();
-
- /**
- * @details Open dialog for verifying file.
- */
- void slotFileVerifyCustom();
-
- /**
- * @details Show the details of the first of the first of selected keys
- */
- void slotShowKeyDetails();
-
- /**
- * @details Refresh key information of selected keys from default keyserver
- */
- void refreshKeysFromKeyserver();
-
- /**
- * @details upload the selected key to the keyserver
- */
- void uploadKeyToServer();
-
- /**
- * @details Open find widget.
- */
- void slotFind();
-
- /**
- * @details start the wizard
- */
- void slotStartWizard();
-
- /**
- * @details Import keys from currently active tab to keylist if possible.
- */
- void slotImportKeyFromEdit();
-
- /**
- * @details Append the selected keys to currently active textedit.
- */
- void slotAppendSelectedKeys();
-
- /**
- * @details Copy the mailaddress of selected key to clipboard.
- * Method for keylists contextmenu.
- */
- void slotCopyMailAddressToClipboard();
-
- /**
- * @details Open key management dialog.
- */
- void slotOpenKeyManagement();
-
- /**
- * @details Open about-dialog.
- */
- void slotAbout();
-
- /**
- * @details Open check-update-tab in about-dialog.
- */
- void slotCheckUpdate();
-
- /**
- * @details Open File Opera Tab
- */
- void slotOpenFileTab();
-
- /**
- * @details Open settings-dialog.
- */
- void slotOpenSettingsDialog();
-
- /**
- * @details Show a warn message in status bar, if there are files in attachment folder.
- */
- void slotCheckAttachmentFolder();
-
- /**
- * @details Replace double linebreaks by single linebreaks in currently active tab.
- */
- void slotCleanDoubleLinebreaks();
-
- /**
- * @details Cut the existing PGP header and footer from current tab.
- */
- void slotCutPgpHeader();
-
- /**
- * @details Add PGP header and footer to current tab.
- */
- void slotAddPgpHeader();
-
- /**
- * @details Disable tab related actions, if number of tabs is 0.
- * @param number number of the opened tabs and -1, if no tab is opened
- */
- void slotDisableTabActions(int number);
-
- /**
- * @details get value of member restartNeeded to needed.
- * @param needed true, if application has to be restarted
- */
- void slotSetRestartNeeded(bool needed);
-
- /**
- * @details called when need to upgrade.
- */
- void slotVersionUpgrade(const QString &currentVersion, const QString &latestVersion);
-
-private:
- /**
- * @details Create actions for the main-menu and the context-menu of the keylist.
- */
- void createActions();
-
- /**
- * @details create the menu of the main-window.
- */
- void createMenus();
-
- /**
- * @details Create edit-, crypt- and key-toolbars.
- */
- void createToolBars();
-
- /**
- * @details Create statusbar of mainwindow.
- */
- void createStatusBar();
-
- /**
- * @details Create keylist- and attachment-dockwindows.
- */
- void createDockWindows();
-
- /**
- * @details Create attachment-dockwindow.
- */
- void createAttachmentDock();
-
- /**
- * @details close attachment-dockwindow.
- */
- void closeAttachmentDock();
-
- /**
- * @details Load settings from ini-file.
- */
- void restoreSettings();
-
- /**
- * @details Save settings to ini-file.
- */
- void saveSettings();
-
- /**
- * @details Get full crypto text
- */
- QString getCryptText(const QString& shortenCryptoText);
-
- /**
- * @details Shorten crypto text
- */
- void shortenCryptText();
-
- /**
- * @brief return true, if restart is needed
- */
- [[nodiscard]] bool getRestartNeeded() const;
-
- TextEdit *edit; /** Tabwidget holding the edit-windows */
- QMenu *fileMenu; /** Submenu for file-operations*/
- QMenu *editMenu; /** Submenu for text-operations*/
- QMenu *cryptMenu; /** Submenu for crypt-operations */
- QMenu *fileEncMenu; /** Submenu for file crypt operations */
- QMenu *helpMenu; /** Submenu for help-operations */
- QMenu *keyMenu; /** Submenu for key-operations */
- QMenu *viewMenu; /** Submenu for view operations */
- QMenu *importKeyMenu; /** Sumenu for import operations */
- QMenu *steganoMenu; /** Submenu for steganographic operations*/
- QToolBar *cryptToolBar; /** Toolbar holding crypt actions */
- QToolBar *fileToolBar; /** Toolbar holding file actions */
- QToolBar *editToolBar; /** Toolbar holding edit actions */
- QToolBar *specialEditToolBar; /** Toolbar holding special edit actions */
- QToolBar *keyToolBar; /** Toolbar holding key operations */
- QToolButton *importButton; /** Toolbutton for import dropdown menu in toolbar */
- QToolButton *fileEncButton; /** Toolbutton for file cryption dropdown menu in toolbar */
- QDockWidget *keyListDock; /** Encrypt Dock*/
- QDockWidget *attachmentDock; /** Attachment Dock */
- QDockWidget *infoBoardDock;
-
- QAction *newTabAct; /** Action to create new tab */
- QAction *switchTabUpAct; /** Action to switch tab up*/
- QAction *switchTabDownAct; /** Action to switch tab down */
- QAction *openAct; /** Action to open file */
- QAction *browserAct; /** Action to open file browser*/
- QAction *saveAct; /** Action to save file */
- QAction *saveAsAct; /** Action to save file as */
- QAction *printAct; /** Action to print */
- QAction *closeTabAct; /** Action to print */
- QAction *quitAct; /** Action to quit application */
- QAction *encryptAct; /** Action to encrypt text */
- QAction *encryptSignAct; /** Action to encrypt and sign text */
- QAction *decryptVerifyAct; /** Action to encrypt and sign text */
- QAction *decryptAct; /** Action to decrypt text */
- QAction *signAct; /** Action to sign text */
- QAction *verifyAct; /** Action to verify text */
- QAction *importKeyFromEditAct; /** Action to import key from edit */
- QAction *cleanDoubleLinebreaksAct; /** Action to remove double line breaks */
-
- QAction *appendSelectedKeysAct; /** Action to append selected keys to edit */
- QAction *copyMailAddressToClipboardAct; /** Action to copy mail to clipboard */
- QAction *openKeyManagementAct; /** Action to open key management */
- QAction *copyAct; /** Action to copy text */
- QAction *quoteAct; /** Action to quote text */
- QAction *cutAct; /** Action to cut text */
- QAction *pasteAct; /** Action to paste text */
- QAction *selectAllAct; /** Action to select whole text */
- QAction *findAct; /** Action to find text */
- QAction *undoAct; /** Action to undo last action */
- QAction *redoAct; /** Action to redo last action */
- QAction *zoomInAct; /** Action to zoom in */
- QAction *zoomOutAct; /** Action to zoom out */
- QAction *aboutAct; /** Action to open about dialog */
- QAction *checkUpdateAct; /** Action to open about dialog */
- QAction *fileEncryptAct; /** Action to open dialog for encrypting file */
- QAction *fileDecryptAct; /** Action to open dialog for decrypting file */
- QAction *fileSignAct; /** Action to open dialog for signing file */
- QAction *fileVerifyAct; /** Action to open dialog for verifying file */
- QAction *openSettingsAct; /** Action to open settings dialog */
- QAction *showKeyDetailsAct; /** Action to open key-details dialog */
- QAction *refreshKeysFromKeyserverAct; /** Action to refresh a key from keyserver */
- QAction *uploadKeyToServerAct; /** Action to append selected keys to edit */
- QAction *startWizardAct; /** Action to open the wizard */
- QAction *cutPgpHeaderAct; /** Action for cutting the PGP header */
- QAction *addPgpHeaderAct; /** Action for adding the PGP header */
-
- QLabel *statusBarIcon; /**< TODO */
-
- QString appPath;
- QSettings settings;
- KeyList *mKeyList;
-
- InfoBoardWidget *infoBoard;
- GpgFrontend::GpgContext *mCtx;
- KeyMgmt *keyMgmt;
- KeyServerImportDialog *importDialog; /**< TODO */
-
- QNetworkAccessManager *networkAccessManager;
-
- bool attachmentDockCreated;
- bool restartNeeded;
-};
-
-#endif // __GPGWIN_H__
diff --git a/src/gpg/CMakeLists.txt b/src/gpg/CMakeLists.txt
index e74ba86f..36a81591 100644
--- a/src/gpg/CMakeLists.txt
+++ b/src/gpg/CMakeLists.txt
@@ -9,10 +9,10 @@ set(UTILS_DIR ${CMAKE_SOURCE_DIR}/utils)
set(GPGME_LIB_DIR ${UTILS_DIR}/gpgme/lib)
-if(ESAY_LOGGING_PP)
- message(STATUS "Link ESAY_LOGGING_PP")
- set(THIRD_PARTY_LIBS easy_logging_pp config++)
-endif()
+if (ESAY_LOGGING_PP)
+ message(STATUS "Link ESAY_LOGGING_PP")
+ set(THIRD_PARTY_LIBS easy_logging_pp config++)
+endif ()
set(BOOST_LIBS Boost::date_time Boost::filesystem)
@@ -23,15 +23,15 @@ if (MINGW)
target_link_libraries(gpg_core ${THIRD_PARTY_LIBS}
${BOOST_LIBS}
gpgme gpg-error assuan wsock32)
-elseif(APPLE)
+elseif (APPLE)
message(STATUS "Link GPG Static Library For macOS")
target_link_libraries(gpg_core ${THIRD_PARTY_LIBS}
${BOOST_LIBS}
libgpgme.a libgpg-error.a libassuan.a dl)
-else()
+else ()
message(STATUS "Link GPG Static Library For Unix")
target_link_libraries(gpg_core ${THIRD_PARTY_LIBS}
libgpgme.a libgpg-error.a libassuan.a
${BOOST_LIBS}
pthread dl)
-endif()
+endif ()
diff --git a/src/gpg/GpgConstants.cpp b/src/gpg/GpgConstants.cpp
index 8090a261..3d80cf90 100644
--- a/src/gpg/GpgConstants.cpp
+++ b/src/gpg/GpgConstants.cpp
@@ -75,11 +75,12 @@ gpgme_error_t GpgFrontend::check_gpg_error(gpgme_error_t err,
}
std::string GpgFrontend::beautify_fingerprint(
- GpgFrontend::BypeArrayRef fingerprint) {
+ GpgFrontend::BypeArrayConstRef fingerprint) {
+ auto _fingerprint = fingerprint;
uint len = fingerprint.size();
if ((len > 0) && (len % 4 == 0))
for (uint n = 0; 4 * (n + 1) < len; ++n)
- fingerprint.insert(static_cast<int>(5u * n + 4u), " ");
+ _fingerprint.insert(static_cast<int>(5u * n + 4u), " ");
return fingerprint;
}
@@ -123,14 +124,15 @@ std::string GpgFrontend::read_all_data_in_file(const std::string& path) {
return in_buffer;
}
-void GpgFrontend::write_buffer_to_file(const std::string& path,
+bool GpgFrontend::write_buffer_to_file(const std::string& path,
const std::string& out_buffer) {
std::ofstream out_file(path);
out_file.open(path.c_str(), std::ios::out);
if (!out_file.good())
- throw std::runtime_error("cannot open file");
+ return false;
out_file.write(out_buffer.c_str(), out_buffer.size());
out_file.close();
+ return true;
}
std::string GpgFrontend::get_file_extension(const std::string& path) {
@@ -142,10 +144,10 @@ std::string GpgFrontend::get_file_extension(const std::string& path) {
return path_obj.extension().string();
}
// In case of no extension return empty string
- return std::string();
+ return {};
}
-std::string get_file_name_with_path(const std::string& path) {
+std::string GpgFrontend::get_file_name_with_path(const std::string& path) {
// Create a Path object from given string
std::filesystem::path path_obj(path);
// Check if file name in the path object has extension
diff --git a/src/gpg/GpgConstants.h b/src/gpg/GpgConstants.h
index 0c126bf7..313e49bb 100644
--- a/src/gpg/GpgConstants.h
+++ b/src/gpg/GpgConstants.h
@@ -29,9 +29,9 @@
#include <functional>
-#include <assert.h>
#include <gpg-error.h>
#include <gpgme.h>
+#include <cassert>
#include <memory>
#include <string>
@@ -43,9 +43,10 @@ const int RESTART_CODE = 1000;
namespace GpgFrontend {
using ByteArray = std::string;
-using BypeArrayPtr = std::unique_ptr<ByteArray>;
+using ByteArrayPtr = std::unique_ptr<ByteArray>;
using StdBypeArrayPtr = std::unique_ptr<ByteArray>;
using BypeArrayRef = ByteArray&;
+using BypeArrayConstRef = const ByteArray&;
using StringArgsPtr = std::unique_ptr<std::vector<std::string>>;
using StringArgsRef = std::vector<std::string>&;
@@ -76,15 +77,14 @@ gpg_err_code_t check_gpg_error_2_err_code(
gpgme_error_t predict = GPG_ERR_NO_ERROR);
// Fingerprint
-std::string beautify_fingerprint(BypeArrayRef fingerprint);
+std::string beautify_fingerprint(BypeArrayConstRef fingerprint);
// File Operation
std::string read_all_data_in_file(const std::string& path);
-void write_buffer_to_file(const std::string& path,
+bool write_buffer_to_file(const std::string& path,
const std::string& out_buffer);
std::string get_file_extension(const std::string& path);
-std::string get_file_extension(const std::string& path);
std::string get_file_name_with_path(const std::string& path);
// Check
diff --git a/src/gpg/GpgModel.h b/src/gpg/GpgModel.h
index fcdadb5c..7b77d678 100644
--- a/src/gpg/GpgModel.h
+++ b/src/gpg/GpgModel.h
@@ -29,22 +29,41 @@
#include "gpg/model/GpgKey.h"
#include <list>
+#include <utility>
namespace GpgFrontend {
-using KeyIdArgsListPtr = std::unique_ptr<std::vector<std::string>>;
+using KeyId = std::string;
+
+using SubkeyId = std::string;
+
+using KeyIdArgsList = std::vector<KeyId>;
+
+using KeyIdArgsListPtr = std::unique_ptr<KeyIdArgsList>;
+
+using UIDArgsList = std::vector<std::string>;
+
+using UIDArgsListPtr = std::unique_ptr<UIDArgsList>;
+
+// KeyID/UID
+using SignIdArgsList = std::vector<std::pair<std::string, std::string>>;
+
+using SignIdArgsListPtr = std::unique_ptr<SignIdArgsList>;
using KeyFprArgsListPtr = std::unique_ptr<std::vector<std::string>>;
-using KeyArgsList = const std::vector<GpgKey>;
+using KeyArgsList = std::vector<GpgKey>;
using KeyListPtr = std::unique_ptr<KeyArgsList>;
-using GpgKeyLinkList = const std::list<GpgFrontend::GpgKey>;
+using GpgKeyLinkList = std::list<GpgFrontend::GpgKey>;
+
+using KeyLinkListPtr = std::unique_ptr<GpgKeyLinkList>;
using KeyPtr = std::unique_ptr<GpgKey>;
using KeyPtrArgsList = const std::initializer_list<KeyPtr>;
+
} // namespace GpgFrontend
#endif // GPGFRONTEND_ZH_CN_TS_GPGMODEL_H
diff --git a/src/gpg/function/BasicOperator.cpp b/src/gpg/function/BasicOperator.cpp
index fbf9afb1..0e44c9e0 100644
--- a/src/gpg/function/BasicOperator.cpp
+++ b/src/gpg/function/BasicOperator.cpp
@@ -29,7 +29,7 @@
GpgFrontend::GpgError GpgFrontend::BasicOperator::Encrypt(
GpgFrontend::KeyArgsList&& keys,
GpgFrontend::BypeArrayRef in_buffer,
- GpgFrontend::BypeArrayPtr& out_buffer,
+ GpgFrontend::ByteArrayPtr& out_buffer,
GpgFrontend::GpgEncrResult& result) {
// gpgme_encrypt_result_t e_result;
gpgme_key_t recipients[keys.size() + 1];
@@ -57,7 +57,7 @@ GpgFrontend::GpgError GpgFrontend::BasicOperator::Encrypt(
GpgFrontend::GpgError GpgFrontend::BasicOperator::Decrypt(
BypeArrayRef in_buffer,
- GpgFrontend::BypeArrayPtr& out_buffer,
+ GpgFrontend::ByteArrayPtr& out_buffer,
GpgFrontend::GpgDecrResult& result) {
gpgme_error_t err;
@@ -75,7 +75,7 @@ GpgFrontend::GpgError GpgFrontend::BasicOperator::Decrypt(
GpgFrontend::GpgError GpgFrontend::BasicOperator::Verify(
BypeArrayRef& in_buffer,
- BypeArrayPtr& sig_buffer,
+ ByteArrayPtr& sig_buffer,
GpgVerifyResult& result) const {
gpgme_error_t err;
@@ -95,7 +95,7 @@ GpgFrontend::GpgError GpgFrontend::BasicOperator::Verify(
GpgFrontend::GpgError GpgFrontend::BasicOperator::Sign(KeyArgsList&& keys,
BypeArrayRef in_buffer,
- BypeArrayPtr& out_buffer,
+ ByteArrayPtr& out_buffer,
gpgme_sig_mode_t mode,
GpgSignResult& result) {
gpgme_error_t err;
@@ -132,7 +132,7 @@ GpgFrontend::GpgError GpgFrontend::BasicOperator::Sign(KeyArgsList&& keys,
gpgme_error_t GpgFrontend::BasicOperator::DecryptVerify(
BypeArrayRef in_buffer,
- BypeArrayPtr& out_buffer,
+ ByteArrayPtr& out_buffer,
GpgDecrResult& decrypt_result,
GpgVerifyResult& verify_result) {
gpgme_error_t err;
@@ -157,7 +157,7 @@ gpgme_error_t GpgFrontend::BasicOperator::EncryptSign(
KeyArgsList&& keys,
KeyArgsList&& signers,
BypeArrayRef in_buffer,
- BypeArrayPtr& out_buffer,
+ ByteArrayPtr& out_buffer,
GpgEncrResult& encr_result,
GpgSignResult& sign_result) {
gpgme_error_t err;
diff --git a/src/gpg/function/BasicOperator.h b/src/gpg/function/BasicOperator.h
index 2e5da307..e8fa943d 100644
--- a/src/gpg/function/BasicOperator.h
+++ b/src/gpg/function/BasicOperator.h
@@ -36,32 +36,32 @@ class BasicOperator : public SingletonFunctionObject<BasicOperator> {
public:
gpg_error_t Encrypt(KeyArgsList&& keys,
BypeArrayRef in_buffer,
- BypeArrayPtr& out_buffer,
+ ByteArrayPtr& out_buffer,
GpgEncrResult& result);
gpgme_error_t EncryptSign(KeyArgsList&& keys,
KeyArgsList&& signers,
BypeArrayRef in_buffer,
- BypeArrayPtr& out_buffer,
+ ByteArrayPtr& out_buffer,
GpgEncrResult& encr_result,
GpgSignResult& sign_result);
gpgme_error_t Decrypt(BypeArrayRef in_buffer,
- BypeArrayPtr& out_buffer,
+ ByteArrayPtr& out_buffer,
GpgDecrResult& result);
gpgme_error_t DecryptVerify(BypeArrayRef in_buffer,
- BypeArrayPtr& out_buffer,
+ ByteArrayPtr& out_buffer,
GpgDecrResult& decrypt_result,
GpgVerifyResult& verify_result);
gpgme_error_t Verify(BypeArrayRef in_buffer,
- BypeArrayPtr& sig_buffer,
+ ByteArrayPtr& sig_buffer,
GpgVerifyResult& result) const;
gpg_error_t Sign(KeyArgsList&& key_fprs,
BypeArrayRef in_buffer,
- BypeArrayPtr& out_buffer,
+ ByteArrayPtr& out_buffer,
gpgme_sig_mode_t mode,
GpgSignResult& result);
diff --git a/src/gpg/function/GpgFileOpera.h b/src/gpg/function/GpgFileOpera.h
index 2eac251b..dece2e52 100644
--- a/src/gpg/function/GpgFileOpera.h
+++ b/src/gpg/function/GpgFileOpera.h
@@ -31,7 +31,7 @@
namespace GpgFrontend {
-class GpgFileOpera {
+class GpgFileOpera : public SingletonFunctionObject<GpgFileOpera> {
public:
GpgError EncryptFile(KeyArgsList&& keys,
const std::string& path,
diff --git a/src/gpg/function/GpgKeyGetter.cpp b/src/gpg/function/GpgKeyGetter.cpp
index f2413706..ce4c9899 100644
--- a/src/gpg/function/GpgKeyGetter.cpp
+++ b/src/gpg/function/GpgKeyGetter.cpp
@@ -44,10 +44,10 @@ GpgFrontend::GpgKey GpgFrontend::GpgKeyGetter::GetPubkey(
return GpgKey(std::move(_p_key));
}
-GpgFrontend::KeyListPtr GpgFrontend::GpgKeyGetter::FetchKey() {
+GpgFrontend::KeyLinkListPtr GpgFrontend::GpgKeyGetter::FetchKey() {
gpgme_error_t err;
- auto keys_list = std::make_unique<std::vector<GpgKey>>();
+ auto keys_list = std::make_unique<GpgKeyLinkList>();
err = gpgme_op_keylist_start(ctx, nullptr, 0);
assert(check_gpg_error_2_err_code(err) == GPG_ERR_NO_ERROR);
@@ -63,3 +63,10 @@ GpgFrontend::KeyListPtr GpgFrontend::GpgKeyGetter::FetchKey() {
return keys_list;
}
+GpgFrontend::KeyListPtr GpgFrontend::GpgKeyGetter::GetKeys(
+ const KeyIdArgsListPtr& ids) {
+ auto keys = std::make_unique<KeyArgsList>();
+ for (const auto& id : *ids)
+ keys->push_back(GetKey(id));
+ return keys;
+}
diff --git a/src/gpg/function/GpgKeyGetter.h b/src/gpg/function/GpgKeyGetter.h
index af22e2f2..8eab4e10 100644
--- a/src/gpg/function/GpgKeyGetter.h
+++ b/src/gpg/function/GpgKeyGetter.h
@@ -37,9 +37,11 @@ class GpgKeyGetter : public SingletonFunctionObject<GpgKeyGetter> {
GpgKey GetKey(const std::string& fpr);
+ KeyListPtr GetKeys(const KeyIdArgsListPtr& ids);
+
GpgKey GetPubkey(const std::string& fpr);
- KeyListPtr FetchKey();
+ KeyLinkListPtr FetchKey();
private:
GpgContext& ctx =
diff --git a/src/gpg/function/GpgKeyImportExportor.cpp b/src/gpg/function/GpgKeyImportExportor.cpp
index 98ffc328..bdfc25bd 100644
--- a/src/gpg/function/GpgKeyImportExportor.cpp
+++ b/src/gpg/function/GpgKeyImportExportor.cpp
@@ -61,7 +61,7 @@ GpgFrontend::GpgImportInformation GpgFrontend::GpgKeyImportExportor::ImportKey(
*/
bool GpgFrontend::GpgKeyImportExportor::ExportKeys(
KeyIdArgsListPtr& uid_list,
- BypeArrayPtr& out_buffer) const {
+ ByteArrayPtr& out_buffer) const {
if (uid_list->empty())
return false;
@@ -89,8 +89,8 @@ bool GpgFrontend::GpgKeyImportExportor::ExportKeys(
* @return if success
*/
bool GpgFrontend::GpgKeyImportExportor::ExportKeys(
- KeyArgsList& keys,
- BypeArrayPtr& out_buffer) const {
+ const KeyArgsList& keys,
+ ByteArrayPtr& out_buffer) const {
KeyIdArgsListPtr key_ids = std::make_unique<std::vector<std::string>>();
for (const auto& key : keys)
key_ids->push_back(key.id());
@@ -105,7 +105,7 @@ bool GpgFrontend::GpgKeyImportExportor::ExportKeys(
*/
bool GpgFrontend::GpgKeyImportExportor::ExportSecretKey(
const GpgKey& key,
- BypeArrayPtr out_buffer) const {
+ ByteArrayPtr& out_buffer) const {
DLOG(INFO) << "Export Secret Key" << key.id().c_str();
gpgme_key_t target_key[2] = {gpgme_key_t(key), nullptr};
diff --git a/src/gpg/function/GpgKeyImportExportor.h b/src/gpg/function/GpgKeyImportExportor.h
index 2cdb4e80..d71daddb 100644
--- a/src/gpg/function/GpgKeyImportExportor.h
+++ b/src/gpg/function/GpgKeyImportExportor.h
@@ -97,11 +97,11 @@ class GpgKeyImportExportor
public:
GpgImportInformation ImportKey(StdBypeArrayPtr inBuffer);
- bool ExportKeys(KeyIdArgsListPtr& uid_list, BypeArrayPtr& out_buffer) const;
+ bool ExportKeys(KeyIdArgsListPtr& uid_list, ByteArrayPtr& out_buffer) const;
- bool ExportKeys(KeyArgsList& keys, BypeArrayPtr& outBuffer) const;
+ bool ExportKeys(const KeyArgsList& keys, ByteArrayPtr& outBuffer) const;
- bool ExportSecretKey(const GpgKey& key, BypeArrayPtr outBuffer) const;
+ bool ExportSecretKey(const GpgKey& key, ByteArrayPtr& outBuffer) const;
private:
GpgContext& ctx =
diff --git a/src/gpg/function/GpgKeyManager.cpp b/src/gpg/function/GpgKeyManager.cpp
index a6697bc4..361c00bd 100644
--- a/src/gpg/function/GpgKeyManager.cpp
+++ b/src/gpg/function/GpgKeyManager.cpp
@@ -23,14 +23,16 @@
*/
#include "gpg/function/GpgKeyManager.h"
-#include "gpg/function/BasicOperator.h"
-#include "gpg/function/GpgKeyGetter.h"
#include <boost/date_time/posix_time/conversion.hpp>
#include <string>
+#include "gpg/function/BasicOperator.h"
+#include "gpg/function/GpgKeyGetter.h"
bool GpgFrontend::GpgKeyManager::signKey(
- const GpgFrontend::GpgKey &target, GpgFrontend::KeyArgsList &keys,
- const std::string &uid, std::unique_ptr<boost::gregorian::date> &expires) {
+ const GpgFrontend::GpgKey& target,
+ GpgFrontend::KeyArgsList& keys,
+ const std::string& uid,
+ const std::unique_ptr<boost::gregorian::date>& expires) {
using namespace boost::posix_time;
BasicOperator::GetInstance().SetSigners(keys);
@@ -50,21 +52,26 @@ bool GpgFrontend::GpgKeyManager::signKey(
}
bool GpgFrontend::GpgKeyManager::revSign(
- const GpgFrontend::GpgKey &key,
- const GpgFrontend::GpgKeySignature &signature) {
-
- auto &key_getter = GpgKeyGetter::GetInstance();
- auto signing_key = key_getter.GetKey(signature.keyid());
-
- auto err = check_gpg_error(gpgme_op_revsig(ctx, gpgme_key_t(key),
- gpgme_key_t(signing_key),
- signature.uid().data(), 0));
- return check_gpg_error_2_err_code(err) == GPG_ERR_NO_ERROR;
+ const GpgFrontend::GpgKey& key,
+ const GpgFrontend::SignIdArgsListPtr& signature_id) {
+ auto& key_getter = GpgKeyGetter::GetInstance();
+
+ for (const auto& sign_id : *signature_id) {
+ auto signing_key = key_getter.GetKey(sign_id.first);
+ assert(signing_key.good());
+ auto err = check_gpg_error(gpgme_op_revsig(ctx, gpgme_key_t(key),
+ gpgme_key_t(signing_key),
+ sign_id.second.c_str(), 0));
+ if (check_gpg_error_2_err_code(err) != GPG_ERR_NO_ERROR)
+ return false;
+ }
+ return true;
}
bool GpgFrontend::GpgKeyManager::setExpire(
- const GpgFrontend::GpgKey &key, std::unique_ptr<GpgSubKey> &subkey,
- std::unique_ptr<boost::gregorian::date> &expires) {
+ const GpgFrontend::GpgKey& key,
+ std::unique_ptr<GpgSubKey>& subkey,
+ std::unique_ptr<boost::gregorian::date>& expires) {
using namespace boost::posix_time;
unsigned long expires_time = 0;
@@ -72,7 +79,7 @@ bool GpgFrontend::GpgKeyManager::setExpire(
if (expires != nullptr)
expires_time = to_time_t(ptime(*expires));
- const char *sub_fprs = nullptr;
+ const char* sub_fprs = nullptr;
if (subkey != nullptr)
sub_fprs = subkey->fpr().c_str();
diff --git a/src/gpg/function/GpgKeyManager.h b/src/gpg/function/GpgKeyManager.h
index 6d57c7d7..f50c8dcc 100644
--- a/src/gpg/function/GpgKeyManager.h
+++ b/src/gpg/function/GpgKeyManager.h
@@ -32,7 +32,7 @@
namespace GpgFrontend {
class GpgKeyManager : public SingletonFunctionObject<GpgKeyManager> {
-public:
+ public:
/**
* Sign a key pair(actually a certain uid)
* @param target target key pair
@@ -40,18 +40,22 @@ public:
* @param expires expire date and time of the signature
* @return if successful
*/
- bool signKey(const GpgKey &target, KeyArgsList &keys, const std::string &uid,
- std::unique_ptr<boost::gregorian::date> &expires);
+ bool signKey(const GpgKey& target,
+ KeyArgsList& keys,
+ const std::string& uid,
+ const std::unique_ptr<boost::gregorian::date>& expires);
- bool revSign(const GpgKey &key, const GpgKeySignature &signature);
+ bool revSign(const GpgFrontend::GpgKey& key,
+ const GpgFrontend::SignIdArgsListPtr& signature_id);
- bool setExpire(const GpgKey &key, std::unique_ptr<GpgSubKey> &subkey,
- std::unique_ptr<boost::gregorian::date> &expires);
+ bool setExpire(const GpgKey& key,
+ std::unique_ptr<GpgSubKey>& subkey,
+ std::unique_ptr<boost::gregorian::date>& expires);
-private:
- GpgContext &ctx = GpgContext::GetInstance();
+ private:
+ GpgContext& ctx = GpgContext::GetInstance();
};
-} // namespace GpgFrontend
+} // namespace GpgFrontend
-#endif // GPGFRONTEND_ZH_CN_TS_GPGKEYMANAGER_H
+#endif // GPGFRONTEND_ZH_CN_TS_GPGKEYMANAGER_H
diff --git a/src/gpg/function/GpgKeyOpera.cpp b/src/gpg/function/GpgKeyOpera.cpp
index f79fb2c3..f61534c5 100644
--- a/src/gpg/function/GpgKeyOpera.cpp
+++ b/src/gpg/function/GpgKeyOpera.cpp
@@ -41,9 +41,9 @@
* @param uidList key ids
*/
void GpgFrontend::GpgKeyOpera::DeleteKeys(
- GpgFrontend::KeyIdArgsListPtr uid_list) {
+ GpgFrontend::KeyIdArgsListPtr key_ids) {
GpgError err;
- for (const auto &tmp : *uid_list) {
+ for (const auto& tmp : *key_ids) {
auto key = GpgKeyGetter::GetInstance().GetKey(tmp);
if (key.good()) {
LOG(INFO) << "GpgKeyOpera DeleteKeys Get Key Good";
@@ -62,21 +62,21 @@ void GpgFrontend::GpgKeyOpera::DeleteKeys(
* @return if successful
*/
void GpgFrontend::GpgKeyOpera::SetExpire(
- const GpgKey &key, std::unique_ptr<GpgSubKey> &subkey,
- std::unique_ptr<boost::gregorian::date> &expires) {
+ const GpgKey& key,
+ const SubkeyId& subkey_id,
+ std::unique_ptr<boost::gregorian::date>& expires) {
unsigned long expires_time = 0;
if (expires != nullptr) {
using namespace boost::posix_time;
expires_time = to_time_t(ptime(*expires));
}
- const char *sub_fprs = nullptr;
-
- if (subkey != nullptr)
- sub_fprs = subkey->fpr().c_str();
-
- auto err =
- gpgme_op_setexpire(ctx, gpgme_key_t(key), expires_time, sub_fprs, 0);
+ GpgError err;
+ if (subkey_id.empty())
+ err = gpgme_op_setexpire(ctx, gpgme_key_t(key), expires_time, nullptr, 0);
+ else
+ err = gpgme_op_setexpire(ctx, gpgme_key_t(key), expires_time,
+ subkey_id.c_str(), 0);
assert(gpg_err_code(err) != GPG_ERR_NO_ERROR);
}
@@ -88,7 +88,8 @@ void GpgFrontend::GpgKeyOpera::SetExpire(
* @return the process doing this job
*/
void GpgFrontend::GpgKeyOpera::GenerateRevokeCert(
- const GpgKey &key, const std::string &output_file_name) {
+ const GpgKey& key,
+ const std::string& output_file_name) {
auto args = std::vector<std::string>{"--command-fd", "0",
"--status-fd", "1",
"-o", output_file_name.c_str(),
@@ -96,7 +97,7 @@ void GpgFrontend::GpgKeyOpera::GenerateRevokeCert(
using boost::process::async_pipe;
GpgCommandExecutor::GetInstance().Execute(
- args, [](async_pipe &in, async_pipe &out) -> void {
+ args, [](async_pipe& in, async_pipe& out) -> void {
boost::asio::streambuf buff;
boost::asio::read_until(in, buff, '\n');
@@ -112,13 +113,12 @@ void GpgFrontend::GpgKeyOpera::GenerateRevokeCert(
* @param params key generation args
* @return error information
*/
-GpgFrontend::GpgError
-GpgFrontend::GpgKeyOpera::GenerateKey(std::unique_ptr<GenKeyInfo> params) {
-
+GpgFrontend::GpgError GpgFrontend::GpgKeyOpera::GenerateKey(
+ const std::unique_ptr<GenKeyInfo>& params) {
auto userid_utf8 = params->getUserid();
- const char *userid = userid_utf8.c_str();
+ const char* userid = userid_utf8.c_str();
auto algo_utf8 = (params->getAlgo() + params->getKeySizeStr());
- const char *algo = algo_utf8.c_str();
+ const char* algo = algo_utf8.c_str();
unsigned long expires = 0;
{
using namespace boost::posix_time;
@@ -150,15 +150,14 @@ GpgFrontend::GpgKeyOpera::GenerateKey(std::unique_ptr<GenKeyInfo> params) {
* @param params opera args
* @return error info
*/
-GpgFrontend::GpgError
-GpgFrontend::GpgKeyOpera::GenerateSubkey(const GpgKey &key,
- std::unique_ptr<GenKeyInfo> params) {
-
+GpgFrontend::GpgError GpgFrontend::GpgKeyOpera::GenerateSubkey(
+ const GpgKey& key,
+ const std::unique_ptr<GenKeyInfo>& params) {
if (!params->isSubKey())
return GPG_ERR_CANCELED;
auto algo_utf8 = (params->getAlgo() + params->getKeySizeStr());
- const char *algo = algo_utf8.c_str();
+ const char* algo = algo_utf8.c_str();
unsigned long expires = 0;
{
using namespace boost::posix_time;
diff --git a/src/gpg/function/GpgKeyOpera.h b/src/gpg/function/GpgKeyOpera.h
index a635084d..36864cc7 100644
--- a/src/gpg/function/GpgKeyOpera.h
+++ b/src/gpg/function/GpgKeyOpera.h
@@ -32,23 +32,25 @@
namespace GpgFrontend {
class GenKeyInfo;
class GpgKeyOpera : public SingletonFunctionObject<GpgKeyOpera> {
-public:
- void DeleteKeys(KeyIdArgsListPtr uid_list);
+ public:
+ void DeleteKeys(KeyIdArgsListPtr key_ids);
- void SetExpire(const GpgKey &key, std::unique_ptr<GpgSubKey> &subkey,
- std::unique_ptr<boost::gregorian::date> &expires);
+ void SetExpire(const GpgKey& key,
+ const SubkeyId& subkey_id,
+ std::unique_ptr<boost::gregorian::date>& expires);
- void GenerateRevokeCert(const GpgKey &key,
- const std::string &output_file_name);
+ void GenerateRevokeCert(const GpgKey& key,
+ const std::string& output_file_name);
- GpgFrontend::GpgError GenerateKey(std::unique_ptr<GenKeyInfo> params);
+ GpgFrontend::GpgError GenerateKey(const std::unique_ptr<GenKeyInfo>& params);
- GpgFrontend::GpgError GenerateSubkey(const GpgKey &key,
- std::unique_ptr<GenKeyInfo> params);
+ GpgFrontend::GpgError GenerateSubkey(
+ const GpgKey& key,
+ const std::unique_ptr<GenKeyInfo>& params);
-private:
- GpgContext &ctx = GpgContext::GetInstance();
+ private:
+ GpgContext& ctx = GpgContext::GetInstance();
};
-} // namespace GpgFrontend
+} // namespace GpgFrontend
-#endif // _GPGKEYOPERA_H \ No newline at end of file
+#endif // _GPGKEYOPERA_H \ No newline at end of file
diff --git a/src/gpg/function/UidOperator.cpp b/src/gpg/function/UidOperator.cpp
index d0058540..5b02855b 100644
--- a/src/gpg/function/UidOperator.cpp
+++ b/src/gpg/function/UidOperator.cpp
@@ -26,34 +26,38 @@
#include "boost/format.hpp"
-bool GpgFrontend::UidOperator::addUID(const GpgFrontend::GpgKey &key,
- const GpgFrontend::GpgUID &uid) {
- auto userid = (boost::format("%1% (%2%) <%3%>") % uid.name() % uid.comment() %
- uid.email())
- .str();
- auto err = gpgme_op_adduid(ctx, gpgme_key_t(key), userid.c_str(), 0);
+bool GpgFrontend::UidOperator::addUID(const GpgFrontend::GpgKey& key,
+ const std::string& uid) {
+ auto err = gpgme_op_adduid(ctx, gpgme_key_t(key), uid.c_str(), 0);
if (check_gpg_error_2_err_code(err) == GPG_ERR_NO_ERROR)
return true;
else
return false;
}
-bool GpgFrontend::UidOperator::revUID(const GpgFrontend::GpgKey &key,
- const GpgFrontend::GpgUID &uid) {
- auto err = check_gpg_error(
- gpgme_op_revuid(ctx, gpgme_key_t(key), uid.uid().c_str(), 0));
+bool GpgFrontend::UidOperator::revUID(const GpgFrontend::GpgKey& key,
+ const std::string& uid) {
+ auto err =
+ check_gpg_error(gpgme_op_revuid(ctx, gpgme_key_t(key), uid.c_str(), 0));
if (check_gpg_error_2_err_code(err) == GPG_ERR_NO_ERROR)
return true;
else
return false;
}
-bool GpgFrontend::UidOperator::setPrimaryUID(const GpgFrontend::GpgKey &key,
- const GpgFrontend::GpgUID &uid) {
+bool GpgFrontend::UidOperator::setPrimaryUID(const GpgFrontend::GpgKey& key,
+ const std::string& uid) {
auto err = check_gpg_error(gpgme_op_set_uid_flag(
- ctx, gpgme_key_t(key), uid.uid().c_str(), "primary", nullptr));
+ ctx, gpgme_key_t(key), uid.c_str(), "primary", nullptr));
if (check_gpg_error_2_err_code(err) == GPG_ERR_NO_ERROR)
return true;
else
return false;
}
+bool GpgFrontend::UidOperator::addUID(const GpgFrontend::GpgKey& key,
+ const std::string& name,
+ const std::string& comment,
+ const std::string& email) {
+ auto uid = boost::format("%1 (%2) <%3>") % name % comment % email;
+ return addUID(key, uid.str());
+}
diff --git a/src/gpg/function/UidOperator.h b/src/gpg/function/UidOperator.h
index d5bbcb3b..e3068b1f 100644
--- a/src/gpg/function/UidOperator.h
+++ b/src/gpg/function/UidOperator.h
@@ -30,15 +30,28 @@
namespace GpgFrontend {
-class UidOperator {
-public:
+class UidOperator : public SingletonFunctionObject<UidOperator> {
+ public:
/**
* create a new uid in certain key pair
* @param key target key pair
- * @param uid uid args
+ * @param uid uid args(combine name&comment&email)
* @return if successful
*/
- bool addUID(const GpgKey &key, const GpgUID &uid);
+ bool addUID(const GpgKey& key, const std::string& uid);
+
+ /**
+ * create a new uid in certain key pair
+ * @param key target key pair
+ * @param name
+ * @param comment
+ * @param email
+ * @return
+ */
+ bool addUID(const GpgKey& key,
+ const std::string& name,
+ const std::string& comment,
+ const std::string& email);
/**
* Revoke(Delete) UID from certain key pair
@@ -46,7 +59,7 @@ public:
* @param uid target uid
* @return if successful
*/
- bool revUID(const GpgKey &key, const GpgUID &uid);
+ bool revUID(const GpgKey& key, const std::string& uid);
/**
* Set one of a uid of a key pair as primary
@@ -54,12 +67,12 @@ public:
* @param uid target uid
* @return if successful
*/
- bool setPrimaryUID(const GpgKey &key, const GpgUID &uid);
+ bool setPrimaryUID(const GpgKey& key, const std::string& uid);
-private:
- GpgContext &ctx = GpgContext::GetInstance();
+ private:
+ GpgContext& ctx = GpgContext::GetInstance();
};
-} // namespace GpgFrontend
+} // namespace GpgFrontend
-#endif // GPGFRONTEND_ZH_CN_TS_UIDOPERATOR_H
+#endif // GPGFRONTEND_ZH_CN_TS_UIDOPERATOR_H
diff --git a/src/gpg/model/GpgData.cpp b/src/gpg/model/GpgData.cpp
index 44e5ae44..1ffff0c5 100644
--- a/src/gpg/model/GpgData.cpp
+++ b/src/gpg/model/GpgData.cpp
@@ -27,18 +27,17 @@
GpgFrontend::GpgData::GpgData() {
gpgme_data_t data;
- gpgme_error_t err = gpgme_data_new(&data);
+ auto err = gpgme_data_new(&data);
assert(gpgme_err_code(err) == GPG_ERR_NO_ERROR);
data_ =
std::unique_ptr<struct gpgme_data, __data_ref_deletor>(std::move(data));
}
-GpgFrontend::GpgData::GpgData(void *buffer, size_t size, bool copy) {
+GpgFrontend::GpgData::GpgData(void* buffer, size_t size, bool copy) {
gpgme_data_t data;
- gpgme_error_t err =
- gpgme_data_new_from_mem(&data, (const char *)buffer, size, copy);
+ auto err = gpgme_data_new_from_mem(&data, (const char*)buffer, size, copy);
assert(gpgme_err_code(err) == GPG_ERR_NO_ERROR);
data_ =
@@ -51,11 +50,11 @@ GpgFrontend::GpgData::GpgData(void *buffer, size_t size, bool copy) {
*/
#define BUF_SIZE (32 * 1024)
-GpgFrontend::BypeArrayPtr GpgFrontend::GpgData::Read2Buffer() {
+GpgFrontend::ByteArrayPtr GpgFrontend::GpgData::Read2Buffer() {
gpgme_off_t ret = gpgme_data_seek(*this, 0, SEEK_SET);
gpgme_error_t err = gpg_error(GPG_ERR_NO_ERROR);
- BypeArrayPtr out_buffer = std::make_unique<std::string>();
+ ByteArrayPtr out_buffer = std::make_unique<std::string>();
if (ret) {
err = gpgme_err_code_from_errno(errno);
diff --git a/src/gpg/model/GpgData.h b/src/gpg/model/GpgData.h
index 0c4615ad..30a1c496 100644
--- a/src/gpg/model/GpgData.h
+++ b/src/gpg/model/GpgData.h
@@ -30,16 +30,16 @@
namespace GpgFrontend {
class GpgData {
-public:
+ public:
GpgData();
- GpgData(void *buffer, size_t size, bool copy = true);
+ GpgData(void* buffer, size_t size, bool copy = true);
operator gpgme_data_t() { return data_.get(); }
- BypeArrayPtr Read2Buffer();
+ ByteArrayPtr Read2Buffer();
-private:
+ private:
struct __data_ref_deletor {
void operator()(gpgme_data_t _data) {
if (_data != nullptr)
@@ -50,6 +50,6 @@ private:
std::unique_ptr<struct gpgme_data, __data_ref_deletor> data_ = nullptr;
};
-} // namespace GpgFrontend
+} // namespace GpgFrontend
-#endif // _GPGDATA_H \ No newline at end of file
+#endif // _GPGDATA_H \ No newline at end of file
diff --git a/src/gpg/model/GpgSubKey.h b/src/gpg/model/GpgSubKey.h
index c251141b..edb52f44 100644
--- a/src/gpg/model/GpgSubKey.h
+++ b/src/gpg/model/GpgSubKey.h
@@ -32,7 +32,7 @@
namespace GpgFrontend {
class GpgSubKey {
-public:
+ public:
[[nodiscard]] std::string id() const { return _subkey_ref->keyid; }
[[nodiscard]] std::string fpr() const { return _subkey_ref->fpr; }
@@ -77,24 +77,26 @@ public:
explicit GpgSubKey(gpgme_subkey_t subkey);
- GpgSubKey(GpgSubKey &&o) noexcept { swap(_subkey_ref, o._subkey_ref); }
+ GpgSubKey(GpgSubKey&& o) noexcept { swap(_subkey_ref, o._subkey_ref); }
- GpgSubKey(const GpgSubKey &) = delete;
+ GpgSubKey(const GpgSubKey&) = delete;
- GpgSubKey &operator=(GpgSubKey &&o) noexcept {
+ GpgSubKey& operator=(GpgSubKey&& o) noexcept {
swap(_subkey_ref, o._subkey_ref);
return *this;
};
- GpgSubKey &operator=(const GpgSubKey &) = delete;
+ GpgSubKey& operator=(const GpgSubKey&) = delete;
-private:
+ bool operator==(const GpgSubKey& o) const { return fpr() == o.fpr(); }
+
+ private:
using SubkeyRefHandler = std::unique_ptr<struct _gpgme_subkey,
std::function<void(gpgme_subkey_t)>>;
SubkeyRefHandler _subkey_ref = nullptr;
};
-} // namespace GpgFrontend
+} // namespace GpgFrontend
-#endif // GPGFRONTEND_GPGSUBKEY_H
+#endif // GPGFRONTEND_GPGSUBKEY_H
diff --git a/src/gpg/result_analyse/ResultAnalyse.cpp b/src/gpg/result_analyse/ResultAnalyse.cpp
index 44e32e7b..3005ea1f 100644
--- a/src/gpg/result_analyse/ResultAnalyse.cpp
+++ b/src/gpg/result_analyse/ResultAnalyse.cpp
@@ -24,15 +24,11 @@
#include "gpg/result_analyse/ResultAnalyse.h"
-const std::string GpgFrontend::ResultAnalyse::getResultReport() {
- if (!analysed_)
- do_analyse();
+const std::string GpgFrontend::ResultAnalyse::getResultReport() const {
return stream.str();
}
-int GpgFrontend::ResultAnalyse::getStatus() {
- if (!analysed_)
- do_analyse();
+int GpgFrontend::ResultAnalyse::getStatus() const {
return status;
}
diff --git a/src/gpg/result_analyse/ResultAnalyse.h b/src/gpg/result_analyse/ResultAnalyse.h
index d2cf0037..d187cd8a 100644
--- a/src/gpg/result_analyse/ResultAnalyse.h
+++ b/src/gpg/result_analyse/ResultAnalyse.h
@@ -31,16 +31,16 @@
namespace GpgFrontend {
class ResultAnalyse {
-public:
+ public:
ResultAnalyse() = default;
- [[nodiscard]] const std::string getResultReport();
+ [[nodiscard]] const std::string getResultReport() const;
- [[nodiscard]] int getStatus();
+ [[nodiscard]] int getStatus() const;
void analyse();
-protected:
+ protected:
virtual void do_analyse() = 0;
std::stringstream stream;
@@ -52,6 +52,6 @@ protected:
void setStatus(int mStatus);
};
-} // namespace GpgFrontend
+} // namespace GpgFrontend
-#endif // GPGFRONTEND_RESULTANALYSE_H
+#endif // GPGFRONTEND_RESULTANALYSE_H
diff --git a/src/main.cpp b/src/main.cpp
index 831a6121..1222adf3 100644
--- a/src/main.cpp
+++ b/src/main.cpp
@@ -22,95 +22,96 @@
*
*/
-#include "MainWindow.h"
#include "GpgFrontendBuildInfo.h"
+#include "ui/MainWindow.h"
-int main(int argc, char *argv[]) {
+int main(int argc, char* argv[]) {
+ Q_INIT_RESOURCE(gpgfrontend);
- Q_INIT_RESOURCE(gpgfrontend);
+ QApplication app(argc, argv);
- QApplication app(argc, argv);
+ // get application path
+ QString appPath = qApp->applicationDirPath();
- // get application path
- QString appPath = qApp->applicationDirPath();
+ QApplication::setApplicationVersion(BUILD_VERSION);
+ QApplication::setApplicationName(PROJECT_NAME);
- QApplication::setApplicationVersion(BUILD_VERSION);
- QApplication::setApplicationName(PROJECT_NAME);
+ // dont show icons in menus
+ QApplication::setAttribute(Qt::AA_DontShowIconsInMenus);
- // dont show icons in menus
- QApplication::setAttribute(Qt::AA_DontShowIconsInMenus);
-
- // unicode in source
- QTextCodec::setCodecForLocale(QTextCodec::codecForName("utf-8"));
+ // unicode in source
+ QTextCodec::setCodecForLocale(QTextCodec::codecForName("utf-8"));
#ifdef WINDOWS
- // css
- QFile file(RESOURCE_DIR(qApp->applicationDirPath()) + "/css/default.qss");
- file.open(QFile::ReadOnly);
- QString styleSheet = QLatin1String(file.readAll());
- qApp->setStyleSheet(styleSheet);
- file.close();
+ // css
+ QFile file(RESOURCE_DIR(qApp->applicationDirPath()) + "/css/default.qss");
+ file.open(QFile::ReadOnly);
+ QString styleSheet = QLatin1String(file.readAll());
+ qApp->setStyleSheet(styleSheet);
+ file.close();
#endif
- /**
- * internationalisation. loop to restart mainwindow
- * with changed translation when settings change.
- */
- if(!QDir(RESOURCE_DIR(appPath) + "/conf").exists()) {
- QDir().mkdir(RESOURCE_DIR(appPath) + "/conf");
+ /**
+ * internationalisation. loop to restart mainwindow
+ * with changed translation when settings change.
+ */
+ if (!QDir(RESOURCE_DIR(appPath) + "/conf").exists()) {
+ QDir().mkdir(RESOURCE_DIR(appPath) + "/conf");
+ }
+ QSettings::setDefaultFormat(QSettings::IniFormat);
+ QSettings settings(RESOURCE_DIR(appPath) + "/conf/gpgfrontend.ini",
+ QSettings::IniFormat);
+ QTranslator translator, translator2;
+ int return_from_event_loop_code;
+
+ qDebug() << "Resource Directory" << RESOURCE_DIR(appPath);
+
+ do {
+ QApplication::removeTranslator(&translator);
+ QApplication::removeTranslator(&translator2);
+
+ QString lang =
+ settings.value("int/lang", QLocale::system().name()).toString();
+ if (lang.isEmpty()) {
+ lang = QLocale::system().name();
}
- QSettings::setDefaultFormat(QSettings::IniFormat);
- QSettings settings(RESOURCE_DIR(appPath) + "/conf/gpgfrontend.ini", QSettings::IniFormat);
- QTranslator translator, translator2;
- int return_from_event_loop_code;
-
- qDebug() << "Resource Directory" << RESOURCE_DIR(appPath);
-
- do {
- QApplication::removeTranslator(&translator);
- QApplication::removeTranslator(&translator2);
-
- QString lang = settings.value("int/lang", QLocale::system().name()).toString();
- if (lang.isEmpty()) {
- lang = QLocale::system().name();
- }
- qDebug() << "Language set" << lang;
- translator.load(RESOURCE_DIR(appPath) + "/ts/" + "gpgfrontend_" + lang);
- qDebug() << "Translator" << translator.filePath();
- QApplication::installTranslator(&translator);
-
- // set qt translations
- translator2.load(RESOURCE_DIR(appPath) + "/ts/qt_" + lang);
- qDebug() << "Translator2" << translator2.filePath();
- QApplication::installTranslator(&translator2);
-
- QApplication::setQuitOnLastWindowClosed(true);
+ qDebug() << "Language set" << lang;
+ translator.load(RESOURCE_DIR(appPath) + "/ts/" + "gpgfrontend_" + lang);
+ qDebug() << "Translator" << translator.filePath();
+ QApplication::installTranslator(&translator);
+ // set qt translations
+ translator2.load(RESOURCE_DIR(appPath) + "/ts/qt_" + lang);
+ qDebug() << "Translator2" << translator2.filePath();
+ QApplication::installTranslator(&translator2);
- /**
- * The function `gpgme_check_version' must be called before any other
- * function in the library, because it initializes the thread support
- * subsystem in GPGME. (from the info page) */
- gpgme_check_version(nullptr);
+ QApplication::setQuitOnLastWindowClosed(true);
- // the locale set here is used for the other setlocale calls which have nullptr
- // -> nullptr means use default, which is configured here
- setlocale(LC_ALL, settings.value("int/lang").toLocale().name().toUtf8().constData());
-
- /** set locale, because tests do also */
- gpgme_set_locale(nullptr, LC_CTYPE, setlocale(LC_CTYPE, nullptr));
- //qDebug() << "Locale set to" << LC_CTYPE << " - " << setlocale(LC_CTYPE, nullptr);
- #ifndef _WIN32
- gpgme_set_locale(nullptr, LC_MESSAGES, setlocale(LC_MESSAGES, nullptr));
- #endif
+ /**
+ * The function `gpgme_check_version' must be called before any other
+ * function in the library, because it initializes the thread support
+ * subsystem in GPGME. (from the info page) */
+ gpgme_check_version(nullptr);
+
+ // the locale set here is used for the other setlocale calls which have
+ // nullptr
+ // -> nullptr means use default, which is configured here
+ setlocale(
+ LC_ALL,
+ settings.value("int/lang").toLocale().name().toUtf8().constData());
+
+ /** set locale, because tests do also */
+ gpgme_set_locale(nullptr, LC_CTYPE, setlocale(LC_CTYPE, nullptr));
+// qDebug() << "Locale set to" << LC_CTYPE << " - " << setlocale(LC_CTYPE,
+// nullptr);
+#ifndef _WIN32
+ gpgme_set_locale(nullptr, LC_MESSAGES, setlocale(LC_MESSAGES, nullptr));
+#endif
- MainWindow window;
- return_from_event_loop_code = QApplication::exec();
+ MainWindow window;
+ return_from_event_loop_code = QApplication::exec();
- } while (return_from_event_loop_code == RESTART_CODE);
+ } while (return_from_event_loop_code == RESTART_CODE);
- return return_from_event_loop_code;
+ return return_from_event_loop_code;
}
-
-
-
diff --git a/src/ui/CMakeLists.txt b/src/ui/CMakeLists.txt
index 170e7454..ecf998d6 100644
--- a/src/ui/CMakeLists.txt
+++ b/src/ui/CMakeLists.txt
@@ -6,7 +6,7 @@ aux_source_directory(./main_window UI_SOURCE)
aux_source_directory(./help UI_SOURCE)
aux_source_directory(./settings UI_SOURCE)
-add_library(gpgfrontend-ui STATIC ${UI_SOURCE})
+add_library(gpgfrontend-ui STATIC ${UI_SOURCE} GpgFrontendUI.h)
target_link_libraries(gpgfrontend-ui
Qt5::Network Qt5::PrintSupport Qt5::Widgets Qt5::Test Qt5::Core) \ No newline at end of file
diff --git a/src/ui/FileEncryptionDialog.cpp b/src/ui/FileEncryptionDialog.cpp
index 55c8e5f0..d141df1e 100755
--- a/src/ui/FileEncryptionDialog.cpp
+++ b/src/ui/FileEncryptionDialog.cpp
@@ -24,266 +24,258 @@
#include "ui/FileEncryptionDialog.h"
-FileEncryptionDialog::FileEncryptionDialog(GpgFrontend::GpgContext *ctx, QStringList keyList, DialogAction action,
- QWidget *parent)
- : QDialog(parent), mAction(action), mCtx(ctx){
-
- if (mAction == Decrypt) {
- setWindowTitle(tr("Decrypt File"));
- } else if (mAction == Encrypt) {
- setWindowTitle(tr("Encrypt File"));
- } else if (mAction == Sign) {
- setWindowTitle(tr("Sign File"));
- } else if (mAction == Verify) {
- setWindowTitle(tr("Verify File"));
- }
-
- setModal(true);
-
- auto *buttonBox = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel);
- connect(buttonBox, SIGNAL(accepted()), this, SLOT(slotExecuteAction()));
- connect(buttonBox, SIGNAL(rejected()), this, SLOT(reject()));
-
- auto *groupBox1 = new QGroupBox(tr("Input Parameters"));
-
- /* Setup input & Outputfileselection*/
- inputFileEdit = new QLineEdit();
- auto *fb1 = new QPushButton("Select");
- connect(fb1, SIGNAL(clicked()), this, SLOT(slotSelectInputFile()));
- auto *fl1 = new QLabel(tr("Target File"));
- fl1->setBuddy(inputFileEdit);
-
- outputFileEdit = new QLineEdit();
- auto *fb2 = new QPushButton("Select");
- connect(fb2, SIGNAL(clicked()), this, SLOT(slotSelectOutputFile()));
- auto *fl2 = new QLabel(tr("Output File"));
- fl2->setBuddy(outputFileEdit);
-
- auto *gLayout = new QGridLayout();
- gLayout->addWidget(fl1, 0, 0);
- gLayout->addWidget(inputFileEdit, 0, 1);
- gLayout->addWidget(fb1, 0, 2);
- signFileEdit = new QLineEdit();
- // verify does not need outfile, but signature file
- if (mAction != Verify) {
- gLayout->addWidget(fl2, 1, 0);
- gLayout->addWidget(outputFileEdit, 1, 1);
- gLayout->addWidget(fb2, 1, 2);
- } else {
- auto *sfb1 = new QPushButton("Select");
- connect(sfb1, SIGNAL(clicked()), this, SLOT(slotSelectSignFile()));
- auto *sfl1 = new QLabel(tr("Signature File(.sig) Path"));
- sfl1->setBuddy(signFileEdit);
-
- gLayout->addWidget(sfl1, 1, 0);
- gLayout->addWidget(signFileEdit, 1, 1);
- gLayout->addWidget(sfb1, 1, 2);
- }
- groupBox1->setLayout(gLayout);
-
- /*Setup KeyList*/
- mKeyList = new KeyList(mCtx, KeyListRow::ONLY_SECRET_KEY,
- KeyListColumn::NAME | KeyListColumn::EmailAddress | KeyListColumn::Usage);
- if(mAction == Verify)
- mKeyList->setFilter([](const GpgKey &key) -> bool {
- if(key.disabled || key.expired || key.revoked) return false;
- else return true;
- });
-
- if(mAction == Encrypt)
- mKeyList->setFilter([](const GpgKey &key) -> bool {
- if(!GpgFrontend::GpgContext::checkIfKeyCanEncr(key)) return false;
- else return true;
- });
-
- if(mAction == Sign)
- mKeyList->setFilter([](const GpgKey &key) -> bool {
- if(!GpgFrontend::GpgContext::checkIfKeyCanSign(key)) return false;
- else return true;
- });
-
- if(mAction == Decrypt)
- mKeyList->setDisabled(true);
-
- mKeyList->slotRefresh();
- mKeyList->setChecked(&keyList);
-
- statusLabel = new QLabel();
- statusLabel->setStyleSheet("QLabel {color: red;}");
-
- auto *vbox2 = new QVBoxLayout();
- vbox2->addWidget(groupBox1);
- vbox2->addWidget(mKeyList);
- vbox2->addWidget(statusLabel);
- vbox2->addWidget(buttonBox);
- vbox2->addStretch(0);
- setLayout(vbox2);
-
- this->setMinimumWidth(480);
- this->show();
-
+#include "gpg/function/BasicOperator.h"
+#include "gpg/function/GpgKeyGetter.h"
+
+namespace GpgFrontend::UI {
+FileEncryptionDialog::FileEncryptionDialog(KeyIdArgsListPtr keyList,
+ DialogAction action,
+ QWidget* parent)
+ : QDialog(parent), mAction(action) {
+ if (mAction == Decrypt) {
+ setWindowTitle(tr("Decrypt File"));
+ } else if (mAction == Encrypt) {
+ setWindowTitle(tr("Encrypt File"));
+ } else if (mAction == Sign) {
+ setWindowTitle(tr("Sign File"));
+ } else if (mAction == Verify) {
+ setWindowTitle(tr("Verify File"));
+ }
+
+ setModal(true);
+
+ auto* buttonBox =
+ new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel);
+ connect(buttonBox, SIGNAL(accepted()), this, SLOT(slotExecuteAction()));
+ connect(buttonBox, SIGNAL(rejected()), this, SLOT(reject()));
+
+ auto* groupBox1 = new QGroupBox(tr("Input Parameters"));
+
+ /* Setup input & Outputfileselection*/
+ inputFileEdit = new QLineEdit();
+ auto* fb1 = new QPushButton("Select");
+ connect(fb1, SIGNAL(clicked()), this, SLOT(slotSelectInputFile()));
+ auto* fl1 = new QLabel(tr("Target File"));
+ fl1->setBuddy(inputFileEdit);
+
+ outputFileEdit = new QLineEdit();
+ auto* fb2 = new QPushButton("Select");
+ connect(fb2, SIGNAL(clicked()), this, SLOT(slotSelectOutputFile()));
+ auto* fl2 = new QLabel(tr("Output File"));
+ fl2->setBuddy(outputFileEdit);
+
+ auto* gLayout = new QGridLayout();
+ gLayout->addWidget(fl1, 0, 0);
+ gLayout->addWidget(inputFileEdit, 0, 1);
+ gLayout->addWidget(fb1, 0, 2);
+ signFileEdit = new QLineEdit();
+ // verify does not need outfile, but signature file
+ if (mAction != Verify) {
+ gLayout->addWidget(fl2, 1, 0);
+ gLayout->addWidget(outputFileEdit, 1, 1);
+ gLayout->addWidget(fb2, 1, 2);
+ } else {
+ auto* sfb1 = new QPushButton("Select");
+ connect(sfb1, SIGNAL(clicked()), this, SLOT(slotSelectSignFile()));
+ auto* sfl1 = new QLabel(tr("Signature File(.sig) Path"));
+ sfl1->setBuddy(signFileEdit);
+
+ gLayout->addWidget(sfl1, 1, 0);
+ gLayout->addWidget(signFileEdit, 1, 1);
+ gLayout->addWidget(sfb1, 1, 2);
+ }
+ groupBox1->setLayout(gLayout);
+
+ /*Setup KeyList*/
+ mKeyList = new KeyList(
+ KeyListRow::ONLY_SECRET_KEY,
+ KeyListColumn::NAME | KeyListColumn::EmailAddress | KeyListColumn::Usage);
+ if (mAction == Verify)
+ mKeyList->setFilter([](const GpgKey& key) -> bool {
+ if (key.disabled() || key.expired() || key.revoked())
+ return false;
+ else
+ return true;
+ });
+
+ if (mAction == Encrypt)
+ mKeyList->setFilter([](const GpgKey& key) -> bool {
+ if (!key.CanEncrActual())
+ return false;
+ else
+ return true;
+ });
+
+ if (mAction == Sign)
+ mKeyList->setFilter([](const GpgKey& key) -> bool {
+ if (!key.CanSignActual())
+ return false;
+ else
+ return true;
+ });
+
+ if (mAction == Decrypt)
+ mKeyList->setDisabled(true);
+
+ mKeyList->slotRefresh();
+ mKeyList->setChecked(keyList);
+
+ statusLabel = new QLabel();
+ statusLabel->setStyleSheet("QLabel {color: red;}");
+
+ auto* vbox2 = new QVBoxLayout();
+ vbox2->addWidget(groupBox1);
+ vbox2->addWidget(mKeyList);
+ vbox2->addWidget(statusLabel);
+ vbox2->addWidget(buttonBox);
+ vbox2->addStretch(0);
+ setLayout(vbox2);
+
+ this->setMinimumWidth(480);
+ this->show();
}
void FileEncryptionDialog::slotSelectInputFile() {
- QString path = "";
- if (inputFileEdit->text().size() > 0) {
- path = QFileInfo(inputFileEdit->text()).absolutePath();
- }
-
-// QString infileName = QFileDialog::getOpenFileName(this, tr("Open File"), path, tr("Files") + tr("All Files (*)"));
- QString infileName = QFileDialog::getOpenFileName(this, tr("Open File"), path);
- inputFileEdit->setText(infileName);
-
- // try to find a matching output-filename, if not yet done
- if (!infileName.isEmpty()
- && outputFileEdit->text().size() == 0
- && signFileEdit->text().size() == 0) {
- if (mAction == Encrypt) {
- outputFileEdit->setText(infileName + ".asc");
- } else if (mAction == Sign) {
- outputFileEdit->setText(infileName + ".sig");
- } else if (mAction == Verify) {
- signFileEdit->setText(infileName + ".sig");
- } else {
- if (infileName.endsWith(".asc", Qt::CaseInsensitive)) {
- QString ofn = infileName;
- ofn.chop(4);
- outputFileEdit->setText(ofn);
- } else {
- outputFileEdit->setText(infileName + ".out");
- }
- }
+ QString path = "";
+ if (inputFileEdit->text().size() > 0) {
+ path = QFileInfo(inputFileEdit->text()).absolutePath();
+ }
+
+ // QString infileName = QFileDialog::getOpenFileName(this, tr("Open File"),
+ // path, tr("Files") + tr("All Files (*)"));
+ QString infileName =
+ QFileDialog::getOpenFileName(this, tr("Open File"), path);
+ inputFileEdit->setText(infileName);
+
+ // try to find a matching output-filename, if not yet done
+ if (!infileName.isEmpty() && outputFileEdit->text().size() == 0 &&
+ signFileEdit->text().size() == 0) {
+ if (mAction == Encrypt) {
+ outputFileEdit->setText(infileName + ".asc");
+ } else if (mAction == Sign) {
+ outputFileEdit->setText(infileName + ".sig");
+ } else if (mAction == Verify) {
+ signFileEdit->setText(infileName + ".sig");
+ } else {
+ if (infileName.endsWith(".asc", Qt::CaseInsensitive)) {
+ QString ofn = infileName;
+ ofn.chop(4);
+ outputFileEdit->setText(ofn);
+ } else {
+ outputFileEdit->setText(infileName + ".out");
+ }
}
+ }
}
void FileEncryptionDialog::slotSelectOutputFile() {
- QString path = "";
- if (outputFileEdit->text().size() > 0) {
- path = QFileInfo(outputFileEdit->text()).absolutePath();
- }
-
- QString outfileName = QFileDialog::getSaveFileName(this, tr("Save File"), path, nullptr, nullptr,
- QFileDialog::DontConfirmOverwrite);
- outputFileEdit->setText(outfileName);
-
+ QString path = "";
+ if (outputFileEdit->text().size() > 0) {
+ path = QFileInfo(outputFileEdit->text()).absolutePath();
+ }
+
+ QString outfileName =
+ QFileDialog::getSaveFileName(this, tr("Save File"), path, nullptr,
+ nullptr, QFileDialog::DontConfirmOverwrite);
+ outputFileEdit->setText(outfileName);
}
void FileEncryptionDialog::slotSelectSignFile() {
- QString path = "";
- if (signFileEdit->text().size() > 0) {
- path = QFileInfo(signFileEdit->text()).absolutePath();
- }
-
- QString signfileName = QFileDialog::getSaveFileName(this, tr("Open File"), path, nullptr, nullptr,
- QFileDialog::DontConfirmOverwrite);
- signFileEdit->setText(signfileName);
-
- if (inputFileEdit->text().size() == 0 && signfileName.endsWith(".sig", Qt::CaseInsensitive)) {
- QString sfn = signfileName;
- sfn.chop(4);
- inputFileEdit->setText(sfn);
- }
-
+ QString path = "";
+ if (signFileEdit->text().size() > 0) {
+ path = QFileInfo(signFileEdit->text()).absolutePath();
+ }
+
+ QString signfileName =
+ QFileDialog::getSaveFileName(this, tr("Open File"), path, nullptr,
+ nullptr, QFileDialog::DontConfirmOverwrite);
+ signFileEdit->setText(signfileName);
+
+ if (inputFileEdit->text().size() == 0 &&
+ signfileName.endsWith(".sig", Qt::CaseInsensitive)) {
+ QString sfn = signfileName;
+ sfn.chop(4);
+ inputFileEdit->setText(sfn);
+ }
}
void FileEncryptionDialog::slotExecuteAction() {
-
- QFile infile;
- infile.setFileName(inputFileEdit->text());
- if (!infile.open(QIODevice::ReadOnly)) {
- statusLabel->setText(tr("Couldn't open file"));
- inputFileEdit->setStyleSheet("QLineEdit { background: yellow }");
- return;
- }
-
- QByteArray inBuffer = infile.readAll();
- auto *outBuffer = new QByteArray();
- infile.close();
-
- QVector<GpgKey> keys;
- mKeyList->getCheckedKeys(keys);
-
- qDebug() << "slotExecuteAction" << mAction;
-
- if (mAction == Encrypt) {
- qDebug() << "Action Encrypt";
- gpgme_error_t err = mCtx->encrypt(keys, inBuffer, outBuffer, nullptr);
- if (gpgme_err_code(err) != GPG_ERR_NO_ERROR) {
- qDebug() << "Error" << gpgme_strerror(err);
- QMessageBox::warning(this, tr("Error"),
- tr("Error Occurred During Encryption"));
- return;
- }
+ QFile infile;
+ infile.setFileName(inputFileEdit->text());
+ if (!infile.open(QIODevice::ReadOnly)) {
+ statusLabel->setText(tr("Couldn't open file"));
+ inputFileEdit->setStyleSheet("QLineEdit { background: yellow }");
+ return;
+ }
+ auto in_data = read_all_data_in_file(inputFileEdit->text().toStdString());
+ auto out_data = std::make_unique<ByteArray>();
+
+ auto key_ids = mKeyList->getChecked();
+ auto keys = std::vector<GpgKey>();
+ for (const auto& key_id : *key_ids)
+ keys.push_back(GpgKeyGetter::GetInstance().GetKey(key_id));
+
+ if (mAction == Encrypt) {
+ qDebug() << "Action Encrypt";
+ GpgEncrResult result = nullptr;
+ gpgme_error_t err = BasicOperator::GetInstance().Encrypt(
+ std::move(keys), in_data, out_data, result);
+ if (gpgme_err_code(err) != GPG_ERR_NO_ERROR) {
+ qDebug() << "Error" << gpgme_strerror(err);
+
+ QMessageBox::warning(this, tr("Error"),
+ tr("Error Occurred During Encryption"));
+ return;
}
-
- if (mAction == Decrypt) {
- qDebug() << "Action Decrypt";
- gpgme_error_t err = mCtx->decrypt(inBuffer, outBuffer, nullptr);
- if (gpgme_err_code(err) != GPG_ERR_NO_ERROR) {
- qDebug() << "Error" << gpgme_strerror(err);
- QMessageBox::warning(this, tr("Error"),
- tr("Error Occurred During Decryption"));
- return;
- }
+ }
+
+ else if (mAction == Decrypt) {
+ qDebug() << "Action Decrypt";
+ GpgDecrResult result = nullptr;
+ gpgme_error_t err =
+ BasicOperator::GetInstance().Decrypt(in_data, out_data, result);
+ if (gpgme_err_code(err) != GPG_ERR_NO_ERROR) {
+ qDebug() << "Error" << gpgme_strerror(err);
+ QMessageBox::warning(this, tr("Error"),
+ tr("Error Occurred During Decryption"));
+ return;
}
-
- if (mAction == Sign) {
- qDebug() << "Action Sign";
- gpgme_error_t err = mCtx->sign(keys, inBuffer, outBuffer, GPGME_SIG_MODE_DETACH, nullptr);
- if (gpgme_err_code(err) != GPG_ERR_NO_ERROR) {
- qDebug() << "Error" << gpgme_strerror(err);
- QMessageBox::warning(this, tr("Error"),
- tr("Error Occurred During Signature"));
- return;
- }
+ }
+
+ else if (mAction == Sign) {
+ qDebug() << "Action Sign";
+ GpgSignResult result = nullptr;
+ gpgme_error_t err = BasicOperator::GetInstance().Sign(
+ std::move(keys), in_data, out_data, GPGME_SIG_MODE_DETACH, result);
+ if (gpgme_err_code(err) != GPG_ERR_NO_ERROR) {
+ qDebug() << "Error" << gpgme_strerror(err);
+ QMessageBox::warning(this, tr("Error"),
+ tr("Error Occurred During Signature"));
+ return;
}
+ }
- if (mAction == Verify) {
- QFile sign_file;
- sign_file.setFileName(signFileEdit->text());
- if (!sign_file.open(QIODevice::ReadOnly)) {
- statusLabel->setText(tr("Couldn't open file"));
- signFileEdit->setStyleSheet("QLineEdit { background: yellow }");
- return;
- }
- auto signBuffer = sign_file.readAll();
- gpgme_verify_result_t result;
- auto error = mCtx->verify(&inBuffer, &signBuffer, &result);
- new VerifyDetailsDialog(this, mCtx, mKeyList, error, result);
- return;
- }
+ if (mAction == Verify) {
+ auto sign_data = std::make_unique<ByteArray>(
+ read_all_data_in_file(signFileEdit->text().toStdString()));
+ GpgVerifyResult result = nullptr;
+ auto error =
+ BasicOperator::GetInstance().Verify(in_data, sign_data, result);
+ new VerifyDetailsDialog(this, mKeyList, error, std::move(result));
+ return;
+ }
- QFile outfile(outputFileEdit->text());
- if (outfile.exists()) {
- QMessageBox::StandardButton ret;
- ret = QMessageBox::warning(this, tr("File"),
- tr("File exists! Do you want to overwrite it?"),
- QMessageBox::Ok | QMessageBox::Cancel);
- if (ret == QMessageBox::Cancel) {
- return;
- }
- }
+ write_buffer_to_file(outputFileEdit->text().toStdString(), *out_data);
- if (!outfile.open(QFile::WriteOnly)) {
- QMessageBox::warning(this, tr("File"),
- tr("Cannot write file %1:\n%2.")
- .arg(outputFileEdit->text())
- .arg(outfile.errorString()));
- return;
- }
-
- QDataStream out(&outfile);
- out.writeRawData(outBuffer->data(), outBuffer->length());
- outfile.close();
- QMessageBox::information(nullptr, "Done", "Output saved to " + outputFileEdit->text());
-
- accept();
+ accept();
}
void FileEncryptionDialog::slotShowKeyList() {
- mKeyList->show();
+ mKeyList->show();
}
void FileEncryptionDialog::slotHideKeyList() {
- mKeyList->hide();
+ mKeyList->hide();
}
+
+} // namespace GpgFrontend::UI
diff --git a/include/ui/FileEncryptionDialog.h b/src/ui/FileEncryptionDialog.h
index da1d48e4..a3e56564 100755
--- a/include/ui/FileEncryptionDialog.h
+++ b/src/ui/FileEncryptionDialog.h
@@ -25,10 +25,12 @@
#ifndef __FILEENCRYPTIONDIALOG_H__
#define __FILEENCRYPTIONDIALOG_H__
+#include "VerifyDetailsDialog.h"
#include "gpg/GpgContext.h"
+#include "ui/GpgFrontendUI.h"
#include "ui/widgets/KeyList.h"
-#include "VerifyDetailsDialog.h"
+namespace GpgFrontend::UI {
/**
* @brief
@@ -36,81 +38,78 @@
* @class FileEncryptionDialog fileencryptiondialog.h "fileencryptiondialog.h"
*/
class FileEncryptionDialog : public QDialog {
-Q_OBJECT
-
-public:
-
- enum DialogAction {
- Encrypt,
- Decrypt,
- Sign,
- Verify
- };
-
- /**
- * @brief
- *
- * @fn FileEncryptionDialog
- * @param ctx
- * @param keyList
- * @param parent
- */
- FileEncryptionDialog(GpgFrontend::GpgContext *ctx, QStringList keyList, DialogAction action, QWidget *parent = nullptr);
-
-public slots:
-
- /**
- * @details
- *
- * @fn selectInputFile
- */
- void slotSelectInputFile();
-
- /**
- * @brief
- *
- * @fn selectOutputFile
- */
- void slotSelectOutputFile();
-
- /**
- * @brief
- *
- * @fn selectSignFile
- */
- void slotSelectSignFile();
-
- /**
- * @brief
- *
- * @fn executeAction
- */
- void slotExecuteAction();
-
- /**
- * @brief
- *
- * @fn hideKeyList
- */
- void slotHideKeyList();
-
- /**
- * @brief
- *
- * @fn showKeyList
- */
- void slotShowKeyList();
-
-private:
- QLineEdit *outputFileEdit;
- QLineEdit *inputFileEdit;
- QLineEdit *signFileEdit;
- DialogAction mAction;
- QLabel *statusLabel;
-protected:
- GpgFrontend::GpgContext *mCtx;
- KeyList *mKeyList;
-
+ Q_OBJECT
+
+ public:
+ enum DialogAction { Encrypt, Decrypt, Sign, Verify };
+
+ /**
+ * @brief
+ *
+ * @fn FileEncryptionDialog
+ * @param ctx
+ * @param keyList
+ * @param parent
+ */
+ FileEncryptionDialog(KeyIdArgsListPtr keyList,
+ DialogAction action,
+ QWidget* parent = nullptr);
+
+ public slots:
+
+ /**
+ * @details
+ *
+ * @fn selectInputFile
+ */
+ void slotSelectInputFile();
+
+ /**
+ * @brief
+ *
+ * @fn selectOutputFile
+ */
+ void slotSelectOutputFile();
+
+ /**
+ * @brief
+ *
+ * @fn selectSignFile
+ */
+ void slotSelectSignFile();
+
+ /**
+ * @brief
+ *
+ * @fn executeAction
+ */
+ void slotExecuteAction();
+
+ /**
+ * @brief
+ *
+ * @fn hideKeyList
+ */
+ void slotHideKeyList();
+
+ /**
+ * @brief
+ *
+ * @fn showKeyList
+ */
+ void slotShowKeyList();
+
+ private:
+ QLineEdit* outputFileEdit;
+ QLineEdit* inputFileEdit;
+ QLineEdit* signFileEdit;
+ DialogAction mAction;
+ QLabel* statusLabel;
+
+ protected:
+ KeyList* mKeyList;
};
-#endif // __FILEENCRYPTIONDIALOG_H__
+} // namespace GpgFrontend::UI
+
+#endif // __FILEENCRYPTIONDIALOG_H__
diff --git a/src/ui/FindWidget.cpp b/src/ui/FindWidget.cpp
index fce62223..f9b92685 100644
--- a/src/ui/FindWidget.cpp
+++ b/src/ui/FindWidget.cpp
@@ -24,135 +24,139 @@
#include "ui/FindWidget.h"
-FindWidget::FindWidget(QWidget *parent, QTextEdit *edit) :
- QWidget(parent)
-{
- mTextpage = edit;
- findEdit = new QLineEdit(this);
- auto *closeButton= new QPushButton(this->style()->standardIcon(QStyle::SP_TitleBarCloseButton),"",this);
- auto *nextButton= new QPushButton(QIcon(":button_next.png"), "");
- auto *previousButton= new QPushButton(QIcon(":button_previous.png"), "");
-
- auto *notificationWidgetLayout = new QHBoxLayout(this);
- notificationWidgetLayout->setContentsMargins(10,0,0,0);
- notificationWidgetLayout->addWidget(new QLabel(tr("Find:")));
- notificationWidgetLayout->addWidget(findEdit,2);
- notificationWidgetLayout->addWidget(nextButton);
- notificationWidgetLayout->addWidget(previousButton);
- notificationWidgetLayout->addWidget(closeButton);
-
- this->setLayout(notificationWidgetLayout);
- connect(findEdit,SIGNAL(textEdited(QString)),this,SLOT(slotFind()));
- connect(findEdit,SIGNAL(returnPressed()),this,SLOT(slotFindNext()));
- connect(nextButton,SIGNAL(clicked()),this,SLOT(slotFindNext()));
- connect(previousButton,SIGNAL(clicked()),this,SLOT(slotFindPrevious()));
- connect(closeButton,SIGNAL(clicked()),this,SLOT(slotClose()));
-
- // The timer is necessary for setting the focus
- QTimer::singleShot(0, findEdit, SLOT(setFocus()));
+namespace GpgFrontend::UI {
+
+FindWidget::FindWidget(QWidget* parent, QTextEdit* edit) : QWidget(parent) {
+ mTextpage = edit;
+ findEdit = new QLineEdit(this);
+ auto* closeButton = new QPushButton(
+ this->style()->standardIcon(QStyle::SP_TitleBarCloseButton), "", this);
+ auto* nextButton = new QPushButton(QIcon(":button_next.png"), "");
+ auto* previousButton = new QPushButton(QIcon(":button_previous.png"), "");
+
+ auto* notificationWidgetLayout = new QHBoxLayout(this);
+ notificationWidgetLayout->setContentsMargins(10, 0, 0, 0);
+ notificationWidgetLayout->addWidget(new QLabel(tr("Find:")));
+ notificationWidgetLayout->addWidget(findEdit, 2);
+ notificationWidgetLayout->addWidget(nextButton);
+ notificationWidgetLayout->addWidget(previousButton);
+ notificationWidgetLayout->addWidget(closeButton);
+
+ this->setLayout(notificationWidgetLayout);
+ connect(findEdit, SIGNAL(textEdited(QString)), this, SLOT(slotFind()));
+ connect(findEdit, SIGNAL(returnPressed()), this, SLOT(slotFindNext()));
+ connect(nextButton, SIGNAL(clicked()), this, SLOT(slotFindNext()));
+ connect(previousButton, SIGNAL(clicked()), this, SLOT(slotFindPrevious()));
+ connect(closeButton, SIGNAL(clicked()), this, SLOT(slotClose()));
+
+ // The timer is necessary for setting the focus
+ QTimer::singleShot(0, findEdit, SLOT(setFocus()));
}
-void FindWidget::setBackground()
-{
- QTextCursor cursor = mTextpage->textCursor();
- // if match is found set background of QLineEdit to white, otherwise to red
- QPalette bgPalette( findEdit->palette() );
-
- if (!findEdit->text().isEmpty() && mTextpage->document()->find(findEdit->text()).position() < 0 ) {
- bgPalette.setColor( QPalette::Base, "#ececba");
- } else {
- bgPalette.setColor( QPalette::Base, Qt::white);
- }
- findEdit->setPalette(bgPalette);
+void FindWidget::setBackground() {
+ QTextCursor cursor = mTextpage->textCursor();
+ // if match is found set background of QLineEdit to white, otherwise to red
+ QPalette bgPalette(findEdit->palette());
+
+ if (!findEdit->text().isEmpty() &&
+ mTextpage->document()->find(findEdit->text()).position() < 0) {
+ bgPalette.setColor(QPalette::Base, "#ececba");
+ } else {
+ bgPalette.setColor(QPalette::Base, Qt::white);
+ }
+ findEdit->setPalette(bgPalette);
}
-void FindWidget::slotFindNext()
-{
- QTextCursor cursor = mTextpage->textCursor();
- cursor = mTextpage->document()->find(findEdit->text(), cursor, QTextDocument::FindCaseSensitively);
-
- // if end of document is reached, restart search from beginning
- if (cursor.position() == -1) {
- cursor = mTextpage->document()->find(findEdit->text(), cursor, QTextDocument::FindCaseSensitively);
- }
-
- // cursor should not stay at -1, otherwise text is not editable
- // todo: check how gedit handles this
- if(cursor.position() != -1) {
- mTextpage->setTextCursor(cursor);
- }
- this->setBackground();
+void FindWidget::slotFindNext() {
+ QTextCursor cursor = mTextpage->textCursor();
+ cursor = mTextpage->document()->find(findEdit->text(), cursor,
+ QTextDocument::FindCaseSensitively);
+
+ // if end of document is reached, restart search from beginning
+ if (cursor.position() == -1) {
+ cursor = mTextpage->document()->find(findEdit->text(), cursor,
+ QTextDocument::FindCaseSensitively);
+ }
+
+ // cursor should not stay at -1, otherwise text is not editable
+ // todo: check how gedit handles this
+ if (cursor.position() != -1) {
+ mTextpage->setTextCursor(cursor);
+ }
+ this->setBackground();
}
-void FindWidget::slotFind()
-{
- QTextCursor cursor = mTextpage->textCursor();
-
- if (cursor.anchor() == -1) {
- cursor = mTextpage->document()->find(findEdit->text(), cursor, QTextDocument::FindCaseSensitively);
- } else {
- cursor = mTextpage->document()->find(findEdit->text(), cursor.anchor(), QTextDocument::FindCaseSensitively);
- }
-
- // if end of document is reached, restart search from beginning
- if (cursor.position() == -1) {
- cursor = mTextpage->document()->find(findEdit->text(), cursor, QTextDocument::FindCaseSensitively);
- }
-
- // cursor should not stay at -1, otherwise text is not editable
- // todo: check how gedit handles this
- if(cursor.position() != -1) {
- mTextpage->setTextCursor(cursor);
- }
- this->setBackground();
+void FindWidget::slotFind() {
+ QTextCursor cursor = mTextpage->textCursor();
+
+ if (cursor.anchor() == -1) {
+ cursor = mTextpage->document()->find(findEdit->text(), cursor,
+ QTextDocument::FindCaseSensitively);
+ } else {
+ cursor = mTextpage->document()->find(findEdit->text(), cursor.anchor(),
+ QTextDocument::FindCaseSensitively);
+ }
+
+ // if end of document is reached, restart search from beginning
+ if (cursor.position() == -1) {
+ cursor = mTextpage->document()->find(findEdit->text(), cursor,
+ QTextDocument::FindCaseSensitively);
+ }
+
+ // cursor should not stay at -1, otherwise text is not editable
+ // todo: check how gedit handles this
+ if (cursor.position() != -1) {
+ mTextpage->setTextCursor(cursor);
+ }
+ this->setBackground();
}
-void FindWidget::slotFindPrevious()
-{
- QTextDocument::FindFlags flags;
- flags |= QTextDocument::FindBackward;
- flags |= QTextDocument::FindCaseSensitively;
-
- QTextCursor cursor = mTextpage->textCursor();
- cursor = mTextpage->document()->find(findEdit->text(), cursor, flags);
-
- // if begin of document is reached, restart search from end
- if (cursor.position() == -1) {
- cursor = mTextpage->document()->find(findEdit->text(), QTextCursor::End, flags);
- }
-
- // cursor should not stay at -1, otherwise text is not editable
- // todo: check how gedit handles this
- if(cursor.position() != -1) {
- mTextpage->setTextCursor(cursor);
- }
- this->setBackground();
+void FindWidget::slotFindPrevious() {
+ QTextDocument::FindFlags flags;
+ flags |= QTextDocument::FindBackward;
+ flags |= QTextDocument::FindCaseSensitively;
+
+ QTextCursor cursor = mTextpage->textCursor();
+ cursor = mTextpage->document()->find(findEdit->text(), cursor, flags);
+
+ // if begin of document is reached, restart search from end
+ if (cursor.position() == -1) {
+ cursor =
+ mTextpage->document()->find(findEdit->text(), QTextCursor::End, flags);
+ }
+
+ // cursor should not stay at -1, otherwise text is not editable
+ // todo: check how gedit handles this
+ if (cursor.position() != -1) {
+ mTextpage->setTextCursor(cursor);
+ }
+ this->setBackground();
}
-void FindWidget::keyPressEvent( QKeyEvent* e )
-{
- switch ( e->key() )
- {
+void FindWidget::keyPressEvent(QKeyEvent* e) {
+ switch (e->key()) {
case Qt::Key_Escape:
- this->slotClose();
- break;
+ this->slotClose();
+ break;
case Qt::Key_F3:
- if (e->modifiers() & Qt::ShiftModifier) {
- this->slotFindPrevious();
- } else {
- this->slotFindNext();
- }
- break;
- }
+ if (e->modifiers() & Qt::ShiftModifier) {
+ this->slotFindPrevious();
+ } else {
+ this->slotFindNext();
+ }
+ break;
+ }
}
void FindWidget::slotClose() {
- QTextCursor cursor = mTextpage->textCursor();
-
- if ( cursor.position() == -1) {
- cursor.setPosition(0);
- mTextpage->setTextCursor(cursor);
- }
- mTextpage->setFocus();
- close();
+ QTextCursor cursor = mTextpage->textCursor();
+
+ if (cursor.position() == -1) {
+ cursor.setPosition(0);
+ mTextpage->setTextCursor(cursor);
+ }
+ mTextpage->setFocus();
+ close();
}
+
+} // namespace GpgFrontend::UI
diff --git a/include/ui/FindWidget.h b/src/ui/FindWidget.h
index 1142b649..f57f95a6 100644
--- a/include/ui/FindWidget.h
+++ b/src/ui/FindWidget.h
@@ -25,43 +25,48 @@
#ifndef FINDWIDGET_H
#define FINDWIDGET_H
+#include "ui/GpgFrontendUI.h"
#include "ui/widgets/EditorPage.h"
+namespace GpgFrontend::UI {
+
/**
* @brief Class for handling the find widget shown at buttom of a textedit-page
*/
class FindWidget : public QWidget {
-Q_OBJECT
+ Q_OBJECT
-public:
- /**
- * @brief
- *
- * @param parent The parent widget
- */
- explicit FindWidget(QWidget *parent, QTextEdit *edit);
+ public:
+ /**
+ * @brief
+ *
+ * @param parent The parent widget
+ */
+ explicit FindWidget(QWidget* parent, QTextEdit* edit);
-private:
- void keyPressEvent(QKeyEvent *e) override;
+ private:
+ void keyPressEvent(QKeyEvent* e) override;
- /**
- * @details Set background of findEdit to red, if no match is found (Documents textcursor position equals -1),
- * otherwise set it to white.
- */
- void setBackground();
+ /**
+ * @details Set background of findEdit to red, if no match is found (Documents
+ * textcursor position equals -1), otherwise set it to white.
+ */
+ void setBackground();
- QTextEdit *mTextpage; /** Textedit associated to the notification */
- QLineEdit *findEdit; /** Label holding the text shown in infoBoard */
+ QTextEdit* mTextpage; /** Textedit associated to the notification */
+ QLineEdit* findEdit; /** Label holding the text shown in infoBoard */
-private slots:
+ private slots:
- void slotFindNext();
+ void slotFindNext();
- void slotFindPrevious();
+ void slotFindPrevious();
- void slotFind();
+ void slotFind();
- void slotClose();
+ void slotClose();
};
-#endif // FINDWIDGET_H
+} // namespace GpgFrontend::UI
+
+#endif // FINDWIDGET_H
diff --git a/src/ui/GpgFrontendUI.h b/src/ui/GpgFrontendUI.h
new file mode 100644
index 00000000..42d125d6
--- /dev/null
+++ b/src/ui/GpgFrontendUI.h
@@ -0,0 +1,35 @@
+/**
+ * This file is part of GPGFrontend.
+ *
+ * GPGFrontend is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Foobar is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Foobar. If not, see <https://www.gnu.org/licenses/>.
+ *
+ * The initial version of the source code is inherited from gpg4usb-team.
+ * Their source code version also complies with GNU General Public License.
+ *
+ * The source code version of this software was modified and released
+ * by Saturneric<[email protected]> starting on May 12, 2021.
+ *
+ */
+
+#ifndef GPGFRONTEND_GPGFRONTENDUI_H
+#define GPGFRONTEND_GPGFRONTENDUI_H
+
+#include <GpgFrontend.h>
+
+#include <QtCore>
+#include <QtNetwork>
+#include <QtPrintSupport>
+#include <QtWidgets>
+
+#endif // GPGFRONTEND_GPGFRONTENDUI_H
diff --git a/src/ui/KeyImportDetailDialog.cpp b/src/ui/KeyImportDetailDialog.cpp
index 8614051b..d2f33a2e 100644
--- a/src/ui/KeyImportDetailDialog.cpp
+++ b/src/ui/KeyImportDetailDialog.cpp
@@ -22,145 +22,168 @@
*
*/
-#include <ui/KeyImportDetailDialog.h>
-
-KeyImportDetailDialog::KeyImportDetailDialog(GpgFrontend::GpgContext *ctx, GpgImportInformation result, bool automatic,
- QWidget *parent)
- : QDialog(parent), mCtx(ctx), mResult(std::move(result)) {
-
- // If no key for import found, just show a message
- if (mResult.considered == 0) {
- if(automatic)
- QMessageBox::information(nullptr, tr("Key Update Details"), tr("No keys found"));
- else
- QMessageBox::information(nullptr, tr("Key Import Details"), tr("No keys found to import"));
- return;
- }
+#include "ui/KeyImportDetailDialog.h"
+
+#include "gpg/function/GpgKeyGetter.h"
+
+namespace GpgFrontend::UI {
+KeyImportDetailDialog::KeyImportDetailDialog(GpgImportInformation result,
+ bool automatic,
+ QWidget* parent)
+ : QDialog(parent), mResult(std::move(result)) {
+ // If no key for import found, just show a message
+ if (mResult.considered == 0) {
+ if (automatic)
+ QMessageBox::information(nullptr, tr("Key Update Details"),
+ tr("No keys found"));
+ else
+ QMessageBox::information(nullptr, tr("Key Import Details"),
+ tr("No keys found to import"));
+ return;
+ }
- auto *mvbox = new QVBoxLayout();
+ auto* mvbox = new QVBoxLayout();
- this->createGeneralInfoBox();
- mvbox->addWidget(generalInfoBox);
+ this->createGeneralInfoBox();
+ mvbox->addWidget(generalInfoBox);
- this->createKeysTable();
- mvbox->addWidget(keysTable);
+ this->createKeysTable();
+ mvbox->addWidget(keysTable);
- this->createButtonBox();
- mvbox->addWidget(buttonBox);
+ this->createButtonBox();
+ mvbox->addWidget(buttonBox);
- this->setLayout(mvbox);
- if(automatic)
- this->setWindowTitle(tr("Key Update Details"));
- else
- this->setWindowTitle(tr("Key Import Details"));
+ this->setLayout(mvbox);
+ if (automatic)
+ this->setWindowTitle(tr("Key Update Details"));
+ else
+ this->setWindowTitle(tr("Key Import Details"));
- this->resize(QSize(600, 300));
- this->setModal(true);
- this->exec();
+ this->resize(QSize(600, 300));
+ this->setModal(true);
+ this->exec();
}
void KeyImportDetailDialog::createGeneralInfoBox() {
- // GridBox for general import information
- generalInfoBox = new QGroupBox(tr("General key info"));
- auto *generalInfoBoxLayout = new QGridLayout(generalInfoBox);
-
- generalInfoBoxLayout->addWidget(new QLabel(tr("Considered:")), 1, 0);
- generalInfoBoxLayout->addWidget(new QLabel(QString::number(mResult.considered)), 1, 1);
- int row = 2;
- if (mResult.unchanged != 0) {
- generalInfoBoxLayout->addWidget(new QLabel(tr("Public unchanged:")), row, 0);
- generalInfoBoxLayout->addWidget(new QLabel(QString::number(mResult.unchanged)), row, 1);
- row++;
- }
- if (mResult.imported != 0) {
- generalInfoBoxLayout->addWidget(new QLabel(tr("Imported:")), row, 0);
- generalInfoBoxLayout->addWidget(new QLabel(QString::number(mResult.imported)), row, 1);
- row++;
- }
- if (mResult.not_imported != 0) {
- generalInfoBoxLayout->addWidget(new QLabel(tr("Not imported:")), row, 0);
- generalInfoBoxLayout->addWidget(new QLabel(QString::number(mResult.not_imported)), row, 1);
- row++;
- }
- if (mResult.secret_read != 0) {
- generalInfoBoxLayout->addWidget(new QLabel(tr("Private read:")), row, 0);
- generalInfoBoxLayout->addWidget(new QLabel(QString::number(mResult.secret_read)), row, 1);
- row++;
- }
- if (mResult.secret_imported != 0) {
- generalInfoBoxLayout->addWidget(new QLabel(tr("Private imported:")), row, 0);
- generalInfoBoxLayout->addWidget(new QLabel(QString::number(mResult.secret_imported)), row, 1);
- row++;
- }
- if (mResult.secret_unchanged != 0) {
- generalInfoBoxLayout->addWidget(new QLabel(tr("Private unchanged:")), row, 0);
- generalInfoBoxLayout->addWidget(new QLabel(QString::number(mResult.secret_unchanged)), row, 1);
- row++;
- }
+ // GridBox for general import information
+ generalInfoBox = new QGroupBox(tr("General key info"));
+ auto* generalInfoBoxLayout = new QGridLayout(generalInfoBox);
+
+ generalInfoBoxLayout->addWidget(new QLabel(tr("Considered:")), 1, 0);
+ generalInfoBoxLayout->addWidget(
+ new QLabel(QString::number(mResult.considered)), 1, 1);
+ int row = 2;
+ if (mResult.unchanged != 0) {
+ generalInfoBoxLayout->addWidget(new QLabel(tr("Public unchanged:")), row,
+ 0);
+ generalInfoBoxLayout->addWidget(
+ new QLabel(QString::number(mResult.unchanged)), row, 1);
+ row++;
+ }
+ if (mResult.imported != 0) {
+ generalInfoBoxLayout->addWidget(new QLabel(tr("Imported:")), row, 0);
+ generalInfoBoxLayout->addWidget(
+ new QLabel(QString::number(mResult.imported)), row, 1);
+ row++;
+ }
+ if (mResult.not_imported != 0) {
+ generalInfoBoxLayout->addWidget(new QLabel(tr("Not imported:")), row, 0);
+ generalInfoBoxLayout->addWidget(
+ new QLabel(QString::number(mResult.not_imported)), row, 1);
+ row++;
+ }
+ if (mResult.secret_read != 0) {
+ generalInfoBoxLayout->addWidget(new QLabel(tr("Private read:")), row, 0);
+ generalInfoBoxLayout->addWidget(
+ new QLabel(QString::number(mResult.secret_read)), row, 1);
+ row++;
+ }
+ if (mResult.secret_imported != 0) {
+ generalInfoBoxLayout->addWidget(new QLabel(tr("Private imported:")), row,
+ 0);
+ generalInfoBoxLayout->addWidget(
+ new QLabel(QString::number(mResult.secret_imported)), row, 1);
+ row++;
+ }
+ if (mResult.secret_unchanged != 0) {
+ generalInfoBoxLayout->addWidget(new QLabel(tr("Private unchanged:")), row,
+ 0);
+ generalInfoBoxLayout->addWidget(
+ new QLabel(QString::number(mResult.secret_unchanged)), row, 1);
+ row++;
+ }
}
void KeyImportDetailDialog::createKeysTable() {
- keysTable = new QTableWidget(this);
- keysTable->setRowCount(0);
- keysTable->setColumnCount(4);
- keysTable->setEditTriggers(QAbstractItemView::NoEditTriggers);
- // Nothing is selectable
- keysTable->setSelectionMode(QAbstractItemView::NoSelection);
-
- QStringList headerLabels;
- headerLabels << tr("Name") << tr("Email") << tr("Status") << tr("Fingerprint");
- keysTable->verticalHeader()->hide();
-
- keysTable->setHorizontalHeaderLabels(headerLabels);
- int row = 0;
- for (const auto &impKey : mResult.importedKeys) {
- keysTable->setRowCount(row + 1);
- GpgKey key = mCtx->getKeyRefByFpr(impKey.fpr);
- if(!key.good) continue;
- keysTable->setItem(row, 0, new QTableWidgetItem(key.name));
- keysTable->setItem(row, 1, new QTableWidgetItem(key.email));
- keysTable->setItem(row, 2, new QTableWidgetItem(getStatusString(impKey.importStatus)));
- keysTable->setItem(row, 3, new QTableWidgetItem(impKey.fpr));
- row++;
- }
- keysTable->horizontalHeader()->setSectionResizeMode(0, QHeaderView::ResizeToContents);
- keysTable->horizontalHeader()->setStretchLastSection(true);
- keysTable->resizeColumnsToContents();
+ keysTable = new QTableWidget(this);
+ keysTable->setRowCount(0);
+ keysTable->setColumnCount(4);
+ keysTable->setEditTriggers(QAbstractItemView::NoEditTriggers);
+ // Nothing is selectable
+ keysTable->setSelectionMode(QAbstractItemView::NoSelection);
+
+ QStringList headerLabels;
+ headerLabels << tr("Name") << tr("Email") << tr("Status")
+ << tr("Fingerprint");
+ keysTable->verticalHeader()->hide();
+
+ keysTable->setHorizontalHeaderLabels(headerLabels);
+ int row = 0;
+ for (const auto& imp_key : mResult.importedKeys) {
+ keysTable->setRowCount(row + 1);
+ GpgKey key = GpgKeyGetter::GetInstance().GetKey(imp_key.fpr);
+ if (!key.good())
+ continue;
+ keysTable->setItem(
+ row, 0, new QTableWidgetItem(QString::fromStdString(key.name())));
+ keysTable->setItem(
+ row, 1, new QTableWidgetItem(QString::fromStdString(key.email())));
+ keysTable->setItem(
+ row, 2, new QTableWidgetItem(getStatusString(imp_key.import_status)));
+ keysTable->setItem(
+ row, 3, new QTableWidgetItem(QString::fromStdString(imp_key.fpr)));
+ row++;
+ }
+ keysTable->horizontalHeader()->setSectionResizeMode(
+ 0, QHeaderView::ResizeToContents);
+ keysTable->horizontalHeader()->setStretchLastSection(true);
+ keysTable->resizeColumnsToContents();
}
QString KeyImportDetailDialog::getStatusString(int keyStatus) {
- QString statusString;
- // keystatus is greater than 15, if key is private
- if (keyStatus > 15) {
- statusString.append(tr("private"));
- keyStatus = keyStatus - 16;
- } else {
- statusString.append(tr("public"));
- }
- if (keyStatus == 0) {
- statusString.append(", " + tr("unchanged"));
+ QString statusString;
+ // keystatus is greater than 15, if key is private
+ if (keyStatus > 15) {
+ statusString.append(tr("private"));
+ keyStatus = keyStatus - 16;
+ } else {
+ statusString.append(tr("public"));
+ }
+ if (keyStatus == 0) {
+ statusString.append(", " + tr("unchanged"));
+ } else {
+ if (keyStatus == 1) {
+ statusString.append(", " + tr("new key"));
} else {
- if (keyStatus == 1) {
- statusString.append(", " + tr("new key"));
- } else {
- if (keyStatus > 7) {
- statusString.append(", " + tr("new subkey"));
- keyStatus = keyStatus - 8;
- }
- if (keyStatus > 3) {
- statusString.append(", " + tr("new signature"));
- keyStatus = keyStatus - 4;
- }
- if (keyStatus > 1) {
- statusString.append(", " + tr("new uid"));
- keyStatus = keyStatus - 2;
- }
- }
+ if (keyStatus > 7) {
+ statusString.append(", " + tr("new subkey"));
+ keyStatus = keyStatus - 8;
+ }
+ if (keyStatus > 3) {
+ statusString.append(", " + tr("new signature"));
+ keyStatus = keyStatus - 4;
+ }
+ if (keyStatus > 1) {
+ statusString.append(", " + tr("new uid"));
+ keyStatus = keyStatus - 2;
+ }
}
- return statusString;
+ }
+ return statusString;
}
void KeyImportDetailDialog::createButtonBox() {
- buttonBox = new QDialogButtonBox(QDialogButtonBox::Ok);
- connect(buttonBox, SIGNAL(accepted()), this, SLOT(close()));
+ buttonBox = new QDialogButtonBox(QDialogButtonBox::Ok);
+ connect(buttonBox, SIGNAL(accepted()), this, SLOT(close()));
}
+} // namespace GpgFrontend::UI
diff --git a/include/ui/KeyImportDetailDialog.h b/src/ui/KeyImportDetailDialog.h
index 243eead3..e3137503 100644
--- a/include/ui/KeyImportDetailDialog.h
+++ b/src/ui/KeyImportDetailDialog.h
@@ -25,27 +25,32 @@
#ifndef __KEYIMPORTDETAILSDIALOG_H__
#define __KEYIMPORTDETAILSDIALOG_H__
+#include <gpg/function/GpgKeyImportExportor.h>
#include "gpg/GpgContext.h"
+#include "ui/GpgFrontendUI.h"
-class KeyImportDetailDialog : public QDialog
-{
- Q_OBJECT
+namespace GpgFrontend::UI {
+class KeyImportDetailDialog : public QDialog {
+ Q_OBJECT
-public:
- KeyImportDetailDialog(GpgFrontend::GpgContext *ctx, GpgImportInformation result, bool automatic, QWidget *parent = 0);
+ public:
+ KeyImportDetailDialog(GpgImportInformation result,
+ bool automatic,
+ QWidget* parent = nullptr);
-private:
- void createGeneralInfoBox();
- void createKeysTable();
- void createButtonBox();
- static QString getStatusString(int keyStatus);
+ private:
+ void createGeneralInfoBox();
+ void createKeysTable();
+ void createButtonBox();
+ static QString getStatusString(int keyStatus);
- QTableWidget *keysTable{};
- GpgFrontend::GpgContext *mCtx;
- QGroupBox *generalInfoBox{};
- QGroupBox *keyInfoBox{};
- QDialogButtonBox *buttonBox{};
- GpgImportInformation mResult;
+ QTableWidget* keysTable{};
+ GpgFrontend::GpgContext* mCtx;
+ QGroupBox* generalInfoBox{};
+ QGroupBox* keyInfoBox{};
+ QDialogButtonBox* buttonBox{};
+ GpgImportInformation mResult;
};
+} // namespace GpgFrontend::UI
-#endif // __KEYIMPORTDETAILSDIALOG_H__
+#endif // __KEYIMPORTDETAILSDIALOG_H__
diff --git a/src/ui/KeyMgmt.cpp b/src/ui/KeyMgmt.cpp
index 9f3665d3..6d15a1eb 100755
--- a/src/ui/KeyMgmt.cpp
+++ b/src/ui/KeyMgmt.cpp
@@ -26,331 +26,345 @@
#include <utility>
-KeyMgmt::KeyMgmt(GpgFrontend::GpgContext *ctx, QWidget *parent) :
- QMainWindow(parent), appPath(qApp->applicationDirPath()),
- settings(RESOURCE_DIR(appPath) + "/conf/gpgfrontend.ini", QSettings::IniFormat) {
- mCtx = ctx;
-
- /* the list of Keys available*/
- mKeyList = new KeyList(mCtx);
- mKeyList->setColumnWidth(2, 250);
- mKeyList->setColumnWidth(3, 250);
- setCentralWidget(mKeyList);
- mKeyList->setDoubleClickedAction([this](const GpgKey &key, QWidget *parent) {
- new KeyDetailsDialog(mCtx, key, parent);
- });
-
- createActions();
- createMenus();
- createToolBars();
- connect(this, SIGNAL(signalStatusBarChanged(QString)), this->parent(), SLOT(slotSetStatusBarText(QString)));
-
- /* Restore the iconstyle */
- this->settings.sync();
-
- QSize iconSize = settings.value("toolbar/iconsize", QSize(24, 24)).toSize();
- settings.setValue("toolbar/iconsize", iconSize);
-
- Qt::ToolButtonStyle buttonStyle = static_cast<Qt::ToolButtonStyle>(settings.value("toolbar/iconstyle",
- Qt::ToolButtonTextUnderIcon).toUInt());
- this->setIconSize(iconSize);
- this->setToolButtonStyle(buttonStyle);
-
- // state sets pos & size of dock-widgets
- this->restoreState(this->settings.value("keymgmt/windowState").toByteArray());
-
- qDebug() << "windows/windowSave" << this->settings.value("window/windowSave").toBool();
-
- // Restore window size & location
- if (this->settings.value("keymgmt/setWindowSize").toBool()) {
- QPoint pos = settings.value("keymgmt/pos", QPoint(100, 100)).toPoint();
- QSize size = settings.value("keymgmt/size", QSize(900, 600)).toSize();
- qDebug() << "Settings size" << size << "pos" << pos;
- this->setMinimumSize(size);
- this->move(pos);
- } else {
- qDebug() << "Use default min windows size and pos";
- QPoint defaultPoint(100, 100);
- QSize defaultMinSize(900, 600);
- this->setMinimumSize(defaultMinSize);
- this->move(defaultPoint);
- this->settings.setValue("keymgmt/pos", defaultPoint);
- this->settings.setValue("keymgmt/size", defaultMinSize);
- this->settings.setValue("keymgmt/setWindowSize", true);
- }
-
- setWindowTitle(tr("Key Pair Management"));
- mKeyList->addMenuAction(deleteSelectedKeysAct);
- mKeyList->addMenuAction(showKeyDetailsAct);
+#include "gpg/function/GpgKeyGetter.h"
+#include "gpg/function/GpgKeyImportExportor.h"
+#include "gpg/function/GpgKeyOpera.h"
+
+namespace GpgFrontend::UI {
+KeyMgmt::KeyMgmt(QWidget* parent)
+ : QMainWindow(parent),
+ appPath(qApp->applicationDirPath()),
+ settings(RESOURCE_DIR(appPath) + "/conf/gpgfrontend.ini",
+ QSettings::IniFormat) {
+ /* the list of Keys available*/
+ mKeyList = new KeyList();
+ mKeyList->setColumnWidth(2, 250);
+ mKeyList->setColumnWidth(3, 250);
+ setCentralWidget(mKeyList);
+ mKeyList->setDoubleClickedAction([this](const GpgKey& key, QWidget* parent) {
+ new KeyDetailsDialog(key, parent);
+ });
+
+ createActions();
+ createMenus();
+ createToolBars();
+ connect(this, SIGNAL(signalStatusBarChanged(QString)), this->parent(),
+ SLOT(slotSetStatusBarText(QString)));
+
+ /* Restore the iconstyle */
+ this->settings.sync();
+
+ QSize iconSize = settings.value("toolbar/iconsize", QSize(24, 24)).toSize();
+ settings.setValue("toolbar/iconsize", iconSize);
+
+ Qt::ToolButtonStyle buttonStyle = static_cast<Qt::ToolButtonStyle>(
+ settings.value("toolbar/iconstyle", Qt::ToolButtonTextUnderIcon)
+ .toUInt());
+ this->setIconSize(iconSize);
+ this->setToolButtonStyle(buttonStyle);
+
+ // state sets pos & size of dock-widgets
+ this->restoreState(this->settings.value("keymgmt/windowState").toByteArray());
+
+ qDebug() << "windows/windowSave"
+ << this->settings.value("window/windowSave").toBool();
+
+ // Restore window size & location
+ if (this->settings.value("keymgmt/setWindowSize").toBool()) {
+ QPoint pos = settings.value("keymgmt/pos", QPoint(100, 100)).toPoint();
+ QSize size = settings.value("keymgmt/size", QSize(900, 600)).toSize();
+ qDebug() << "Settings size" << size << "pos" << pos;
+ this->setMinimumSize(size);
+ this->move(pos);
+ } else {
+ qDebug() << "Use default min windows size and pos";
+ QPoint defaultPoint(100, 100);
+ QSize defaultMinSize(900, 600);
+ this->setMinimumSize(defaultMinSize);
+ this->move(defaultPoint);
+ this->settings.setValue("keymgmt/pos", defaultPoint);
+ this->settings.setValue("keymgmt/size", defaultMinSize);
+ this->settings.setValue("keymgmt/setWindowSize", true);
+ }
+
+ setWindowTitle(tr("Key Pair Management"));
+ mKeyList->addMenuAction(deleteSelectedKeysAct);
+ mKeyList->addMenuAction(showKeyDetailsAct);
}
void KeyMgmt::createActions() {
- openKeyFileAct = new QAction(tr("&Open"), this);
- openKeyFileAct->setShortcut(tr("Ctrl+O"));
- openKeyFileAct->setToolTip(tr("Open Key File"));
- connect(openKeyFileAct, SIGNAL(triggered()), this, SLOT(slotImportKeyFromFile()));
-
- closeAct = new QAction(tr("&Close"), this);
- closeAct->setShortcut(tr("Ctrl+Q"));
- closeAct->setIcon(QIcon(":exit.png"));
- closeAct->setToolTip(tr("Close"));
- connect(closeAct, SIGNAL(triggered()), this, SLOT(close()));
-
- generateKeyPairAct = new QAction(tr("New Keypair"), this);
- generateKeyPairAct->setShortcut(tr("Ctrl+N"));
- generateKeyPairAct->setIcon(QIcon(":key_generate.png"));
- generateKeyPairAct->setToolTip(tr("Generate KeyPair"));
- connect(generateKeyPairAct, SIGNAL(triggered()), this, SLOT(slotGenerateKeyDialog()));
-
- generateSubKeyAct = new QAction(tr("New Subkey"), this);
- generateSubKeyAct->setShortcut(tr("Ctrl+Shift+N"));
- generateSubKeyAct->setIcon(QIcon(":key_generate.png"));
- generateSubKeyAct->setToolTip(tr("Generate Subkey For Selected KeyPair"));
- connect(generateSubKeyAct, SIGNAL(triggered()), this, SLOT(slotGenerateSubKey()));
-
- importKeyFromFileAct = new QAction(tr("&File"), this);
- importKeyFromFileAct->setIcon(QIcon(":import_key_from_file.png"));
- importKeyFromFileAct->setToolTip(tr("Import New Key From File"));
- connect(importKeyFromFileAct, SIGNAL(triggered()), this, SLOT(slotImportKeyFromFile()));
-
- importKeyFromClipboardAct = new QAction(tr("&Clipboard"), this);
- importKeyFromClipboardAct->setIcon(QIcon(":import_key_from_clipboard.png"));
- importKeyFromClipboardAct->setToolTip(tr("Import New Key From Clipboard"));
- connect(importKeyFromClipboardAct, SIGNAL(triggered()), this, SLOT(slotImportKeyFromClipboard()));
-
- importKeyFromKeyServerAct = new QAction(tr("&Keyserver"), this);
- importKeyFromKeyServerAct->setIcon(QIcon(":import_key_from_server.png"));
- importKeyFromKeyServerAct->setToolTip(tr("Import New Key From Keyserver"));
- connect(importKeyFromKeyServerAct, SIGNAL(triggered()), this, SLOT(slotImportKeyFromKeyServer()));
-
- exportKeyToClipboardAct = new QAction(tr("Export To &Clipboard"), this);
- exportKeyToClipboardAct->setIcon(QIcon(":export_key_to_clipboard.png"));
- exportKeyToClipboardAct->setToolTip(tr("Export Selected Key(s) To Clipboard"));
- connect(exportKeyToClipboardAct, SIGNAL(triggered()), this, SLOT(slotExportKeyToClipboard()));
-
- exportKeyToFileAct = new QAction(tr("Export To &File"), this);
- exportKeyToFileAct->setIcon(QIcon(":export_key_to_file.png"));
- exportKeyToFileAct->setToolTip(tr("Export Selected Key(s) To File"));
- connect(exportKeyToFileAct, SIGNAL(triggered()), this, SLOT(slotExportKeyToFile()));
-
- deleteSelectedKeysAct = new QAction(tr("Delete Selected Key(s)"), this);
- deleteSelectedKeysAct->setToolTip(tr("Delete the Selected keys"));
- connect(deleteSelectedKeysAct, SIGNAL(triggered()), this, SLOT(slotDeleteSelectedKeys()));
-
- deleteCheckedKeysAct = new QAction(tr("Delete Checked Key(s)"), this);
- deleteCheckedKeysAct->setToolTip(tr("Delete the Checked keys"));
- deleteCheckedKeysAct->setIcon(QIcon(":button_delete.png"));
- connect(deleteCheckedKeysAct, SIGNAL(triggered()), this, SLOT(slotDeleteCheckedKeys()));
-
- showKeyDetailsAct = new QAction(tr("Show Key Details"), this);
- showKeyDetailsAct->setToolTip(tr("Show Details for this Key"));
- connect(showKeyDetailsAct, SIGNAL(triggered()), this, SLOT(slotShowKeyDetails()));
+ openKeyFileAct = new QAction(tr("&Open"), this);
+ openKeyFileAct->setShortcut(tr("Ctrl+O"));
+ openKeyFileAct->setToolTip(tr("Open Key File"));
+ connect(openKeyFileAct, SIGNAL(triggered()), this,
+ SLOT(slotImportKeyFromFile()));
+
+ closeAct = new QAction(tr("&Close"), this);
+ closeAct->setShortcut(tr("Ctrl+Q"));
+ closeAct->setIcon(QIcon(":exit.png"));
+ closeAct->setToolTip(tr("Close"));
+ connect(closeAct, SIGNAL(triggered()), this, SLOT(close()));
+
+ generateKeyPairAct = new QAction(tr("New Keypair"), this);
+ generateKeyPairAct->setShortcut(tr("Ctrl+N"));
+ generateKeyPairAct->setIcon(QIcon(":key_generate.png"));
+ generateKeyPairAct->setToolTip(tr("Generate KeyPair"));
+ connect(generateKeyPairAct, SIGNAL(triggered()), this,
+ SLOT(slotGenerateKeyDialog()));
+
+ generateSubKeyAct = new QAction(tr("New Subkey"), this);
+ generateSubKeyAct->setShortcut(tr("Ctrl+Shift+N"));
+ generateSubKeyAct->setIcon(QIcon(":key_generate.png"));
+ generateSubKeyAct->setToolTip(tr("Generate Subkey For Selected KeyPair"));
+ connect(generateSubKeyAct, SIGNAL(triggered()), this,
+ SLOT(slotGenerateSubKey()));
+
+ importKeyFromFileAct = new QAction(tr("&File"), this);
+ importKeyFromFileAct->setIcon(QIcon(":import_key_from_file.png"));
+ importKeyFromFileAct->setToolTip(tr("Import New Key From File"));
+ connect(importKeyFromFileAct, SIGNAL(triggered()), this,
+ SLOT(slotImportKeyFromFile()));
+
+ importKeyFromClipboardAct = new QAction(tr("&Clipboard"), this);
+ importKeyFromClipboardAct->setIcon(QIcon(":import_key_from_clipboard.png"));
+ importKeyFromClipboardAct->setToolTip(tr("Import New Key From Clipboard"));
+ connect(importKeyFromClipboardAct, SIGNAL(triggered()), this,
+ SLOT(slotImportKeyFromClipboard()));
+
+ importKeyFromKeyServerAct = new QAction(tr("&Keyserver"), this);
+ importKeyFromKeyServerAct->setIcon(QIcon(":import_key_from_server.png"));
+ importKeyFromKeyServerAct->setToolTip(tr("Import New Key From Keyserver"));
+ connect(importKeyFromKeyServerAct, SIGNAL(triggered()), this,
+ SLOT(slotImportKeyFromKeyServer()));
+
+ exportKeyToClipboardAct = new QAction(tr("Export To &Clipboard"), this);
+ exportKeyToClipboardAct->setIcon(QIcon(":export_key_to_clipboard.png"));
+ exportKeyToClipboardAct->setToolTip(
+ tr("Export Selected Key(s) To Clipboard"));
+ connect(exportKeyToClipboardAct, SIGNAL(triggered()), this,
+ SLOT(slotExportKeyToClipboard()));
+
+ exportKeyToFileAct = new QAction(tr("Export To &File"), this);
+ exportKeyToFileAct->setIcon(QIcon(":export_key_to_file.png"));
+ exportKeyToFileAct->setToolTip(tr("Export Selected Key(s) To File"));
+ connect(exportKeyToFileAct, SIGNAL(triggered()), this,
+ SLOT(slotExportKeyToFile()));
+
+ deleteSelectedKeysAct = new QAction(tr("Delete Selected Key(s)"), this);
+ deleteSelectedKeysAct->setToolTip(tr("Delete the Selected keys"));
+ connect(deleteSelectedKeysAct, SIGNAL(triggered()), this,
+ SLOT(slotDeleteSelectedKeys()));
+
+ deleteCheckedKeysAct = new QAction(tr("Delete Checked Key(s)"), this);
+ deleteCheckedKeysAct->setToolTip(tr("Delete the Checked keys"));
+ deleteCheckedKeysAct->setIcon(QIcon(":button_delete.png"));
+ connect(deleteCheckedKeysAct, SIGNAL(triggered()), this,
+ SLOT(slotDeleteCheckedKeys()));
+
+ showKeyDetailsAct = new QAction(tr("Show Key Details"), this);
+ showKeyDetailsAct->setToolTip(tr("Show Details for this Key"));
+ connect(showKeyDetailsAct, SIGNAL(triggered()), this,
+ SLOT(slotShowKeyDetails()));
}
void KeyMgmt::createMenus() {
- fileMenu = menuBar()->addMenu(tr("&File"));
- fileMenu->addAction(openKeyFileAct);
- fileMenu->addAction(closeAct);
-
- keyMenu = menuBar()->addMenu(tr("&Key"));
- generateKeyMenu = keyMenu->addMenu(tr("&Generate Key"));
- generateKeyMenu->addAction(generateKeyPairAct);
- generateKeyMenu->addAction(generateSubKeyAct);
-
- importKeyMenu = keyMenu->addMenu(tr("&Import Key"));
- importKeyMenu->addAction(importKeyFromFileAct);
- importKeyMenu->addAction(importKeyFromClipboardAct);
- importKeyMenu->addAction(importKeyFromKeyServerAct);
- keyMenu->addAction(exportKeyToFileAct);
- keyMenu->addAction(exportKeyToClipboardAct);
- keyMenu->addSeparator();
- keyMenu->addAction(deleteCheckedKeysAct);
+ fileMenu = menuBar()->addMenu(tr("&File"));
+ fileMenu->addAction(openKeyFileAct);
+ fileMenu->addAction(closeAct);
+
+ keyMenu = menuBar()->addMenu(tr("&Key"));
+ generateKeyMenu = keyMenu->addMenu(tr("&Generate Key"));
+ generateKeyMenu->addAction(generateKeyPairAct);
+ generateKeyMenu->addAction(generateSubKeyAct);
+
+ importKeyMenu = keyMenu->addMenu(tr("&Import Key"));
+ importKeyMenu->addAction(importKeyFromFileAct);
+ importKeyMenu->addAction(importKeyFromClipboardAct);
+ importKeyMenu->addAction(importKeyFromKeyServerAct);
+ keyMenu->addAction(exportKeyToFileAct);
+ keyMenu->addAction(exportKeyToClipboardAct);
+ keyMenu->addSeparator();
+ keyMenu->addAction(deleteCheckedKeysAct);
}
void KeyMgmt::createToolBars() {
- QToolBar *keyToolBar = addToolBar(tr("Key"));
- keyToolBar->setObjectName("keytoolbar");
-
- // add button with popup menu for import
- auto *generateToolButton = new QToolButton(this);
- generateToolButton->setMenu(generateKeyMenu);
- generateToolButton->setPopupMode(QToolButton::InstantPopup);
- generateToolButton->setIcon(QIcon(":key_generate.png"));
- generateToolButton->setText(tr("Generate"));
- generateToolButton->setToolTip(tr("Generate A New Keypair or Subkey"));
- generateToolButton->setToolButtonStyle(Qt::ToolButtonTextUnderIcon);
- keyToolBar->addWidget(generateToolButton);
-
- // add button with popup menu for import
- auto *toolButton = new QToolButton(this);
- toolButton->setMenu(importKeyMenu);
- toolButton->setPopupMode(QToolButton::InstantPopup);
- toolButton->setIcon(QIcon(":key_import.png"));
- toolButton->setToolTip(tr("Import key"));
- toolButton->setText(tr("Import Key"));
- toolButton->setToolButtonStyle(Qt::ToolButtonTextUnderIcon);
- keyToolBar->addWidget(toolButton);
-
- keyToolBar->addSeparator();
- keyToolBar->addAction(deleteCheckedKeysAct);
- keyToolBar->addSeparator();
- keyToolBar->addAction(exportKeyToFileAct);
- keyToolBar->addAction(exportKeyToClipboardAct);
-
+ QToolBar* keyToolBar = addToolBar(tr("Key"));
+ keyToolBar->setObjectName("keytoolbar");
+
+ // add button with popup menu for import
+ auto* generateToolButton = new QToolButton(this);
+ generateToolButton->setMenu(generateKeyMenu);
+ generateToolButton->setPopupMode(QToolButton::InstantPopup);
+ generateToolButton->setIcon(QIcon(":key_generate.png"));
+ generateToolButton->setText(tr("Generate"));
+ generateToolButton->setToolTip(tr("Generate A New Keypair or Subkey"));
+ generateToolButton->setToolButtonStyle(Qt::ToolButtonTextUnderIcon);
+ keyToolBar->addWidget(generateToolButton);
+
+ // add button with popup menu for import
+ auto* toolButton = new QToolButton(this);
+ toolButton->setMenu(importKeyMenu);
+ toolButton->setPopupMode(QToolButton::InstantPopup);
+ toolButton->setIcon(QIcon(":key_import.png"));
+ toolButton->setToolTip(tr("Import key"));
+ toolButton->setText(tr("Import Key"));
+ toolButton->setToolButtonStyle(Qt::ToolButtonTextUnderIcon);
+ keyToolBar->addWidget(toolButton);
+
+ keyToolBar->addSeparator();
+ keyToolBar->addAction(deleteCheckedKeysAct);
+ keyToolBar->addSeparator();
+ keyToolBar->addAction(exportKeyToFileAct);
+ keyToolBar->addAction(exportKeyToClipboardAct);
}
-void KeyMgmt::slotImportKeys(QByteArray inBuffer) {
- GpgImportInformation result = mCtx->importKey(std::move(inBuffer));
- new KeyImportDetailDialog(mCtx, result, false, this);
-
+void KeyMgmt::slotImportKeys(ByteArrayPtr in_buffer) {
+ GpgImportInformation result =
+ GpgKeyImportExportor::GetInstance().ImportKey(std::move(in_buffer));
+ new KeyImportDetailDialog(result, false, this);
}
void KeyMgmt::slotImportKeyFromFile() {
- QString fileName = QFileDialog::getOpenFileName(this, tr("Open Key"), "",
- tr("Key Files") + " (*.asc *.txt);;" + tr("Keyring files") +
- " (*.gpg);;All Files (*)");
- if (!fileName.isNull()) {
- QFile file;
- file.setFileName(fileName);
- if (!file.open(QIODevice::ReadOnly)) {
- qDebug() << tr("Couldn't Open File: ") + fileName;
- return;
- }
- QByteArray inBuffer = file.readAll();
- slotImportKeys(inBuffer);
- file.close();
- }
+ QString file_name = QFileDialog::getOpenFileName(
+ this, tr("Open Key"), "",
+ tr("Key Files") + " (*.asc *.txt);;" + tr("Keyring files") +
+ " (*.gpg);;All Files (*)");
+ if (!file_name.isNull()) {
+ slotImportKeys(std::make_unique<ByteArray>(
+ read_all_data_in_file(file_name.toStdString())));
+ }
}
void KeyMgmt::slotImportKeyFromKeyServer() {
- importDialog = new KeyServerImportDialog(mCtx, mKeyList, false, this);
- importDialog->show();
+ importDialog = new KeyServerImportDialog(mKeyList, false, this);
+ importDialog->show();
}
void KeyMgmt::slotImportKeyFromClipboard() {
- QClipboard *cb = QApplication::clipboard();
- slotImportKeys(cb->text(QClipboard::Clipboard).toUtf8());
+ QClipboard* cb = QApplication::clipboard();
+ slotImportKeys(std::make_unique<ByteArray>(
+ cb->text(QClipboard::Clipboard).toUtf8().toStdString()));
}
void KeyMgmt::slotDeleteSelectedKeys() {
- deleteKeysWithWarning(mKeyList->getSelected());
+ deleteKeysWithWarning(mKeyList->getSelected());
}
void KeyMgmt::slotDeleteCheckedKeys() {
- deleteKeysWithWarning(mKeyList->getChecked());
+ deleteKeysWithWarning(mKeyList->getChecked());
}
-void KeyMgmt::deleteKeysWithWarning(QStringList *uidList) {
- /**
- * TODO: Different Messages for private/public key, check if
- * more than one selected... compare to seahorse "delete-dialog"
- */
-
- if (uidList->isEmpty()) {
- return;
- }
- QString keynames;
- for (const auto &uid : *uidList) {
- auto key = mCtx->getKeyRefById(uid);
- if (!key.good) continue;
- keynames.append(key.name);
- keynames.append("<i> &lt;");
- keynames.append(key.email);
- keynames.append("&gt; </i><br/>");
- }
-
- int ret = QMessageBox::warning(this, tr("Deleting Keys"),
- "<b>" + tr("Are you sure that you want to delete the following keys?") +
- "</b><br/><br/>" + keynames +
- +"<br/>" + tr("The action can not be undone."),
- QMessageBox::No | QMessageBox::Yes);
-
- if (ret == QMessageBox::Yes) {
- mCtx->deleteKeys(uidList);
- }
+void KeyMgmt::deleteKeysWithWarning(KeyIdArgsListPtr key_ids) {
+ /**
+ * TODO: Different Messages for private/public key, check if
+ * more than one selected... compare to seahorse "delete-dialog"
+ */
+
+ if (key_ids->empty())
+ return;
+ QString keynames;
+ for (const auto& key_id : *key_ids) {
+ auto key = GpgKeyGetter::GetInstance().GetKey(key_id);
+ if (!key.good())
+ continue;
+ keynames.append(QString::fromStdString(key.name()));
+ keynames.append("<i> &lt;");
+ keynames.append(QString::fromStdString(key.email()));
+ keynames.append("&gt; </i><br/>");
+ }
+
+ int ret = QMessageBox::warning(
+ this, tr("Deleting Keys"),
+ "<b>" + tr("Are you sure that you want to delete the following keys?") +
+ "</b><br/><br/>" + keynames + +"<br/>" +
+ tr("The action can not be undone."),
+ QMessageBox::No | QMessageBox::Yes);
+
+ if (ret == QMessageBox::Yes)
+ GpgKeyOpera::GetInstance().DeleteKeys(std::move(key_ids));
}
void KeyMgmt::slotShowKeyDetails() {
- if (mKeyList->getSelected()->isEmpty()) {
- return;
- }
+ auto keys_selected = mKeyList->getSelected();
+ if (keys_selected->empty())
+ return;
- auto key = mCtx->getKeyRefById(mKeyList->getSelected()->first());
+ auto key = GpgKeyGetter::GetInstance().GetKey(keys_selected->front());
- if (!key.good) {
- QMessageBox::critical(nullptr, tr("Error"), tr("Key Not Found."));
- return;
- }
+ if (!key.good()) {
+ QMessageBox::critical(nullptr, tr("Error"), tr("Key Not Found."));
+ return;
+ }
- new KeyDetailsDialog(mCtx, key);
+ new KeyDetailsDialog(key);
}
void KeyMgmt::slotExportKeyToFile() {
- auto *keyArray = new QByteArray();
- if (!mCtx->exportKeys(mKeyList->getChecked(), keyArray)) {
- delete keyArray;
- return;
- }
- auto key = mCtx->getKeyRefById(mKeyList->getSelected()->first());
- if (!key.good) {
- QMessageBox::critical(nullptr, tr("Error"), tr("Key Not Found."));
- return;
- }
- QString fileString = key.name + " " + key.email + "(" + key.id + ")_pub.asc";
-
- QString fileName = QFileDialog::getSaveFileName(this, tr("Export Key To File"), fileString,
- tr("Key Files") + " (*.asc *.txt);;All Files (*)");
- QFile file(fileName);
- if (!file.open(QIODevice::WriteOnly | QIODevice::Text)) {
- delete keyArray;
- return;
- }
- QTextStream stream(&file);
- stream << *keyArray;
- file.close();
- delete keyArray;
- emit signalStatusBarChanged(QString(tr("key(s) exported")));
+ ByteArrayPtr key_export_data = nullptr;
+ auto keys_checked = mKeyList->getChecked();
+ if (!GpgKeyImportExportor::GetInstance().ExportKeys(keys_checked,
+ key_export_data)) {
+ return;
+ }
+ auto key =
+ GpgKeyGetter::GetInstance().GetKey(mKeyList->getSelected()->front());
+ if (!key.good()) {
+ QMessageBox::critical(nullptr, tr("Error"), tr("Key Not Found."));
+ return;
+ }
+ QString fileString = QString::fromStdString(key.name() + " " + key.email() +
+ "(" + key.id() + ")_pub.asc");
+
+ QString file_name = QFileDialog::getSaveFileName(
+ this, tr("Export Key To File"), fileString,
+ tr("Key Files") + " (*.asc *.txt);;All Files (*)");
+
+ write_buffer_to_file(file_name.toStdString(), *key_export_data);
+
+ emit signalStatusBarChanged(QString(tr("key(s) exported")));
}
void KeyMgmt::slotExportKeyToClipboard() {
- auto *keyArray = new QByteArray();
- QClipboard *cb = QApplication::clipboard();
- if (!mCtx->exportKeys(mKeyList->getChecked(), keyArray)) {
- return;
- }
- cb->setText(*keyArray);
- delete keyArray;
+ ByteArrayPtr key_export_data = nullptr;
+ auto keys_checked = mKeyList->getChecked();
+ if (!GpgKeyImportExportor::GetInstance().ExportKeys(keys_checked,
+ key_export_data)) {
+ return;
+ }
+ QApplication::clipboard()->setText(QString::fromStdString(*key_export_data));
}
void KeyMgmt::slotGenerateKeyDialog() {
- auto *keyGenDialog = new KeyGenDialog(mCtx, this);
- keyGenDialog->show();
+ auto* keyGenDialog = new KeyGenDialog(this);
+ keyGenDialog->show();
}
-void KeyMgmt::closeEvent(QCloseEvent *event) {
- QMainWindow::closeEvent(event);
+void KeyMgmt::closeEvent(QCloseEvent* event) {
+ QMainWindow::closeEvent(event);
}
void KeyMgmt::slotGenerateSubKey() {
- auto selectedList = mKeyList->getSelected();
- if (selectedList->empty()) {
- QMessageBox::information(nullptr,
- tr("Invalid Operation"),
- tr("Please select one KeyPair before doing this operation."));
- return;
- }
- const auto key = mCtx->getKeyRefById(selectedList->first());
- if (!key.good) {
- QMessageBox::critical(nullptr, tr("Error"), tr("Key Not Found."));
- return;
- }
- if (!key.is_private_key) {
- QMessageBox::critical(nullptr,
- tr("Invalid Operation"),
- tr("If a key pair does not have a private key then it will not be able to generate sub-keys."));
- return;
- }
-
- auto dialog = new SubkeyGenerateDialog(mCtx, key, this);
- dialog->show();
+ auto keys_selected = mKeyList->getSelected();
+ if (keys_selected->empty()) {
+ QMessageBox::information(
+ nullptr, tr("Invalid Operation"),
+ tr("Please select one KeyPair before doing this operation."));
+ return;
+ }
+ const auto key = GpgKeyGetter::GetInstance().GetKey(keys_selected->front());
+ if (!key.good()) {
+ QMessageBox::critical(nullptr, tr("Error"), tr("Key Not Found."));
+ return;
+ }
+ if (!key.is_private_key()) {
+ QMessageBox::critical(nullptr, tr("Invalid Operation"),
+ tr("If a key pair does not have a private key then "
+ "it will not be able to generate sub-keys."));
+ return;
+ }
+
+ auto dialog = new SubkeyGenerateDialog(key.id(), this);
+ dialog->show();
}
+
+} // namespace GpgFrontend::UI
diff --git a/src/ui/KeyMgmt.h b/src/ui/KeyMgmt.h
new file mode 100755
index 00000000..deddb4f7
--- /dev/null
+++ b/src/ui/KeyMgmt.h
@@ -0,0 +1,111 @@
+/**
+ * This file is part of GPGFrontend.
+ *
+ * GPGFrontend is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Foobar is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Foobar. If not, see <https://www.gnu.org/licenses/>.
+ *
+ * The initial version of the source code is inherited from gpg4usb-team.
+ * Their source code version also complies with GNU General Public License.
+ *
+ * The source code version of this software was modified and released
+ * by Saturneric<[email protected]> starting on May 12, 2021.
+ *
+ */
+
+#ifndef __KEYMGMT_H__
+#define __KEYMGMT_H__
+
+#include "KeyImportDetailDialog.h"
+#include "KeyServerImportDialog.h"
+#include "ui/GpgFrontendUI.h"
+#include "ui/keygen/KeygenDialog.h"
+#include "ui/keypair_details/KeyDetailsDialog.h"
+#include "ui/widgets/KeyList.h"
+
+namespace GpgFrontend::UI {
+
+class KeyMgmt : public QMainWindow {
+ Q_OBJECT
+
+ public:
+ explicit KeyMgmt(QWidget* parent = nullptr);
+
+ QAction* importKeyFromClipboardAct{};
+ QAction* importKeyFromFileAct{};
+ QAction* importKeyFromKeyServerAct{};
+
+ QAction* generateKeyPairAct{};
+ QAction* generateSubKeyAct{};
+
+ public slots:
+
+ void slotGenerateSubKey();
+
+ void slotImportKeyFromFile();
+
+ void slotImportKeyFromClipboard();
+
+ void slotImportKeyFromKeyServer();
+
+ void slotImportKeys(GpgFrontend::ByteArrayPtr in_buffer);
+
+ void slotExportKeyToFile();
+
+ void slotExportKeyToClipboard();
+
+ void slotDeleteSelectedKeys();
+
+ void slotDeleteCheckedKeys();
+
+ void slotGenerateKeyDialog();
+
+ void slotShowKeyDetails();
+
+ signals:
+
+ void signalStatusBarChanged(QString);
+
+ private:
+ void createMenus();
+
+ void createActions();
+
+ void createToolBars();
+
+ void deleteKeysWithWarning(GpgFrontend::KeyIdArgsListPtr uidList);
+
+ QString appPath;
+ QSettings settings;
+
+ KeyList* mKeyList;
+ QMenu* fileMenu{};
+ QMenu* keyMenu{};
+ QMenu* generateKeyMenu{};
+ QMenu* importKeyMenu{};
+ QAction* openKeyFileAct{};
+ QAction* exportKeyToFileAct{};
+ QAction* exportKeyToClipboardAct{};
+ QAction* deleteCheckedKeysAct{};
+ QAction* deleteSelectedKeysAct{};
+ QAction* generateKeyDialogAct{};
+ QAction* closeAct{};
+ QAction* showKeyDetailsAct{};
+ KeyServerImportDialog* importDialog{};
+
+ protected:
+ void closeEvent(QCloseEvent* event) override;
+};
+
+} // namespace GpgFrontend::UI
+
+#endif // __KEYMGMT_H__
diff --git a/src/ui/KeyServerImportDialog.cpp b/src/ui/KeyServerImportDialog.cpp
index 4343eb79..dae8f723 100644
--- a/src/ui/KeyServerImportDialog.cpp
+++ b/src/ui/KeyServerImportDialog.cpp
@@ -26,451 +26,479 @@
#include <utility>
-KeyServerImportDialog::KeyServerImportDialog(GpgFrontend::GpgContext *ctx, KeyList *keyList, bool automatic,
- QWidget *parent)
- : QDialog(parent), appPath(qApp->applicationDirPath()),
- settings(RESOURCE_DIR(appPath) + "/conf/gpgfrontend.ini", QSettings::IniFormat),
- mCtx(ctx), mKeyList(keyList), mAutomatic(automatic) {
-
- if(automatic) {
- setWindowFlags(Qt::Window | Qt::WindowTitleHint | Qt::CustomizeWindowHint);
- }
-
- // Buttons
- closeButton = createButton(tr("&Close"), SLOT(close()));
- importButton = createButton(tr("&Import ALL"), SLOT(slotImport()));
- searchButton = createButton(tr("&Search"), SLOT(slotSearch()));
-
- // Line edit for search string
- searchLabel = new QLabel(tr("Search String:"));
- searchLineEdit = new QLineEdit();
-
- // combobox for keyserverlist
- keyServerLabel = new QLabel(tr("Key Server:"));
- keyServerComboBox = createComboBox();
-
- // table containing the keys found
- createKeysTable();
- message = new QLabel;
- message->setFixedHeight(24);
- icon = new QLabel;
- icon->setFixedHeight(24);
-
- // Network Waiting
- waitingBar = new QProgressBar();
- waitingBar->setVisible(false);
- waitingBar->setRange(0, 0);
- waitingBar->setFixedWidth(200);
-
- // Layout for messagebox
- auto *messageLayout = new QHBoxLayout;
- messageLayout->addWidget(icon);
- messageLayout->addWidget(message);
- messageLayout->addWidget(waitingBar);
- messageLayout->addStretch();
-
- // Layout for import and close button
- auto *buttonsLayout = new QHBoxLayout;
- buttonsLayout->addStretch();
- if(!automatic)
- buttonsLayout->addWidget(importButton);
- buttonsLayout->addWidget(closeButton);
-
- auto *mainLayout = new QGridLayout;
-
- // 自动化调用界面布局
- if(automatic) {
- mainLayout->addLayout(messageLayout, 0, 0, 1, 3);
- } else {
- mainLayout->addWidget(searchLabel, 1, 0);
- mainLayout->addWidget(searchLineEdit, 1, 1);
- mainLayout->addWidget(searchButton, 1, 2);
- mainLayout->addWidget(keyServerLabel, 2, 0);
- mainLayout->addWidget(keyServerComboBox, 2, 1);
- mainLayout->addWidget(keysTable, 3, 0, 1, 3);
- mainLayout->addLayout(messageLayout, 4, 0, 1, 3);
- mainLayout->addLayout(buttonsLayout, 6, 0, 1, 3);
- }
-
- this->setLayout(mainLayout);
- if(automatic)
- this->setWindowTitle(tr("Update Keys from Keyserver"));
- else
- this->setWindowTitle(tr("Import Keys from Keyserver"));
-
- if(automatic) {
- this->setFixedSize(240, 42);
+#include "gpg/function/GpgKeyImportExportor.h"
+
+namespace GpgFrontend::UI {
+
+KeyServerImportDialog::KeyServerImportDialog(KeyList* keyList,
+ bool automatic,
+ QWidget* parent)
+ : QDialog(parent),
+ appPath(qApp->applicationDirPath()),
+ settings(RESOURCE_DIR(appPath) + "/conf/gpgfrontend.ini",
+ QSettings::IniFormat),
+ mKeyList(keyList),
+ mAutomatic(automatic) {
+ if (automatic) {
+ setWindowFlags(Qt::Window | Qt::WindowTitleHint | Qt::CustomizeWindowHint);
+ }
+
+ // Buttons
+ closeButton = createButton(tr("&Close"), SLOT(close()));
+ importButton = createButton(tr("&Import ALL"), SLOT(slotImport()));
+ searchButton = createButton(tr("&Search"), SLOT(slotSearch()));
+
+ // Line edit for search string
+ searchLabel = new QLabel(tr("Search String:"));
+ searchLineEdit = new QLineEdit();
+
+ // combobox for keyserverlist
+ keyServerLabel = new QLabel(tr("Key Server:"));
+ keyServerComboBox = createComboBox();
+
+ // table containing the keys found
+ createKeysTable();
+ message = new QLabel;
+ message->setFixedHeight(24);
+ icon = new QLabel;
+ icon->setFixedHeight(24);
+
+ // Network Waiting
+ waitingBar = new QProgressBar();
+ waitingBar->setVisible(false);
+ waitingBar->setRange(0, 0);
+ waitingBar->setFixedWidth(200);
+
+ // Layout for messagebox
+ auto* messageLayout = new QHBoxLayout;
+ messageLayout->addWidget(icon);
+ messageLayout->addWidget(message);
+ messageLayout->addWidget(waitingBar);
+ messageLayout->addStretch();
+
+ // Layout for import and close button
+ auto* buttonsLayout = new QHBoxLayout;
+ buttonsLayout->addStretch();
+ if (!automatic)
+ buttonsLayout->addWidget(importButton);
+ buttonsLayout->addWidget(closeButton);
+
+ auto* mainLayout = new QGridLayout;
+
+ // 自动化调用界面布局
+ if (automatic) {
+ mainLayout->addLayout(messageLayout, 0, 0, 1, 3);
+ } else {
+ mainLayout->addWidget(searchLabel, 1, 0);
+ mainLayout->addWidget(searchLineEdit, 1, 1);
+ mainLayout->addWidget(searchButton, 1, 2);
+ mainLayout->addWidget(keyServerLabel, 2, 0);
+ mainLayout->addWidget(keyServerComboBox, 2, 1);
+ mainLayout->addWidget(keysTable, 3, 0, 1, 3);
+ mainLayout->addLayout(messageLayout, 4, 0, 1, 3);
+ mainLayout->addLayout(buttonsLayout, 6, 0, 1, 3);
+ }
+
+ this->setLayout(mainLayout);
+ if (automatic)
+ this->setWindowTitle(tr("Update Keys from Keyserver"));
+ else
+ this->setWindowTitle(tr("Import Keys from Keyserver"));
+
+ if (automatic) {
+ this->setFixedSize(240, 42);
+ } else {
+ // Restore window size & location
+ if (this->settings.value("ImportKeyFromServer/setWindowSize").toBool()) {
+ QPoint pos =
+ settings.value("ImportKeyFromServer/pos", QPoint(150, 150)).toPoint();
+ QSize size =
+ settings.value("ImportKeyFromServer/size", QSize(500, 300)).toSize();
+ qDebug() << "Settings size" << size << "pos" << pos;
+ this->setMinimumSize(size);
+ this->move(pos);
} else {
- // Restore window size & location
- if (this->settings.value("ImportKeyFromServer/setWindowSize").toBool()) {
- QPoint pos = settings.value("ImportKeyFromServer/pos", QPoint(150, 150)).toPoint();
- QSize size = settings.value("ImportKeyFromServer/size", QSize(500, 300)).toSize();
- qDebug() << "Settings size" << size << "pos" << pos;
- this->setMinimumSize(size);
- this->move(pos);
- } else {
- qDebug() << "Use default min windows size and pos";
- QPoint defaultPoint(150, 150);
- QSize defaultMinSize(500, 300);
- this->setMinimumSize(defaultMinSize);
- this->move(defaultPoint);
- this->settings.setValue("ImportKeyFromServer/pos", defaultPoint);
- this->settings.setValue("ImportKeyFromServer/size", defaultMinSize);
- this->settings.setValue("ImportKeyFromServer/setWindowSize", true);
- }
+ qDebug() << "Use default min windows size and pos";
+ QPoint defaultPoint(150, 150);
+ QSize defaultMinSize(500, 300);
+ this->setMinimumSize(defaultMinSize);
+ this->move(defaultPoint);
+ this->settings.setValue("ImportKeyFromServer/pos", defaultPoint);
+ this->settings.setValue("ImportKeyFromServer/size", defaultMinSize);
+ this->settings.setValue("ImportKeyFromServer/setWindowSize", true);
}
+ }
- this->setModal(true);
+ this->setModal(true);
}
-QPushButton *KeyServerImportDialog::createButton(const QString &text, const char *member) {
- auto *button = new QPushButton(text);
- connect(button, SIGNAL(clicked()), this, member);
- return button;
+QPushButton* KeyServerImportDialog::createButton(const QString& text,
+ const char* member) {
+ auto* button = new QPushButton(text);
+ connect(button, SIGNAL(clicked()), this, member);
+ return button;
}
-QComboBox *KeyServerImportDialog::createComboBox() {
- auto *comboBox = new QComboBox;
- comboBox->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Preferred);
+QComboBox* KeyServerImportDialog::createComboBox() {
+ auto* comboBox = new QComboBox;
+ comboBox->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Preferred);
- // Read keylist from ini-file and fill it into combobox
- comboBox->addItems(settings.value("keyserver/keyServerList").toStringList());
+ // Read keylist from ini-file and fill it into combobox
+ comboBox->addItems(settings.value("keyserver/keyServerList").toStringList());
- // set default keyserver in combobox
- QString keyserver = settings.value("keyserver/defaultKeyServer").toString();
- comboBox->setCurrentIndex(comboBox->findText(keyserver));
+ // set default keyserver in combobox
+ QString keyserver = settings.value("keyserver/defaultKeyServer").toString();
+ comboBox->setCurrentIndex(comboBox->findText(keyserver));
- return comboBox;
+ return comboBox;
}
void KeyServerImportDialog::createKeysTable() {
- keysTable = new QTableWidget();
- keysTable->setColumnCount(4);
+ keysTable = new QTableWidget();
+ keysTable->setColumnCount(4);
- // always a whole row is marked
- keysTable->setSelectionBehavior(QAbstractItemView::SelectRows);
- keysTable->setEditTriggers(QAbstractItemView::NoEditTriggers);
+ // always a whole row is marked
+ keysTable->setSelectionBehavior(QAbstractItemView::SelectRows);
+ keysTable->setEditTriggers(QAbstractItemView::NoEditTriggers);
- // Make just one row selectable
- keysTable->setSelectionMode(QAbstractItemView::SingleSelection);
+ // Make just one row selectable
+ keysTable->setSelectionMode(QAbstractItemView::SingleSelection);
- QStringList labels;
- labels << tr("UID") << tr("Creation date") << tr("KeyID") << tr("Tag");
- keysTable->horizontalHeader()->setSectionResizeMode(0, QHeaderView::ResizeToContents);
- keysTable->setHorizontalHeaderLabels(labels);
- keysTable->verticalHeader()->hide();
+ QStringList labels;
+ labels << tr("UID") << tr("Creation date") << tr("KeyID") << tr("Tag");
+ keysTable->horizontalHeader()->setSectionResizeMode(
+ 0, QHeaderView::ResizeToContents);
+ keysTable->setHorizontalHeaderLabels(labels);
+ keysTable->verticalHeader()->hide();
- connect(keysTable, SIGNAL(cellActivated(int, int)),
- this, SLOT(slotImport()));
+ connect(keysTable, SIGNAL(cellActivated(int, int)), this, SLOT(slotImport()));
}
-void KeyServerImportDialog::setMessage(const QString &text, bool error) {
- message->setText(text);
- if (error) {
- icon->setPixmap(QPixmap(":error.png").scaled(QSize(24, 24), Qt::KeepAspectRatio));
- } else {
- icon->setPixmap(QPixmap(":info.png").scaled(QSize(24, 24), Qt::KeepAspectRatio));
- }
+void KeyServerImportDialog::setMessage(const QString& text, bool error) {
+ message->setText(text);
+ if (error) {
+ icon->setPixmap(
+ QPixmap(":error.png").scaled(QSize(24, 24), Qt::KeepAspectRatio));
+ } else {
+ icon->setPixmap(
+ QPixmap(":info.png").scaled(QSize(24, 24), Qt::KeepAspectRatio));
+ }
}
void KeyServerImportDialog::slotSearch() {
+ if (searchLineEdit->text().isEmpty()) {
+ setMessage("<h4>" + tr("Text is empty.") + "</h4>", false);
+ return;
+ }
- if (searchLineEdit->text().isEmpty()) {
- setMessage("<h4>" + tr("Text is empty.") + "</h4>", false);
- return;
- }
-
- QUrl urlFromRemote = keyServerComboBox->currentText() + "/pks/lookup?search=" + searchLineEdit->text() +
- "&op=index&options=mr";
- qnam = new QNetworkAccessManager(this);
- QNetworkReply *reply = qnam->get(QNetworkRequest(urlFromRemote));
+ QUrl urlFromRemote = keyServerComboBox->currentText() +
+ "/pks/lookup?search=" + searchLineEdit->text() +
+ "&op=index&options=mr";
+ qnam = new QNetworkAccessManager(this);
+ QNetworkReply* reply = qnam->get(QNetworkRequest(urlFromRemote));
- connect(reply, SIGNAL(finished()),
- this, SLOT(slotSearchFinished()));
+ connect(reply, SIGNAL(finished()), this, SLOT(slotSearchFinished()));
- setLoading(true);
+ setLoading(true);
- while (reply->isRunning()) {
- QApplication::processEvents();
- }
-
- setLoading(false);
+ while (reply->isRunning()) {
+ QApplication::processEvents();
+ }
+ setLoading(false);
}
void KeyServerImportDialog::slotSearchFinished() {
- auto *reply = qobject_cast<QNetworkReply *>(sender());
-
- keysTable->clearContents();
- keysTable->setRowCount(0);
- QString firstLine = QString(reply->readLine(1024));
-
- auto error = reply->error();
- if (error != QNetworkReply::NoError) {
- qDebug() << "Error From Reply" << reply->errorString();
- switch (error) {
- case QNetworkReply::ContentNotFoundError :
- setMessage(tr("Not Key Found"), true);
- break;
- case QNetworkReply::TimeoutError :
- setMessage(tr("Timeout"), true);
- break;
- case QNetworkReply::HostNotFoundError :
- setMessage(tr("Key Server Not Found"), true);
- break;
- default:
- setMessage(tr("Connection Error"), true);
- }
+ auto* reply = qobject_cast<QNetworkReply*>(sender());
+
+ keysTable->clearContents();
+ keysTable->setRowCount(0);
+ QString firstLine = QString(reply->readLine(1024));
+
+ auto error = reply->error();
+ if (error != QNetworkReply::NoError) {
+ qDebug() << "Error From Reply" << reply->errorString();
+ switch (error) {
+ case QNetworkReply::ContentNotFoundError:
+ setMessage(tr("Not Key Found"), true);
+ break;
+ case QNetworkReply::TimeoutError:
+ setMessage(tr("Timeout"), true);
+ break;
+ case QNetworkReply::HostNotFoundError:
+ setMessage(tr("Key Server Not Found"), true);
+ break;
+ default:
+ setMessage(tr("Connection Error"), true);
+ }
+ return;
+ }
+
+ if (firstLine.contains("Error")) {
+ QString text = QString(reply->readLine(1024));
+ if (text.contains("Too many responses")) {
+ setMessage("<h4>" + tr("Too many responses from keyserver!") + "</h4>",
+ true);
+ return;
+ } else if (text.contains("No keys found")) {
+ // if string looks like hex string, search again with 0x prepended
+ QRegExp rx("[0-9A-Fa-f]*");
+ QString query = searchLineEdit->text();
+ if (rx.exactMatch(query)) {
+ setMessage("<h4>" +
+ tr("No keys found, input may be kexId, retrying search "
+ "with 0x.") +
+ "</h4>",
+ true);
+ searchLineEdit->setText(query.prepend("0x"));
+ this->slotSearch();
return;
+ } else {
+ setMessage("<h4>" + tr("No keys found containing the search string!") +
+ "</h4>",
+ true);
+ return;
+ }
+ } else if (text.contains("Insufficiently specific words")) {
+ setMessage(
+ "<h4>" + tr("Insufficiently specific search string!") + "</h4>",
+ true);
+ return;
+ } else {
+ setMessage(text, true);
+ return;
}
+ } else {
+ int row = 0;
+ bool strikeout = false;
+ while (reply->canReadLine()) {
+ auto line_buff = reply->readLine().trimmed();
+ QString decoded =
+ QString::fromUtf8(line_buff.constData(), line_buff.size());
+ QStringList line = decoded.split(":");
+ // TODO: have a look at two following pub lines
+ if (line[0] == "pub") {
+ strikeout = false;
+
+ QString flags = line[line.size() - 1];
+ keysTable->setRowCount(row + 1);
+
+ // flags can be "d" for disabled, "r" for revoked
+ // or "e" for expired
+ if (flags.contains("r") or flags.contains("d") or flags.contains("e")) {
+ strikeout = true;
+ if (flags.contains("e")) {
+ keysTable->setItem(row, 3,
+ new QTableWidgetItem(QString("expired")));
+ }
+ if (flags.contains("r")) {
+ keysTable->setItem(row, 3,
+ new QTableWidgetItem(QString(tr("revoked"))));
+ }
+ if (flags.contains("d")) {
+ keysTable->setItem(row, 3,
+ new QTableWidgetItem(QString(tr("disabled"))));
+ }
+ }
+
+ QStringList line2 = QString(reply->readLine()).split(":");
- if (firstLine.contains("Error")) {
- QString text = QString(reply->readLine(1024));
- if (text.contains("Too many responses")) {
- setMessage("<h4>" +tr("Too many responses from keyserver!") + "</h4>", true);
- return;
- } else if (text.contains("No keys found")) {
- // if string looks like hex string, search again with 0x prepended
- QRegExp rx("[0-9A-Fa-f]*");
- QString query = searchLineEdit->text();
- if (rx.exactMatch(query)) {
- setMessage("<h4>" + tr("No keys found, input may be kexId, retrying search with 0x.") + "</h4>", true);
- searchLineEdit->setText(query.prepend("0x"));
- this->slotSearch();
- return;
- } else {
- setMessage("<h4>" +tr("No keys found containing the search string!") + "</h4>", true);
- return;
- }
- } else if (text.contains("Insufficiently specific words")) {
- setMessage("<h4>" + tr("Insufficiently specific search string!") + "</h4>", true);
- return;
- } else {
- setMessage(text, true);
- return;
+ auto* uid = new QTableWidgetItem();
+ if (line2.size() > 1) {
+ uid->setText(line2[1]);
+ keysTable->setItem(row, 0, uid);
}
- } else {
- int row = 0;
- bool strikeout = false;
- while (reply->canReadLine()) {
- auto line_buff = reply->readLine().trimmed();
- QString decoded = QString::fromUtf8(line_buff.constData(), line_buff.size());
- QStringList line = decoded.split(":");
- //TODO: have a look at two following pub lines
- if (line[0] == "pub") {
- strikeout = false;
-
- QString flags = line[line.size() - 1];
- keysTable->setRowCount(row + 1);
-
- // flags can be "d" for disabled, "r" for revoked
- // or "e" for expired
- if (flags.contains("r") or flags.contains("d") or flags.contains("e")) {
- strikeout = true;
- if (flags.contains("e")) {
- keysTable->setItem(row, 3, new QTableWidgetItem(QString("expired")));
- }
- if (flags.contains("r")) {
- keysTable->setItem(row, 3, new QTableWidgetItem(QString(tr("revoked"))));
- }
- if (flags.contains("d")) {
- keysTable->setItem(row, 3, new QTableWidgetItem(QString(tr("disabled"))));
- }
- }
-
- QStringList line2 = QString(reply->readLine()).split(":");
-
- auto *uid = new QTableWidgetItem();
- if (line2.size() > 1) {
- uid->setText(line2[1]);
- keysTable->setItem(row, 0, uid);
- }
- auto *creation_date = new QTableWidgetItem(
- QDateTime::fromTime_t(line[4].toInt()).toString("dd. MMM. yyyy"));
- keysTable->setItem(row, 1, creation_date);
- auto *keyid = new QTableWidgetItem(line[1]);
- keysTable->setItem(row, 2, keyid);
- if (strikeout) {
- QFont strike = uid->font();
- strike.setStrikeOut(true);
- uid->setFont(strike);
- creation_date->setFont(strike);
- keyid->setFont(strike);
- }
- row++;
- } else {
- if (line[0] == "uid") {
- QStringList l;
- int height = keysTable->rowHeight(row - 1);
- keysTable->setRowHeight(row - 1, height + 16);
- QString tmp = keysTable->item(row - 1, 0)->text();
- tmp.append(QString("\n") + line[1]);
- auto *tmp1 = new QTableWidgetItem(tmp);
- keysTable->setItem(row - 1, 0, tmp1);
- if (strikeout) {
- QFont strike = tmp1->font();
- strike.setStrikeOut(true);
- tmp1->setFont(strike);
- }
- }
- }
- setMessage(tr("<h4>%1 keys found. Double click a key to import it.</h4>").arg(row), false);
+ auto* creation_date = new QTableWidgetItem(
+ QDateTime::fromTime_t(line[4].toInt()).toString("dd. MMM. yyyy"));
+ keysTable->setItem(row, 1, creation_date);
+ auto* keyid = new QTableWidgetItem(line[1]);
+ keysTable->setItem(row, 2, keyid);
+ if (strikeout) {
+ QFont strike = uid->font();
+ strike.setStrikeOut(true);
+ uid->setFont(strike);
+ creation_date->setFont(strike);
+ keyid->setFont(strike);
+ }
+ row++;
+ } else {
+ if (line[0] == "uid") {
+ QStringList l;
+ int height = keysTable->rowHeight(row - 1);
+ keysTable->setRowHeight(row - 1, height + 16);
+ QString tmp = keysTable->item(row - 1, 0)->text();
+ tmp.append(QString("\n") + line[1]);
+ auto* tmp1 = new QTableWidgetItem(tmp);
+ keysTable->setItem(row - 1, 0, tmp1);
+ if (strikeout) {
+ QFont strike = tmp1->font();
+ strike.setStrikeOut(true);
+ tmp1->setFont(strike);
+ }
}
- keysTable->resizeColumnsToContents();
+ }
+ setMessage(tr("<h4>%1 keys found. Double click a key to import it.</h4>")
+ .arg(row),
+ false);
}
- reply->deleteLater();
+ keysTable->resizeColumnsToContents();
+ }
+ reply->deleteLater();
}
void KeyServerImportDialog::slotImport() {
- if (keysTable->currentRow() > -1) {
- QString keyid = keysTable->item(keysTable->currentRow(), 2)->text();
- slotImport(QStringList(keyid), keyServerComboBox->currentText());
- }
+ if (keysTable->currentRow() > -1) {
+ QString keyid = keysTable->item(keysTable->currentRow(), 2)->text();
+ slotImport(QStringList(keyid), keyServerComboBox->currentText());
+ }
}
void KeyServerImportDialog::slotImport(const QStringList& keyIds) {
- QString keyserver = settings.value("keyserver/defaultKeyServer").toString();
- qDebug() << "Select Key Server" << keyserver;
- slotImport(keyIds, QUrl(keyserver));
+ QString keyserver = settings.value("keyserver/defaultKeyServer").toString();
+ qDebug() << "Select Key Server" << keyserver;
+ slotImport(keyIds, QUrl(keyserver));
}
-void KeyServerImportDialog::slotImportKey(const QVector<GpgKey>& keys) {
- QString keyserver = settings.value("keyserver/defaultKeyServer").toString();
- qDebug() << "Select Key Server" << keyserver;
- auto keyIds = QStringList();
- for(const auto &key : keys) {
- keyIds.append(key.id);
- }
- slotImport(keyIds, QUrl(keyserver));
+void KeyServerImportDialog::slotImportKey(const KeyIdArgsListPtr& keys) {
+ QString keyserver = settings.value("keyserver/defaultKeyServer").toString();
+ qDebug() << "Select Key Server" << keyserver;
+ auto key_ids = QStringList();
+ for (const auto& key_id : *keys) {
+ key_ids.append(QString::fromStdString(key_id));
+ }
+ slotImport(key_ids, QUrl(keyserver));
}
+void KeyServerImportDialog::slotImport(const QStringList& keyIds,
+ const QUrl& keyServerUrl) {
+ for (const auto& keyId : keyIds) {
+ QUrl reqUrl(keyServerUrl.scheme() + "://" + keyServerUrl.host() +
+ "/pks/lookup?op=get&search=0x" + keyId + "&options=mr");
+ qDebug() << "slotImport reqUrl" << reqUrl;
+ auto pManager = new QNetworkAccessManager(this);
-void KeyServerImportDialog::slotImport(const QStringList& keyIds, const QUrl &keyServerUrl) {
- for (const auto &keyId : keyIds) {
- QUrl reqUrl(
- keyServerUrl.scheme() + "://" + keyServerUrl.host() + "/pks/lookup?op=get&search=0x" + keyId +
- "&options=mr");
- qDebug() << "slotImport reqUrl" << reqUrl;
- auto pManager = new QNetworkAccessManager(this);
+ QNetworkReply* reply = pManager->get(QNetworkRequest(reqUrl));
- QNetworkReply *reply = pManager->get(QNetworkRequest(reqUrl));
+ connect(reply, SIGNAL(finished()), this, SLOT(slotImportFinished()));
- connect(reply, SIGNAL(finished()),
- this, SLOT(slotImportFinished()));
-
- setLoading(true);
-
- while(reply->isRunning()) {
- QApplication::processEvents();
- }
+ setLoading(true);
- setLoading(false);
+ while (reply->isRunning()) {
+ QApplication::processEvents();
}
+
+ setLoading(false);
+ }
}
void KeyServerImportDialog::slotImportFinished() {
- auto *reply = qobject_cast<QNetworkReply *>(sender());
-
- QByteArray key = reply->readAll();
-
- QVariant redirectionTarget = reply->attribute(QNetworkRequest::RedirectionTargetAttribute);
-
- auto error = reply->error();
- if (error != QNetworkReply::NoError) {
- qDebug() << "Error From Reply" << reply->errorString();
- switch (error) {
- case QNetworkReply::ContentNotFoundError :
- setMessage(tr("Key Not Found"), true);
- break;
- case QNetworkReply::TimeoutError :
- setMessage(tr("Timeout"), true);
- break;
- case QNetworkReply::HostNotFoundError :
- setMessage(tr("Key Server Not Found"), true);
- break;
- default:
- setMessage(tr("Connection Error"), true);
- }
- if(mAutomatic) {
- setWindowFlags(Qt::Window | Qt::WindowTitleHint | Qt::CustomizeWindowHint | Qt::WindowCloseButtonHint);
- }
- return;
- }
-
- // Add keyserver to list in config-file, if it isn't contained
- QStringList keyServerList = settings.value("keyserver/keyServerList").toStringList();
- if (!keyServerList.contains(keyServerComboBox->currentText())) {
- keyServerList.append(keyServerComboBox->currentText());
- settings.setValue("keyserver/keyServerList", keyServerList);
+ auto* reply = qobject_cast<QNetworkReply*>(sender());
+
+ QByteArray key = reply->readAll();
+
+ QVariant redirectionTarget =
+ reply->attribute(QNetworkRequest::RedirectionTargetAttribute);
+
+ auto error = reply->error();
+ if (error != QNetworkReply::NoError) {
+ qDebug() << "Error From Reply" << reply->errorString();
+ switch (error) {
+ case QNetworkReply::ContentNotFoundError:
+ setMessage(tr("Key Not Found"), true);
+ break;
+ case QNetworkReply::TimeoutError:
+ setMessage(tr("Timeout"), true);
+ break;
+ case QNetworkReply::HostNotFoundError:
+ setMessage(tr("Key Server Not Found"), true);
+ break;
+ default:
+ setMessage(tr("Connection Error"), true);
}
- reply->deleteLater();
-
- this->importKeys(key.constData());
- if(mAutomatic) {
- setMessage(tr("<h4>Key Updated</h4>"), false);
- } else {
- setMessage(tr("<h4>Key Imported</h4>"), false);
+ if (mAutomatic) {
+ setWindowFlags(Qt::Window | Qt::WindowTitleHint |
+ Qt::CustomizeWindowHint | Qt::WindowCloseButtonHint);
}
-
-
+ return;
+ }
+
+ // Add keyserver to list in config-file, if it isn't contained
+ QStringList keyServerList =
+ settings.value("keyserver/keyServerList").toStringList();
+ if (!keyServerList.contains(keyServerComboBox->currentText())) {
+ keyServerList.append(keyServerComboBox->currentText());
+ settings.setValue("keyserver/keyServerList", keyServerList);
+ }
+ reply->deleteLater();
+
+ this->importKeys(std::make_unique<ByteArray>(key.constData(), key.length()));
+ if (mAutomatic) {
+ setMessage(tr("<h4>Key Updated</h4>"), false);
+ } else {
+ setMessage(tr("<h4>Key Imported</h4>"), false);
+ }
}
-void KeyServerImportDialog::importKeys(QByteArray inBuffer) {
- GpgImportInformation result = mCtx->importKey(std::move(inBuffer));
- if(mAutomatic) {
- new KeyImportDetailDialog(mCtx, result, false, this);
- this->accept();
- } else {
- new KeyImportDetailDialog(mCtx, result, false, this);
- }
+void KeyServerImportDialog::importKeys(ByteArrayPtr in_data) {
+ GpgImportInformation result =
+ GpgKeyImportExportor::GetInstance().ImportKey(std::move(in_data));
+ if (mAutomatic) {
+ new KeyImportDetailDialog(result, true, this);
+ this->accept();
+ } else {
+ new KeyImportDetailDialog(result, false, this);
+ }
}
void KeyServerImportDialog::setLoading(bool status) {
- if (status) {
- waitingBar->setVisible(true);
- icon->setVisible(false);
- message->setVisible(false);
- } else {
- waitingBar->setVisible(false);
- icon->setVisible(true);
- message->setVisible(true);
- }
-}
-
-KeyServerImportDialog::KeyServerImportDialog(GpgFrontend::GpgContext *ctx, QWidget *parent)
- : QDialog(parent), appPath(qApp->applicationDirPath()),
- settings(RESOURCE_DIR(appPath) + "/conf/gpgfrontend.ini", QSettings::IniFormat),
- mCtx(ctx), mAutomatic(true) {
-
- setWindowFlags(Qt::Window | Qt::WindowTitleHint | Qt::CustomizeWindowHint);
-
- message = new QLabel;
- message->setFixedHeight(24);
- icon = new QLabel;
- icon->setFixedHeight(24);
-
- // Network Waiting
- waitingBar = new QProgressBar();
+ if (status) {
+ waitingBar->setVisible(true);
+ icon->setVisible(false);
+ message->setVisible(false);
+ } else {
waitingBar->setVisible(false);
- waitingBar->setRange(0, 0);
- waitingBar->setFixedHeight(24);
- waitingBar->setFixedWidth(200);
-
- // Layout for messagebox
- auto *messageLayout = new QHBoxLayout;
- messageLayout->addWidget(icon);
- messageLayout->addWidget(message);
- messageLayout->addWidget(waitingBar);
- messageLayout->addStretch();
-
- keyServerComboBox = createComboBox();
-
- auto *mainLayout = new QGridLayout;
-
- mainLayout->addLayout(messageLayout, 0, 0, 1, 3);
+ icon->setVisible(true);
+ message->setVisible(true);
+ }
+}
- this->setLayout(mainLayout);
- this->setWindowTitle(tr("Upload Keys from Keyserver"));
- this->setFixedSize(200, 42);
- this->setModal(true);
+KeyServerImportDialog::KeyServerImportDialog(QWidget* parent)
+ : QDialog(parent),
+ appPath(qApp->applicationDirPath()),
+ settings(RESOURCE_DIR(appPath) + "/conf/gpgfrontend.ini",
+ QSettings::IniFormat),
+ mAutomatic(true) {
+ setWindowFlags(Qt::Window | Qt::WindowTitleHint | Qt::CustomizeWindowHint);
+
+ message = new QLabel;
+ message->setFixedHeight(24);
+ icon = new QLabel;
+ icon->setFixedHeight(24);
+
+ // Network Waiting
+ waitingBar = new QProgressBar();
+ waitingBar->setVisible(false);
+ waitingBar->setRange(0, 0);
+ waitingBar->setFixedHeight(24);
+ waitingBar->setFixedWidth(200);
+
+ // Layout for messagebox
+ auto* messageLayout = new QHBoxLayout;
+ messageLayout->addWidget(icon);
+ messageLayout->addWidget(message);
+ messageLayout->addWidget(waitingBar);
+ messageLayout->addStretch();
+
+ keyServerComboBox = createComboBox();
+
+ auto* mainLayout = new QGridLayout;
+
+ mainLayout->addLayout(messageLayout, 0, 0, 1, 3);
+
+ this->setLayout(mainLayout);
+ this->setWindowTitle(tr("Upload Keys from Keyserver"));
+ this->setFixedSize(200, 42);
+ this->setModal(true);
}
+
+} // namespace GpgFrontend::UI
diff --git a/src/ui/KeyServerImportDialog.h b/src/ui/KeyServerImportDialog.h
new file mode 100644
index 00000000..615a77c6
--- /dev/null
+++ b/src/ui/KeyServerImportDialog.h
@@ -0,0 +1,94 @@
+/**
+ * This file is part of GPGFrontend.
+ *
+ * GPGFrontend is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Foobar is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Foobar. If not, see <https://www.gnu.org/licenses/>.
+ *
+ * The initial version of the source code is inherited from gpg4usb-team.
+ * Their source code version also complies with GNU General Public License.
+ *
+ * The source code version of this software was modified and released
+ * by Saturneric<[email protected]> starting on May 12, 2021.
+ *
+ */
+
+#ifndef __KEYSERVERIMPORTDIALOG_H__
+#define __KEYSERVERIMPORTDIALOG_H__
+
+#include "KeyImportDetailDialog.h"
+#include "gpg/GpgContext.h"
+#include "ui/GpgFrontendUI.h"
+#include "ui/widgets/KeyList.h"
+
+namespace GpgFrontend::UI {
+
+class KeyServerImportDialog : public QDialog {
+ Q_OBJECT
+
+ public:
+ KeyServerImportDialog(KeyList* keyList, bool automatic, QWidget* parent);
+
+ KeyServerImportDialog(QWidget* parent);
+
+ void slotImport(const QStringList& keyIds);
+
+ void slotImport(const QStringList& keyIds, const QUrl& keyserverUrl);
+
+ void slotImportKey(const KeyIdArgsListPtr& keys);
+
+ private slots:
+
+ void slotImport();
+
+ void slotSearchFinished();
+
+ void slotImportFinished();
+
+ void slotSearch();
+
+ private:
+ void createKeysTable();
+
+ void setMessage(const QString& text, bool error);
+
+ void importKeys(ByteArrayPtr in_data);
+
+ void setLoading(bool status);
+
+ QPushButton* createButton(const QString& text, const char* member);
+
+ QComboBox* createComboBox();
+
+ bool mAutomatic;
+
+ QString appPath;
+ QSettings settings;
+
+ KeyList* mKeyList{};
+ QLineEdit* searchLineEdit{};
+ QComboBox* keyServerComboBox{};
+ QProgressBar* waitingBar;
+ QLabel* searchLabel{};
+ QLabel* keyServerLabel{};
+ QLabel* message{};
+ QLabel* icon{};
+ QPushButton* closeButton{};
+ QPushButton* importButton{};
+ QPushButton* searchButton{};
+ QTableWidget* keysTable{};
+ QNetworkAccessManager* qnam{};
+};
+
+} // namespace GpgFrontend::UI
+
+#endif // __KEYSERVERIMPORTDIALOG_H__
diff --git a/src/ui/KeyUploadDialog.cpp b/src/ui/KeyUploadDialog.cpp
index 321441b7..06b1d074 100644
--- a/src/ui/KeyUploadDialog.cpp
+++ b/src/ui/KeyUploadDialog.cpp
@@ -24,105 +24,116 @@
#include "ui/KeyUploadDialog.h"
-KeyUploadDialog::KeyUploadDialog(GpgFrontend::GpgContext *ctx, const QVector<GpgKey> &keys, QWidget *parent)
+#include <algorithm>
+
+#include "gpg/function/GpgKeyGetter.h"
+#include "gpg/function/GpgKeyImportExportor.h"
+
+namespace GpgFrontend::UI {
+
+KeyUploadDialog::KeyUploadDialog(const KeyIdArgsListPtr& keys_ids,
+ QWidget* parent)
: appPath(qApp->applicationDirPath()),
- settings(RESOURCE_DIR(appPath) + "/conf/gpgfrontend.ini", QSettings::IniFormat),
- mCtx(ctx),
- mKeys(keys),
- QDialog(parent) {
-
-
- auto *pb = new QProgressBar();
- pb->setRange(0, 0);
- pb->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Preferred);
- pb->setTextVisible(false);
-
- auto *layout = new QVBoxLayout();
- layout->addWidget(pb);
- layout->setContentsMargins(0, 0, 0, 0);
- layout->setSpacing(0);
- this->setLayout(layout);
-
- this->setModal(true);
- this->setWindowTitle(tr("Uploading Public Key"));
- this->setFixedSize(240, 42);
+ settings(RESOURCE_DIR(appPath) + "/conf/gpgfrontend.ini",
+ QSettings::IniFormat),
+ mKeys(GpgKeyGetter::GetInstance().GetKeys(keys_ids)),
+ QDialog(parent) {
+ auto* pb = new QProgressBar();
+ pb->setRange(0, 0);
+ pb->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Preferred);
+ pb->setTextVisible(false);
+
+ auto* layout = new QVBoxLayout();
+ layout->addWidget(pb);
+ layout->setContentsMargins(0, 0, 0, 0);
+ layout->setSpacing(0);
+ this->setLayout(layout);
+
+ this->setModal(true);
+ this->setWindowTitle(tr("Uploading Public Key"));
+ this->setFixedSize(240, 42);
}
void KeyUploadDialog::slotUpload() {
- mCtx->exportKeys(mKeys, mKeyData);
- uploadKeyToServer(mKeyData);
+ auto out_data = std::make_unique<ByteArray>();
+ GpgKeyImportExportor::GetInstance().ExportKeys(*mKeys, out_data);
+ uploadKeyToServer(std::move(out_data));
}
-void KeyUploadDialog::uploadKeyToServer(QByteArray &keys) {
+void KeyUploadDialog::uploadKeyToServer(ByteArrayPtr keys_data) {
+ // set default keyserver
+ QString keyserver = settings.value("keyserver/defaultKeyServer").toString();
- // set default keyserver
- QString keyserver = settings.value("keyserver/defaultKeyServer").toString();
+ QUrl reqUrl(keyserver + "/pks/add");
+ auto qnam = new QNetworkAccessManager(this);
- QUrl reqUrl(keyserver + "/pks/add");
- auto qnam = new QNetworkAccessManager(this);
+ // Building Post Data
+ QByteArray postData;
- // Building Post Data
- QByteArray postData;
+ auto& data = *keys_data;
- keys.replace("\n", "%0A")
- .replace("\r", "%0D")
- .replace("(", "%28")
- .replace(")", "%29")
- .replace("/", "%2F")
- .replace(":", "%3A")
- .replace("+", "%2B")
- .replace('=', "%3D")
- .replace(' ', '+');
+ boost::algorithm::replace_all(data, "\n", "%0A");
+ boost::algorithm::replace_all(data, "\r", "%0D");
+ boost::algorithm::replace_all(data, "(", "%28");
+ boost::algorithm::replace_all(data, ")", "%29");
+ boost::algorithm::replace_all(data, "/", "%2F");
+ boost::algorithm::replace_all(data, ":", "%3A");
+ boost::algorithm::replace_all(data, "+", "%2B");
+ boost::algorithm::replace_all(data, '=', "%3D");
+ boost::algorithm::replace_all(data, ' ', '+');
- QNetworkRequest request(reqUrl);
- request.setHeader(QNetworkRequest::ContentTypeHeader, "application/x-www-form-urlencoded");
+ QNetworkRequest request(reqUrl);
+ request.setHeader(QNetworkRequest::ContentTypeHeader,
+ "application/x-www-form-urlencoded");
- postData.append("keytext").append("=").append(keys);
+ postData.append("keytext").append("=").append(
+ QString::fromStdString(data).toUtf8());
- // Send Post Data
- QNetworkReply *reply = qnam->post(request, postData);
- connect(reply, SIGNAL(finished()),
- this, SLOT(slotUploadFinished()));
+ // Send Post Data
+ QNetworkReply* reply = qnam->post(request, postData);
+ connect(reply, SIGNAL(finished()), this, SLOT(slotUploadFinished()));
+ // Keep Waiting
+ while (reply->isRunning()) {
+ QApplication::processEvents();
+ }
- // Keep Waiting
- while(reply->isRunning()) {
- QApplication::processEvents();
- }
-
- // Done
- this->hide();
- this->close();
+ // Done
+ this->hide();
+ this->close();
}
void KeyUploadDialog::slotUploadFinished() {
- auto *reply = qobject_cast<QNetworkReply *>(sender());
-
- QByteArray response = reply->readAll();
- qDebug() << "Response: " << response.data();
-
- auto error = reply->error();
- if (error != QNetworkReply::NoError) {
- qDebug() << "Error From Reply" << reply->errorString();
- QString message;
- switch (error) {
- case QNetworkReply::ContentNotFoundError :
- message = tr("Key Not Found");
- break;
- case QNetworkReply::TimeoutError :
- message = tr("Timeout");
- break;
- case QNetworkReply::HostNotFoundError :
- message = tr("Key Server Not Found");
- break;
- default:
- message = tr("Connection Error");
- }
- QMessageBox::critical(this, "Upload Failed", message);
- return;
- } else {
- QMessageBox::information(this, "Upload Success", "Upload Public Key Successfully");
- qDebug() << "Success while contacting keyserver!";
+ auto* reply = qobject_cast<QNetworkReply*>(sender());
+
+ QByteArray response = reply->readAll();
+ qDebug() << "Response: " << response.data();
+
+ auto error = reply->error();
+ if (error != QNetworkReply::NoError) {
+ qDebug() << "Error From Reply" << reply->errorString();
+ QString message;
+ switch (error) {
+ case QNetworkReply::ContentNotFoundError:
+ message = tr("Key Not Found");
+ break;
+ case QNetworkReply::TimeoutError:
+ message = tr("Timeout");
+ break;
+ case QNetworkReply::HostNotFoundError:
+ message = tr("Key Server Not Found");
+ break;
+ default:
+ message = tr("Connection Error");
}
- reply->deleteLater();
+ QMessageBox::critical(this, "Upload Failed", message);
+ return;
+ } else {
+ QMessageBox::information(this, "Upload Success",
+ "Upload Public Key Successfully");
+ qDebug() << "Success while contacting keyserver!";
+ }
+ reply->deleteLater();
}
+
+} // namespace GpgFrontend::UI
diff --git a/include/ui/KeyUploadDialog.h b/src/ui/KeyUploadDialog.h
index e6c3b836..b57440d4 100644
--- a/include/ui/KeyUploadDialog.h
+++ b/src/ui/KeyUploadDialog.h
@@ -25,33 +25,33 @@
#ifndef GPGFRONTEND_KEYUPLOADWIDGET_H
#define GPGFRONTEND_KEYUPLOADWIDGET_H
-#include "GpgFrontend.h"
#include "gpg/GpgContext.h"
+#include "ui/GpgFrontendUI.h"
-class KeyUploadDialog : public QDialog {
-Q_OBJECT
-public:
- KeyUploadDialog(GpgFrontend::GpgContext *ctx, const QVector<GpgKey> &keys, QWidget *parent = nullptr);
-
-public slots:
+namespace GpgFrontend::UI {
- void slotUpload();
+class KeyUploadDialog : public QDialog {
+ Q_OBJECT
+ public:
+ explicit KeyUploadDialog(const KeyIdArgsListPtr& keys_ids, QWidget* parent);
-private slots:
+ public slots:
- void uploadKeyToServer(QByteArray &keys);
+ void slotUpload();
- void slotUploadFinished();
+ private slots:
-private:
+ void uploadKeyToServer(GpgFrontend::ByteArrayPtr keys_data);
- GpgFrontend::GpgContext *mCtx;
- const QVector<GpgKey> &mKeys;
- QString appPath;
- QSettings settings;
- QByteArray mKeyData;
+ void slotUploadFinished();
+ private:
+ QString appPath;
+ QSettings settings;
+ KeyListPtr mKeys;
+ QByteArray mKeyData;
};
+} // namespace GpgFrontend::UI
-#endif //GPGFRONTEND_KEYUPLOADWIDGET_H
+#endif // GPGFRONTEND_KEYUPLOADWIDGET_H
diff --git a/src/ui/MainWindow.cpp b/src/ui/MainWindow.cpp
new file mode 100644
index 00000000..33478b8a
--- /dev/null
+++ b/src/ui/MainWindow.cpp
@@ -0,0 +1,249 @@
+/**
+ * This file is part of GPGFrontend.
+ *
+ * GPGFrontend is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Foobar is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Foobar. If not, see <https://www.gnu.org/licenses/>.
+ *
+ * The initial version of the source code is inherited from gpg4usb-team.
+ * Their source code version also complies with GNU General Public License.
+ *
+ * The source code version of this software was modified and released
+ * by Saturneric<[email protected]> starting on May 12, 2021.
+ *
+ */
+
+#include "MainWindow.h"
+#include "ui/help/VersionCheckThread.h"
+
+namespace GpgFrontend::UI {
+
+MainWindow::MainWindow()
+ : appPath(qApp->applicationDirPath()),
+ settings(RESOURCE_DIR(appPath) + "/conf/gpgfrontend.ini",
+ QSettings::IniFormat) {
+ networkAccessManager = new QNetworkAccessManager(this);
+
+ auto waitingDialog = new WaitingDialog(tr("Loading Gnupg"), this);
+
+ QString baseUrl =
+ "https://api.github.com/repos/saturneric/gpgfrontend/releases/latest";
+
+ QNetworkRequest request;
+ request.setUrl(QUrl(baseUrl));
+
+ QNetworkReply* replay = networkAccessManager->get(request);
+
+ auto version_thread = new VersionCheckThread(replay);
+
+ connect(version_thread, SIGNAL(finished()), version_thread,
+ SLOT(deleteLater()));
+ connect(version_thread,
+ SIGNAL(upgradeVersion(const QString&, const QString&)), this,
+ SLOT(slotVersionUpgrade(const QString&, const QString&)));
+
+ version_thread->start();
+
+ // Check Context Status
+ if (!GpgContext::GetInstance().good()) {
+ QMessageBox::critical(
+ nullptr, tr("ENV Loading Failed"),
+ tr("Gnupg is not installed correctly, please follow the ReadME "
+ "instructions to install gnupg and then open GPGFrontend."));
+ QCoreApplication::quit();
+ exit(0);
+ }
+
+ /* get path were app was started */
+ setCorner(Qt::BottomLeftCorner, Qt::LeftDockWidgetArea);
+ setCorner(Qt::BottomRightCorner, Qt::RightDockWidgetArea);
+
+ edit = new TextEdit(this);
+ setCentralWidget(edit);
+
+ /* the list of Keys available*/
+ mKeyList = new KeyList(KeyListRow::SECRET_OR_PUBLIC_KEY,
+ KeyListColumn::TYPE | KeyListColumn::NAME |
+ KeyListColumn::EmailAddress |
+ KeyListColumn::Usage | KeyListColumn::Validity,
+ this);
+ mKeyList->setFilter([](const GpgKey& key) -> bool {
+ if (key.revoked() || key.disabled() || key.expired())
+ return false;
+ else
+ return true;
+ });
+ mKeyList->slotRefresh();
+
+ infoBoard = new InfoBoardWidget(this, mKeyList);
+
+ /* List of binary Attachments */
+ attachmentDockCreated = false;
+
+ /* Variable containing if restart is needed */
+ this->slotSetRestartNeeded(false);
+
+ keyMgmt = new KeyMgmt(this);
+ keyMgmt->hide();
+ /* test attachmentdir for files alll 15s */
+ auto* timer = new QTimer(this);
+ connect(timer, SIGNAL(timeout()), this, SLOT(slotCheckAttachmentFolder()));
+ timer->start(5000);
+
+ createActions();
+ createMenus();
+ createToolBars();
+ createStatusBar();
+ createDockWindows();
+
+ connect(edit->tabWidget, SIGNAL(currentChanged(int)), this,
+ SLOT(slotDisableTabActions(int)));
+
+ mKeyList->addMenuAction(appendSelectedKeysAct);
+ mKeyList->addMenuAction(copyMailAddressToClipboardAct);
+ mKeyList->addMenuAction(showKeyDetailsAct);
+ mKeyList->addSeparator();
+ mKeyList->addMenuAction(refreshKeysFromKeyserverAct);
+ mKeyList->addMenuAction(uploadKeyToServerAct);
+
+ restoreSettings();
+
+ // open filename if provided as first command line parameter
+ QStringList args = qApp->arguments();
+ if (args.size() > 1) {
+ if (!args[1].startsWith("-")) {
+ if (QFile::exists(args[1]))
+ edit->loadFile(args[1]);
+ }
+ }
+ edit->curTextPage()->setFocus();
+ this->setMinimumSize(1200, 700);
+ this->setWindowTitle(qApp->applicationName());
+ this->show();
+
+ // Show wizard, if the don't show wizard message box wasn't checked
+ // and keylist doesn't contain a private key
+ qDebug() << "wizard/showWizard"
+ << settings.value("wizard/showWizard", true).toBool();
+ qDebug() << "wizard/nextPage" << settings.value("wizard/nextPage").isNull();
+ if (settings.value("wizard/showWizard", true).toBool() ||
+ !settings.value("wizard/nextPage").isNull()) {
+ slotStartWizard();
+ }
+}
+
+void MainWindow::restoreSettings() {
+ // state sets pos & size of dock-widgets
+ this->restoreState(settings.value("window/windowState").toByteArray());
+
+ // Restore window size & location
+ if (settings.value("window/windowSave").toBool()) {
+ QPoint pos = settings.value("window/pos", QPoint(100, 100)).toPoint();
+ QSize size = settings.value("window/size", QSize(800, 450)).toSize();
+ this->resize(size);
+ this->move(pos);
+ } else {
+ this->resize(QSize(800, 450));
+ this->move(QPoint(100, 100));
+ }
+
+ // Iconsize
+ QSize iconSize = settings.value("toolbar/iconsize", QSize(24, 24)).toSize();
+ this->setIconSize(iconSize);
+
+ importButton->setIconSize(iconSize);
+ fileEncButton->setIconSize(iconSize);
+ // set list of keyserver if not defined
+ QStringList* keyServerDefaultList;
+ keyServerDefaultList = new QStringList("http://keys.gnupg.net");
+ keyServerDefaultList->append("https://keyserver.ubuntu.com");
+ keyServerDefaultList->append("http://pool.sks-keyservers.net");
+
+ QStringList keyServerList =
+ settings.value("keyserver/keyServerList", *keyServerDefaultList)
+ .toStringList();
+ settings.setValue("keyserver/keyServerList", keyServerList);
+
+ // set default keyserver, if it's not set
+ QString defaultKeyServer = settings
+ .value("keyserver/defaultKeyServer",
+ QString("https://keyserver.ubuntu.com"))
+ .toString();
+ settings.setValue("keyserver/defaultKeyServer", defaultKeyServer);
+
+ // Iconstyle
+ Qt::ToolButtonStyle buttonStyle = static_cast<Qt::ToolButtonStyle>(
+ settings.value("toolbar/iconstyle", Qt::ToolButtonTextUnderIcon)
+ .toUInt());
+ this->setToolButtonStyle(buttonStyle);
+ importButton->setToolButtonStyle(buttonStyle);
+ fileEncButton->setToolButtonStyle(buttonStyle);
+
+ // Checked Keys
+ if (settings.value("keys/saveKeyChecked").toBool()) {
+ QStringList keyIds =
+ settings.value("keys/savedCheckedKeyList").toStringList();
+ auto key_ids_ptr = std::make_unique<KeyIdArgsList>();
+ for (auto& key_id : keyIds)
+ key_ids_ptr->push_back(key_id.toStdString());
+ mKeyList->setChecked(key_ids_ptr);
+ }
+}
+
+void MainWindow::saveSettings() {
+ // window position and size
+ settings.setValue("window/windowState", saveState());
+ settings.setValue("window/pos", pos());
+ settings.setValue("window/size", size());
+
+ // keyid-list of private checked keys
+ if (settings.value("keys/saveKeyChecked").toBool()) {
+ auto keyIds = mKeyList->getChecked();
+ if (!keyIds->empty()) {
+ QStringList key_ids_str_list;
+ for (const auto& key_id : keyIds)
+ key_ids_str_list << QString::fromStdString(key_id);
+ settings.setValue("keys/savedCheckedKeyList", key_ids_str_list);
+ } else {
+ settings.setValue("keys/savedCheckedKeyList", "");
+ }
+ } else {
+ settings.remove("keys/savedCheckedKeyList");
+ }
+}
+
+void MainWindow::closeAttachmentDock() {
+ if (!attachmentDockCreated) {
+ return;
+ }
+ attachmentDock->close();
+ attachmentDock->deleteLater();
+ attachmentDockCreated = false;
+}
+
+void MainWindow::closeEvent(QCloseEvent* event) {
+ /*
+ * ask to save changes, if there are
+ * modified documents in any tab
+ */
+ if (edit->maybeSaveAnyTab()) {
+ saveSettings();
+ event->accept();
+ } else {
+ event->ignore();
+ }
+
+ // clear password from memory
+ // GpgContext::GetInstance().clearPasswordCache();
+}
+
+} // namespace GpgFrontend::UI
diff --git a/src/ui/MainWindow.h b/src/ui/MainWindow.h
new file mode 100644
index 00000000..333ee971
--- /dev/null
+++ b/src/ui/MainWindow.h
@@ -0,0 +1,425 @@
+/**
+ * This file is part of GPGFrontend.
+ *
+ * GPGFrontend is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Foobar is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Foobar. If not, see <https://www.gnu.org/licenses/>.
+ *
+ * The initial version of the source code is inherited from gpg4usb-team.
+ * Their source code version also complies with GNU General Public License.
+ *
+ * The source code version of this software was modified and released
+ * by Saturneric<[email protected]> starting on May 12, 2021.
+ *
+ */
+
+#ifndef __GPGWIN_H__
+#define __GPGWIN_H__
+
+#include "gpg/GpgConstants.h"
+#include "ui/FileEncryptionDialog.h"
+#include "ui/FindWidget.h"
+#include "ui/GpgFrontendUI.h"
+#include "ui/KeyMgmt.h"
+#include "ui/KeyUploadDialog.h"
+#include "ui/SettingsDialog.h"
+#include "ui/WaitingDialog.h"
+#include "ui/Wizard.h"
+#include "ui/help/AboutDialog.h"
+#include "ui/widgets/InfoBoardWidget.h"
+#include "ui/widgets/TextEdit.h"
+
+#include "gpg/result_analyse/DecryptResultAnalyse.h"
+#include "gpg/result_analyse/EncryptResultAnalyse.h"
+#include "gpg/result_analyse/SignResultAnalyse.h"
+
+namespace GpgFrontend::UI {
+/**
+ * @brief
+ *
+ */
+class MainWindow : public QMainWindow {
+ Q_OBJECT
+
+ public:
+ /**
+ * @brief
+ *
+ */
+ MainWindow();
+
+ public slots:
+
+ void slotSetStatusBarText(const QString& text);
+
+ protected:
+ /**
+ * @details Close event shows a save dialog, if there are unsaved documents on
+ * exit.
+ * @param event
+ */
+ void closeEvent(QCloseEvent* event) override;
+
+ public slots:
+
+ /**
+ * @details Open a new tab for path
+ */
+ void slotOpenFile(QString& path);
+
+ /**
+ * @details Open dialog for encrypting file.
+ */
+ void slotFileEncrypt();
+
+ /**
+ * @details Open dialog for decrypting file.
+ */
+ void slotFileDecrypt();
+
+ /**
+ * @details Open dialog for signing file.
+ */
+ void slotFileSign();
+
+ /**
+ * @details Open dialog for verifying file.
+ */
+ void slotFileVerify();
+
+ /**
+ * @details Open dialog for signing file.
+ */
+ void slotFileEncryptSign();
+
+ /**
+ * @details Open dialog for verifying file.
+ */
+ void slotFileDecryptVerify();
+
+ private slots:
+
+ /**
+ * @details encrypt the text of currently active textedit-page
+ * with the currently checked keys
+ */
+ void slotEncrypt();
+
+ /**
+ * @details encrypt and sign the text of currently active textedit-page
+ * with the currently checked keys
+ */
+ void slotEncryptSign();
+
+ /**
+ * @details Show a passphrase dialog and decrypt the text of currently active
+ * tab.
+ */
+ void slotDecrypt();
+
+ /**
+ * @details Sign the text of currently active tab with the checked private
+ * keys
+ */
+ void slotSign();
+
+ /**
+ * @details Verify the text of currently active tab and show verify
+ * information. If document is signed with a key, which is not in keylist,
+ * show import missing key from keyserver in Menu of verifynotification.
+ */
+ void slotVerify();
+
+ /**
+ * @details decrypt and verify the text of currently active textedit-page
+ * with the currently checked keys
+ */
+ void slotDecryptVerify();
+
+ /**
+ * @details Open dialog for encrypting file.
+ */
+ void slotFileEncryptCustom();
+
+ /**
+ * @details Open dialog for decrypting file.
+ */
+ void slotFileDecryptCustom();
+
+ /**
+ * @details Open dialog for signing file.
+ */
+ void slotFileSignCustom();
+
+ /**
+ * @details Open dialog for verifying file.
+ */
+ void slotFileVerifyCustom();
+
+ /**
+ * @details Show the details of the first of the first of selected keys
+ */
+ void slotShowKeyDetails();
+
+ /**
+ * @details Refresh key information of selected keys from default keyserver
+ */
+ void refreshKeysFromKeyserver();
+
+ /**
+ * @details upload the selected key to the keyserver
+ */
+ void uploadKeyToServer();
+
+ /**
+ * @details Open find widget.
+ */
+ void slotFind();
+
+ /**
+ * @details start the wizard
+ */
+ void slotStartWizard();
+
+ /**
+ * @details Import keys from currently active tab to keylist if possible.
+ */
+ void slotImportKeyFromEdit();
+
+ /**
+ * @details Append the selected keys to currently active textedit.
+ */
+ void slotAppendSelectedKeys();
+
+ /**
+ * @details Copy the mailaddress of selected key to clipboard.
+ * Method for keylists contextmenu.
+ */
+ void slotCopyMailAddressToClipboard();
+
+ /**
+ * @details Open key management dialog.
+ */
+ void slotOpenKeyManagement();
+
+ /**
+ * @details Open about-dialog.
+ */
+ void slotAbout();
+
+ /**
+ * @details Open check-update-tab in about-dialog.
+ */
+ void slotCheckUpdate();
+
+ /**
+ * @details Open File Opera Tab
+ */
+ void slotOpenFileTab();
+
+ /**
+ * @details Open settings-dialog.
+ */
+ void slotOpenSettingsDialog();
+
+ /**
+ * @details Show a warn message in status bar, if there are files in
+ * attachment folder.
+ */
+ void slotCheckAttachmentFolder();
+
+ /**
+ * @details Replace double linebreaks by single linebreaks in currently active
+ * tab.
+ */
+ void slotCleanDoubleLinebreaks();
+
+ /**
+ * @details Cut the existing PGP header and footer from current tab.
+ */
+ void slotCutPgpHeader();
+
+ /**
+ * @details Add PGP header and footer to current tab.
+ */
+ void slotAddPgpHeader();
+
+ /**
+ * @details Disable tab related actions, if number of tabs is 0.
+ * @param number number of the opened tabs and -1, if no tab is opened
+ */
+ void slotDisableTabActions(int number);
+
+ /**
+ * @details get value of member restartNeeded to needed.
+ * @param needed true, if application has to be restarted
+ */
+ void slotSetRestartNeeded(bool needed);
+
+ /**
+ * @details called when need to upgrade.
+ */
+ void slotVersionUpgrade(const QString& currentVersion,
+ const QString& latestVersion);
+
+ private:
+ /**
+ * @details Create actions for the main-menu and the context-menu of the
+ * keylist.
+ */
+ void createActions();
+
+ /**
+ * @details create the menu of the main-window.
+ */
+ void createMenus();
+
+ /**
+ * @details Create edit-, crypt- and key-toolbars.
+ */
+ void createToolBars();
+
+ /**
+ * @details Create statusbar of mainwindow.
+ */
+ void createStatusBar();
+
+ /**
+ * @details Create keylist- and attachment-dockwindows.
+ */
+ void createDockWindows();
+
+ /**
+ * @details Create attachment-dockwindow.
+ */
+ void createAttachmentDock();
+
+ /**
+ * @details close attachment-dockwindow.
+ */
+ void closeAttachmentDock();
+
+ /**
+ * @details Load settings from ini-file.
+ */
+ void restoreSettings();
+
+ /**
+ * @details Save settings to ini-file.
+ */
+ void saveSettings();
+
+ /**
+ * @details Get full crypto text
+ */
+ QString getCryptText(const QString& shortenCryptoText);
+
+ /**
+ * @details Shorten crypto text
+ */
+ void shortenCryptText();
+
+ /**
+ * @brief return true, if restart is needed
+ */
+ [[nodiscard]] bool getRestartNeeded() const;
+
+ TextEdit* edit; /** Tabwidget holding the edit-windows */
+ QMenu* fileMenu; /** Submenu for file-operations*/
+ QMenu* editMenu; /** Submenu for text-operations*/
+ QMenu* cryptMenu; /** Submenu for crypt-operations */
+ QMenu* fileEncMenu; /** Submenu for file crypt operations */
+ QMenu* helpMenu; /** Submenu for help-operations */
+ QMenu* keyMenu; /** Submenu for key-operations */
+ QMenu* viewMenu; /** Submenu for view operations */
+ QMenu* importKeyMenu; /** Sumenu for import operations */
+ QMenu* steganoMenu; /** Submenu for steganographic operations*/
+ QToolBar* cryptToolBar; /** Toolbar holding crypt actions */
+ QToolBar* fileToolBar; /** Toolbar holding file actions */
+ QToolBar* editToolBar; /** Toolbar holding edit actions */
+ QToolBar* specialEditToolBar; /** Toolbar holding special edit actions */
+ QToolBar* keyToolBar; /** Toolbar holding key operations */
+ QToolButton*
+ importButton; /** Toolbutton for import dropdown menu in toolbar */
+ QToolButton* fileEncButton; /** Toolbutton for file cryption dropdown menu in
+ toolbar */
+ QDockWidget* keyListDock; /** Encrypt Dock*/
+ QDockWidget* attachmentDock; /** Attachment Dock */
+ QDockWidget* infoBoardDock;
+
+ QAction* newTabAct; /** Action to create new tab */
+ QAction* switchTabUpAct; /** Action to switch tab up*/
+ QAction* switchTabDownAct; /** Action to switch tab down */
+ QAction* openAct; /** Action to open file */
+ QAction* browserAct; /** Action to open file browser*/
+ QAction* saveAct; /** Action to save file */
+ QAction* saveAsAct; /** Action to save file as */
+ QAction* printAct; /** Action to print */
+ QAction* closeTabAct; /** Action to print */
+ QAction* quitAct; /** Action to quit application */
+ QAction* encryptAct; /** Action to encrypt text */
+ QAction* encryptSignAct; /** Action to encrypt and sign text */
+ QAction* decryptVerifyAct; /** Action to encrypt and sign text */
+ QAction* decryptAct; /** Action to decrypt text */
+ QAction* signAct; /** Action to sign text */
+ QAction* verifyAct; /** Action to verify text */
+ QAction* importKeyFromEditAct; /** Action to import key from edit */
+ QAction* cleanDoubleLinebreaksAct; /** Action to remove double line breaks */
+
+ QAction* appendSelectedKeysAct; /** Action to append selected keys to edit */
+ QAction*
+ copyMailAddressToClipboardAct; /** Action to copy mail to clipboard */
+ QAction* openKeyManagementAct; /** Action to open key management */
+ QAction* copyAct; /** Action to copy text */
+ QAction* quoteAct; /** Action to quote text */
+ QAction* cutAct; /** Action to cut text */
+ QAction* pasteAct; /** Action to paste text */
+ QAction* selectAllAct; /** Action to select whole text */
+ QAction* findAct; /** Action to find text */
+ QAction* undoAct; /** Action to undo last action */
+ QAction* redoAct; /** Action to redo last action */
+ QAction* zoomInAct; /** Action to zoom in */
+ QAction* zoomOutAct; /** Action to zoom out */
+ QAction* aboutAct; /** Action to open about dialog */
+ QAction* checkUpdateAct; /** Action to open about dialog */
+ QAction* fileEncryptAct; /** Action to open dialog for encrypting file */
+ QAction* fileDecryptAct; /** Action to open dialog for decrypting file */
+ QAction* fileSignAct; /** Action to open dialog for signing file */
+ QAction* fileVerifyAct; /** Action to open dialog for verifying file */
+ QAction* openSettingsAct; /** Action to open settings dialog */
+ QAction* showKeyDetailsAct; /** Action to open key-details dialog */
+ QAction*
+ refreshKeysFromKeyserverAct; /** Action to refresh a key from keyserver */
+ QAction* uploadKeyToServerAct; /** Action to append selected keys to edit */
+ QAction* startWizardAct; /** Action to open the wizard */
+ QAction* cutPgpHeaderAct; /** Action for cutting the PGP header */
+ QAction* addPgpHeaderAct; /** Action for adding the PGP header */
+
+ QLabel* statusBarIcon; /**< TODO */
+
+ QString appPath;
+ QSettings settings;
+ KeyList* mKeyList;
+
+ InfoBoardWidget* infoBoard;
+ KeyMgmt* keyMgmt;
+ KeyServerImportDialog* importDialog; /**< TODO */
+
+ QNetworkAccessManager* networkAccessManager;
+
+ bool attachmentDockCreated;
+ bool restartNeeded;
+};
+
+} // namespace GpgFrontend::UI
+
+#endif // __GPGWIN_H__
diff --git a/src/ui/QuitDialog.cpp b/src/ui/QuitDialog.cpp
index 783a8a61..f6b3f196 100755
--- a/src/ui/QuitDialog.cpp
+++ b/src/ui/QuitDialog.cpp
@@ -24,109 +24,116 @@
#include "ui/QuitDialog.h"
-QuitDialog::QuitDialog(QWidget *parent, const QHash<int, QString>& unsavedDocs)
- : QDialog(parent) {
- setWindowTitle(tr("Unsaved Files"));
- setModal(true);
- discarded = false;
+namespace GpgFrontend::UI {
- /*
- * Table of unsaved documents
- */
- QHashIterator<int, QString> i(unsavedDocs);
- int row = 0;
- mFileList = new QTableWidget(this);
- mFileList->horizontalHeader()->hide();
- mFileList->setColumnCount(3);
- mFileList->setColumnWidth(0, 20);
- mFileList->setColumnHidden(2, true);
- mFileList->verticalHeader()->hide();
- mFileList->setShowGrid(false);
- mFileList->setEditTriggers(QAbstractItemView::NoEditTriggers);
- mFileList->setFocusPolicy(Qt::NoFocus);
- mFileList->horizontalHeader()->setStretchLastSection(true);
- // fill the table
- i.toFront(); //jump to the end of list to fill the table backwards
- while (i.hasNext()) {
- i.next();
- mFileList->setRowCount(mFileList->rowCount() + 1);
+QuitDialog::QuitDialog(QWidget* parent, const QHash<int, QString>& unsavedDocs)
+ : QDialog(parent) {
+ setWindowTitle(tr("Unsaved Files"));
+ setModal(true);
+ discarded = false;
- // checkbox in front of filename
- auto *tmp0 = new QTableWidgetItem();
- tmp0->setFlags(Qt::ItemIsUserCheckable | Qt::ItemIsEnabled);
- tmp0->setCheckState(Qt::Checked);
- mFileList->setItem(row, 0, tmp0);
+ /*
+ * Table of unsaved documents
+ */
+ QHashIterator<int, QString> i(unsavedDocs);
+ int row = 0;
+ mFileList = new QTableWidget(this);
+ mFileList->horizontalHeader()->hide();
+ mFileList->setColumnCount(3);
+ mFileList->setColumnWidth(0, 20);
+ mFileList->setColumnHidden(2, true);
+ mFileList->verticalHeader()->hide();
+ mFileList->setShowGrid(false);
+ mFileList->setEditTriggers(QAbstractItemView::NoEditTriggers);
+ mFileList->setFocusPolicy(Qt::NoFocus);
+ mFileList->horizontalHeader()->setStretchLastSection(true);
+ // fill the table
+ i.toFront(); // jump to the end of list to fill the table backwards
+ while (i.hasNext()) {
+ i.next();
+ mFileList->setRowCount(mFileList->rowCount() + 1);
- // filename
- auto *tmp1 = new QTableWidgetItem(i.value());
- mFileList->setItem(row, 1, tmp1);
+ // checkbox in front of filename
+ auto* tmp0 = new QTableWidgetItem();
+ tmp0->setFlags(Qt::ItemIsUserCheckable | Qt::ItemIsEnabled);
+ tmp0->setCheckState(Qt::Checked);
+ mFileList->setItem(row, 0, tmp0);
- // tab-index in hidden column
- auto *tmp2 = new QTableWidgetItem(QString::number(i.key()));
- mFileList->setItem(row, 2, tmp2);
- ++row;
- }
- /*
- * Warnbox with icon and text
- */
- auto pixmap = QPixmap(":error.png");
- pixmap = pixmap.scaled(50, 50, Qt::KeepAspectRatio, Qt::SmoothTransformation);
- auto *warn_icon = new QLabel();
- warn_icon->setPixmap(pixmap);
- auto *warn_label = new QLabel(
- tr("%1 files contain unsaved information.<br/>Save the changes before closing?").arg(row));
- auto *warnBoxLayout = new QHBoxLayout();
- warnBoxLayout->addWidget(warn_icon);
- warnBoxLayout->addWidget(warn_label);
- warnBoxLayout->setAlignment(Qt::AlignLeft);
- auto *warnBox = new QWidget(this);
- warnBox->setLayout(warnBoxLayout);
+ // filename
+ auto* tmp1 = new QTableWidgetItem(i.value());
+ mFileList->setItem(row, 1, tmp1);
- /*
- * Two labels on top and under the filelist
- */
- auto *checkLabel = new QLabel(tr("Check the files you want to save:"));
- auto *note_label = new QLabel(tr("<b>Note:</b> If you don't save these files, all changes are lost.<br/>"));
+ // tab-index in hidden column
+ auto* tmp2 = new QTableWidgetItem(QString::number(i.key()));
+ mFileList->setItem(row, 2, tmp2);
+ ++row;
+ }
+ /*
+ * Warnbox with icon and text
+ */
+ auto pixmap = QPixmap(":error.png");
+ pixmap = pixmap.scaled(50, 50, Qt::KeepAspectRatio, Qt::SmoothTransformation);
+ auto* warn_icon = new QLabel();
+ warn_icon->setPixmap(pixmap);
+ auto* warn_label =
+ new QLabel(tr("%1 files contain unsaved information.<br/>Save the "
+ "changes before closing?")
+ .arg(row));
+ auto* warnBoxLayout = new QHBoxLayout();
+ warnBoxLayout->addWidget(warn_icon);
+ warnBoxLayout->addWidget(warn_label);
+ warnBoxLayout->setAlignment(Qt::AlignLeft);
+ auto* warnBox = new QWidget(this);
+ warnBox->setLayout(warnBoxLayout);
- /*
- * Buttonbox
- */
- auto *buttonBox = new QDialogButtonBox(
- QDialogButtonBox::Discard | QDialogButtonBox::Save | QDialogButtonBox::Cancel);
- connect(buttonBox, SIGNAL(accepted()), this, SLOT(accept()));
- connect(buttonBox, SIGNAL(rejected()), this, SLOT(reject()));
- QPushButton *btnNoKey = buttonBox->button(QDialogButtonBox::Discard);
- connect(btnNoKey, SIGNAL(clicked()), SLOT(slotMyDiscard()));
+ /*
+ * Two labels on top and under the filelist
+ */
+ auto* checkLabel = new QLabel(tr("Check the files you want to save:"));
+ auto* note_label =
+ new QLabel(tr("<b>Note:</b> If you don't save these files, all changes "
+ "are lost.<br/>"));
- /*
- * Set the layout
- */
- auto *vbox = new QVBoxLayout();
- vbox->addWidget(warnBox);
- vbox->addWidget(checkLabel);
- vbox->addWidget(mFileList);
- vbox->addWidget(note_label);
- vbox->addWidget(buttonBox);
- this->setLayout(vbox);
-}
+ /*
+ * Buttonbox
+ */
+ auto* buttonBox =
+ new QDialogButtonBox(QDialogButtonBox::Discard | QDialogButtonBox::Save |
+ QDialogButtonBox::Cancel);
+ connect(buttonBox, SIGNAL(accepted()), this, SLOT(accept()));
+ connect(buttonBox, SIGNAL(rejected()), this, SLOT(reject()));
+ QPushButton* btnNoKey = buttonBox->button(QDialogButtonBox::Discard);
+ connect(btnNoKey, SIGNAL(clicked()), SLOT(slotMyDiscard()));
+ /*
+ * Set the layout
+ */
+ auto* vbox = new QVBoxLayout();
+ vbox->addWidget(warnBox);
+ vbox->addWidget(checkLabel);
+ vbox->addWidget(mFileList);
+ vbox->addWidget(note_label);
+ vbox->addWidget(buttonBox);
+ this->setLayout(vbox);
+}
void QuitDialog::slotMyDiscard() {
- discarded = true;
- reject();
+ discarded = true;
+ reject();
}
bool QuitDialog::isDiscarded() const {
- return discarded;
+ return discarded;
}
QList<int> QuitDialog::getTabIdsToSave() {
- QList<int> tabIdsToSave;
- for (int i = 0; i < mFileList->rowCount(); i++) {
- if (mFileList->item(i, 0)->checkState() == Qt::Checked) {
- tabIdsToSave << mFileList->item(i, 2)->text().toInt();
- }
+ QList<int> tabIdsToSave;
+ for (int i = 0; i < mFileList->rowCount(); i++) {
+ if (mFileList->item(i, 0)->checkState() == Qt::Checked) {
+ tabIdsToSave << mFileList->item(i, 2)->text().toInt();
}
- return tabIdsToSave;
+ }
+ return tabIdsToSave;
}
+} // namespace GpgFrontend::UI
diff --git a/include/ui/QuitDialog.h b/src/ui/QuitDialog.h
index 19af7534..86616667 100755
--- a/include/ui/QuitDialog.h
+++ b/src/ui/QuitDialog.h
@@ -25,25 +25,29 @@
#ifndef __QUITDIALOG_H__
#define __QUITDIALOG_H__
-#include <GpgFrontend.h>
+#include "ui/GpgFrontendUI.h"
+
+namespace GpgFrontend::UI {
class QuitDialog : public QDialog {
-Q_OBJECT
+ Q_OBJECT
-public:
- QuitDialog(QWidget *parent, const QHash<int, QString>& unsavedDocs);
+ public:
+ QuitDialog(QWidget* parent, const QHash<int, QString>& unsavedDocs);
- [[nodiscard]] bool isDiscarded() const;
+ [[nodiscard]] bool isDiscarded() const;
- QList<int> getTabIdsToSave();
+ QList<int> getTabIdsToSave();
-private slots:
+ private slots:
- void slotMyDiscard();
+ void slotMyDiscard();
-private:
- bool discarded;
- QTableWidget *mFileList;
+ private:
+ bool discarded;
+ QTableWidget* mFileList;
};
-#endif // __QUITDIALOG_H__
+} // namespace GpgFrontend::UI
+
+#endif // __QUITDIALOG_H__
diff --git a/src/ui/SendMailDialog.cpp b/src/ui/SendMailDialog.cpp
index 5bea7cb2..e140ca87 100644
--- a/src/ui/SendMailDialog.cpp
+++ b/src/ui/SendMailDialog.cpp
@@ -25,149 +25,171 @@
#include "ui/SendMailDialog.h"
#include <utility>
-#include "smtp/SmtpMime"
-
-SendMailDialog::SendMailDialog(QString text, QWidget *parent)
- : QDialog(parent), appPath(qApp->applicationDirPath()),
- settings(RESOURCE_DIR(appPath) + "/conf/gpgfrontend.ini", QSettings::IniFormat), mText(std::move(text)) {
-
- if (smtpAddress.isEmpty()) {
- QMessageBox::critical(this, tr("Incomplete configuration"),
- tr("The SMTP address is empty, please go to the setting interface to complete the configuration."));
-
- deleteLater();
- return;
-
- }
-
- senderEdit = new QLineEdit();
- senderEdit->setText(defaultSender);
- recipientEdit = new QTextEdit();
- recipientEdit->setPlaceholderText("One or more email addresses. Please use ; to separate.");
- subjectEdit = new QLineEdit();
-
- errorLabel = new QLabel();
-
- qDebug() << "Send Mail Settings" << smtpAddress << username << password << defaultSender << connectionTypeSettings;
-
- confirmButton = new QPushButton("Confirm");
- auto layout = new QGridLayout();
- layout->addWidget(new QLabel("Sender"), 0, 0);
- layout->addWidget(senderEdit, 0, 1);
- layout->addWidget(new QLabel("Recipient"), 1, 0);
- layout->addWidget(recipientEdit, 1, 1);
- layout->addWidget(new QLabel("Subject"), 2, 0);
- layout->addWidget(subjectEdit, 2, 1);
- layout->addWidget(confirmButton, 3, 1);
- layout->addWidget(errorLabel, 4, 0, 1, 2);
-
- connect(confirmButton, SIGNAL(clicked(bool)), this, SLOT(slotConfirm()));
+#ifdef STMP_ENABLED
+#include "smtp/SmtpMime"
+#endif
+
+namespace GpgFrontend::UI {
+
+SendMailDialog::SendMailDialog(QString text, QWidget* parent)
+ : QDialog(parent),
+ appPath(qApp->applicationDirPath()),
+ settings(RESOURCE_DIR(appPath) + "/conf/gpgfrontend.ini",
+ QSettings::IniFormat),
+ mText(std::move(text)) {
+ if (smtpAddress.isEmpty()) {
+ QMessageBox::critical(
+ this, tr("Incomplete configuration"),
+ tr("The SMTP address is empty, please go to the setting interface to "
+ "complete the configuration."));
- this->setLayout(layout);
- this->setWindowTitle("Send Mail");
- this->setModal(true);
- this->setFixedWidth(320);
- this->show();
+ deleteLater();
+ return;
+ }
+
+ senderEdit = new QLineEdit();
+ senderEdit->setText(defaultSender);
+ recipientEdit = new QTextEdit();
+ recipientEdit->setPlaceholderText(
+ "One or more email addresses. Please use ; to separate.");
+ subjectEdit = new QLineEdit();
+
+ errorLabel = new QLabel();
+
+ qDebug() << "Send Mail Settings" << smtpAddress << username << password
+ << defaultSender << connectionTypeSettings;
+
+ confirmButton = new QPushButton("Confirm");
+
+ auto layout = new QGridLayout();
+ layout->addWidget(new QLabel("Sender"), 0, 0);
+ layout->addWidget(senderEdit, 0, 1);
+ layout->addWidget(new QLabel("Recipient"), 1, 0);
+ layout->addWidget(recipientEdit, 1, 1);
+ layout->addWidget(new QLabel("Subject"), 2, 0);
+ layout->addWidget(subjectEdit, 2, 1);
+ layout->addWidget(confirmButton, 3, 1);
+ layout->addWidget(errorLabel, 4, 0, 1, 2);
+
+#ifdef STMP_ENABLED
+ connect(confirmButton, SIGNAL(clicked(bool)), this, SLOT(slotConfirm()));
+#endif
+
+ this->setLayout(layout);
+ this->setWindowTitle("Send Mail");
+ this->setModal(true);
+ this->setFixedWidth(320);
+ this->show();
}
-bool SendMailDialog::check_email_address(const QString &str) {
- return re_email.match(str).hasMatch();
+bool SendMailDialog::check_email_address(const QString& str) {
+ return re_email.match(str).hasMatch();
}
-void SendMailDialog::slotConfirm() {
-
- QString errString;
- errorLabel->clear();
-
- QStringList rcptStringList = recipientEdit->toPlainText().split(';');
-
- if (rcptStringList.isEmpty()) {
- errString.append(tr(" Recipient cannot be empty \n"));
- } else {
- for (const auto& reci : rcptStringList) {
- qDebug() << "Receiver" << reci.trimmed();
- if (!check_email_address(reci.trimmed())) {
- errString.append(tr(" One or more Recipient's Email Address is invalid \n"));
- break;
- }
- }
- }
- if (senderEdit->text().isEmpty()) {
- errString.append(tr(" Sender cannot be empty \n"));
- } else if (!check_email_address(senderEdit->text())) {
- errString.append(tr(" Sender's Email Address is invalid \n"));
- }
-
- if (!errString.isEmpty()) {
- errorLabel->setAutoFillBackground(true);
- QPalette error = errorLabel->palette();
- error.setColor(QPalette::Window, "#ff8080");
- errorLabel->setPalette(error);
- errorLabel->setText(errString);
- return;
- }
-
- SmtpClient::ConnectionType connectionType = SmtpClient::ConnectionType::TcpConnection;
-
- if (connectionTypeSettings == "SSL") {
- connectionType = SmtpClient::ConnectionType::SslConnection;
- } else if (connectionTypeSettings == "TLS") {
- connectionType = SmtpClient::ConnectionType::TlsConnection;
- } else if (connectionTypeSettings == "STARTTLS") {
- connectionType = SmtpClient::ConnectionType::TlsConnection;
- } else {
- connectionType = SmtpClient::ConnectionType::TcpConnection;
- }
-
- SmtpClient smtp(smtpAddress, port, connectionType);
-
- // We need to set the username (your email address) and the password
- // for smtp authentification.
+#ifdef STMP_ENABLED
- smtp.setUser(username);
- smtp.setPassword(password);
-
- // Now we create a MimeMessage object. This will be the email.
-
- MimeMessage message;
-
- message.setSender(new EmailAddress(senderEdit->text()));
- for (const auto &reci : rcptStringList) {
- if(!reci.isEmpty())
- message.addRecipient(new EmailAddress(reci.trimmed()));
+void SendMailDialog::slotConfirm() {
+ QString errString;
+ errorLabel->clear();
+
+ QStringList rcptStringList = recipientEdit->toPlainText().split(';');
+
+ if (rcptStringList.isEmpty()) {
+ errString.append(tr(" Recipient cannot be empty \n"));
+ } else {
+ for (const auto& reci : rcptStringList) {
+ qDebug() << "Receiver" << reci.trimmed();
+ if (!check_email_address(reci.trimmed())) {
+ errString.append(
+ tr(" One or more Recipient's Email Address is invalid \n"));
+ break;
+ }
}
- message.setSubject(subjectEdit->text());
-
- // Now add some text to the email.
- // First we create a MimeText object.
-
- MimeText text;
-
- text.setText(mText);
+ }
+ if (senderEdit->text().isEmpty()) {
+ errString.append(tr(" Sender cannot be empty \n"));
+ } else if (!check_email_address(senderEdit->text())) {
+ errString.append(tr(" Sender's Email Address is invalid \n"));
+ }
+
+ if (!errString.isEmpty()) {
+ errorLabel->setAutoFillBackground(true);
+ QPalette error = errorLabel->palette();
+ error.setColor(QPalette::Window, "#ff8080");
+ errorLabel->setPalette(error);
+ errorLabel->setText(errString);
+ return;
+ }
+
+ SmtpClient::ConnectionType connectionType =
+ SmtpClient::ConnectionType::TcpConnection;
+
+ if (connectionTypeSettings == "SSL") {
+ connectionType = SmtpClient::ConnectionType::SslConnection;
+ } else if (connectionTypeSettings == "TLS") {
+ connectionType = SmtpClient::ConnectionType::TlsConnection;
+ } else if (connectionTypeSettings == "STARTTLS") {
+ connectionType = SmtpClient::ConnectionType::TlsConnection;
+ } else {
+ connectionType = SmtpClient::ConnectionType::TcpConnection;
+ }
+
+ SmtpClient smtp(smtpAddress, port, connectionType);
+
+ // We need to set the username (your email address) and the password
+ // for smtp authentification.
+
+ smtp.setUser(username);
+ smtp.setPassword(password);
+
+ // Now we create a MimeMessage object. This will be the email.
+
+ MimeMessage message;
+
+ message.setSender(new EmailAddress(senderEdit->text()));
+ for (const auto& reci : rcptStringList) {
+ if (!reci.isEmpty())
+ message.addRecipient(new EmailAddress(reci.trimmed()));
+ }
+ message.setSubject(subjectEdit->text());
+
+ // Now add some text to the email.
+ // First we create a MimeText object.
+
+ MimeText text;
+
+ text.setText(mText);
+
+ // Now add it to the mail
+ message.addPart(&text);
+
+ // Now we can send the mail
+ if (!smtp.connectToHost()) {
+ qDebug() << "Connect to SMTP Server Failed";
+ QMessageBox::critical(this, tr("Fail"), tr("Fail to Connect SMTP Server"));
+ return;
+ }
+ if (!smtp.login()) {
+ qDebug() << "Login to SMTP Server Failed";
+ QMessageBox::critical(this, tr("Fail"),
+ tr("Fail to Login into SMTP Server"));
+ return;
+ }
+ if (!smtp.sendMail(message)) {
+ qDebug() << "Send Mail to SMTP Server Failed";
+ QMessageBox::critical(this, tr("Fail"),
+ tr("Fail to Send Mail to SMTP Server"));
+ return;
+ }
+ smtp.quit();
+
+ // Close after sending email
+ QMessageBox::information(this, tr("Success"),
+ tr("Succeed in Sending Mail to SMTP Server"));
+ deleteLater();
+}
- // Now add it to the mail
- message.addPart(&text);
+#endif
- // Now we can send the mail
- if (!smtp.connectToHost()) {
- qDebug() << "Connect to SMTP Server Failed";
- QMessageBox::critical(this, tr("Fail"), tr("Fail to Connect SMTP Server"));
- return;
- }
- if (!smtp.login()) {
- qDebug() << "Login to SMTP Server Failed";
- QMessageBox::critical(this, tr("Fail"), tr("Fail to Login into SMTP Server"));
- return;
- }
- if (!smtp.sendMail(message)) {
- qDebug() << "Send Mail to SMTP Server Failed";
- QMessageBox::critical(this, tr("Fail"), tr("Fail to Send Mail to SMTP Server"));
- return;
- }
- smtp.quit();
-
- // Close after sending email
- QMessageBox::information(this, tr("Success"), tr("Succeed in Sending Mail to SMTP Server"));
- deleteLater();
-}
+} // namespace GpgFrontend::UI
diff --git a/src/ui/SendMailDialog.h b/src/ui/SendMailDialog.h
new file mode 100644
index 00000000..6afdfe79
--- /dev/null
+++ b/src/ui/SendMailDialog.h
@@ -0,0 +1,71 @@
+/**
+ * This file is part of GPGFrontend.
+ *
+ * GPGFrontend is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Foobar is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Foobar. If not, see <https://www.gnu.org/licenses/>.
+ *
+ * The initial version of the source code is inherited from gpg4usb-team.
+ * Their source code version also complies with GNU General Public License.
+ *
+ * The source code version of this software was modified and released
+ * by Saturneric<[email protected]> starting on May 12, 2021.
+ *
+ */
+
+#ifndef GPGFRONTEND_SENDMAILDIALOG_H
+#define GPGFRONTEND_SENDMAILDIALOG_H
+
+#include "ui/GpgFrontendUI.h"
+
+namespace GpgFrontend::UI {
+
+class SendMailDialog : public QDialog {
+ Q_OBJECT
+ public:
+ explicit SendMailDialog(QString text, QWidget* parent = nullptr);
+
+ private slots:
+
+ void slotConfirm();
+
+ private:
+ QString appPath;
+ QSettings settings;
+
+ QLineEdit* senderEdit;
+ QTextEdit* recipientEdit;
+ QLineEdit* subjectEdit;
+ QPushButton* confirmButton;
+
+ QLabel* errorLabel;
+ QString mText;
+
+ QString smtpAddress =
+ settings.value("sendMail/smtpAddress", QString()).toString();
+ QString username = settings.value("sendMail/username", QString()).toString();
+ QString password = settings.value("sendMail/password", QString()).toString();
+ QString defaultSender =
+ settings.value("sendMail/defaultSender", QString()).toString();
+ QString connectionTypeSettings =
+ settings.value("sendMail/connectionType", QString()).toString();
+ int port = settings.value("sendMail/port", QString()).toInt();
+
+ QRegularExpression re_email{
+ R"((?:[a-z0-9!#$%&'*+/=?^_`{|}~-]+(?:\.[a-z0-9!#$%&'*+/=?^_`{|}~-]+)*|"(?:[\x01-\x08\x0b\x0c\x0e-\x1f\x21\x23-\x5b\x5d-\x7f]|\\[\x01-\x09\x0b\x0c\x0e-\x7f])*")@(?:(?:[a-z0-9](?:[a-z0-9-]*[a-z0-9])?\.)+[a-z0-9](?:[a-z0-9-]*[a-z0-9])?|\[(?:(?:(2(5[0-5]|[0-4][0-9])|1[0-9][0-9]|[1-9]?[0-9]))\.){3}(?:(2(5[0-5]|[0-4][0-9])|1[0-9][0-9]|[1-9]?[0-9])|[a-z0-9-]*[a-z0-9]:(?:[\x01-\x08\x0b\x0c\x0e-\x1f\x21-\x5a\x53-\x7f]|\\[\x01-\x09\x0b\x0c\x0e-\x7f])+)\]))"};
+
+ bool check_email_address(const QString& str);
+};
+
+} // namespace GpgFrontend::UI
+
+#endif // GPGFRONTEND_SENDMAILDIALOG_H
diff --git a/src/ui/SettingsDialog.h b/src/ui/SettingsDialog.h
new file mode 100755
index 00000000..d205f8fe
--- /dev/null
+++ b/src/ui/SettingsDialog.h
@@ -0,0 +1,255 @@
+/**
+ * This file is part of GPGFrontend.
+ *
+ * GPGFrontend is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Foobar is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Foobar. If not, see <https://www.gnu.org/licenses/>.
+ *
+ * The initial version of the source code is inherited from gpg4usb-team.
+ * Their source code version also complies with GNU General Public License.
+ *
+ * The source code version of this software was modified and released
+ * by Saturneric<[email protected]> starting on May 12, 2021.
+ *
+ */
+
+#ifndef __SETTINGSDIALOG_H__
+#define __SETTINGSDIALOG_H__
+
+#include "ui/GpgFrontendUI.h"
+#include "ui/widgets/KeyList.h"
+
+namespace GpgFrontend::UI {
+
+class GeneralTab : public QWidget {
+ Q_OBJECT
+
+ public:
+ explicit GeneralTab(QWidget* parent = nullptr);
+
+ void setSettings();
+
+ void applySettings();
+
+ private:
+ QString appPath;
+ QSettings settings;
+
+ QComboBox* serverSelectBox;
+ QCheckBox* saveCheckedKeysCheckBox;
+ QCheckBox* importConfirmationCheckBox;
+ QComboBox* langSelectBox;
+ QComboBox* ownKeySelectBox;
+ QPushButton* getServiceTokenButton;
+ QLabel* serviceTokenLabel;
+ QHash<QString, QString> lang;
+
+ std::unordered_map<std::string, std::string> keyIds;
+ std::vector<std::string> keyIdsList;
+ std::string serviceToken;
+ KeyList* mKeyList;
+
+ private slots:
+
+ void slotOwnKeyIdChanged();
+
+ void slotLanguageChanged();
+
+ void slotGetServiceToken();
+
+ signals:
+
+ void signalRestartNeeded(bool needed);
+};
+
+class SendMailTab : public QWidget {
+ Q_OBJECT
+
+ public:
+ explicit SendMailTab(QWidget* parent = nullptr);
+
+ void setSettings();
+
+ void applySettings();
+
+ private slots:
+
+ void slotCheckConnection();
+
+ void slotCheckBoxSetEnableDisable(int state);
+
+ private:
+ QString appPath;
+ QSettings settings;
+
+ QCheckBox* enableCheckBox;
+
+ QLineEdit* smtpAddress;
+ QLineEdit* username;
+ QLineEdit* password;
+ QSpinBox* portSpin;
+ QComboBox* connectionTypeComboBox;
+ QLineEdit* defaultSender;
+
+ QPushButton* checkConnectionButton;
+
+ signals:
+
+ void signalRestartNeeded(bool needed);
+};
+
+class AppearanceTab : public QWidget {
+ Q_OBJECT
+
+ public:
+ // void setSettings();
+ explicit AppearanceTab(QWidget* parent = nullptr);
+
+ void setSettings();
+
+ void applySettings();
+
+ private:
+ QString appPath;
+ QSettings settings;
+
+ QButtonGroup* iconStyleGroup;
+ QRadioButton* iconSizeSmall;
+ QRadioButton* iconSizeMedium;
+ QRadioButton* iconSizeLarge;
+ QButtonGroup* iconSizeGroup;
+ QRadioButton* iconTextButton;
+ QRadioButton* iconIconsButton;
+ QRadioButton* iconAllButton;
+ QSpinBox* infoBoardFontSizeSpin;
+ QCheckBox* windowSizeCheckBox;
+
+ signals:
+
+ void signalRestartNeeded(bool needed);
+};
+
+class KeyserverTab : public QWidget {
+ Q_OBJECT
+
+ public:
+ explicit KeyserverTab(QWidget* parent = nullptr);
+
+ void setSettings();
+
+ void applySettings();
+
+ private:
+ QString appPath;
+ QSettings settings;
+ QComboBox* comboBox;
+ QLineEdit* newKeyServerEdit;
+ QTableWidget* keyServerTable;
+ QStringList keyServerStrList;
+
+ private slots:
+
+ void addKeyServer();
+
+ void refreshTable();
+
+ signals:
+
+ void signalRestartNeeded(bool needed);
+};
+
+class AdvancedTab : public QWidget {
+ Q_OBJECT
+
+ public:
+ explicit AdvancedTab(QWidget* parent = nullptr);
+
+ void setSettings();
+
+ void applySettings();
+
+ private:
+ QString appPath;
+ QSettings settings;
+
+ QCheckBox* steganoCheckBox;
+ QCheckBox* autoPubkeyExchangeCheckBox;
+
+ signals:
+
+ void signalRestartNeeded(bool needed);
+};
+
+class GpgPathsTab : public QWidget {
+ Q_OBJECT
+ public:
+ explicit GpgPathsTab(QWidget* parent = nullptr);
+
+ void applySettings();
+
+ private:
+ static QString getRelativePath(const QString& dir1, const QString& dir2);
+
+ QString appPath;
+ QSettings settings;
+
+ QString defKeydbPath; /** The default keydb path used by gpg4usb */
+ QString accKeydbPath; /** The currently used keydb path */
+ QLabel* keydbLabel;
+
+ void setSettings();
+
+ private slots:
+
+ QString chooseKeydbDir();
+
+ void setKeydbPathToDefault();
+};
+
+class SettingsDialog : public QDialog {
+ Q_OBJECT
+
+ public:
+ explicit SettingsDialog(QWidget* parent = nullptr);
+
+ GeneralTab* generalTab;
+ SendMailTab* sendMailTab;
+ AppearanceTab* appearanceTab;
+ KeyserverTab* keyserverTab;
+ AdvancedTab* advancedTab;
+ GpgPathsTab* gpgPathsTab;
+
+ static QHash<QString, QString> listLanguages();
+
+ public slots:
+
+ void slotAccept();
+
+ signals:
+
+ void signalRestartNeeded(bool needed);
+
+ private:
+ QTabWidget* tabWidget;
+ QDialogButtonBox* buttonBox;
+ bool restartNeeded{};
+
+ bool getRestartNeeded() const;
+
+ private slots:
+
+ void slotSetRestartNeeded(bool needed);
+};
+
+} // namespace GpgFrontend::UI
+
+#endif // __SETTINGSDIALOG_H__
diff --git a/src/ui/ShowCopyDialog.cpp b/src/ui/ShowCopyDialog.cpp
index 3286f6c4..98a1df3c 100644
--- a/src/ui/ShowCopyDialog.cpp
+++ b/src/ui/ShowCopyDialog.cpp
@@ -24,30 +24,37 @@
#include "ui/ShowCopyDialog.h"
-ShowCopyDialog::ShowCopyDialog(const QString &text, const QString &info, QWidget *parent) : QDialog(parent) {
- textEdit = new QTextEdit();
- textEdit->setReadOnly(true);
- textEdit->setLineWrapMode(QTextEdit::WidgetWidth);
- textEdit->setText(text);
- copyButton = new QPushButton("Copy");
- connect(copyButton, SIGNAL(clicked(bool)), this, SLOT(slotCopyText()));
-
- infoLabel = new QLabel();
- infoLabel->setText(info);
- infoLabel->setWordWrap(true);
-
- auto *layout = new QVBoxLayout();
- layout->addWidget(textEdit);
- layout->addWidget(copyButton);
- layout->addWidget(infoLabel);
-
- this->setWindowTitle("Short Ciphertext");
- this->resize(320, 120);
- this->setModal(true);
- this->setLayout(layout);
+namespace GpgFrontend::UI {
+
+ShowCopyDialog::ShowCopyDialog(const QString& text,
+ const QString& info,
+ QWidget* parent)
+ : QDialog(parent) {
+ textEdit = new QTextEdit();
+ textEdit->setReadOnly(true);
+ textEdit->setLineWrapMode(QTextEdit::WidgetWidth);
+ textEdit->setText(text);
+ copyButton = new QPushButton("Copy");
+ connect(copyButton, SIGNAL(clicked(bool)), this, SLOT(slotCopyText()));
+
+ infoLabel = new QLabel();
+ infoLabel->setText(info);
+ infoLabel->setWordWrap(true);
+
+ auto* layout = new QVBoxLayout();
+ layout->addWidget(textEdit);
+ layout->addWidget(copyButton);
+ layout->addWidget(infoLabel);
+
+ this->setWindowTitle("Short Ciphertext");
+ this->resize(320, 120);
+ this->setModal(true);
+ this->setLayout(layout);
}
void ShowCopyDialog::slotCopyText() {
- QClipboard *cb = QApplication::clipboard();
- cb->setText(textEdit->toPlainText());
+ QClipboard* cb = QApplication::clipboard();
+ cb->setText(textEdit->toPlainText());
}
+
+} // namespace GpgFrontend::UI
diff --git a/include/ui/ShowCopyDialog.h b/src/ui/ShowCopyDialog.h
index 45b06e2d..82deedee 100644
--- a/include/ui/ShowCopyDialog.h
+++ b/src/ui/ShowCopyDialog.h
@@ -25,22 +25,27 @@
#ifndef GPGFRONTEND_ZH_CN_TS_SHOWCOPYDIALOG_H
#define GPGFRONTEND_ZH_CN_TS_SHOWCOPYDIALOG_H
-#include "GpgFrontend.h"
+#include "ui/GpgFrontendUI.h"
+
+namespace GpgFrontend::UI {
class ShowCopyDialog : public QDialog {
-Q_OBJECT
-public:
- explicit ShowCopyDialog(const QString &text, const QString &info = "", QWidget *parent = nullptr);
+ Q_OBJECT
+ public:
+ explicit ShowCopyDialog(const QString& text,
+ const QString& info = "",
+ QWidget* parent = nullptr);
-private slots:
+ private slots:
- void slotCopyText();
+ void slotCopyText();
-private:
- QLabel *infoLabel;
- QTextEdit *textEdit;
- QPushButton *copyButton;
+ private:
+ QLabel* infoLabel;
+ QTextEdit* textEdit;
+ QPushButton* copyButton;
};
+} // namespace GpgFrontend::UI
-#endif //GPGFRONTEND_ZH_CN_TS_SHOWCOPYDIALOG_H
+#endif // GPGFRONTEND_ZH_CN_TS_SHOWCOPYDIALOG_H
diff --git a/src/ui/VerifyDetailsDialog.cpp b/src/ui/VerifyDetailsDialog.cpp
index 3462ad69..f06c31a4 100644
--- a/src/ui/VerifyDetailsDialog.cpp
+++ b/src/ui/VerifyDetailsDialog.cpp
@@ -24,60 +24,69 @@
#include "ui/VerifyDetailsDialog.h"
-VerifyDetailsDialog::VerifyDetailsDialog(QWidget *parent, GpgFrontend::GpgContext *ctx, KeyList *keyList, gpg_error_t error,
- gpgme_verify_result_t result) :
- QDialog(parent), mCtx(ctx), mKeyList(keyList), sign(result->signatures), error(error) {
+namespace GpgFrontend::UI {
+VerifyDetailsDialog::VerifyDetailsDialog(QWidget* parent,
+ KeyList* keyList,
+ GpgError error,
+ GpgVerifyResult result)
+ : QDialog(parent),
+ mKeyList(keyList),
+ mResult(std::move(result)),
+ error(error) {
+ this->setWindowTitle(tr("Signature Details"));
- this->setWindowTitle(tr("Signature Details"));
+ mainLayout = new QHBoxLayout();
+ this->setLayout(mainLayout);
- connect(mCtx, SIGNAL(signalKeyInfoChanged()), this, SLOT(slotRefresh()));
- mainLayout = new QHBoxLayout();
- this->setLayout(mainLayout);
+ slotRefresh();
- slotRefresh();
-
- this->exec();
+ this->exec();
}
void VerifyDetailsDialog::slotRefresh() {
+ mVbox = new QWidget();
+ auto* mVboxLayout = new QVBoxLayout(mVbox);
+ mainLayout->addWidget(mVbox);
- mVbox = new QWidget();
- auto *mVboxLayout = new QVBoxLayout(mVbox);
- mainLayout->addWidget(mVbox);
+ // Button Box for close button
+ buttonBox = new QDialogButtonBox(QDialogButtonBox::Close);
+ connect(buttonBox, SIGNAL(rejected()), this, SLOT(close()));
- // Button Box for close button
- buttonBox = new QDialogButtonBox(QDialogButtonBox::Close);
- connect(buttonBox, SIGNAL(rejected()), this, SLOT(close()));
+ mVboxLayout->addWidget(new QLabel(tr("Status: ") + gpgme_strerror(error)));
- mVboxLayout->addWidget(new QLabel(tr("Status: ") + gpgme_strerror(error)));
+ auto sign = mResult->signatures;
- if (sign == nullptr) {
- mVboxLayout->addWidget(new QLabel(tr("No valid input found")));
- mVboxLayout->addWidget(buttonBox);
- return;
- }
+ if (sign == nullptr) {
+ mVboxLayout->addWidget(new QLabel(tr("No valid input found")));
+ mVboxLayout->addWidget(buttonBox);
+ return;
+ }
- // Get timestamp of signature of current text
- QDateTime timestamp;
- timestamp.setTime_t(sign->timestamp);
+ // Get timestamp of signature of current text
+ QDateTime timestamp;
+ timestamp.setTime_t(sign->timestamp);
- // Set the title widget depending on sign status
- if (gpg_err_code(sign->status) == GPG_ERR_BAD_SIGNATURE) {
- mVboxLayout->addWidget(new QLabel(tr("Error Validating signature")));
- } else if (mInputSignature != nullptr) {
- mVboxLayout->addWidget(new QLabel(
- tr("File was signed on %1 <br/> It Contains:<br/><br/>").arg(QLocale::system().toString(timestamp))));
- } else {
- mVboxLayout->addWidget(new QLabel(tr("Signed on %1 <br/> It Contains:<br /><br/>").arg(
- QLocale::system().toString(timestamp))));
- }
- // Add informationbox for every single key
- while (sign) {
- auto *sbox = new VerifyKeyDetailBox(this, mCtx, mKeyList, sign);
- sign = sign->next;
- mVboxLayout->addWidget(sbox);
- }
+ // Set the title widget depending on sign status
+ if (gpg_err_code(sign->status) == GPG_ERR_BAD_SIGNATURE) {
+ mVboxLayout->addWidget(new QLabel(tr("Error Validating signature")));
+ } else if (mInputSignature != nullptr) {
+ mVboxLayout->addWidget(
+ new QLabel(tr("File was signed on %1 <br/> It Contains:<br/><br/>")
+ .arg(QLocale::system().toString(timestamp))));
+ } else {
+ mVboxLayout->addWidget(
+ new QLabel(tr("Signed on %1 <br/> It Contains:<br /><br/>")
+ .arg(QLocale::system().toString(timestamp))));
+ }
+ // Add information box for every single key
+ while (sign) {
+ auto* sign_box = new VerifyKeyDetailBox(this, mKeyList, sign);
+ sign = sign->next;
+ mVboxLayout->addWidget(sign_box);
+ }
- mVboxLayout->addWidget(buttonBox);
+ mVboxLayout->addWidget(buttonBox);
}
+
+} // namespace GpgFrontend::UI \ No newline at end of file
diff --git a/include/ui/VerifyDetailsDialog.h b/src/ui/VerifyDetailsDialog.h
index a66667c0..3d201194 100644
--- a/include/ui/VerifyDetailsDialog.h
+++ b/src/ui/VerifyDetailsDialog.h
@@ -25,29 +25,35 @@
#ifndef __VERIFYDETAILSDIALOG_H__
#define __VERIFYDETAILSDIALOG_H__
+#include "ui/GpgFrontendUI.h"
#include "ui/widgets/EditorPage.h"
#include "ui/widgets/VerifyKeyDetailBox.h"
+namespace GpgFrontend::UI {
+
class VerifyDetailsDialog : public QDialog {
-Q_OBJECT
-public:
- explicit VerifyDetailsDialog(QWidget *parent, GpgFrontend::GpgContext *ctx, KeyList *keyList, gpg_error_t error,
- gpgme_verify_result_t result);
-
-private slots:
-
- void slotRefresh();
-
-private:
- GpgFrontend::GpgContext *mCtx;
- KeyList *mKeyList;
- QHBoxLayout *mainLayout;
- QWidget *mVbox{};
- QByteArray *mInputData{}; /** Data to be verified */
- QByteArray *mInputSignature{}; /** Data to be verified */
- QDialogButtonBox *buttonBox{};
- gpgme_signature_t sign;
- gpgme_error_t error;
+ Q_OBJECT
+ public:
+ explicit VerifyDetailsDialog(QWidget* parent,
+ KeyList* keyList,
+ GpgError error,
+ GpgVerifyResult result);
+
+ private slots:
+
+ void slotRefresh();
+
+ private:
+ KeyList* mKeyList;
+ QHBoxLayout* mainLayout;
+ QWidget* mVbox{};
+ QByteArray* mInputData{}; /** Data to be verified */
+ QByteArray* mInputSignature{}; /** Data to be verified */
+ QDialogButtonBox* buttonBox{};
+ GpgVerifyResult mResult;
+ gpgme_error_t error;
};
-#endif // __VERIFYDETAILSDIALOG_H__
+} // namespace GpgFrontend::UI
+
+#endif // __VERIFYDETAILSDIALOG_H__
diff --git a/src/ui/WaitingDialog.cpp b/src/ui/WaitingDialog.cpp
index daccc3ca..44727193 100644
--- a/src/ui/WaitingDialog.cpp
+++ b/src/ui/WaitingDialog.cpp
@@ -1,20 +1,50 @@
+/**
+ * This file is part of GPGFrontend.
+ *
+ * GPGFrontend is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Foobar is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Foobar. If not, see <https://www.gnu.org/licenses/>.
+ *
+ * The initial version of the source code is inherited from gpg4usb-team.
+ * Their source code version also complies with GNU General Public License.
+ *
+ * The source code version of this software was modified and released
+ * by Saturneric<[email protected]> starting on May 12, 2021.
+ *
+ */
+
#include "ui/WaitingDialog.h"
-WaitingDialog::WaitingDialog(const QString &title, QWidget *parent) : QDialog(parent) {
- auto *pb = new QProgressBar();
- pb->setRange(0, 0);
- pb->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Preferred);
- pb->setTextVisible(false);
+namespace GpgFrontend::UI {
+
+WaitingDialog::WaitingDialog(const QString& title, QWidget* parent)
+ : QDialog(parent) {
+ auto* pb = new QProgressBar();
+ pb->setRange(0, 0);
+ pb->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Preferred);
+ pb->setTextVisible(false);
- auto *layout = new QVBoxLayout();
- layout->setContentsMargins(0, 0, 0, 0);
- layout->setSpacing(0);
- layout->addWidget(pb);
- this->setLayout(layout);
+ auto* layout = new QVBoxLayout();
+ layout->setContentsMargins(0, 0, 0, 0);
+ layout->setSpacing(0);
+ layout->addWidget(pb);
+ this->setLayout(layout);
- this->setModal(true);
- this->setWindowFlags(Qt::Window | Qt::WindowTitleHint | Qt::CustomizeWindowHint);
- this->setWindowTitle(title);
- this->setFixedSize(240, 42);
- this->show();
+ this->setModal(true);
+ this->setWindowFlags(Qt::Window | Qt::WindowTitleHint |
+ Qt::CustomizeWindowHint);
+ this->setWindowTitle(title);
+ this->setFixedSize(240, 42);
+ this->show();
}
+
+} // namespace GpgFrontend::UI
diff --git a/include/ui/WaitingDialog.h b/src/ui/WaitingDialog.h
index df781073..a81ab9ce 100644
--- a/include/ui/WaitingDialog.h
+++ b/src/ui/WaitingDialog.h
@@ -22,19 +22,20 @@
*
*/
-#include "GpgFrontend.h"
+#include "ui/GpgFrontendUI.h"
-class WaitingDialog : public QDialog {
-Q_OBJECT
-public:
-
- WaitingDialog(const QString &title, QWidget *parent);
-
-public slots:
+namespace GpgFrontend::UI {
-private slots:
+class WaitingDialog : public QDialog {
+ Q_OBJECT
+ public:
+ WaitingDialog(const QString& title, QWidget* parent);
-private:
+ public slots:
+ private slots:
+ private:
};
+
+} // namespace GpgFrontend::UI
diff --git a/src/ui/Wizard.cpp b/src/ui/Wizard.cpp
index 4c7b8d7c..2f050e80 100644
--- a/src/ui/Wizard.cpp
+++ b/src/ui/Wizard.cpp
@@ -24,234 +24,256 @@
#include "ui/Wizard.h"
-Wizard::Wizard(GpgFrontend::GpgContext *ctx, KeyMgmt *keyMgmt, QWidget *parent)
- : QWizard(parent), appPath(qApp->applicationDirPath()),
- settings(RESOURCE_DIR(appPath) + "/conf/gpgfrontend.ini", QSettings::IniFormat) {
- mCtx = ctx;
- mKeyMgmt = keyMgmt;
-
- setPage(Page_Intro, new IntroPage(this));
- setPage(Page_Choose, new ChoosePage(this));
- setPage(Page_GenKey, new KeyGenPage(mCtx, this));
- setPage(Page_Conclusion, new ConclusionPage(this));
+namespace GpgFrontend::UI {
+
+Wizard::Wizard(KeyMgmt* keyMgmt, QWidget* parent)
+ : QWizard(parent),
+ appPath(qApp->applicationDirPath()),
+ settings(RESOURCE_DIR(appPath) + "/conf/gpgfrontend.ini",
+ QSettings::IniFormat) {
+ mKeyMgmt = keyMgmt;
+
+ setPage(Page_Intro, new IntroPage(this));
+ setPage(Page_Choose, new ChoosePage(this));
+ setPage(Page_GenKey, new KeyGenPage(this));
+ setPage(Page_Conclusion, new ConclusionPage(this));
#ifndef Q_WS_MAC
- setWizardStyle(ModernStyle);
+ setWizardStyle(ModernStyle);
#endif
- setWindowTitle(tr("First Start Wizard"));
+ setWindowTitle(tr("First Start Wizard"));
- // http://www.flickr.com/photos/laureenp/6141822934/
- setPixmap(QWizard::WatermarkPixmap, QPixmap(":/keys2.jpg"));
- setPixmap(QWizard::LogoPixmap, QPixmap(":/logo_small.png"));
- setPixmap(QWizard::BannerPixmap, QPixmap(":/banner.png"));
+ // http://www.flickr.com/photos/laureenp/6141822934/
+ setPixmap(QWizard::WatermarkPixmap, QPixmap(":/keys2.jpg"));
+ setPixmap(QWizard::LogoPixmap, QPixmap(":/logo_small.png"));
+ setPixmap(QWizard::BannerPixmap, QPixmap(":/banner.png"));
- setStartId(settings.value("wizard/nextPage", -1).toInt());
- settings.remove("wizard/nextPage");
-
- connect(this, SIGNAL(accepted()), this, SLOT(slotWizardAccepted()));
+ setStartId(settings.value("wizard/nextPage", -1).toInt());
+ settings.remove("wizard/nextPage");
+ connect(this, SIGNAL(accepted()), this, SLOT(slotWizardAccepted()));
}
void Wizard::slotWizardAccepted() {
- // Don't show is mapped to show -> negation
- settings.setValue("wizard/showWizard", !field("showWizard").toBool());
+ // Don't show is mapped to show -> negation
+ settings.setValue("wizard/showWizard", !field("showWizard").toBool());
- if (field("openHelp").toBool()) {
- emit signalOpenHelp("docu.html#content");
- }
+ if (field("openHelp").toBool()) {
+ emit signalOpenHelp("docu.html#content");
+ }
}
-IntroPage::IntroPage(QWidget *parent)
- : QWizardPage(parent), appPath(qApp->applicationDirPath()),
- settings(RESOURCE_DIR(appPath) + "/conf/gpgfrontend.ini", QSettings::IniFormat) {
- setTitle(tr("Getting Started..."));
- setSubTitle(tr("... with GPGFrontend"));
-
- auto *topLabel = new QLabel(tr("Welcome to use GPGFrontend for decrypting and signing text or file!") +
- " <br><br><a href='https://gpgfrontend.pub'>GpgFrontend</a> " +
- tr("is a Powerful, Easy-to-Use, Compact, Cross-Platform, and Installation-Free OpenPGP Crypto Tool.") +
- tr("For brief information have a look at the") +
- " <a href='https://gpgfrontend.pub/index.html#/overview'>" +
- tr("Overview") + "</a> (" +
- tr("by clicking the link, the page will open in the web browser") +
- "). <br>");
- topLabel->setTextFormat(Qt::RichText);
- topLabel->setTextInteractionFlags(Qt::TextBrowserInteraction);
- topLabel->setOpenExternalLinks(true);
- topLabel->setWordWrap(true);
-
- // QComboBox for language selection
- auto *langLabel = new QLabel(tr("Choose a Language"));
- langLabel->setWordWrap(true);
-
- languages = SettingsDialog::listLanguages();
- auto *langSelectBox = new QComboBox();
-
- for (const auto &l : languages) {
- langSelectBox->addItem(l);
- }
- // selected entry from config
- QString langKey = settings.value("int/lang").toString();
- QString langValue = languages.value(langKey);
- if (langKey != "") {
- langSelectBox->setCurrentIndex(langSelectBox->findText(langValue));
- }
-
- connect(langSelectBox, SIGNAL(currentIndexChanged(QString)), this, SLOT(slotLangChange(QString)));
-
- // set layout and add widgets
- auto *layout = new QVBoxLayout;
- layout->addWidget(topLabel);
- layout->addWidget(langLabel);
- layout->addWidget(langSelectBox);
- setLayout(layout);
+IntroPage::IntroPage(QWidget* parent)
+ : QWizardPage(parent),
+ appPath(qApp->applicationDirPath()),
+ settings(RESOURCE_DIR(appPath) + "/conf/gpgfrontend.ini",
+ QSettings::IniFormat) {
+ setTitle(tr("Getting Started..."));
+ setSubTitle(tr("... with GPGFrontend"));
+
+ auto* topLabel = new QLabel(
+ tr("Welcome to use GPGFrontend for decrypting and signing text or "
+ "file!") +
+ " <br><br><a href='https://gpgfrontend.pub'>GpgFrontend</a> " +
+ tr("is a Powerful, Easy-to-Use, Compact, Cross-Platform, and "
+ "Installation-Free OpenPGP Crypto Tool.") +
+ tr("For brief information have a look at the") +
+ " <a href='https://gpgfrontend.pub/index.html#/overview'>" +
+ tr("Overview") + "</a> (" +
+ tr("by clicking the link, the page will open in the web browser") +
+ "). <br>");
+ topLabel->setTextFormat(Qt::RichText);
+ topLabel->setTextInteractionFlags(Qt::TextBrowserInteraction);
+ topLabel->setOpenExternalLinks(true);
+ topLabel->setWordWrap(true);
+
+ // QComboBox for language selection
+ auto* langLabel = new QLabel(tr("Choose a Language"));
+ langLabel->setWordWrap(true);
+
+ languages = SettingsDialog::listLanguages();
+ auto* langSelectBox = new QComboBox();
+
+ for (const auto& l : languages) {
+ langSelectBox->addItem(l);
+ }
+ // selected entry from config
+ QString langKey = settings.value("int/lang").toString();
+ QString langValue = languages.value(langKey);
+ if (langKey != "") {
+ langSelectBox->setCurrentIndex(langSelectBox->findText(langValue));
+ }
+
+ connect(langSelectBox, SIGNAL(currentIndexChanged(QString)), this,
+ SLOT(slotLangChange(QString)));
+
+ // set layout and add widgets
+ auto* layout = new QVBoxLayout;
+ layout->addWidget(topLabel);
+ layout->addWidget(langLabel);
+ layout->addWidget(langSelectBox);
+ setLayout(layout);
}
-void IntroPage::slotLangChange(const QString &lang) {
- settings.setValue("int/lang", languages.key(lang));
- settings.setValue("wizard/nextPage", this->wizard()->currentId());
- qApp->exit(RESTART_CODE);
+void IntroPage::slotLangChange(const QString& lang) {
+ settings.setValue("int/lang", languages.key(lang));
+ settings.setValue("wizard/nextPage", this->wizard()->currentId());
+ qApp->exit(RESTART_CODE);
}
int IntroPage::nextId() const {
- return Wizard::Page_Choose;
+ return Wizard::Page_Choose;
}
-ChoosePage::ChoosePage(QWidget *parent)
- : QWizardPage(parent) {
- setTitle(tr("Choose your action..."));
- setSubTitle(tr("...by clicking on the appropriate link."));
-
- auto *keygenLabel = new QLabel(tr("If you have never used GPGFrontend before and also don't own a gpg key yet you "
- "may possibly want to read how to") +
- " <a href=\"https://gpgfrontend.pub/index.html#/manual/generate-key\">"
- + tr("Generate Key") + "</a><hr>");
- keygenLabel->setTextFormat(Qt::RichText);
- keygenLabel->setTextInteractionFlags(Qt::TextBrowserInteraction);
- keygenLabel->setOpenExternalLinks(true);
- keygenLabel->setWordWrap(true);
-
- auto *encrDecyTextLabel = new QLabel(
- tr("If you want to learn how to encrypt, decrypt, sign and verify text, you can read ")
- + "<a href=\"https://gpgfrontend.pub/index.html#/manual/encrypt-decrypt-text\">"
- + tr("Encrypt & Decrypt Text") + "</a> " + tr("or")
- + " <a href=\"https://gpgfrontend.pub/index.html#/manual/sign-verify-text\">"
- + tr("Sign & Verify Text")
- + "</a><hr>");
-
- encrDecyTextLabel->setTextFormat(Qt::RichText);
- encrDecyTextLabel->setTextInteractionFlags(Qt::TextBrowserInteraction);
- encrDecyTextLabel->setOpenExternalLinks(true);
- encrDecyTextLabel->setWordWrap(true);
-
- auto *signVerifyTextLabel = new QLabel(tr("If you want to operate file, you can read ")
- +
- "<a href=\"https://gpgfrontend.pub/index.html#/manual/encrypt-decrypt-file\">"
- + tr("Encrypt & Sign File") + "</a> " + tr("or")
- +
- " <a href=\"https://gpgfrontend.pub/index.html#/manual/sign-verify-file\">"
- + tr("Sign & Verify File")
- + "</a><hr>");
- signVerifyTextLabel->setTextFormat(Qt::RichText);
- signVerifyTextLabel->setTextInteractionFlags(Qt::TextBrowserInteraction);
- signVerifyTextLabel->setOpenExternalLinks(true);
- signVerifyTextLabel->setWordWrap(true);
-
- auto *layout = new QVBoxLayout();
- layout->addWidget(keygenLabel);
- layout->addWidget(encrDecyTextLabel);
- layout->addWidget(signVerifyTextLabel);
- setLayout(layout);
- nextPage = Wizard::Page_Conclusion;
+ChoosePage::ChoosePage(QWidget* parent) : QWizardPage(parent) {
+ setTitle(tr("Choose your action..."));
+ setSubTitle(tr("...by clicking on the appropriate link."));
+
+ auto* keygenLabel = new QLabel(
+ tr("If you have never used GPGFrontend before and also don't own a gpg "
+ "key yet you "
+ "may possibly want to read how to") +
+ " <a href=\"https://gpgfrontend.pub/index.html#/manual/generate-key\">" +
+ tr("Generate Key") + "</a><hr>");
+ keygenLabel->setTextFormat(Qt::RichText);
+ keygenLabel->setTextInteractionFlags(Qt::TextBrowserInteraction);
+ keygenLabel->setOpenExternalLinks(true);
+ keygenLabel->setWordWrap(true);
+
+ auto* encrDecyTextLabel = new QLabel(
+ tr("If you want to learn how to encrypt, decrypt, sign and verify text, "
+ "you can read ") +
+ "<a "
+ "href=\"https://gpgfrontend.pub/index.html#/manual/"
+ "encrypt-decrypt-text\">" +
+ tr("Encrypt & Decrypt Text") + "</a> " + tr("or") +
+ " <a "
+ "href=\"https://gpgfrontend.pub/index.html#/manual/sign-verify-text\">" +
+ tr("Sign & Verify Text") + "</a><hr>");
+
+ encrDecyTextLabel->setTextFormat(Qt::RichText);
+ encrDecyTextLabel->setTextInteractionFlags(Qt::TextBrowserInteraction);
+ encrDecyTextLabel->setOpenExternalLinks(true);
+ encrDecyTextLabel->setWordWrap(true);
+
+ auto* signVerifyTextLabel = new QLabel(
+ tr("If you want to operate file, you can read ") +
+ "<a "
+ "href=\"https://gpgfrontend.pub/index.html#/manual/"
+ "encrypt-decrypt-file\">" +
+ tr("Encrypt & Sign File") + "</a> " + tr("or") +
+ " <a "
+ "href=\"https://gpgfrontend.pub/index.html#/manual/sign-verify-file\">" +
+ tr("Sign & Verify File") + "</a><hr>");
+ signVerifyTextLabel->setTextFormat(Qt::RichText);
+ signVerifyTextLabel->setTextInteractionFlags(Qt::TextBrowserInteraction);
+ signVerifyTextLabel->setOpenExternalLinks(true);
+ signVerifyTextLabel->setWordWrap(true);
+
+ auto* layout = new QVBoxLayout();
+ layout->addWidget(keygenLabel);
+ layout->addWidget(encrDecyTextLabel);
+ layout->addWidget(signVerifyTextLabel);
+ setLayout(layout);
+ nextPage = Wizard::Page_Conclusion;
}
int ChoosePage::nextId() const {
- return nextPage;
+ return nextPage;
}
-void ChoosePage::slotJumpPage(const QString &page) {
- QMetaObject qmo = Wizard::staticMetaObject;
- int index = qmo.indexOfEnumerator("WizardPages");
- QMetaEnum m = qmo.enumerator(index);
+void ChoosePage::slotJumpPage(const QString& page) {
+ QMetaObject qmo = Wizard::staticMetaObject;
+ int index = qmo.indexOfEnumerator("WizardPages");
+ QMetaEnum m = qmo.enumerator(index);
- nextPage = m.keyToValue(page.toUtf8().data());
- wizard()->next();
+ nextPage = m.keyToValue(page.toUtf8().data());
+ wizard()->next();
}
-KeyGenPage::KeyGenPage(GpgFrontend::GpgContext *ctx, QWidget *parent)
- : QWizardPage(parent) {
- mCtx = ctx;
- setTitle(tr("Create a keypair..."));
- setSubTitle(tr("...for decrypting and signing messages"));
- auto *topLabel = new QLabel(tr("You should create a new keypair."
- "The pair consists of a public and a private key.<br>"
- "Other users can use the public key to encrypt messages for you "
- "and verify messages signed by you."
- "You can use the private key to decrypt and sign messages.<br>"
- "For more information have a look at the offline tutorial (which then is shown in the main window):"));
- topLabel->setWordWrap(true);
- auto *linkLabel = new QLabel("<a href=""docu_keygen.html#content"">" + tr("Offline tutorial") + "</a>");
- //linkLabel->setOpenExternalLinks(true);
-
- // connect(linkLabel, SIGNAL(linkActivated(QString)), parentWidget()->parentWidget(), SLOT(openHelp(QString)));
-
- auto *createKeyButtonBox = new QWidget(this);
- auto *createKeyButtonBoxLayout = new QHBoxLayout(createKeyButtonBox);
- auto *createKeyButton = new QPushButton(tr("Create New Key"));
- createKeyButtonBoxLayout->addWidget(createKeyButton);
- createKeyButtonBoxLayout->addStretch(1);
- auto *layout = new QVBoxLayout();
- layout->addWidget(topLabel);
- layout->addWidget(linkLabel);
- layout->addWidget(createKeyButtonBox);
- connect(createKeyButton, SIGNAL(clicked(bool)), this, SLOT(slotGenerateKeyDialog()));
-
- setLayout(layout);
+KeyGenPage::KeyGenPage(QWidget* parent) : QWizardPage(parent) {
+ setTitle(tr("Create a keypair..."));
+ setSubTitle(tr("...for decrypting and signing messages"));
+ auto* topLabel = new QLabel(
+ tr("You should create a new keypair."
+ "The pair consists of a public and a private key.<br>"
+ "Other users can use the public key to encrypt messages for you "
+ "and verify messages signed by you."
+ "You can use the private key to decrypt and sign messages.<br>"
+ "For more information have a look at the offline tutorial (which then "
+ "is shown in the main window):"));
+ topLabel->setWordWrap(true);
+ auto* linkLabel = new QLabel(
+ "<a href="
+ "docu_keygen.html#content"
+ ">" +
+ tr("Offline tutorial") + "</a>");
+ // linkLabel->setOpenExternalLinks(true);
+
+ // connect(linkLabel, SIGNAL(linkActivated(QString)),
+ // parentWidget()->parentWidget(), SLOT(openHelp(QString)));
+
+ auto* createKeyButtonBox = new QWidget(this);
+ auto* createKeyButtonBoxLayout = new QHBoxLayout(createKeyButtonBox);
+ auto* createKeyButton = new QPushButton(tr("Create New Key"));
+ createKeyButtonBoxLayout->addWidget(createKeyButton);
+ createKeyButtonBoxLayout->addStretch(1);
+ auto* layout = new QVBoxLayout();
+ layout->addWidget(topLabel);
+ layout->addWidget(linkLabel);
+ layout->addWidget(createKeyButtonBox);
+ connect(createKeyButton, SIGNAL(clicked(bool)), this,
+ SLOT(slotGenerateKeyDialog()));
+
+ setLayout(layout);
}
int KeyGenPage::nextId() const {
- return Wizard::Page_Conclusion;
+ return Wizard::Page_Conclusion;
}
void KeyGenPage::slotGenerateKeyDialog() {
- qDebug() << "Try Opening KeyGenDialog";
- auto *keyGenDialog = new KeyGenDialog(mCtx, this);
- keyGenDialog->show();
- wizard()->next();
+ qDebug() << "Try Opening KeyGenDialog";
+ (new KeyGenDialog(this))->show();
+ wizard()->next();
}
-ConclusionPage::ConclusionPage(QWidget *parent)
- : QWizardPage(parent) {
- setTitle(tr("Ready."));
- setSubTitle(tr("Have fun with GPGFrontend!"));
-
- auto *bottomLabel = new QLabel(tr("You are ready to use GPGFrontend now.<br><br>") +
- "<a href=\"https://saturneric.github.io/GpgFrontend/index.html#/overview\">"
- + tr("The Online Document") + "</a>"
- +
- tr(" will get you started with GPGFrontend. It will open in the main window.<br>"));
-
- bottomLabel->setTextFormat(Qt::RichText);
- bottomLabel->setTextInteractionFlags(Qt::TextBrowserInteraction);
- bottomLabel->setOpenExternalLinks(true);
- bottomLabel->setWordWrap(true);
-
- openHelpCheckBox = new QCheckBox(tr("Open offline help."));
- openHelpCheckBox->setChecked(Qt::Checked);
-
- dontShowWizardCheckBox = new QCheckBox(tr("Dont show the wizard again."));
- dontShowWizardCheckBox->setChecked(Qt::Checked);
-
- registerField("showWizard", dontShowWizardCheckBox);
- // registerField("openHelp", openHelpCheckBox);
-
- auto *layout = new QVBoxLayout;
- layout->addWidget(bottomLabel);
- // layout->addWidget(openHelpCheckBox);
- layout->addWidget(dontShowWizardCheckBox);
- setLayout(layout);
- setVisible(true);
+ConclusionPage::ConclusionPage(QWidget* parent) : QWizardPage(parent) {
+ setTitle(tr("Ready."));
+ setSubTitle(tr("Have fun with GPGFrontend!"));
+
+ auto* bottomLabel =
+ new QLabel(tr("You are ready to use GPGFrontend now.<br><br>") +
+ "<a "
+ "href=\"https://saturneric.github.io/GpgFrontend/index.html#/"
+ "overview\">" +
+ tr("The Online Document") + "</a>" +
+ tr(" will get you started with GPGFrontend. It will open in "
+ "the main window.<br>"));
+
+ bottomLabel->setTextFormat(Qt::RichText);
+ bottomLabel->setTextInteractionFlags(Qt::TextBrowserInteraction);
+ bottomLabel->setOpenExternalLinks(true);
+ bottomLabel->setWordWrap(true);
+
+ openHelpCheckBox = new QCheckBox(tr("Open offline help."));
+ openHelpCheckBox->setChecked(Qt::Checked);
+
+ dontShowWizardCheckBox = new QCheckBox(tr("Dont show the wizard again."));
+ dontShowWizardCheckBox->setChecked(Qt::Checked);
+
+ registerField("showWizard", dontShowWizardCheckBox);
+ // registerField("openHelp", openHelpCheckBox);
+
+ auto* layout = new QVBoxLayout;
+ layout->addWidget(bottomLabel);
+ // layout->addWidget(openHelpCheckBox);
+ layout->addWidget(dontShowWizardCheckBox);
+ setLayout(layout);
+ setVisible(true);
}
int ConclusionPage::nextId() const {
- return -1;
+ return -1;
}
+
+} // namespace GpgFrontend::UI
diff --git a/src/ui/Wizard.h b/src/ui/Wizard.h
new file mode 100644
index 00000000..cb6cd13e
--- /dev/null
+++ b/src/ui/Wizard.h
@@ -0,0 +1,129 @@
+/**
+ * This file is part of GPGFrontend.
+ *
+ * GPGFrontend is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Foobar is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Foobar. If not, see <https://www.gnu.org/licenses/>.
+ *
+ * The initial version of the source code is inherited from gpg4usb-team.
+ * Their source code version also complies with GNU General Public License.
+ *
+ * The source code version of this software was modified and released
+ * by Saturneric<[email protected]> starting on May 12, 2021.
+ *
+ */
+
+#ifndef WIZARD_H
+#define WIZARD_H
+
+#include "SettingsDialog.h"
+#include "gpg/GpgConstants.h"
+#include "ui/GpgFrontendUI.h"
+#include "ui/KeyMgmt.h"
+#include "ui/keygen/KeygenDialog.h"
+
+namespace GpgFrontend::UI {
+
+class Wizard : public QWizard {
+ Q_OBJECT
+ Q_ENUMS(WizardPages)
+
+ public:
+ enum WizardPages {
+ Page_Intro,
+ Page_Choose,
+ Page_ImportFromGpg4usb,
+ Page_ImportFromGnupg,
+ Page_GenKey,
+ Page_Conclusion
+ };
+
+ Wizard(KeyMgmt* keyMgmt, QWidget* parent = nullptr);
+
+ private:
+ KeyMgmt* mKeyMgmt;
+ QString appPath;
+ QSettings settings;
+
+ private slots:
+
+ void slotWizardAccepted();
+
+ signals:
+
+ void signalOpenHelp(QString page);
+};
+
+class IntroPage : public QWizardPage {
+ Q_OBJECT
+
+ public:
+ explicit IntroPage(QWidget* parent = nullptr);
+
+ QHash<QString, QString> languages;
+
+ [[nodiscard]] int nextId() const override;
+
+ private:
+ QString appPath;
+ QSettings settings;
+
+ private slots:
+
+ void slotLangChange(const QString& lang);
+};
+
+class ChoosePage : public QWizardPage {
+ Q_OBJECT
+
+ public:
+ explicit ChoosePage(QWidget* parent = nullptr);
+
+ private slots:
+
+ void slotJumpPage(const QString& page);
+
+ private:
+ [[nodiscard]] int nextId() const override;
+
+ int nextPage;
+};
+
+class KeyGenPage : public QWizardPage {
+ Q_OBJECT
+
+ public:
+ explicit KeyGenPage(QWidget* parent = nullptr);
+
+ [[nodiscard]] int nextId() const override;
+
+ private slots:
+
+ void slotGenerateKeyDialog();
+};
+
+class ConclusionPage : public QWizardPage {
+ Q_OBJECT
+
+ public:
+ explicit ConclusionPage(QWidget* parent = nullptr);
+
+ [[nodiscard]] int nextId() const override;
+
+ private:
+ QCheckBox* dontShowWizardCheckBox;
+ QCheckBox* openHelpCheckBox;
+};
+
+} // namespace GpgFrontend::UI
+
+#endif
diff --git a/src/ui/help/AboutDialog.cpp b/src/ui/help/AboutDialog.cpp
index deb6a3bc..4c6c2348 100644
--- a/src/ui/help/AboutDialog.cpp
+++ b/src/ui/help/AboutDialog.cpp
@@ -30,188 +30,209 @@
using namespace rapidjson;
-AboutDialog::AboutDialog(int defaultIndex, QWidget *parent)
- : QDialog(parent) {
- this->setWindowTitle(tr("About ") + qApp->applicationName());
+namespace GpgFrontend::UI {
- auto *tabWidget = new QTabWidget;
- auto *infoTab = new InfoTab();
- auto *translatorsTab = new TranslatorsTab();
- updateTab = new UpdateTab();
+AboutDialog::AboutDialog(int defaultIndex, QWidget* parent) : QDialog(parent) {
+ this->setWindowTitle(tr("About ") + qApp->applicationName());
- tabWidget->addTab(infoTab, tr("General"));
- tabWidget->addTab(translatorsTab, tr("Translators"));
- tabWidget->addTab(updateTab, tr("Update"));
+ auto* tabWidget = new QTabWidget;
+ auto* infoTab = new InfoTab();
+ auto* translatorsTab = new TranslatorsTab();
+ updateTab = new UpdateTab();
- connect(tabWidget, &QTabWidget::currentChanged, this, [&](int index) {
- qDebug() << "Current Index" << index;
- });
+ tabWidget->addTab(infoTab, tr("General"));
+ tabWidget->addTab(translatorsTab, tr("Translators"));
+ tabWidget->addTab(updateTab, tr("Update"));
- if(defaultIndex < tabWidget->count() && defaultIndex >= 0) {
- tabWidget->setCurrentIndex(defaultIndex);
- }
+ connect(tabWidget, &QTabWidget::currentChanged, this,
+ [&](int index) { qDebug() << "Current Index" << index; });
- auto *buttonBox = new QDialogButtonBox(QDialogButtonBox::Ok);
- connect(buttonBox, SIGNAL(accepted()), this, SLOT(close()));
+ if (defaultIndex < tabWidget->count() && defaultIndex >= 0) {
+ tabWidget->setCurrentIndex(defaultIndex);
+ }
- auto *mainLayout = new QVBoxLayout;
- mainLayout->addWidget(tabWidget);
- mainLayout->addWidget(buttonBox);
- setLayout(mainLayout);
+ auto* buttonBox = new QDialogButtonBox(QDialogButtonBox::Ok);
+ connect(buttonBox, SIGNAL(accepted()), this, SLOT(close()));
- this->show();
+ auto* mainLayout = new QVBoxLayout;
+ mainLayout->addWidget(tabWidget);
+ mainLayout->addWidget(buttonBox);
+ setLayout(mainLayout);
+
+ this->show();
}
-void AboutDialog::showEvent(QShowEvent *ev) {
- QDialog::showEvent(ev);
- updateTab->getLatestVersion();
+void AboutDialog::showEvent(QShowEvent* ev) {
+ QDialog::showEvent(ev);
+ updateTab->getLatestVersion();
}
-InfoTab::InfoTab(QWidget *parent)
- : QWidget(parent) {
- auto *pixmap = new QPixmap(":gpgfrontend-logo.png");
- auto *text = new QString("<center><h2>" + qApp->applicationName() + "</h2></center>"
- + "<center><b>" + qApp->applicationVersion() + "</b></center>"
- + "<center>" + GIT_VERSION + "</center>"
- + tr("<br><center>GPGFrontend is an easy-to-use, compact, cross-platform, <br>"
- "and installation-free gpg front-end tool.<br>"
- "It visualizes most of the common operations of gpg commands.<br>"
- "It's licensed under the GPL v3<br><br>"
- "<b>Developer:</b><br>"
- "Saturneric<br><br>"
- "If you have any questions or suggestions, raise an issue<br/>"
- "at <a href=\"https://github.com/saturneric/GpgFrontend\">GitHub</a> or send a mail to my mailing list at <a href=\"mailto:[email protected]\">[email protected]</a>.") +
- tr("<br><br> Built with Qt ") + qVersion()
- + tr(" and GPGME ") + GpgFrontend::GpgContext::getGpgmeVersion() +
- tr("<br>Built at ") + BUILD_TIMESTAMP + "</center>");
-
- auto *layout = new QGridLayout();
- auto *pixmapLabel = new QLabel();
- pixmapLabel->setPixmap(*pixmap);
- layout->addWidget(pixmapLabel, 0, 0, 1, -1, Qt::AlignCenter);
- auto *aboutLabel = new QLabel();
- aboutLabel->setText(*text);
- aboutLabel->setOpenExternalLinks(true);
- layout->addWidget(aboutLabel, 1, 0, 1, -1);
- layout->addItem(new QSpacerItem(20, 10, QSizePolicy::Minimum,
- QSizePolicy::Fixed), 2, 1, 1, 1);
-
- setLayout(layout);
+InfoTab::InfoTab(QWidget* parent) : QWidget(parent) {
+ auto* pixmap = new QPixmap(":gpgfrontend-logo.png");
+ auto* text = new QString(
+ "<center><h2>" + qApp->applicationName() + "</h2></center>" +
+ "<center><b>" + qApp->applicationVersion() + "</b></center>" +
+ "<center>" + GIT_VERSION + "</center>" +
+ tr("<br><center>GPGFrontend is an easy-to-use, compact, cross-platform, "
+ "<br>"
+ "and installation-free gpg front-end tool.<br>"
+ "It visualizes most of the common operations of gpg commands.<br>"
+ "It's licensed under the GPL v3<br><br>"
+ "<b>Developer:</b><br>"
+ "Saturneric<br><br>"
+ "If you have any questions or suggestions, raise an issue<br/>"
+ "at <a href=\"https://github.com/saturneric/GpgFrontend\">GitHub</a> "
+ "or send a mail to my mailing list at <a "
+ "href=\"mailto:[email protected]\">[email protected]</a>.") +
+ tr("<br><br> Built with Qt ") + qVersion() + tr(" and GPGME ") +
+ GpgFrontend::GpgContext::getGpgmeVersion().c_str() + tr("<br>Built at ") +
+ BUILD_TIMESTAMP + "</center>");
+
+ auto* layout = new QGridLayout();
+ auto* pixmapLabel = new QLabel();
+ pixmapLabel->setPixmap(*pixmap);
+ layout->addWidget(pixmapLabel, 0, 0, 1, -1, Qt::AlignCenter);
+ auto* aboutLabel = new QLabel();
+ aboutLabel->setText(*text);
+ aboutLabel->setOpenExternalLinks(true);
+ layout->addWidget(aboutLabel, 1, 0, 1, -1);
+ layout->addItem(
+ new QSpacerItem(20, 10, QSizePolicy::Minimum, QSizePolicy::Fixed), 2, 1,
+ 1, 1);
+
+ setLayout(layout);
}
-TranslatorsTab::TranslatorsTab(QWidget *parent)
- : QWidget(parent) {
- QFile translatorsFile;
- translatorsFile.setFileName(qApp->applicationDirPath() + "/About");
- translatorsFile.open(QIODevice::ReadOnly);
- QByteArray inBuffer = translatorsFile.readAll();
+TranslatorsTab::TranslatorsTab(QWidget* parent) : QWidget(parent) {
+ QFile translatorsFile;
+ translatorsFile.setFileName(qApp->applicationDirPath() + "/About");
+ translatorsFile.open(QIODevice::ReadOnly);
+ QByteArray inBuffer = translatorsFile.readAll();
- auto *label = new QLabel(inBuffer);
- auto *mainLayout = new QVBoxLayout(this);
- mainLayout->addWidget(label);
+ auto* label = new QLabel(inBuffer);
+ auto* mainLayout = new QVBoxLayout(this);
+ mainLayout->addWidget(label);
- setLayout(mainLayout);
+ setLayout(mainLayout);
}
-UpdateTab::UpdateTab(QWidget *parent) {
- auto *pixmap = new QPixmap(":gpgfrontend-logo.png");
- auto *layout = new QGridLayout();
- auto *pixmapLabel = new QLabel();
- pixmapLabel->setPixmap(*pixmap);
- layout->addWidget(pixmapLabel, 0, 0, 1, -1, Qt::AlignCenter);
-
- currentVersion = "v" + QString::number(VERSION_MAJOR) + "."
- + QString::number(VERSION_MINOR) + "."
- + QString::number(VERSION_PATCH);
-
- auto tipsLabel = new QLabel();
- tipsLabel->setText("<center>" +
- tr("It is recommended that you always check the version of GpgFrontend and upgrade to the latest version.") +
- "</center><br><center>" +
- tr("New versions not only represent new features, but also often represent functional and security fixes.") + "</center>");
- tipsLabel->setWordWrap(true);
-
- currentVersionLabel = new QLabel();
- currentVersionLabel->setText("<center>" + tr("Current Version: ") + "<b>" + currentVersion + "</b></center>");
- currentVersionLabel->setWordWrap(true);
-
- latestVersionLabel = new QLabel();
- latestVersionLabel->setWordWrap(true);
-
- upgradeLabel = new QLabel();
- upgradeLabel->setText("<center>" +
- tr("The current version is inconsistent with the latest version on github.") +
- "</center><br><center>" +
- tr("Please click <a href=\"https://github.com/saturneric/GpgFrontend/releases\">here</a> to download the latest version.") + "</center>");
- upgradeLabel->setWordWrap(true);
- upgradeLabel->setOpenExternalLinks(true);
- upgradeLabel->setHidden(true);
-
- pb = new QProgressBar();
- pb->setRange(0, 0);
- pb->setTextVisible(false);
-
- layout->addWidget(tipsLabel, 1, 0, 1, -1);
- layout->addWidget(currentVersionLabel, 2, 0, 1, -1);
- layout->addWidget(latestVersionLabel, 3, 0, 1, -1);
- layout->addWidget(upgradeLabel, 4, 0, 1, -1);
- layout->addWidget(pb, 5, 0, 1, -1);
- layout->addItem(new QSpacerItem(20, 10, QSizePolicy::Minimum,
- QSizePolicy::Fixed), 2, 1, 1, 1);
-
- connect(this, SIGNAL(replyFromUpdateServer(QByteArray)), this, SLOT(processReplyDataFromUpdateServer(QByteArray)));
-
- setLayout(layout);
+UpdateTab::UpdateTab(QWidget* parent) {
+ auto* pixmap = new QPixmap(":gpgfrontend-logo.png");
+ auto* layout = new QGridLayout();
+ auto* pixmapLabel = new QLabel();
+ pixmapLabel->setPixmap(*pixmap);
+ layout->addWidget(pixmapLabel, 0, 0, 1, -1, Qt::AlignCenter);
+
+ currentVersion = "v" + QString::number(VERSION_MAJOR) + "." +
+ QString::number(VERSION_MINOR) + "." +
+ QString::number(VERSION_PATCH);
+
+ auto tipsLabel = new QLabel();
+ tipsLabel->setText("<center>" +
+ tr("It is recommended that you always check the version "
+ "of GpgFrontend and upgrade to the latest version.") +
+ "</center><br><center>" +
+ tr("New versions not only represent new features, but "
+ "also often represent functional and security fixes.") +
+ "</center>");
+ tipsLabel->setWordWrap(true);
+
+ currentVersionLabel = new QLabel();
+ currentVersionLabel->setText("<center>" + tr("Current Version: ") + "<b>" +
+ currentVersion + "</b></center>");
+ currentVersionLabel->setWordWrap(true);
+
+ latestVersionLabel = new QLabel();
+ latestVersionLabel->setWordWrap(true);
+
+ upgradeLabel = new QLabel();
+ upgradeLabel->setText(
+ "<center>" +
+ tr("The current version is inconsistent with the latest version on "
+ "github.") +
+ "</center><br><center>" +
+ tr("Please click <a "
+ "href=\"https://github.com/saturneric/GpgFrontend/releases\">here</a> "
+ "to download the latest version.") +
+ "</center>");
+ upgradeLabel->setWordWrap(true);
+ upgradeLabel->setOpenExternalLinks(true);
+ upgradeLabel->setHidden(true);
+
+ pb = new QProgressBar();
+ pb->setRange(0, 0);
+ pb->setTextVisible(false);
+
+ layout->addWidget(tipsLabel, 1, 0, 1, -1);
+ layout->addWidget(currentVersionLabel, 2, 0, 1, -1);
+ layout->addWidget(latestVersionLabel, 3, 0, 1, -1);
+ layout->addWidget(upgradeLabel, 4, 0, 1, -1);
+ layout->addWidget(pb, 5, 0, 1, -1);
+ layout->addItem(
+ new QSpacerItem(20, 10, QSizePolicy::Minimum, QSizePolicy::Fixed), 2, 1,
+ 1, 1);
+
+ connect(this, SIGNAL(replyFromUpdateServer(QByteArray)), this,
+ SLOT(processReplyDataFromUpdateServer(QByteArray)));
+
+ setLayout(layout);
}
void UpdateTab::getLatestVersion() {
+ this->pb->setHidden(false);
- this->pb->setHidden(false);
-
- qDebug() << "Try to get latest version";
-
- QString baseUrl = "https://api.github.com/repos/saturneric/gpgfrontend/releases/latest";
+ qDebug() << "Try to get latest version";
- auto manager = new QNetworkAccessManager(this);
+ QString baseUrl =
+ "https://api.github.com/repos/saturneric/gpgfrontend/releases/latest";
- QNetworkRequest request;
- request.setUrl(QUrl(baseUrl));
- QNetworkReply *replay = manager->get(request);
- auto thread = QThread::create([replay, this]() {
- while(replay->isRunning()) QApplication::processEvents();
- emit replyFromUpdateServer(replay->readAll());
- });
- connect(thread, SIGNAL(finished()), thread, SLOT(deleteLater()));
- thread->start();
+ auto manager = new QNetworkAccessManager(this);
+ QNetworkRequest request;
+ request.setUrl(QUrl(baseUrl));
+ QNetworkReply* replay = manager->get(request);
+ auto thread = QThread::create([replay, this]() {
+ while (replay->isRunning())
+ QApplication::processEvents();
+ emit replyFromUpdateServer(replay->readAll());
+ });
+ connect(thread, SIGNAL(finished()), thread, SLOT(deleteLater()));
+ thread->start();
}
void UpdateTab::processReplyDataFromUpdateServer(const QByteArray& data) {
-
- qDebug() << "Try to Process Reply Data From Update Server";
-
- this->pb->setHidden(true);
-
- Document d;
- if (d.Parse(data.constData()).HasParseError() || !d.IsObject()) {
- qDebug() << "VersionCheckThread Found Network Error";
- auto latestVersion = "Unknown";
- latestVersionLabel->setText("<center><b>" + tr("Latest Version From Github: ") + latestVersion + "</b></center>");
- return;
- }
-
- QString latestVersion = d["tag_name"].GetString();
-
- qDebug() << "Latest Version From Github" << latestVersion;
-
- QRegularExpression re(R"(^[vV](\d+\.)?(\d+\.)?(\*|\d+))");
- QRegularExpressionMatch match = re.match(latestVersion);
- if (match.hasMatch()) {
- latestVersion = match.captured(0);
- qDebug() << "Latest Version Matched" << latestVersion;
- } else latestVersion = "Unknown";
-
- latestVersionLabel->setText("<center><b>" + tr("Latest Version From Github: ") + latestVersion + "</b></center>");
-
- if(latestVersion > currentVersion) upgradeLabel->setHidden(false);
+ qDebug() << "Try to Process Reply Data From Update Server";
+
+ this->pb->setHidden(true);
+
+ Document d;
+ if (d.Parse(data.constData()).HasParseError() || !d.IsObject()) {
+ qDebug() << "VersionCheckThread Found Network Error";
+ auto latestVersion = "Unknown";
+ latestVersionLabel->setText("<center><b>" +
+ tr("Latest Version From Github: ") +
+ latestVersion + "</b></center>");
+ return;
+ }
+
+ QString latestVersion = d["tag_name"].GetString();
+
+ qDebug() << "Latest Version From Github" << latestVersion;
+
+ QRegularExpression re(R"(^[vV](\d+\.)?(\d+\.)?(\*|\d+))");
+ QRegularExpressionMatch match = re.match(latestVersion);
+ if (match.hasMatch()) {
+ latestVersion = match.captured(0);
+ qDebug() << "Latest Version Matched" << latestVersion;
+ } else
+ latestVersion = "Unknown";
+
+ latestVersionLabel->setText("<center><b>" +
+ tr("Latest Version From Github: ") +
+ latestVersion + "</b></center>");
+
+ if (latestVersion > currentVersion)
+ upgradeLabel->setHidden(false);
}
+
+} // namespace GpgFrontend::UI
diff --git a/include/ui/help/AboutDialog.h b/src/ui/help/AboutDialog.h
index dee2c018..3b7d42c8 100644
--- a/include/ui/help/AboutDialog.h
+++ b/src/ui/help/AboutDialog.h
@@ -25,19 +25,19 @@
#ifndef __ABOUTDIALOG_H__
#define __ABOUTDIALOG_H__
-#include <GpgFrontend.h>
-
#include "gpg/GpgContext.h"
+#include "ui/GpgFrontendUI.h"
+namespace GpgFrontend::UI {
/**
* @brief Class containing the main tab of about dialog
*
*/
class InfoTab : public QWidget {
-Q_OBJECT
+ Q_OBJECT
-public:
- explicit InfoTab(QWidget *parent = nullptr);
+ public:
+ explicit InfoTab(QWidget* parent = nullptr);
};
/**
@@ -45,10 +45,10 @@ public:
*
*/
class TranslatorsTab : public QWidget {
-Q_OBJECT
+ Q_OBJECT
-public:
- explicit TranslatorsTab(QWidget *parent = nullptr);
+ public:
+ explicit TranslatorsTab(QWidget* parent = nullptr);
};
/**
@@ -56,28 +56,29 @@ public:
*
*/
class UpdateTab : public QWidget {
-Q_OBJECT
+ Q_OBJECT
- QLabel *currentVersionLabel;
+ QLabel* currentVersionLabel;
- QLabel *latestVersionLabel;
+ QLabel* latestVersionLabel;
- QLabel *upgradeLabel;
+ QLabel* upgradeLabel;
- QProgressBar *pb;
+ QProgressBar* pb;
- QString currentVersion;
+ QString currentVersion;
-public:
- explicit UpdateTab(QWidget *parent = nullptr);
+ public:
+ explicit UpdateTab(QWidget* parent = nullptr);
- void getLatestVersion();
+ void getLatestVersion();
-private slots:
- void processReplyDataFromUpdateServer(const QByteArray& data);;
+ private slots:
+ void processReplyDataFromUpdateServer(const QByteArray& data);
+ ;
-signals:
- void replyFromUpdateServer(QByteArray data);
+ signals:
+ void replyFromUpdateServer(QByteArray data);
};
/**
@@ -85,18 +86,18 @@ signals:
*
*/
class AboutDialog : public QDialog {
-Q_OBJECT
-
-public:
- explicit AboutDialog(int defaultIndex, QWidget *parent);
+ Q_OBJECT
+ public:
+ explicit AboutDialog(int defaultIndex, QWidget* parent);
-protected:
- void showEvent(QShowEvent *ev) override;
+ protected:
+ void showEvent(QShowEvent* ev) override;
-private:
- UpdateTab *updateTab;
+ private:
+ UpdateTab* updateTab;
};
-#endif // __ABOUTDIALOG_H__
+} // namespace GpgFrontend::UI
+#endif // __ABOUTDIALOG_H__
diff --git a/src/ui/help/VersionCheckThread.cpp b/src/ui/help/VersionCheckThread.cpp
index bf1bbeda..3204dadf 100644
--- a/src/ui/help/VersionCheckThread.cpp
+++ b/src/ui/help/VersionCheckThread.cpp
@@ -25,51 +25,52 @@
#include "ui/help/VersionCheckThread.h"
#include "GpgFrontendBuildInfo.h"
#include "rapidjson/document.h"
-#include "rapidjson/writer.h"
using namespace rapidjson;
-void VersionCheckThread::run() {
- qDebug() << "Start Version Thread to get latest version from Github";
+namespace GpgFrontend::UI {
- auto currentVersion = "v" + QString::number(VERSION_MAJOR) + "."
- + QString::number(VERSION_MINOR) + "."
- + QString::number(VERSION_PATCH);
+void VersionCheckThread::run() {
+ qDebug() << "Start Version Thread to get latest version from Github";
- while(mNetworkReply->isRunning()) {
- QApplication::processEvents();
- }
+ auto currentVersion = "v" + QString::number(VERSION_MAJOR) + "." +
+ QString::number(VERSION_MINOR) + "." +
+ QString::number(VERSION_PATCH);
- if(mNetworkReply->error() != QNetworkReply::NoError) {
- qDebug() << "VersionCheckThread Found Network Error";
- return;
- }
+ while (mNetworkReply->isRunning()) {
+ QApplication::processEvents();
+ }
- QByteArray bytes = mNetworkReply->readAll();
+ if (mNetworkReply->error() != QNetworkReply::NoError) {
+ qDebug() << "VersionCheckThread Found Network Error";
+ return;
+ }
- Document d;
- d.Parse(bytes.constData());
+ QByteArray bytes = mNetworkReply->readAll();
- QString latestVersion = d["tag_name"].GetString();
+ Document d;
+ d.Parse(bytes.constData());
- qDebug() << "Latest Version From Github" << latestVersion;
+ QString latestVersion = d["tag_name"].GetString();
- QRegularExpression re("^[vV](\\d+\\.)?(\\d+\\.)?(\\*|\\d+)");
- QRegularExpressionMatch match = re.match(latestVersion);
- if (match.hasMatch()) {
- latestVersion = match.captured(0); // matched == "23 def"
- qDebug() << "Latest Version Matched" << latestVersion;
- } else {
- latestVersion = currentVersion;
- qDebug() << "Latest Version Unknown" << latestVersion;
- }
+ qDebug() << "Latest Version From Github" << latestVersion;
- if(latestVersion != currentVersion) {
- emit upgradeVersion(currentVersion, latestVersion);
- }
+ QRegularExpression re("^[vV](\\d+\\.)?(\\d+\\.)?(\\*|\\d+)");
+ QRegularExpressionMatch match = re.match(latestVersion);
+ if (match.hasMatch()) {
+ latestVersion = match.captured(0); // matched == "23 def"
+ qDebug() << "Latest Version Matched" << latestVersion;
+ } else {
+ latestVersion = currentVersion;
+ qDebug() << "Latest Version Unknown" << latestVersion;
+ }
+ if (latestVersion != currentVersion) {
+ emit upgradeVersion(currentVersion, latestVersion);
+ }
}
-VersionCheckThread::VersionCheckThread(QNetworkReply *networkReply):mNetworkReply(networkReply) {
+VersionCheckThread::VersionCheckThread(QNetworkReply* networkReply)
+ : mNetworkReply(networkReply) {}
-}
+} // namespace GpgFrontend::UI
diff --git a/include/ui/help/VersionCheckThread.h b/src/ui/help/VersionCheckThread.h
index 7ee90077..eedbfa5b 100644
--- a/include/ui/help/VersionCheckThread.h
+++ b/src/ui/help/VersionCheckThread.h
@@ -25,28 +25,28 @@
#ifndef GPGFRONTEND_VERSIONCHECKTHREAD_H
#define GPGFRONTEND_VERSIONCHECKTHREAD_H
-#include "GpgFrontend.h"
+#include "ui/GpgFrontendUI.h"
-class VersionCheckThread : public QThread {
-Q_OBJECT
-
-public:
-
- VersionCheckThread(QNetworkReply *networkReply);
+namespace GpgFrontend::UI {
-signals:
-
- void upgradeVersion(const QString &currentVersion, const QString &latestVersion);
+class VersionCheckThread : public QThread {
+ Q_OBJECT
-protected:
+ public:
+ explicit VersionCheckThread(QNetworkReply* networkReply);
- void run() override;
+ signals:
-private:
+ void upgradeVersion(const QString& currentVersion,
+ const QString& latestVersion);
- QNetworkReply* mNetworkReply;
+ protected:
+ void run() override;
+ private:
+ QNetworkReply* mNetworkReply;
};
+} // namespace GpgFrontend::UI
-#endif //GPGFRONTEND_VERSIONCHECKTHREAD_H
+#endif // GPGFRONTEND_VERSIONCHECKTHREAD_H
diff --git a/src/ui/keygen/KeygenDialog.cpp b/src/ui/keygen/KeygenDialog.cpp
index 958f9ecc..0786d644 100644
--- a/src/ui/keygen/KeygenDialog.cpp
+++ b/src/ui/keygen/KeygenDialog.cpp
@@ -23,339 +23,340 @@
*/
#include "ui/keygen/KeygenDialog.h"
+#include "gpg/function/GpgKeyOpera.h"
#include "ui/WaitingDialog.h"
-KeyGenDialog::KeyGenDialog(GpgFrontend::GpgContext *ctx, QWidget *parent)
- : QDialog(parent), mCtx(ctx) {
+namespace GpgFrontend::UI {
- buttonBox = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel);
+KeyGenDialog::KeyGenDialog(QWidget* parent) : QDialog(parent) {
+ buttonBox =
+ new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel);
- this->setWindowTitle(tr("Generate Key"));
- this->setModal(true);
- generateKeyDialog();
+ this->setWindowTitle(tr("Generate Key"));
+ this->setModal(true);
+ generateKeyDialog();
}
void KeyGenDialog::generateKeyDialog() {
+ keyUsageGroupBox = create_key_usage_group_box();
- keyUsageGroupBox = create_key_usage_group_box();
+ auto* groupGrid = new QGridLayout(this);
+ groupGrid->addWidget(create_basic_info_group_box(), 0, 0);
+ groupGrid->addWidget(keyUsageGroupBox, 1, 0);
- auto *groupGrid = new QGridLayout(this);
- groupGrid->addWidget(create_basic_info_group_box(), 0, 0);
- groupGrid->addWidget(keyUsageGroupBox, 1, 0);
+ auto* nameList = new QWidget(this);
+ nameList->setLayout(groupGrid);
- auto *nameList = new QWidget(this);
- nameList->setLayout(groupGrid);
+ auto* vbox2 = new QVBoxLayout();
+ vbox2->addWidget(nameList);
+ vbox2->addWidget(errorLabel);
+ vbox2->addWidget(buttonBox);
- auto *vbox2 = new QVBoxLayout();
- vbox2->addWidget(nameList);
- vbox2->addWidget(errorLabel);
- vbox2->addWidget(buttonBox);
+ this->setLayout(vbox2);
- this->setLayout(vbox2);
-
- set_signal_slot();
-
- refresh_widgets_state();
+ set_signal_slot();
+ refresh_widgets_state();
}
void KeyGenDialog::slotKeyGenAccept() {
- QString errorString = "";
-
+ QString errorString = "";
+
+ /**
+ * check for errors in keygen dialog input
+ */
+ if ((nameEdit->text()).size() < 5) {
+ errorString.append(tr(" Name must contain at least five characters. \n"));
+ }
+ if (emailEdit->text().isEmpty() || !check_email_address(emailEdit->text())) {
+ errorString.append(tr(" Please give a email address. \n"));
+ }
+
+ /**
+ * primary keys should have a reasonable expiration date (no more than 2 years
+ * in the future)
+ */
+ if (dateEdit->dateTime() > QDateTime::currentDateTime().addYears(2)) {
+ errorString.append(tr(" Expiration time no more than 2 years. \n"));
+ }
+
+ if (errorString.isEmpty()) {
/**
- * check for errors in keygen dialog input
+ * create the string for key generation
*/
- if ((nameEdit->text()).size() < 5) {
- errorString.append(tr(" Name must contain at least five characters. \n"));
- } if(emailEdit->text().isEmpty() || !check_email_address(emailEdit->text())) {
- errorString.append(tr(" Please give a email address. \n"));
- }
-
- /**
- * primary keys should have a reasonable expiration date (no more than 2 years in the future)
- */
- if(dateEdit->dateTime() > QDateTime::currentDateTime().addYears(2)) {
- errorString.append(tr(" Expiration time no more than 2 years. \n"));
- }
-
- if (errorString.isEmpty()) {
- /**
- * create the string for key generation
- */
- genKeyInfo.setUserid(QString("%1 (%3) <%2>").arg(nameEdit->text(), emailEdit->text(), commentEdit->text()));
+ genKeyInfo->setUserid(
+ QString("%1 (%3) <%2>")
+ .arg(nameEdit->text(), emailEdit->text(), commentEdit->text())
+ .toStdString());
- genKeyInfo.setKeySize(keySizeSpinBox->value());
+ genKeyInfo->setKeySize(keySizeSpinBox->value());
- if (expireCheckBox->checkState()) {
- genKeyInfo.setNonExpired(true);
- } else {
- genKeyInfo.setExpired(dateEdit->dateTime());
- }
+ if (expireCheckBox->checkState()) {
+ genKeyInfo->setNonExpired(true);
+ } else {
+ genKeyInfo->setExpired(
+ boost::posix_time::from_time_t(dateEdit->dateTime().toTime_t())
+ .date());
+ }
- gpgme_error_t error = false;
- auto thread = QThread::create([&]() {
- error = mCtx->generateKey(&genKeyInfo);
- });
- thread->start();
+ gpgme_error_t error = false;
+ auto thread = QThread::create(
+ [&]() { error = GpgKeyOpera::GetInstance().GenerateKey(genKeyInfo); });
+ thread->start();
- auto *dialog = new WaitingDialog("Generating", this);
- dialog->show();
+ auto* dialog = new WaitingDialog("Generating", this);
+ dialog->show();
- while (thread->isRunning()) {
- QCoreApplication::processEvents();
- }
+ while (thread->isRunning()) {
+ QCoreApplication::processEvents();
+ }
- dialog->close();
+ dialog->close();
- if(gpgme_err_code(error) == GPG_ERR_NO_ERROR) {
- QMessageBox::information(this, tr("Success"), tr("The new key pair has been generated."));
- this->close();
- }
- else
- QMessageBox::critical(this, tr("Failure"), tr(gpgme_strerror(error)));
+ if (gpgme_err_code(error) == GPG_ERR_NO_ERROR) {
+ QMessageBox::information(this, tr("Success"),
+ tr("The new key pair has been generated."));
+ this->close();
+ } else
+ QMessageBox::critical(this, tr("Failure"), tr(gpgme_strerror(error)));
- } else {
- /**
- * create error message
- */
- errorLabel->setAutoFillBackground(true);
- QPalette error = errorLabel->palette();
- error.setColor(QPalette::Window, "#ff8080");
- errorLabel->setPalette(error);
- errorLabel->setText(errorString);
-
- this->show();
- }
+ } else {
+ /**
+ * create error message
+ */
+ errorLabel->setAutoFillBackground(true);
+ QPalette error = errorLabel->palette();
+ error.setColor(QPalette::Window, "#ff8080");
+ errorLabel->setPalette(error);
+ errorLabel->setText(errorString);
+
+ this->show();
+ }
}
void KeyGenDialog::slotExpireBoxChanged() {
- if (expireCheckBox->checkState()) {
- dateEdit->setEnabled(false);
- } else {
- dateEdit->setEnabled(true);
- }
+ if (expireCheckBox->checkState()) {
+ dateEdit->setEnabled(false);
+ } else {
+ dateEdit->setEnabled(true);
+ }
}
-QGroupBox *KeyGenDialog::create_key_usage_group_box() {
+QGroupBox* KeyGenDialog::create_key_usage_group_box() {
+ auto* groupBox = new QGroupBox(this);
+ auto* grid = new QGridLayout(this);
- auto *groupBox = new QGroupBox(this);
- auto *grid = new QGridLayout(this);
+ groupBox->setTitle(tr("Key Usage"));
- groupBox->setTitle(tr("Key Usage"));
+ auto* encrypt = new QCheckBox(tr("Encryption"), groupBox);
+ encrypt->setTristate(false);
- auto* encrypt = new QCheckBox(tr("Encryption"), groupBox);
- encrypt->setTristate(false);
+ auto* sign = new QCheckBox(tr("Signing"), groupBox);
+ sign->setTristate(false);
- auto* sign = new QCheckBox(tr("Signing"),groupBox);
- sign->setTristate(false);
+ auto* cert = new QCheckBox(tr("Certification"), groupBox);
+ cert->setTristate(false);
- auto* cert = new QCheckBox(tr("Certification"),groupBox);
- cert->setTristate(false);
+ auto* auth = new QCheckBox(tr("Authentication"), groupBox);
+ auth->setTristate(false);
- auto* auth = new QCheckBox(tr("Authentication"), groupBox);
- auth->setTristate(false);
+ keyUsageCheckBoxes.push_back(encrypt);
+ keyUsageCheckBoxes.push_back(sign);
+ keyUsageCheckBoxes.push_back(cert);
+ keyUsageCheckBoxes.push_back(auth);
- keyUsageCheckBoxes.push_back(encrypt);
- keyUsageCheckBoxes.push_back(sign);
- keyUsageCheckBoxes.push_back(cert);
- keyUsageCheckBoxes.push_back(auth);
+ grid->addWidget(encrypt, 0, 0);
+ grid->addWidget(sign, 0, 1);
+ grid->addWidget(cert, 1, 0);
+ grid->addWidget(auth, 1, 1);
- grid->addWidget(encrypt, 0, 0);
- grid->addWidget(sign, 0, 1);
- grid->addWidget(cert, 1, 0);
- grid->addWidget(auth, 1, 1);
+ groupBox->setLayout(grid);
- groupBox->setLayout(grid);
-
- return groupBox;
+ return groupBox;
}
void KeyGenDialog::slotEncryptionBoxChanged(int state) {
- if(state == 0) {
- genKeyInfo.setAllowEncryption(false);
- } else {
- genKeyInfo.setAllowEncryption(true);
- }
+ if (state == 0) {
+ genKeyInfo->setAllowEncryption(false);
+ } else {
+ genKeyInfo->setAllowEncryption(true);
+ }
}
void KeyGenDialog::slotSigningBoxChanged(int state) {
- if(state == 0) {
- genKeyInfo.setAllowSigning(false);
- } else {
- genKeyInfo.setAllowSigning(true);
- }
+ if (state == 0) {
+ genKeyInfo->setAllowSigning(false);
+ } else {
+ genKeyInfo->setAllowSigning(true);
+ }
}
void KeyGenDialog::slotCertificationBoxChanged(int state) {
- if(state == 0) {
- genKeyInfo.setAllowCertification(false);
- } else {
- genKeyInfo.setAllowCertification(true);
- }
+ if (state == 0) {
+ genKeyInfo->setAllowCertification(false);
+ } else {
+ genKeyInfo->setAllowCertification(true);
+ }
}
void KeyGenDialog::slotAuthenticationBoxChanged(int state) {
- if(state == 0) {
- genKeyInfo.setAllowAuthentication(false);
- } else {
- genKeyInfo.setAllowAuthentication(true);
- }
+ if (state == 0) {
+ genKeyInfo->setAllowAuthentication(false);
+ } else {
+ genKeyInfo->setAllowAuthentication(true);
+ }
}
void KeyGenDialog::slotActivatedKeyType(int index) {
+ qDebug() << "key type index changed " << index;
- qDebug() << "key type index changed " << index;
-
- genKeyInfo.setAlgo(this->keyTypeComboBox->itemText(index));
- refresh_widgets_state();
+ genKeyInfo->setAlgo(this->keyTypeComboBox->itemText(index).toStdString());
+ refresh_widgets_state();
}
void KeyGenDialog::refresh_widgets_state() {
-
- qDebug() << "refresh_widgets_state called";
-
- if(genKeyInfo.isAllowEncryption())
- keyUsageCheckBoxes[0]->setCheckState(Qt::CheckState::Checked);
- else
- keyUsageCheckBoxes[0]->setCheckState(Qt::CheckState::Unchecked);
-
- if(genKeyInfo.isAllowChangeEncryption())
- keyUsageCheckBoxes[0]->setDisabled(false);
- else
- keyUsageCheckBoxes[0]->setDisabled(true);
-
-
- if(genKeyInfo.isAllowSigning())
- keyUsageCheckBoxes[1]->setCheckState(Qt::CheckState::Checked);
- else
- keyUsageCheckBoxes[1]->setCheckState(Qt::CheckState::Unchecked);
-
- if(genKeyInfo.isAllowChangeSigning())
- keyUsageCheckBoxes[1]->setDisabled(false);
- else
- keyUsageCheckBoxes[1]->setDisabled(true);
-
-
- if(genKeyInfo.isAllowCertification())
- keyUsageCheckBoxes[2]->setCheckState(Qt::CheckState::Checked);
- else
- keyUsageCheckBoxes[2]->setCheckState(Qt::CheckState::Unchecked);
-
- if(genKeyInfo.isAllowChangeCertification())
- keyUsageCheckBoxes[2]->setDisabled(false);
- else
- keyUsageCheckBoxes[2]->setDisabled(true);
-
-
- if(genKeyInfo.isAllowAuthentication())
- keyUsageCheckBoxes[3]->setCheckState(Qt::CheckState::Checked);
- else
- keyUsageCheckBoxes[3]->setCheckState(Qt::CheckState::Unchecked);
-
- if(genKeyInfo.isAllowChangeAuthentication())
- keyUsageCheckBoxes[3]->setDisabled(false);
- else
- keyUsageCheckBoxes[3]->setDisabled(true);
-
-
-
- if(genKeyInfo.isAllowNoPassPhrase())
- noPassPhraseCheckBox->setDisabled(false);
- else
- noPassPhraseCheckBox->setDisabled(true);
-
-
- keySizeSpinBox->setRange(genKeyInfo.getSuggestMinKeySize(), genKeyInfo.getSuggestMaxKeySize());
- keySizeSpinBox->setValue(genKeyInfo.getKeySize());
- keySizeSpinBox->setSingleStep(genKeyInfo.getSizeChangeStep());
-
-
+ qDebug() << "refresh_widgets_state called";
+
+ if (genKeyInfo->isAllowEncryption())
+ keyUsageCheckBoxes[0]->setCheckState(Qt::CheckState::Checked);
+ else
+ keyUsageCheckBoxes[0]->setCheckState(Qt::CheckState::Unchecked);
+
+ if (genKeyInfo->isAllowChangeEncryption())
+ keyUsageCheckBoxes[0]->setDisabled(false);
+ else
+ keyUsageCheckBoxes[0]->setDisabled(true);
+
+ if (genKeyInfo->isAllowSigning())
+ keyUsageCheckBoxes[1]->setCheckState(Qt::CheckState::Checked);
+ else
+ keyUsageCheckBoxes[1]->setCheckState(Qt::CheckState::Unchecked);
+
+ if (genKeyInfo->isAllowChangeSigning())
+ keyUsageCheckBoxes[1]->setDisabled(false);
+ else
+ keyUsageCheckBoxes[1]->setDisabled(true);
+
+ if (genKeyInfo->isAllowCertification())
+ keyUsageCheckBoxes[2]->setCheckState(Qt::CheckState::Checked);
+ else
+ keyUsageCheckBoxes[2]->setCheckState(Qt::CheckState::Unchecked);
+
+ if (genKeyInfo->isAllowChangeCertification())
+ keyUsageCheckBoxes[2]->setDisabled(false);
+ else
+ keyUsageCheckBoxes[2]->setDisabled(true);
+
+ if (genKeyInfo->isAllowAuthentication())
+ keyUsageCheckBoxes[3]->setCheckState(Qt::CheckState::Checked);
+ else
+ keyUsageCheckBoxes[3]->setCheckState(Qt::CheckState::Unchecked);
+
+ if (genKeyInfo->isAllowChangeAuthentication())
+ keyUsageCheckBoxes[3]->setDisabled(false);
+ else
+ keyUsageCheckBoxes[3]->setDisabled(true);
+
+ if (genKeyInfo->isAllowNoPassPhrase())
+ noPassPhraseCheckBox->setDisabled(false);
+ else
+ noPassPhraseCheckBox->setDisabled(true);
+
+ keySizeSpinBox->setRange(genKeyInfo->getSuggestMinKeySize(),
+ genKeyInfo->getSuggestMaxKeySize());
+ keySizeSpinBox->setValue(genKeyInfo->getKeySize());
+ keySizeSpinBox->setSingleStep(genKeyInfo->getSizeChangeStep());
}
void KeyGenDialog::set_signal_slot() {
-
- connect(buttonBox, SIGNAL(accepted()), this, SLOT(slotKeyGenAccept()));
- connect(buttonBox, SIGNAL(rejected()), this, SLOT(reject()));
-
- connect(expireCheckBox, SIGNAL(stateChanged(int)), this, SLOT(slotExpireBoxChanged()));
-
- connect(keyUsageCheckBoxes[0], SIGNAL(stateChanged(int)), this, SLOT(slotEncryptionBoxChanged(int)));
- connect(keyUsageCheckBoxes[1], SIGNAL(stateChanged(int)), this, SLOT(slotSigningBoxChanged(int)));
- connect(keyUsageCheckBoxes[2], SIGNAL(stateChanged(int)), this, SLOT(slotCertificationBoxChanged(int)));
- connect(keyUsageCheckBoxes[3], SIGNAL(stateChanged(int)), this, SLOT(slotAuthenticationBoxChanged(int)));
-
- connect(keyTypeComboBox, SIGNAL(currentIndexChanged(int)), this, SLOT(slotActivatedKeyType(int)));
-
- connect(noPassPhraseCheckBox, &QCheckBox::stateChanged, this, [this](int state) -> void {
- if(state == 0) {
- genKeyInfo.setNonPassPhrase(false);
- } else {
- genKeyInfo.setNonPassPhrase(true);
- }
-
- });
-
+ connect(buttonBox, SIGNAL(accepted()), this, SLOT(slotKeyGenAccept()));
+ connect(buttonBox, SIGNAL(rejected()), this, SLOT(reject()));
+
+ connect(expireCheckBox, SIGNAL(stateChanged(int)), this,
+ SLOT(slotExpireBoxChanged()));
+
+ connect(keyUsageCheckBoxes[0], SIGNAL(stateChanged(int)), this,
+ SLOT(slotEncryptionBoxChanged(int)));
+ connect(keyUsageCheckBoxes[1], SIGNAL(stateChanged(int)), this,
+ SLOT(slotSigningBoxChanged(int)));
+ connect(keyUsageCheckBoxes[2], SIGNAL(stateChanged(int)), this,
+ SLOT(slotCertificationBoxChanged(int)));
+ connect(keyUsageCheckBoxes[3], SIGNAL(stateChanged(int)), this,
+ SLOT(slotAuthenticationBoxChanged(int)));
+
+ connect(keyTypeComboBox, SIGNAL(currentIndexChanged(int)), this,
+ SLOT(slotActivatedKeyType(int)));
+
+ connect(noPassPhraseCheckBox, &QCheckBox::stateChanged, this,
+ [this](int state) -> void {
+ if (state == 0) {
+ genKeyInfo->setNonPassPhrase(false);
+ } else {
+ genKeyInfo->setNonPassPhrase(true);
+ }
+ });
}
-bool KeyGenDialog::check_email_address(const QString &str) {
- return re_email.match(str).hasMatch();
+bool KeyGenDialog::check_email_address(const QString& str) {
+ return re_email.match(str).hasMatch();
}
-QGroupBox *KeyGenDialog::create_basic_info_group_box() {
-
- errorLabel = new QLabel(tr(""));
- nameEdit = new QLineEdit(this);
- emailEdit = new QLineEdit(this);
- commentEdit = new QLineEdit(this);
- keySizeSpinBox = new QSpinBox(this);
- keyTypeComboBox = new QComboBox(this);
-
- for(auto &algo : GenKeyInfo::SupportedKeyAlgo) {
- keyTypeComboBox->addItem(algo);
- }
- if(!GenKeyInfo::SupportedKeyAlgo.isEmpty()) {
- keyTypeComboBox->setCurrentIndex(0);
- }
-
- QDateTime maxDateTime = QDateTime::currentDateTime().addYears(2);
-
- dateEdit = new QDateTimeEdit(maxDateTime, this);
- dateEdit->setMinimumDateTime(QDateTime::currentDateTime());
- dateEdit->setMaximumDateTime(maxDateTime);
- dateEdit->setDisplayFormat("dd/MM/yyyy hh:mm:ss");
- dateEdit->setCalendarPopup(true);
- dateEdit->setEnabled(true);
-
- expireCheckBox = new QCheckBox(this);
- expireCheckBox->setCheckState(Qt::Unchecked);
-
- noPassPhraseCheckBox = new QCheckBox(this);
- noPassPhraseCheckBox->setCheckState(Qt::Unchecked);
-
- auto *vbox1 = new QGridLayout;
-
- vbox1->addWidget(new QLabel(tr("Name:")), 0, 0);
- vbox1->addWidget(new QLabel(tr("Email Address:")), 1, 0);
- vbox1->addWidget(new QLabel(tr("Comment:")), 2, 0);
- vbox1->addWidget(new QLabel(tr("Expiration Date:")), 3, 0);
- vbox1->addWidget(new QLabel(tr("Never Expire")), 3, 3);
- vbox1->addWidget(new QLabel(tr("KeySize (in Bit):")), 4, 0);
- vbox1->addWidget(new QLabel(tr("Key Type:")), 5, 0);
- vbox1->addWidget(new QLabel(tr("Non Pass Phrase")), 6, 0);
-
- vbox1->addWidget(nameEdit, 0, 1, 1, 3);
- vbox1->addWidget(emailEdit, 1, 1, 1, 3);
- vbox1->addWidget(commentEdit, 2, 1, 1, 3);
- vbox1->addWidget(dateEdit, 3, 1);
- vbox1->addWidget(expireCheckBox, 3, 2);
- vbox1->addWidget(keySizeSpinBox, 4, 1);
- vbox1->addWidget(keyTypeComboBox, 5, 1);
- vbox1->addWidget(noPassPhraseCheckBox, 6, 1);
-
- auto basicInfoGroupBox = new QGroupBox();
- basicInfoGroupBox->setLayout(vbox1);
- basicInfoGroupBox->setTitle(tr("Basic Information"));
-
- return basicInfoGroupBox;
+QGroupBox* KeyGenDialog::create_basic_info_group_box() {
+ errorLabel = new QLabel(tr(""));
+ nameEdit = new QLineEdit(this);
+ emailEdit = new QLineEdit(this);
+ commentEdit = new QLineEdit(this);
+ keySizeSpinBox = new QSpinBox(this);
+ keyTypeComboBox = new QComboBox(this);
+
+ for (auto& algo : GenKeyInfo::SupportedKeyAlgo) {
+ keyTypeComboBox->addItem(QString::fromStdString(algo));
+ }
+ if (!GenKeyInfo::SupportedKeyAlgo.empty()) {
+ keyTypeComboBox->setCurrentIndex(0);
+ }
+
+ QDateTime maxDateTime = QDateTime::currentDateTime().addYears(2);
+
+ dateEdit = new QDateTimeEdit(maxDateTime, this);
+ dateEdit->setMinimumDateTime(QDateTime::currentDateTime());
+ dateEdit->setMaximumDateTime(maxDateTime);
+ dateEdit->setDisplayFormat("dd/MM/yyyy hh:mm:ss");
+ dateEdit->setCalendarPopup(true);
+ dateEdit->setEnabled(true);
+
+ expireCheckBox = new QCheckBox(this);
+ expireCheckBox->setCheckState(Qt::Unchecked);
+
+ noPassPhraseCheckBox = new QCheckBox(this);
+ noPassPhraseCheckBox->setCheckState(Qt::Unchecked);
+
+ auto* vbox1 = new QGridLayout;
+
+ vbox1->addWidget(new QLabel(tr("Name:")), 0, 0);
+ vbox1->addWidget(new QLabel(tr("Email Address:")), 1, 0);
+ vbox1->addWidget(new QLabel(tr("Comment:")), 2, 0);
+ vbox1->addWidget(new QLabel(tr("Expiration Date:")), 3, 0);
+ vbox1->addWidget(new QLabel(tr("Never Expire")), 3, 3);
+ vbox1->addWidget(new QLabel(tr("KeySize (in Bit):")), 4, 0);
+ vbox1->addWidget(new QLabel(tr("Key Type:")), 5, 0);
+ vbox1->addWidget(new QLabel(tr("Non Pass Phrase")), 6, 0);
+
+ vbox1->addWidget(nameEdit, 0, 1, 1, 3);
+ vbox1->addWidget(emailEdit, 1, 1, 1, 3);
+ vbox1->addWidget(commentEdit, 2, 1, 1, 3);
+ vbox1->addWidget(dateEdit, 3, 1);
+ vbox1->addWidget(expireCheckBox, 3, 2);
+ vbox1->addWidget(keySizeSpinBox, 4, 1);
+ vbox1->addWidget(keyTypeComboBox, 5, 1);
+ vbox1->addWidget(noPassPhraseCheckBox, 6, 1);
+
+ auto basicInfoGroupBox = new QGroupBox();
+ basicInfoGroupBox->setLayout(vbox1);
+ basicInfoGroupBox->setTitle(tr("Basic Information"));
+
+ return basicInfoGroupBox;
}
+
+} // namespace GpgFrontend::UI
diff --git a/src/ui/keygen/KeygenDialog.h b/src/ui/keygen/KeygenDialog.h
new file mode 100644
index 00000000..97846eb5
--- /dev/null
+++ b/src/ui/keygen/KeygenDialog.h
@@ -0,0 +1,114 @@
+/**
+ * This file is part of GPGFrontend.
+ *
+ * GPGFrontend is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Foobar is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Foobar. If not, see <https://www.gnu.org/licenses/>.
+ *
+ * The initial version of the source code is inherited from gpg4usb-team.
+ * Their source code version also complies with GNU General Public License.
+ *
+ * The source code version of this software was modified and released
+ * by Saturneric<[email protected]><[email protected]> starting on May 12, 2021.
+ *
+ */
+
+#ifndef __KEYGENDIALOG_H__
+#define __KEYGENDIALOG_H__
+
+#include "gpg/GpgContext.h"
+#include "gpg/GpgGenKeyInfo.h"
+#include "ui/GpgFrontendUI.h"
+
+namespace GpgFrontend::UI {
+
+class KeyGenDialog : public QDialog {
+ Q_OBJECT
+
+ public:
+ /**
+ * @details Constructor of this class
+ *
+ * @param ctx The current GpgME context
+ * @param key The key to show details of
+ * @param parent The parent of this widget
+ */
+ explicit KeyGenDialog(QWidget* parent = nullptr);
+
+ private:
+ QGroupBox* create_key_usage_group_box();
+
+ QGroupBox* create_basic_info_group_box();
+
+ QRegularExpression re_email{
+ R"((?:[a-z0-9!#$%&'*+/=?^_`{|}~-]+(?:\.[a-z0-9!#$%&'*+/=?^_`{|}~-]+)*|"(?:[\x01-\x08\x0b\x0c\x0e-\x1f\x21\x23-\x5b\x5d-\x7f]|\\[\x01-\x09\x0b\x0c\x0e-\x7f])*")@(?:(?:[a-z0-9](?:[a-z0-9-]*[a-z0-9])?\.)+[a-z0-9](?:[a-z0-9-]*[a-z0-9])?|\[(?:(?:(2(5[0-5]|[0-4][0-9])|1[0-9][0-9]|[1-9]?[0-9]))\.){3}(?:(2(5[0-5]|[0-4][0-9])|1[0-9][0-9]|[1-9]?[0-9])|[a-z0-9-]*[a-z0-9]:(?:[\x01-\x08\x0b\x0c\x0e-\x1f\x21-\x5a\x53-\x7f]|\\[\x01-\x09\x0b\x0c\x0e-\x7f])+)\]))"};
+
+ QStringList errorMessages; /** List of errors occuring when checking entries
+ of lineedits */
+ std::unique_ptr<GenKeyInfo> genKeyInfo = std::make_unique<GenKeyInfo>();
+
+ QDialogButtonBox* buttonBox; /** Box for standard buttons */
+ QLabel* errorLabel{}; /** Label containing error message */
+ QLineEdit* nameEdit{}; /** Line edit for the keys name */
+ QLineEdit* emailEdit{}; /** Line edit for the keys email */
+ QLineEdit* commentEdit{}; /** Line edit for the keys comment */
+ QSpinBox* keySizeSpinBox{}; /** Spinbox for the keys size (in bit) */
+ QComboBox* keyTypeComboBox{}; /** Combobox for Key type */
+ QDateTimeEdit* dateEdit{}; /** Date edit for expiration date */
+ QCheckBox* expireCheckBox{}; /** Checkbox, if key should expire */
+ QCheckBox* noPassPhraseCheckBox{};
+
+ QGroupBox* keyUsageGroupBox{}; /** Group of Widgets detecting the usage of the
+ Key **/
+
+ // ENCR, SIGN, CERT, AUTH
+ std::vector<QCheckBox*> keyUsageCheckBoxes;
+
+ void generateKeyDialog();
+
+ /**
+ * @details Refresh widgets state by GenKeyInfo
+ */
+ void refresh_widgets_state();
+
+ void set_signal_slot();
+
+ bool check_email_address(const QString& str);
+
+ private slots:
+
+ /**
+ * @details when expirebox was checked/unchecked, enable/disable the
+ * expiration date box
+ */
+ void slotExpireBoxChanged();
+
+ /**
+ * @details check all lineedits for false entries. Show error, when there is
+ * one, otherwise generate the key
+ */
+ void slotKeyGenAccept();
+
+ void slotEncryptionBoxChanged(int state);
+
+ void slotSigningBoxChanged(int state);
+
+ void slotCertificationBoxChanged(int state);
+
+ void slotAuthenticationBoxChanged(int state);
+
+ void slotActivatedKeyType(int index);
+};
+
+} // namespace GpgFrontend::UI
+
+#endif // __KEYGENDIALOG_H__
diff --git a/src/ui/keygen/SubkeyGenerateDialog.cpp b/src/ui/keygen/SubkeyGenerateDialog.cpp
index 8e5d01a3..1da37393 100644
--- a/src/ui/keygen/SubkeyGenerateDialog.cpp
+++ b/src/ui/keygen/SubkeyGenerateDialog.cpp
@@ -23,277 +23,288 @@
*/
#include "ui/keygen/SubkeyGenerateDialog.h"
+
+#include "gpg/function/GpgKeyGetter.h"
+#include "gpg/function/GpgKeyOpera.h"
#include "ui/WaitingDialog.h"
-SubkeyGenerateDialog::SubkeyGenerateDialog(GpgFrontend::GpgContext *ctx, const GpgKey &key, QWidget *parent)
- : genKeyInfo(true), mCtx(ctx), mKey(key), QDialog(parent) {
+namespace GpgFrontend::UI {
- buttonBox = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel);
+SubkeyGenerateDialog::SubkeyGenerateDialog(const KeyId& key_id, QWidget* parent)
+ : QDialog(parent), mKey(GpgKeyGetter::GetInstance().GetKey(key_id)) {
+ buttonBox =
+ new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel);
- keyUsageGroupBox = create_key_usage_group_box();
+ keyUsageGroupBox = create_key_usage_group_box();
- auto *groupGrid = new QGridLayout(this);
- groupGrid->addWidget(create_basic_info_group_box(), 0, 0);
- groupGrid->addWidget(keyUsageGroupBox, 1, 0);
+ auto* groupGrid = new QGridLayout(this);
+ groupGrid->addWidget(create_basic_info_group_box(), 0, 0);
+ groupGrid->addWidget(keyUsageGroupBox, 1, 0);
- auto *nameList = new QWidget(this);
- nameList->setLayout(groupGrid);
+ auto* nameList = new QWidget(this);
+ nameList->setLayout(groupGrid);
- auto *vbox2 = new QVBoxLayout();
- vbox2->addWidget(nameList);
- vbox2->addWidget(errorLabel);
- vbox2->addWidget(buttonBox);
+ auto* vbox2 = new QVBoxLayout();
+ vbox2->addWidget(nameList);
+ vbox2->addWidget(errorLabel);
+ vbox2->addWidget(buttonBox);
- this->setWindowTitle(tr("Generate New Subkey"));
+ this->setWindowTitle(tr("Generate New Subkey"));
- this->setLayout(vbox2);
- this->setModal(true);
+ this->setLayout(vbox2);
+ this->setModal(true);
- set_signal_slot();
- refresh_widgets_state();
+ set_signal_slot();
+ refresh_widgets_state();
}
-QGroupBox *SubkeyGenerateDialog::create_key_usage_group_box() {
- auto *groupBox = new QGroupBox(this);
- auto *grid = new QGridLayout(this);
+QGroupBox* SubkeyGenerateDialog::create_key_usage_group_box() {
+ auto* groupBox = new QGroupBox(this);
+ auto* grid = new QGridLayout(this);
- groupBox->setTitle("Key Usage");
+ groupBox->setTitle("Key Usage");
- auto* encrypt = new QCheckBox(tr("Encryption"), groupBox);
- encrypt->setTristate(false);
+ auto* encrypt = new QCheckBox(tr("Encryption"), groupBox);
+ encrypt->setTristate(false);
- auto* sign = new QCheckBox(tr("Signing"),groupBox);
- sign->setTristate(false);
+ auto* sign = new QCheckBox(tr("Signing"), groupBox);
+ sign->setTristate(false);
- auto* cert = new QCheckBox(tr("Certification"),groupBox);
- cert->setTristate(false);
+ auto* cert = new QCheckBox(tr("Certification"), groupBox);
+ cert->setTristate(false);
- auto* auth = new QCheckBox(tr("Authentication"), groupBox);
- auth->setTristate(false);
+ auto* auth = new QCheckBox(tr("Authentication"), groupBox);
+ auth->setTristate(false);
- keyUsageCheckBoxes.push_back(encrypt);
- keyUsageCheckBoxes.push_back(sign);
- keyUsageCheckBoxes.push_back(cert);
- keyUsageCheckBoxes.push_back(auth);
+ keyUsageCheckBoxes.push_back(encrypt);
+ keyUsageCheckBoxes.push_back(sign);
+ keyUsageCheckBoxes.push_back(cert);
+ keyUsageCheckBoxes.push_back(auth);
- grid->addWidget(encrypt, 0, 0);
- grid->addWidget(sign, 0, 1);
- grid->addWidget(cert, 1, 0);
- grid->addWidget(auth, 1, 1);
+ grid->addWidget(encrypt, 0, 0);
+ grid->addWidget(sign, 0, 1);
+ grid->addWidget(cert, 1, 0);
+ grid->addWidget(auth, 1, 1);
- groupBox->setLayout(grid);
+ groupBox->setLayout(grid);
- return groupBox;
+ return groupBox;
}
-QGroupBox *SubkeyGenerateDialog::create_basic_info_group_box() {
- errorLabel = new QLabel(tr(""));
- keySizeSpinBox = new QSpinBox(this);
- keyTypeComboBox = new QComboBox(this);
+QGroupBox* SubkeyGenerateDialog::create_basic_info_group_box() {
+ errorLabel = new QLabel(tr(""));
+ keySizeSpinBox = new QSpinBox(this);
+ keyTypeComboBox = new QComboBox(this);
- for(auto &algo : GenKeyInfo::SupportedSubkeyAlgo) {
- keyTypeComboBox->addItem(algo);
- }
- if(!GenKeyInfo::SupportedKeyAlgo.isEmpty()) {
- keyTypeComboBox->setCurrentIndex(0);
- }
+ for (auto& algo : GenKeyInfo::SupportedSubkeyAlgo) {
+ keyTypeComboBox->addItem(QString::fromStdString(algo));
+ }
+ if (!GenKeyInfo::SupportedKeyAlgo.empty()) {
+ keyTypeComboBox->setCurrentIndex(0);
+ }
- QDateTime maxDateTime = QDateTime::currentDateTime().addYears(2);
+ QDateTime maxDateTime = QDateTime::currentDateTime().addYears(2);
- dateEdit = new QDateTimeEdit(maxDateTime, this);
- dateEdit->setMinimumDateTime(QDateTime::currentDateTime());
- dateEdit->setMaximumDateTime(maxDateTime);
- dateEdit->setDisplayFormat("dd/MM/yyyy hh:mm:ss");
- dateEdit->setCalendarPopup(true);
- dateEdit->setEnabled(true);
+ dateEdit = new QDateTimeEdit(maxDateTime, this);
+ dateEdit->setMinimumDateTime(QDateTime::currentDateTime());
+ dateEdit->setMaximumDateTime(maxDateTime);
+ dateEdit->setDisplayFormat("dd/MM/yyyy hh:mm:ss");
+ dateEdit->setCalendarPopup(true);
+ dateEdit->setEnabled(true);
- expireCheckBox = new QCheckBox(this);
- expireCheckBox->setCheckState(Qt::Unchecked);
+ expireCheckBox = new QCheckBox(this);
+ expireCheckBox->setCheckState(Qt::Unchecked);
- auto *vbox1 = new QGridLayout;
+ auto* vbox1 = new QGridLayout;
- vbox1->addWidget(new QLabel(tr("Expiration Date:")), 2, 0);
- vbox1->addWidget(new QLabel(tr("Never Expire")), 2, 3);
- vbox1->addWidget(new QLabel(tr("KeySize (in Bit):")), 1, 0);
- vbox1->addWidget(new QLabel(tr("Key Type:")), 0, 0);
+ vbox1->addWidget(new QLabel(tr("Expiration Date:")), 2, 0);
+ vbox1->addWidget(new QLabel(tr("Never Expire")), 2, 3);
+ vbox1->addWidget(new QLabel(tr("KeySize (in Bit):")), 1, 0);
+ vbox1->addWidget(new QLabel(tr("Key Type:")), 0, 0);
- vbox1->addWidget(dateEdit, 2, 1);
- vbox1->addWidget(expireCheckBox, 2, 2);
- vbox1->addWidget(keySizeSpinBox, 1, 1);
- vbox1->addWidget(keyTypeComboBox, 0, 1);
+ vbox1->addWidget(dateEdit, 2, 1);
+ vbox1->addWidget(expireCheckBox, 2, 2);
+ vbox1->addWidget(keySizeSpinBox, 1, 1);
+ vbox1->addWidget(keyTypeComboBox, 0, 1);
- auto basicInfoGroupBox = new QGroupBox();
- basicInfoGroupBox->setLayout(vbox1);
- basicInfoGroupBox->setTitle(tr("Basic Information"));
+ auto basicInfoGroupBox = new QGroupBox();
+ basicInfoGroupBox->setLayout(vbox1);
+ basicInfoGroupBox->setTitle(tr("Basic Information"));
- return basicInfoGroupBox;
+ return basicInfoGroupBox;
}
void SubkeyGenerateDialog::set_signal_slot() {
- connect(buttonBox, SIGNAL(accepted()), this, SLOT(slotKeyGenAccept()));
- connect(buttonBox, SIGNAL(rejected()), this, SLOT(reject()));
-
- connect(expireCheckBox, SIGNAL(stateChanged(int)), this, SLOT(slotExpireBoxChanged()));
-
- connect(keyUsageCheckBoxes[0], SIGNAL(stateChanged(int)), this, SLOT(slotEncryptionBoxChanged(int)));
- connect(keyUsageCheckBoxes[1], SIGNAL(stateChanged(int)), this, SLOT(slotSigningBoxChanged(int)));
- connect(keyUsageCheckBoxes[2], SIGNAL(stateChanged(int)), this, SLOT(slotCertificationBoxChanged(int)));
- connect(keyUsageCheckBoxes[3], SIGNAL(stateChanged(int)), this, SLOT(slotAuthenticationBoxChanged(int)));
-
- connect(keyTypeComboBox, SIGNAL(currentIndexChanged(int)), this, SLOT(slotActivatedKeyType(int)));
+ connect(buttonBox, SIGNAL(accepted()), this, SLOT(slotKeyGenAccept()));
+ connect(buttonBox, SIGNAL(rejected()), this, SLOT(reject()));
+
+ connect(expireCheckBox, SIGNAL(stateChanged(int)), this,
+ SLOT(slotExpireBoxChanged()));
+
+ connect(keyUsageCheckBoxes[0], SIGNAL(stateChanged(int)), this,
+ SLOT(slotEncryptionBoxChanged(int)));
+ connect(keyUsageCheckBoxes[1], SIGNAL(stateChanged(int)), this,
+ SLOT(slotSigningBoxChanged(int)));
+ connect(keyUsageCheckBoxes[2], SIGNAL(stateChanged(int)), this,
+ SLOT(slotCertificationBoxChanged(int)));
+ connect(keyUsageCheckBoxes[3], SIGNAL(stateChanged(int)), this,
+ SLOT(slotAuthenticationBoxChanged(int)));
+
+ connect(keyTypeComboBox, SIGNAL(currentIndexChanged(int)), this,
+ SLOT(slotActivatedKeyType(int)));
}
void SubkeyGenerateDialog::slotExpireBoxChanged() {
- if (expireCheckBox->checkState()) {
- dateEdit->setEnabled(false);
- } else {
- dateEdit->setEnabled(true);
- }
+ if (expireCheckBox->checkState()) {
+ dateEdit->setEnabled(false);
+ } else {
+ dateEdit->setEnabled(true);
+ }
}
void SubkeyGenerateDialog::refresh_widgets_state() {
- qDebug() << "refresh_widgets_state called";
-
- if(genKeyInfo.isAllowEncryption())
- keyUsageCheckBoxes[0]->setCheckState(Qt::CheckState::Checked);
- else
- keyUsageCheckBoxes[0]->setCheckState(Qt::CheckState::Unchecked);
-
- if(genKeyInfo.isAllowChangeEncryption())
- keyUsageCheckBoxes[0]->setDisabled(false);
- else
- keyUsageCheckBoxes[0]->setDisabled(true);
-
-
- if(genKeyInfo.isAllowSigning())
- keyUsageCheckBoxes[1]->setCheckState(Qt::CheckState::Checked);
- else
- keyUsageCheckBoxes[1]->setCheckState(Qt::CheckState::Unchecked);
-
- if(genKeyInfo.isAllowChangeSigning())
- keyUsageCheckBoxes[1]->setDisabled(false);
- else
- keyUsageCheckBoxes[1]->setDisabled(true);
-
-
- if(genKeyInfo.isAllowCertification())
- keyUsageCheckBoxes[2]->setCheckState(Qt::CheckState::Checked);
- else
- keyUsageCheckBoxes[2]->setCheckState(Qt::CheckState::Unchecked);
-
- if(genKeyInfo.isAllowChangeCertification())
- keyUsageCheckBoxes[2]->setDisabled(false);
- else
- keyUsageCheckBoxes[2]->setDisabled(true);
-
-
- if(genKeyInfo.isAllowAuthentication())
- keyUsageCheckBoxes[3]->setCheckState(Qt::CheckState::Checked);
- else
- keyUsageCheckBoxes[3]->setCheckState(Qt::CheckState::Unchecked);
-
- if(genKeyInfo.isAllowChangeAuthentication())
- keyUsageCheckBoxes[3]->setDisabled(false);
- else
- keyUsageCheckBoxes[3]->setDisabled(true);
-
-
- keySizeSpinBox->setRange(genKeyInfo.getSuggestMinKeySize(), genKeyInfo.getSuggestMaxKeySize());
- keySizeSpinBox->setValue(genKeyInfo.getKeySize());
- keySizeSpinBox->setSingleStep(genKeyInfo.getSizeChangeStep());
-
+ qDebug() << "refresh_widgets_state called";
+
+ if (genKeyInfo->isAllowEncryption())
+ keyUsageCheckBoxes[0]->setCheckState(Qt::CheckState::Checked);
+ else
+ keyUsageCheckBoxes[0]->setCheckState(Qt::CheckState::Unchecked);
+
+ if (genKeyInfo->isAllowChangeEncryption())
+ keyUsageCheckBoxes[0]->setDisabled(false);
+ else
+ keyUsageCheckBoxes[0]->setDisabled(true);
+
+ if (genKeyInfo->isAllowSigning())
+ keyUsageCheckBoxes[1]->setCheckState(Qt::CheckState::Checked);
+ else
+ keyUsageCheckBoxes[1]->setCheckState(Qt::CheckState::Unchecked);
+
+ if (genKeyInfo->isAllowChangeSigning())
+ keyUsageCheckBoxes[1]->setDisabled(false);
+ else
+ keyUsageCheckBoxes[1]->setDisabled(true);
+
+ if (genKeyInfo->isAllowCertification())
+ keyUsageCheckBoxes[2]->setCheckState(Qt::CheckState::Checked);
+ else
+ keyUsageCheckBoxes[2]->setCheckState(Qt::CheckState::Unchecked);
+
+ if (genKeyInfo->isAllowChangeCertification())
+ keyUsageCheckBoxes[2]->setDisabled(false);
+ else
+ keyUsageCheckBoxes[2]->setDisabled(true);
+
+ if (genKeyInfo->isAllowAuthentication())
+ keyUsageCheckBoxes[3]->setCheckState(Qt::CheckState::Checked);
+ else
+ keyUsageCheckBoxes[3]->setCheckState(Qt::CheckState::Unchecked);
+
+ if (genKeyInfo->isAllowChangeAuthentication())
+ keyUsageCheckBoxes[3]->setDisabled(false);
+ else
+ keyUsageCheckBoxes[3]->setDisabled(true);
+
+ keySizeSpinBox->setRange(genKeyInfo->getSuggestMinKeySize(),
+ genKeyInfo->getSuggestMaxKeySize());
+ keySizeSpinBox->setValue(genKeyInfo->getKeySize());
+ keySizeSpinBox->setSingleStep(genKeyInfo->getSizeChangeStep());
}
void SubkeyGenerateDialog::slotKeyGenAccept() {
- QString errorString = "";
-
- /**
- * primary keys should have a reasonable expiration date (no more than 2 years in the future)
- */
- if(dateEdit->dateTime() > QDateTime::currentDateTime().addYears(2)) {
-
- errorString.append(tr(" Expiration time no more than 2 years. "));
- }
+ QString errorString = "";
- if (errorString.isEmpty()) {
+ /**
+ * primary keys should have a reasonable expiration date (no more than 2 years
+ * in the future)
+ */
+ if (dateEdit->dateTime() > QDateTime::currentDateTime().addYears(2)) {
+ errorString.append(tr(" Expiration time no more than 2 years. "));
+ }
- genKeyInfo.setKeySize(keySizeSpinBox->value());
+ if (errorString.isEmpty()) {
+ genKeyInfo->setKeySize(keySizeSpinBox->value());
- if (expireCheckBox->checkState()) {
- genKeyInfo.setNonExpired(true);
- } else {
- genKeyInfo.setExpired(dateEdit->dateTime());
- }
+ if (expireCheckBox->checkState()) {
+ genKeyInfo->setNonExpired(true);
+ } else {
+ genKeyInfo->setExpired(
+ boost::posix_time::from_time_t(dateEdit->dateTime().toTime_t())
+ .date());
+ }
- gpgme_error_t error = false;
- auto thread = QThread::create([&]() {
- error = mCtx->generateSubkey(mKey, &genKeyInfo);
- });
- thread->start();
+ gpgme_error_t error = false;
+ auto thread = QThread::create([&]() {
+ error = GpgKeyOpera::GetInstance().GenerateSubkey(mKey, genKeyInfo);
+ });
+ thread->start();
- auto *dialog = new WaitingDialog("Generating", this);
- dialog->show();
+ auto* dialog = new WaitingDialog("Generating", this);
+ dialog->show();
- while (thread->isRunning()) {
- QCoreApplication::processEvents();
- }
+ while (thread->isRunning()) {
+ QCoreApplication::processEvents();
+ }
- dialog->close();
+ dialog->close();
- if (gpgme_err_code(error) == GPG_ERR_NO_ERROR) {
- QMessageBox::information(nullptr, tr("Success"), tr("The new subkey has been generated."));
- this->close();
- } else
- QMessageBox::critical(this, tr("Failure"), tr(gpgme_strerror(error)));
+ if (gpgme_err_code(error) == GPG_ERR_NO_ERROR) {
+ QMessageBox::information(nullptr, tr("Success"),
+ tr("The new subkey has been generated."));
+ this->close();
+ } else
+ QMessageBox::critical(this, tr("Failure"), tr(gpgme_strerror(error)));
- } else {
- /**
- * create error message
- */
- errorLabel->setAutoFillBackground(true);
- QPalette error = errorLabel->palette();
- error.setColor(QPalette::Window, "#ff8080");
- errorLabel->setPalette(error);
- errorLabel->setText(errorString);
-
- this->show();
- }
+ } else {
+ /**
+ * create error message
+ */
+ errorLabel->setAutoFillBackground(true);
+ QPalette error = errorLabel->palette();
+ error.setColor(QPalette::Window, "#ff8080");
+ errorLabel->setPalette(error);
+ errorLabel->setText(errorString);
+
+ this->show();
+ }
}
void SubkeyGenerateDialog::slotEncryptionBoxChanged(int state) {
- if(state == 0) {
- genKeyInfo.setAllowEncryption(false);
- } else {
- genKeyInfo.setAllowEncryption(true);
- }
+ if (state == 0) {
+ genKeyInfo->setAllowEncryption(false);
+ } else {
+ genKeyInfo->setAllowEncryption(true);
+ }
}
void SubkeyGenerateDialog::slotSigningBoxChanged(int state) {
- if(state == 0) {
- genKeyInfo.setAllowSigning(false);
- } else {
- genKeyInfo.setAllowSigning(true);
- }
+ if (state == 0) {
+ genKeyInfo->setAllowSigning(false);
+ } else {
+ genKeyInfo->setAllowSigning(true);
+ }
}
void SubkeyGenerateDialog::slotCertificationBoxChanged(int state) {
- if(state == 0) {
- genKeyInfo.setAllowCertification(false);
- } else {
- genKeyInfo.setAllowCertification(true);
- }
+ if (state == 0) {
+ genKeyInfo->setAllowCertification(false);
+ } else {
+ genKeyInfo->setAllowCertification(true);
+ }
}
void SubkeyGenerateDialog::slotAuthenticationBoxChanged(int state) {
- if(state == 0) {
- genKeyInfo.setAllowAuthentication(false);
- } else {
- genKeyInfo.setAllowAuthentication(true);
- }
+ if (state == 0) {
+ genKeyInfo->setAllowAuthentication(false);
+ } else {
+ genKeyInfo->setAllowAuthentication(true);
+ }
}
void SubkeyGenerateDialog::slotActivatedKeyType(int index) {
- qDebug() << "key type index changed " << index;
- genKeyInfo.setAlgo(this->keyTypeComboBox->itemText(index));
- refresh_widgets_state();
+ qDebug() << "key type index changed " << index;
+ genKeyInfo->setAlgo(this->keyTypeComboBox->itemText(index).toStdString());
+ refresh_widgets_state();
}
+
+} // namespace GpgFrontend::UI
diff --git a/src/ui/keygen/SubkeyGenerateDialog.h b/src/ui/keygen/SubkeyGenerateDialog.h
new file mode 100644
index 00000000..1b4249b4
--- /dev/null
+++ b/src/ui/keygen/SubkeyGenerateDialog.h
@@ -0,0 +1,94 @@
+/**
+ * This file is part of GPGFrontend.
+ *
+ * GPGFrontend is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Foobar is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Foobar. If not, see <https://www.gnu.org/licenses/>.
+ *
+ * The initial version of the source code is inherited from gpg4usb-team.
+ * Their source code version also complies with GNU General Public License.
+ *
+ * The source code version of this software was modified and released
+ * by Saturneric<[email protected]><[email protected]> starting on May 12, 2021.
+ *
+ */
+
+#ifndef GPGFRONTEND_SUBKEYGENERATEDIALOG_H
+#define GPGFRONTEND_SUBKEYGENERATEDIALOG_H
+
+#include <gpg/GpgGenKeyInfo.h>
+#include "gpg/GpgContext.h"
+#include "ui/GpgFrontendUI.h"
+
+namespace GpgFrontend::UI {
+
+class SubkeyGenerateDialog : public QDialog {
+ Q_OBJECT
+
+ public:
+ explicit SubkeyGenerateDialog(const KeyId& key_id, QWidget* parent);
+
+ private:
+ GpgKey mKey;
+
+ std::unique_ptr<GenKeyInfo> genKeyInfo = std::make_unique<GenKeyInfo>();
+
+ QGroupBox* keyUsageGroupBox{};
+ QDialogButtonBox* buttonBox; /** Box for standardbuttons */
+ QLabel* errorLabel{}; /** Label containing error message */
+ QSpinBox* keySizeSpinBox{}; /** Spinbox for the keys size (in bit) */
+ QComboBox* keyTypeComboBox{}; /** Combobox for Keytpe */
+ QDateTimeEdit* dateEdit{}; /** Dateedit for expiration date */
+ QCheckBox* expireCheckBox{}; /** Checkbox, if key should expire */
+
+ // ENCR, SIGN, CERT, AUTH
+ std::vector<QCheckBox*> keyUsageCheckBoxes;
+
+ QGroupBox* create_key_usage_group_box();
+
+ QGroupBox* create_basic_info_group_box();
+
+ void set_signal_slot();
+
+ /**
+ * @details Refresh widgets state by GenKeyInfo
+ */
+ void refresh_widgets_state();
+
+ private slots:
+
+ /**
+ * @details when expirebox was checked/unchecked, enable/disable the
+ * expiration date box
+ */
+ void slotExpireBoxChanged();
+
+ /**
+ * @details check all lineedits for false entries. Show error, when there is
+ * one, otherwise generate the key
+ */
+ void slotKeyGenAccept();
+
+ void slotEncryptionBoxChanged(int state);
+
+ void slotSigningBoxChanged(int state);
+
+ void slotCertificationBoxChanged(int state);
+
+ void slotAuthenticationBoxChanged(int state);
+
+ void slotActivatedKeyType(int index);
+};
+
+} // namespace GpgFrontend::UI
+
+#endif // GPGFRONTEND_SUBKEYGENERATEDIALOG_H
diff --git a/include/ui/keypair_details/EditSubKeyDialog.h b/src/ui/keypair_details/EditSubKeyDialog.h
index 6577d382..6577d382 100644
--- a/include/ui/keypair_details/EditSubKeyDialog.h
+++ b/src/ui/keypair_details/EditSubKeyDialog.h
diff --git a/src/ui/keypair_details/KeyDetailsDialog.cpp b/src/ui/keypair_details/KeyDetailsDialog.cpp
index 0d94e584..54bc6286 100644
--- a/src/ui/keypair_details/KeyDetailsDialog.cpp
+++ b/src/ui/keypair_details/KeyDetailsDialog.cpp
@@ -24,21 +24,22 @@
#include "ui/keypair_details/KeyDetailsDialog.h"
-KeyDetailsDialog::KeyDetailsDialog(GpgFrontend::GpgContext *ctx, const GpgKey& key, QWidget *parent)
- : QDialog(parent) {
+namespace GpgFrontend::UI {
+KeyDetailsDialog::KeyDetailsDialog(const GpgKey& key, QWidget* parent)
+ : QDialog(parent) {
+ tabWidget = new QTabWidget();
+ tabWidget->addTab(new KeyPairDetailTab(key.id(), tabWidget), tr("KeyPair"));
+ tabWidget->addTab(new KeyPairUIDTab(key.id(), tabWidget), tr("UIDs"));
+ tabWidget->addTab(new KeyPairSubkeyTab(key.id(), tabWidget), tr("Subkeys"));
- tabWidget = new QTabWidget();
- tabWidget->addTab(new KeyPairDetailTab(ctx, key, tabWidget), tr("KeyPair"));
- tabWidget->addTab(new KeyPairUIDTab(ctx, key, tabWidget), tr("UIDs"));
- tabWidget->addTab(new KeyPairSubkeyTab(ctx, key, tabWidget), tr("Subkeys"));
+ auto* mainLayout = new QVBoxLayout;
+ mainLayout->addWidget(tabWidget);
- auto *mainLayout = new QVBoxLayout;
- mainLayout->addWidget(tabWidget);
-
- this->setAttribute(Qt::WA_DeleteOnClose, true);
- this->setLayout(mainLayout);
- this->setWindowTitle(tr("Key Details"));
- this->setModal(true);
- this->setMinimumSize(380, 620);
- this->show();
-} \ No newline at end of file
+ this->setAttribute(Qt::WA_DeleteOnClose, true);
+ this->setLayout(mainLayout);
+ this->setWindowTitle(tr("Key Details"));
+ this->setModal(true);
+ this->setMinimumSize(380, 620);
+ this->show();
+}
+} // namespace GpgFrontend::UI
diff --git a/include/ui/keypair_details/KeyDetailsDialog.h b/src/ui/keypair_details/KeyDetailsDialog.h
index 4d2cde88..0f7342aa 100644
--- a/include/ui/keypair_details/KeyDetailsDialog.h
+++ b/src/ui/keypair_details/KeyDetailsDialog.h
@@ -25,22 +25,23 @@
#ifndef __KEYDETAILSDIALOG_H__
#define __KEYDETAILSDIALOG_H__
-#include "gpg/GpgContext.h"
#include "KeyPairDetailTab.h"
-#include "KeyPairUIDTab.h"
#include "KeyPairSubkeyTab.h"
+#include "KeyPairUIDTab.h"
+#include "gpg/GpgContext.h"
+#include "ui/GpgFrontendUI.h"
-class KeyDetailsDialog : public QDialog {
-Q_OBJECT
-
-public:
-
- KeyDetailsDialog(GpgFrontend::GpgContext *ctx, const GpgKey& key, QWidget *parent = nullptr);
+namespace GpgFrontend::UI {
-private:
+class KeyDetailsDialog : public QDialog {
+ Q_OBJECT
- QTabWidget *tabWidget{};
+ public:
+ explicit KeyDetailsDialog(const GpgKey& key, QWidget* parent = nullptr);
+ private:
+ QTabWidget* tabWidget{};
};
+} // namespace GpgFrontend::UI
-#endif // __KEYDETAILSDIALOG_H__
+#endif // __KEYDETAILSDIALOG_H__
diff --git a/src/ui/keypair_details/KeyNewUIDDialog.cpp b/src/ui/keypair_details/KeyNewUIDDialog.cpp
index 7c6e1ca5..a22250c1 100644
--- a/src/ui/keypair_details/KeyNewUIDDialog.cpp
+++ b/src/ui/keypair_details/KeyNewUIDDialog.cpp
@@ -24,79 +24,77 @@
#include "ui/keypair_details/KeyNewUIDDialog.h"
-KeyNewUIDDialog::KeyNewUIDDialog(GpgFrontend::GpgContext *ctx, const GpgKey &key, QWidget *parent) :
- mCtx(ctx), mKey(key), QDialog(parent) {
-
- name = new QLineEdit();
- name->setMinimumWidth(240);
- email = new QLineEdit();
- email->setMinimumWidth(240);
- comment = new QLineEdit();
- comment->setMinimumWidth(240);
- createButton = new QPushButton("Create");
- errorLabel = new QLabel();
-
- auto gridLayout = new QGridLayout();
- gridLayout->addWidget(new QLabel(tr("Name")), 0, 0);
- gridLayout->addWidget(new QLabel(tr("Email")), 1, 0);
- gridLayout->addWidget(new QLabel(tr("Comment")), 2, 0);
-
-
- gridLayout->addWidget(name, 0 ,1);
- gridLayout->addWidget(email, 1 ,1);
- gridLayout->addWidget(comment, 2 ,1);
-
- gridLayout->addWidget(createButton, 3, 0, 1, 2);
- gridLayout->addWidget(errorLabel, 4, 0, 1, 2);
-
- connect(createButton, SIGNAL(clicked(bool)), this, SLOT(slotCreateNewUID()));
-
- this->setLayout(gridLayout);
- this->setWindowTitle(tr("Create New UID"));
- this->setAttribute(Qt::WA_DeleteOnClose, true);
- this->setModal(true);
+#include "gpg/function/GpgKeyGetter.h"
+#include "gpg/function/UidOperator.h"
+
+namespace GpgFrontend::UI {
+KeyNewUIDDialog::KeyNewUIDDialog(const KeyId& key_id, QWidget* parent)
+ : QDialog(parent), mKey(GpgKeyGetter::GetInstance().GetKey(key_id)) {
+ name = new QLineEdit();
+ name->setMinimumWidth(240);
+ email = new QLineEdit();
+ email->setMinimumWidth(240);
+ comment = new QLineEdit();
+ comment->setMinimumWidth(240);
+ createButton = new QPushButton("Create");
+ errorLabel = new QLabel();
+
+ auto gridLayout = new QGridLayout();
+ gridLayout->addWidget(new QLabel(tr("Name")), 0, 0);
+ gridLayout->addWidget(new QLabel(tr("Email")), 1, 0);
+ gridLayout->addWidget(new QLabel(tr("Comment")), 2, 0);
+
+ gridLayout->addWidget(name, 0, 1);
+ gridLayout->addWidget(email, 1, 1);
+ gridLayout->addWidget(comment, 2, 1);
+
+ gridLayout->addWidget(createButton, 3, 0, 1, 2);
+ gridLayout->addWidget(errorLabel, 4, 0, 1, 2);
+
+ connect(createButton, SIGNAL(clicked(bool)), this, SLOT(slotCreateNewUID()));
+
+ this->setLayout(gridLayout);
+ this->setWindowTitle(tr("Create New UID"));
+ this->setAttribute(Qt::WA_DeleteOnClose, true);
+ this->setModal(true);
}
void KeyNewUIDDialog::slotCreateNewUID() {
-
- QString errorString = "";
-
+ QString errorString = "";
+
+ /**
+ * check for errors in keygen dialog input
+ */
+ if ((name->text()).size() < 5) {
+ errorString.append(tr(" Name must contain at least five characters. \n"));
+ }
+ if (email->text().isEmpty() || !check_email_address(email->text())) {
+ errorString.append(tr(" Please give a email address. \n"));
+ }
+
+ if (errorString.isEmpty()) {
+ if (UidOperator::GetInstance().addUID(mKey, name->text().toStdString(),
+ comment->text().toStdString(),
+ email->text().toStdString()))
+ emit finished(1);
+ else
+ emit finished(-1);
+
+ } else {
/**
- * check for errors in keygen dialog input
+ * create error message
*/
- if ((name->text()).size() < 5) {
- errorString.append(tr(" Name must contain at least five characters. \n"));
- } if(email->text().isEmpty() || !check_email_address(email->text())) {
- errorString.append(tr(" Please give a email address. \n"));
- }
-
- if (errorString.isEmpty()) {
- GpgUID uid;
- uid.name = name->text();
- uid.email = email->text();
- uid.comment = comment->text();
-
- if(mCtx->addUID(mKey, uid)) {
- emit finished(1);
-
- } else {
- emit finished(-1);
- }
-
- } else {
- /**
- * create error message
- */
- errorLabel->setAutoFillBackground(true);
- QPalette error = errorLabel->palette();
- error.setColor(QPalette::Window, "#ff8080");
- errorLabel->setPalette(error);
- errorLabel->setText(errorString);
-
- this->show();
- }
+ errorLabel->setAutoFillBackground(true);
+ QPalette error = errorLabel->palette();
+ error.setColor(QPalette::Window, "#ff8080");
+ errorLabel->setPalette(error);
+ errorLabel->setText(errorString);
+
+ this->show();
+ }
}
-bool KeyNewUIDDialog::check_email_address(const QString &str) {
- return re_email.match(str).hasMatch();
+bool KeyNewUIDDialog::check_email_address(const QString& str) {
+ return re_email.match(str).hasMatch();
}
+} // namespace GpgFrontend::UI
diff --git a/include/ui/keypair_details/KeyNewUIDDialog.h b/src/ui/keypair_details/KeyNewUIDDialog.h
index c8b42661..076a69ed 100644
--- a/include/ui/keypair_details/KeyNewUIDDialog.h
+++ b/src/ui/keypair_details/KeyNewUIDDialog.h
@@ -25,42 +25,37 @@
#ifndef GPGFRONTEND_KEYNEWUIDDIALOG_H
#define GPGFRONTEND_KEYNEWUIDDIALOG_H
-#include "GpgFrontend.h"
-
#include "gpg/GpgContext.h"
+#include "ui/GpgFrontendUI.h"
+namespace GpgFrontend::UI {
class KeyNewUIDDialog : public QDialog {
-Q_OBJECT
-
-public:
-
- KeyNewUIDDialog(GpgFrontend::GpgContext *ctx, const GpgKey &key ,QWidget *parent = nullptr);
+ Q_OBJECT
+ public:
+ KeyNewUIDDialog(const KeyId& key, QWidget* parent = nullptr);
-private slots:
+ private slots:
- void slotCreateNewUID();
+ void slotCreateNewUID();
-private:
+ private:
+ GpgKey mKey;
- GpgFrontend::GpgContext *mCtx;
- const GpgKey &mKey;
+ QLineEdit* name{};
+ QLineEdit* email{};
+ QLineEdit* comment{};
- QLineEdit *name{};
- QLineEdit *email{};
- QLineEdit *comment{};
+ QPushButton* createButton{};
- QPushButton *createButton{};
+ QStringList errorMessages;
+ QLabel* errorLabel{};
- QStringList errorMessages;
- QLabel *errorLabel{};
-
- QRegularExpression re_email{
- R"((?:[a-z0-9!#$%&'*+/=?^_`{|}~-]+(?:\.[a-z0-9!#$%&'*+/=?^_`{|}~-]+)*|"(?:[\x01-\x08\x0b\x0c\x0e-\x1f\x21\x23-\x5b\x5d-\x7f]|\\[\x01-\x09\x0b\x0c\x0e-\x7f])*")@(?:(?:[a-z0-9](?:[a-z0-9-]*[a-z0-9])?\.)+[a-z0-9](?:[a-z0-9-]*[a-z0-9])?|\[(?:(?:(2(5[0-5]|[0-4][0-9])|1[0-9][0-9]|[1-9]?[0-9]))\.){3}(?:(2(5[0-5]|[0-4][0-9])|1[0-9][0-9]|[1-9]?[0-9])|[a-z0-9-]*[a-z0-9]:(?:[\x01-\x08\x0b\x0c\x0e-\x1f\x21-\x5a\x53-\x7f]|\\[\x01-\x09\x0b\x0c\x0e-\x7f])+)\]))"};
-
- bool check_email_address(const QString &str);
+ QRegularExpression re_email{
+ R"((?:[a-z0-9!#$%&'*+/=?^_`{|}~-]+(?:\.[a-z0-9!#$%&'*+/=?^_`{|}~-]+)*|"(?:[\x01-\x08\x0b\x0c\x0e-\x1f\x21\x23-\x5b\x5d-\x7f]|\\[\x01-\x09\x0b\x0c\x0e-\x7f])*")@(?:(?:[a-z0-9](?:[a-z0-9-]*[a-z0-9])?\.)+[a-z0-9](?:[a-z0-9-]*[a-z0-9])?|\[(?:(?:(2(5[0-5]|[0-4][0-9])|1[0-9][0-9]|[1-9]?[0-9]))\.){3}(?:(2(5[0-5]|[0-4][0-9])|1[0-9][0-9]|[1-9]?[0-9])|[a-z0-9-]*[a-z0-9]:(?:[\x01-\x08\x0b\x0c\x0e-\x1f\x21-\x5a\x53-\x7f]|\\[\x01-\x09\x0b\x0c\x0e-\x7f])+)\]))"};
+ bool check_email_address(const QString& str);
};
+} // namespace GpgFrontend::UI
-
-#endif //GPGFRONTEND_KEYNEWUIDDIALOG_H
+#endif // GPGFRONTEND_KEYNEWUIDDIALOG_H
diff --git a/src/ui/keypair_details/KeyPairDetailTab.cpp b/src/ui/keypair_details/KeyPairDetailTab.cpp
index 1f5d4095..fe95a10e 100644
--- a/src/ui/keypair_details/KeyPairDetailTab.cpp
+++ b/src/ui/keypair_details/KeyPairDetailTab.cpp
@@ -23,330 +23,346 @@
*/
#include "ui/keypair_details/KeyPairDetailTab.h"
+#include "gpg/function/GpgKeyGetter.h"
+#include "gpg/function/GpgKeyImportExportor.h"
#include "ui/WaitingDialog.h"
-KeyPairDetailTab::KeyPairDetailTab(GpgFrontend::GpgContext *ctx, const GpgKey &mKey, QWidget *parent) : mKey(mKey),
- QWidget(parent) {
-
- mCtx = ctx;
- keyid = new QString(mKey.id);
-
- ownerBox = new QGroupBox(tr("Owner"));
- keyBox = new QGroupBox(tr("Master Key"));
- fingerprintBox = new QGroupBox(tr("Fingerprint"));
- additionalUidBox = new QGroupBox(tr("Additional UIDs"));
-
- nameVarLabel = new QLabel();
- nameVarLabel->setTextInteractionFlags(Qt::TextSelectableByMouse);
- emailVarLabel = new QLabel();
- emailVarLabel->setTextInteractionFlags(Qt::TextSelectableByMouse);
-
- commentVarLabel = new QLabel();
- commentVarLabel->setTextInteractionFlags(Qt::TextSelectableByMouse);
- keyidVarLabel = new QLabel();
- keyidVarLabel->setTextInteractionFlags(Qt::TextSelectableByMouse);
-
- usageVarLabel = new QLabel();
- actualUsageVarLabel = new QLabel();
-
- keySizeVarLabel = new QLabel();
- expireVarLabel = new QLabel();
- createdVarLabel = new QLabel();
- algorithmVarLabel = new QLabel();
-
- // Show the situation that master key not exists.
- masterKeyExistVarLabel = new QLabel(mKey.has_master_key ? tr("Exists") : tr("Not Exists"));
- if (!mKey.has_master_key) {
- auto paletteExpired = masterKeyExistVarLabel->palette();
- paletteExpired.setColor(masterKeyExistVarLabel->foregroundRole(), Qt::red);
- masterKeyExistVarLabel->setPalette(paletteExpired);
- } else {
- auto paletteValid = masterKeyExistVarLabel->palette();
- paletteValid.setColor(masterKeyExistVarLabel->foregroundRole(), Qt::darkGreen);
- masterKeyExistVarLabel->setPalette(paletteValid);
+namespace GpgFrontend::UI {
+KeyPairDetailTab::KeyPairDetailTab(const std::string& key_id, QWidget* parent)
+ : QWidget(parent),
+ mKey(std::move(GpgKeyGetter::GetInstance().GetKey(key_id))) {
+ keyid = mKey.id();
+
+ ownerBox = new QGroupBox(tr("Owner"));
+ keyBox = new QGroupBox(tr("Master Key"));
+ fingerprintBox = new QGroupBox(tr("Fingerprint"));
+ additionalUidBox = new QGroupBox(tr("Additional UIDs"));
+
+ nameVarLabel = new QLabel();
+ nameVarLabel->setTextInteractionFlags(Qt::TextSelectableByMouse);
+ emailVarLabel = new QLabel();
+ emailVarLabel->setTextInteractionFlags(Qt::TextSelectableByMouse);
+
+ commentVarLabel = new QLabel();
+ commentVarLabel->setTextInteractionFlags(Qt::TextSelectableByMouse);
+ keyidVarLabel = new QLabel();
+ keyidVarLabel->setTextInteractionFlags(Qt::TextSelectableByMouse);
+
+ usageVarLabel = new QLabel();
+ actualUsageVarLabel = new QLabel();
+
+ keySizeVarLabel = new QLabel();
+ expireVarLabel = new QLabel();
+ createdVarLabel = new QLabel();
+ algorithmVarLabel = new QLabel();
+
+ // Show the situation that master key not exists.
+ masterKeyExistVarLabel =
+ new QLabel(mKey.has_master_key() ? tr("Exists") : tr("Not Exists"));
+ if (!mKey.has_master_key()) {
+ auto paletteExpired = masterKeyExistVarLabel->palette();
+ paletteExpired.setColor(masterKeyExistVarLabel->foregroundRole(), Qt::red);
+ masterKeyExistVarLabel->setPalette(paletteExpired);
+ } else {
+ auto paletteValid = masterKeyExistVarLabel->palette();
+ paletteValid.setColor(masterKeyExistVarLabel->foregroundRole(),
+ Qt::darkGreen);
+ masterKeyExistVarLabel->setPalette(paletteValid);
+ }
+
+ if (mKey.expired()) {
+ auto paletteExpired = expireVarLabel->palette();
+ paletteExpired.setColor(expireVarLabel->foregroundRole(), Qt::red);
+ expireVarLabel->setPalette(paletteExpired);
+ } else {
+ auto paletteValid = expireVarLabel->palette();
+ paletteValid.setColor(expireVarLabel->foregroundRole(), Qt::darkGreen);
+ expireVarLabel->setPalette(paletteValid);
+ }
+
+ auto* mvbox = new QVBoxLayout();
+ auto* vboxKD = new QGridLayout();
+ auto* vboxOD = new QGridLayout();
+
+ vboxOD->addWidget(new QLabel(tr("Name:")), 0, 0);
+ vboxOD->addWidget(new QLabel(tr("Email Address:")), 1, 0);
+ vboxOD->addWidget(new QLabel(tr("Comment:")), 2, 0);
+ vboxOD->addWidget(nameVarLabel, 0, 1);
+ vboxOD->addWidget(emailVarLabel, 1, 1);
+ vboxOD->addWidget(commentVarLabel, 2, 1);
+
+ vboxKD->addWidget(new QLabel(tr("Key ID: ")), 0, 0);
+ vboxKD->addWidget(new QLabel(tr("Algorithm: ")), 1, 0);
+ vboxKD->addWidget(new QLabel(tr("Key Size:")), 2, 0);
+ vboxKD->addWidget(new QLabel(tr("Nominal Usage: ")), 3, 0);
+ vboxKD->addWidget(new QLabel(tr("Actual Usage: ")), 4, 0);
+ vboxKD->addWidget(new QLabel(tr("Expires on: ")), 5, 0);
+ vboxKD->addWidget(new QLabel(tr("Last Update: ")), 6, 0);
+ vboxKD->addWidget(new QLabel(tr("Secret Key Existence: ")), 7, 0);
+
+ vboxKD->addWidget(keySizeVarLabel, 2, 1);
+ vboxKD->addWidget(expireVarLabel, 5, 1);
+ vboxKD->addWidget(algorithmVarLabel, 1, 1);
+ vboxKD->addWidget(createdVarLabel, 6, 1);
+ vboxKD->addWidget(keyidVarLabel, 0, 1);
+ vboxKD->addWidget(usageVarLabel, 3, 1);
+ vboxKD->addWidget(actualUsageVarLabel, 4, 1);
+ vboxKD->addWidget(masterKeyExistVarLabel, 7, 1);
+
+ ownerBox->setLayout(vboxOD);
+ mvbox->addWidget(ownerBox);
+ keyBox->setLayout(vboxKD);
+ mvbox->addWidget(keyBox);
+
+ fingerPrintVarLabel =
+ new QLabel(beautifyFingerprint(QString::fromStdString(mKey.fpr())));
+ fingerPrintVarLabel->setTextInteractionFlags(Qt::TextSelectableByMouse);
+ fingerPrintVarLabel->setStyleSheet("margin-left: 0; margin-right: 5;");
+ auto* hboxFP = new QHBoxLayout();
+
+ hboxFP->addWidget(fingerPrintVarLabel);
+
+ auto* copyFingerprintButton = new QPushButton(tr("Copy"));
+ copyFingerprintButton->setFlat(true);
+ copyFingerprintButton->setToolTip(tr("copy fingerprint to clipboard"));
+ connect(copyFingerprintButton, SIGNAL(clicked()), this,
+ SLOT(slotCopyFingerprint()));
+
+ hboxFP->addWidget(copyFingerprintButton);
+
+ fingerprintBox->setLayout(hboxFP);
+ mvbox->addWidget(fingerprintBox);
+ mvbox->addStretch();
+
+ if (mKey.is_private_key()) {
+ auto* privKeyBox = new QGroupBox(tr("Operations"));
+ auto* vboxPK = new QVBoxLayout();
+
+ auto* exportButton =
+ new QPushButton(tr("Export Private Key (Include Subkey)"));
+ vboxPK->addWidget(exportButton);
+ connect(exportButton, SIGNAL(clicked()), this,
+ SLOT(slotExportPrivateKey()));
+
+ if (mKey.has_master_key()) {
+ auto* editExpiresButton =
+ new QPushButton(tr("Modify Expiration Datetime (Master Key)"));
+ vboxPK->addWidget(editExpiresButton);
+ connect(editExpiresButton, SIGNAL(clicked()), this,
+ SLOT(slotModifyEditDatetime()));
+
+ auto hBoxLayout = new QHBoxLayout();
+ auto* keyServerOperaButton =
+ new QPushButton(tr("Key Server Operation (Pubkey)"));
+ keyServerOperaButton->setStyleSheet("text-align:center;");
+
+ auto* revokeCertGenButton =
+ new QPushButton(tr("Generate Revoke Certificate"));
+ connect(revokeCertGenButton, SIGNAL(clicked()), this,
+ SLOT(slotGenRevokeCert()));
+
+ hBoxLayout->addWidget(keyServerOperaButton);
+ hBoxLayout->addWidget(revokeCertGenButton);
+
+ vboxPK->addLayout(hBoxLayout);
+ connect(keyServerOperaButton, SIGNAL(clicked()), this,
+ SLOT(slotModifyEditDatetime()));
+
+ // Set Menu
+ createKeyServerOperaMenu();
+ keyServerOperaButton->setMenu(keyServerOperaMenu);
}
- if (mKey.expired) {
- auto paletteExpired = expireVarLabel->palette();
- paletteExpired.setColor(expireVarLabel->foregroundRole(), Qt::red);
- expireVarLabel->setPalette(paletteExpired);
- } else {
- auto paletteValid = expireVarLabel->palette();
- paletteValid.setColor(expireVarLabel->foregroundRole(), Qt::darkGreen);
- expireVarLabel->setPalette(paletteValid);
- }
+ privKeyBox->setLayout(vboxPK);
+ mvbox->addWidget(privKeyBox);
+ }
- auto *mvbox = new QVBoxLayout();
- auto *vboxKD = new QGridLayout();
- auto *vboxOD = new QGridLayout();
-
- vboxOD->addWidget(new QLabel(tr("Name:")), 0, 0);
- vboxOD->addWidget(new QLabel(tr("Email Address:")), 1, 0);
- vboxOD->addWidget(new QLabel(tr("Comment:")), 2, 0);
- vboxOD->addWidget(nameVarLabel, 0, 1);
- vboxOD->addWidget(emailVarLabel, 1, 1);
- vboxOD->addWidget(commentVarLabel, 2, 1);
-
- vboxKD->addWidget(new QLabel(tr("Key ID: ")), 0, 0);
- vboxKD->addWidget(new QLabel(tr("Algorithm: ")), 1, 0);
- vboxKD->addWidget(new QLabel(tr("Key Size:")), 2, 0);
- vboxKD->addWidget(new QLabel(tr("Nominal Usage: ")), 3, 0);
- vboxKD->addWidget(new QLabel(tr("Actual Usage: ")), 4, 0);
- vboxKD->addWidget(new QLabel(tr("Expires on: ")), 5, 0);
- vboxKD->addWidget(new QLabel(tr("Last Update: ")), 6, 0);
- vboxKD->addWidget(new QLabel(tr("Secret Key Existence: ")), 7, 0);
-
-
- vboxKD->addWidget(keySizeVarLabel, 2, 1);
- vboxKD->addWidget(expireVarLabel, 5, 1);
- vboxKD->addWidget(algorithmVarLabel, 1, 1);
- vboxKD->addWidget(createdVarLabel, 6, 1);
- vboxKD->addWidget(keyidVarLabel, 0, 1);
- vboxKD->addWidget(usageVarLabel, 3, 1);
- vboxKD->addWidget(actualUsageVarLabel, 4, 1);
- vboxKD->addWidget(masterKeyExistVarLabel, 7, 1);
-
- ownerBox->setLayout(vboxOD);
- mvbox->addWidget(ownerBox);
- keyBox->setLayout(vboxKD);
- mvbox->addWidget(keyBox);
-
- fingerPrintVarLabel = new QLabel(beautifyFingerprint(mKey.fpr));
- fingerPrintVarLabel->setTextInteractionFlags(Qt::TextSelectableByMouse);
- fingerPrintVarLabel->setStyleSheet("margin-left: 0; margin-right: 5;");
- auto *hboxFP = new QHBoxLayout();
-
- hboxFP->addWidget(fingerPrintVarLabel);
-
- auto *copyFingerprintButton = new QPushButton(tr("Copy"));
- copyFingerprintButton->setFlat(true);
- copyFingerprintButton->setToolTip(tr("copy fingerprint to clipboard"));
- connect(copyFingerprintButton, SIGNAL(clicked()), this, SLOT(slotCopyFingerprint()));
-
- hboxFP->addWidget(copyFingerprintButton);
-
- fingerprintBox->setLayout(hboxFP);
- mvbox->addWidget(fingerprintBox);
- mvbox->addStretch();
-
- if (mKey.is_private_key) {
- auto *privKeyBox = new QGroupBox(tr("Operations"));
- auto *vboxPK = new QVBoxLayout();
-
- auto *exportButton = new QPushButton(tr("Export Private Key (Include Subkey)"));
- vboxPK->addWidget(exportButton);
- connect(exportButton, SIGNAL(clicked()), this, SLOT(slotExportPrivateKey()));
-
- if (mKey.has_master_key) {
- auto *editExpiresButton = new QPushButton(tr("Modify Expiration Datetime (Master Key)"));
- vboxPK->addWidget(editExpiresButton);
- connect(editExpiresButton, SIGNAL(clicked()), this, SLOT(slotModifyEditDatetime()));
-
- auto hBoxLayout = new QHBoxLayout();
- auto *keyServerOperaButton = new QPushButton(tr("Key Server Operation (Pubkey)"));
- keyServerOperaButton->setStyleSheet("text-align:center;");
-
- auto *revokeCertGenButton = new QPushButton(tr("Generate Revoke Certificate"));
- connect(revokeCertGenButton, SIGNAL(clicked()), this, SLOT(slotGenRevokeCert()));
-
- hBoxLayout->addWidget(keyServerOperaButton);
- hBoxLayout->addWidget(revokeCertGenButton);
-
- vboxPK->addLayout(hBoxLayout);
- connect(keyServerOperaButton, SIGNAL(clicked()), this, SLOT(slotModifyEditDatetime()));
-
- // Set Menu
- createKeyServerOperaMenu();
- keyServerOperaButton->setMenu(keyServerOperaMenu);
- }
-
- privKeyBox->setLayout(vboxPK);
- mvbox->addWidget(privKeyBox);
- }
+ if ((mKey.expired()) || (mKey.revoked())) {
+ auto* expBox = new QHBoxLayout();
+ QPixmap pixmap(":warning.png");
- if ((mKey.expired) || (mKey.revoked)) {
- auto *expBox = new QHBoxLayout();
- QPixmap pixmap(":warning.png");
-
- auto *expLabel = new QLabel();
- auto *iconLabel = new QLabel();
- if (mKey.expired) {
- expLabel->setText(tr("Warning: The Master Key has expired."));
- }
- if (mKey.revoked) {
- expLabel->setText(tr("Warning: The Master Key has been revoked"));
- }
-
- iconLabel->setPixmap(pixmap.scaled(24, 24, Qt::KeepAspectRatio));
- QFont font = expLabel->font();
- font.setBold(true);
- expLabel->setFont(font);
- expLabel->setAlignment(Qt::AlignCenter);
- expBox->addWidget(iconLabel);
- expBox->addWidget(expLabel);
- mvbox->addLayout(expBox);
+ auto* expLabel = new QLabel();
+ auto* iconLabel = new QLabel();
+ if (mKey.expired()) {
+ expLabel->setText(tr("Warning: The Master Key has expired."));
+ }
+ if (mKey.revoked()) {
+ expLabel->setText(tr("Warning: The Master Key has been revoked"));
}
- mvbox->setContentsMargins(0, 0, 0, 0);
-
- connect(mCtx, SIGNAL(signalKeyInfoChanged()), this, SLOT(slotRefreshKeyInfo()));
-
- slotRefreshKeyInfo();
- setAttribute(Qt::WA_DeleteOnClose, true);
- setLayout(mvbox);
+ iconLabel->setPixmap(pixmap.scaled(24, 24, Qt::KeepAspectRatio));
+ QFont font = expLabel->font();
+ font.setBold(true);
+ expLabel->setFont(font);
+ expLabel->setAlignment(Qt::AlignCenter);
+ expBox->addWidget(iconLabel);
+ expBox->addWidget(expLabel);
+ mvbox->addLayout(expBox);
+ }
+
+ mvbox->setContentsMargins(0, 0, 0, 0);
+
+ slotRefreshKeyInfo();
+ setAttribute(Qt::WA_DeleteOnClose, true);
+ setLayout(mvbox);
}
void KeyPairDetailTab::slotExportPrivateKey() {
- // Show a information box with explanation about private key
- int ret = QMessageBox::information(this, tr("Exporting private Key"),
- "<h3>" + tr("You are about to export your") + "<font color=\"red\">" +
- tr("PRIVATE KEY") + "</font>!</h3>\n" +
- tr("This is NOT your Public Key, so DON'T give it away.") + "<br />" +
- tr("Do you REALLY want to export your PRIVATE KEY?"),
- QMessageBox::Cancel | QMessageBox::Ok);
-
- // export key, if ok was clicked
- if (ret == QMessageBox::Ok) {
- auto *keyArray = new QByteArray();
-
- if (!mCtx->exportSecretKey(mKey, keyArray)) {
- QMessageBox::critical(this, "Error", "An error occurred during the export operation.");
- return;
- }
-
- auto key = mCtx->getKeyRefById(*keyid);
- if (!key.good) {
- QMessageBox::critical(nullptr, tr("Error"), tr("Key Not Found."));
- return;
- }
- QString fileString = key.name + " " + key.email + "(" +
- key.id + ")_secret.asc";
- QString fileName = QFileDialog::getSaveFileName(this, tr("Export Key To File"), fileString,
- tr("Key Files") + " (*.asc *.txt);;All Files (*)");
- QFile file(fileName);
- if (!file.open(QIODevice::WriteOnly | QIODevice::Text)) {
- QMessageBox::critical(nullptr, tr("Export Error"), tr("Couldn't open %1 for writing").arg(fileName));
- return;
- }
- QTextStream stream(&file);
- stream << *keyArray;
- file.close();
- delete keyArray;
+ // Show a information box with explanation about private key
+ int ret = QMessageBox::information(
+ this, tr("Exporting private Key"),
+ "<h3>" + tr("You are about to export your") + "<font color=\"red\">" +
+ tr("PRIVATE KEY") + "</font>!</h3>\n" +
+ tr("This is NOT your Public Key, so DON'T give it away.") + "<br />" +
+ tr("Do you REALLY want to export your PRIVATE KEY?"),
+ QMessageBox::Cancel | QMessageBox::Ok);
+
+ // export key, if ok was clicked
+ if (ret == QMessageBox::Ok) {
+ ByteArrayPtr keyArray = nullptr;
+
+ if (!GpgKeyImportExportor::GetInstance().ExportSecretKey(mKey, keyArray)) {
+ QMessageBox::critical(this, "Error",
+ "An error occurred during the export operation.");
+ return;
+ }
+
+ auto key = GpgKeyGetter::GetInstance().GetKey(keyid);
+ if (!key.good()) {
+ QMessageBox::critical(nullptr, tr("Error"), tr("Key Not Found."));
+ return;
}
+ auto fileString =
+ key.name() + " " + key.email() + "(" + key.id() + ")_secret.asc";
+ auto fileName =
+ QFileDialog::getSaveFileName(
+ this, tr("Export Key To File"), QString::fromStdString(fileString),
+ tr("Key Files") + " (*.asc *.txt);;All Files (*)")
+ .toStdString();
+
+ if (!write_buffer_to_file(fileName, *keyArray)) {
+ QMessageBox::critical(nullptr, tr("Export Error"),
+ tr("Couldn't open %1 for writing")
+ .arg(QString::fromStdString(fileName)));
+ return;
+ }
+ }
}
QString KeyPairDetailTab::beautifyFingerprint(QString fingerprint) {
- uint len = fingerprint.length();
- if ((len > 0) && (len % 4 == 0))
- for (uint n = 0; 4 * (n + 1) < len; ++n)
- fingerprint.insert(static_cast<int>(5u * n + 4u), ' ');
- return fingerprint;
+ uint len = fingerprint.length();
+ if ((len > 0) && (len % 4 == 0))
+ for (uint n = 0; 4 * (n + 1) < len; ++n)
+ fingerprint.insert(static_cast<int>(5u * n + 4u), ' ');
+ return fingerprint;
}
void KeyPairDetailTab::slotCopyFingerprint() {
- QString fpr = fingerPrintVarLabel->text().trimmed().replace(" ", "");
- QClipboard *cb = QApplication::clipboard();
- cb->setText(fpr);
+ QString fpr = fingerPrintVarLabel->text().trimmed().replace(" ", "");
+ QClipboard* cb = QApplication::clipboard();
+ cb->setText(fpr);
}
void KeyPairDetailTab::slotModifyEditDatetime() {
- auto dialog = new KeySetExpireDateDialog(mCtx, mKey, nullptr, this);
- dialog->show();
+ auto dialog = new KeySetExpireDateDialog(mKey, this);
+ dialog->show();
}
void KeyPairDetailTab::slotRefreshKeyInfo() {
-
- nameVarLabel->setText(mKey.name);
- emailVarLabel->setText(mKey.email);
-
- commentVarLabel->setText(mKey.comment);
- keyidVarLabel->setText(mKey.id);
-
- QString usage;
- QTextStream usage_steam(&usage);
-
- if (mKey.can_certify)
- usage_steam << "Cert ";
- if (mKey.can_encrypt)
- usage_steam << "Encr ";
- if (mKey.can_sign)
- usage_steam << "Sign ";
- if (mKey.can_authenticate)
- usage_steam << "Auth ";
-
- usageVarLabel->setText(usage);
-
- QString actualUsage;
- QTextStream actual_usage_steam(&actualUsage);
-
- if (GpgFrontend::GpgContext::checkIfKeyCanCert(mKey))
- actual_usage_steam << "Cert ";
- if (GpgFrontend::GpgContext::checkIfKeyCanEncr(mKey))
- actual_usage_steam << "Encr ";
- if (GpgFrontend::GpgContext::checkIfKeyCanSign(mKey))
- actual_usage_steam << "Sign ";
- if (GpgFrontend::GpgContext::checkIfKeyCanAuth(mKey))
- actual_usage_steam << "Auth ";
-
- actualUsageVarLabel->setText(actualUsage);
-
- QString keySizeVal, keyExpireVal, keyCreateTimeVal, keyAlgoVal;
-
- keySizeVal = QString::number(mKey.length);
-
- if (mKey.expires.toTime_t() == 0) {
- keyExpireVal = tr("Never Expire");
- } else {
- keyExpireVal = mKey.expires.toString();
- }
-
- keyAlgoVal = mKey.pubkey_algo;
- keyCreateTimeVal = mKey.create_time.toString();
-
- keySizeVarLabel->setText(keySizeVal);
- expireVarLabel->setText(keyExpireVal);
- createdVarLabel->setText(keyCreateTimeVal);
- algorithmVarLabel->setText(keyAlgoVal);
-
- fingerPrintVarLabel->setText(beautifyFingerprint(mKey.fpr));
-
+ nameVarLabel->setText(QString::fromStdString(mKey.name()));
+ emailVarLabel->setText(QString::fromStdString(mKey.email()));
+
+ commentVarLabel->setText(QString::fromStdString(mKey.comment()));
+ keyidVarLabel->setText(QString::fromStdString(mKey.id()));
+
+ QString usage;
+ QTextStream usage_steam(&usage);
+
+ if (mKey.can_certify())
+ usage_steam << "Cert ";
+ if (mKey.can_encrypt())
+ usage_steam << "Encr ";
+ if (mKey.can_sign())
+ usage_steam << "Sign ";
+ if (mKey.can_authenticate())
+ usage_steam << "Auth ";
+
+ usageVarLabel->setText(usage);
+
+ QString actualUsage;
+ QTextStream actual_usage_steam(&actualUsage);
+
+ if (mKey.CanCertActual())
+ actual_usage_steam << "Cert ";
+ if (mKey.CanEncrActual())
+ actual_usage_steam << "Encr ";
+ if (mKey.CanSignActual())
+ actual_usage_steam << "Sign ";
+ if (mKey.CanAuthActual())
+ actual_usage_steam << "Auth ";
+
+ actualUsageVarLabel->setText(actualUsage);
+
+ QString keySizeVal, keyExpireVal, keyCreateTimeVal, keyAlgoVal;
+
+ keySizeVal = QString::number(mKey.length());
+
+ if (to_time_t(boost::posix_time::ptime(mKey.expires())) == 0) {
+ keyExpireVal = tr("Never Expire");
+ } else {
+ keyExpireVal =
+ QString::fromStdString(boost::gregorian::to_iso_string(mKey.expires()));
+ }
+
+ keyAlgoVal = QString::fromStdString(mKey.pubkey_algo());
+ keyCreateTimeVal = QString::fromStdString(to_iso_string(mKey.create_time()));
+
+ keySizeVarLabel->setText(keySizeVal);
+ expireVarLabel->setText(keyExpireVal);
+ createdVarLabel->setText(keyCreateTimeVal);
+ algorithmVarLabel->setText(keyAlgoVal);
+
+ auto key_fpr = mKey.fpr();
+ fingerPrintVarLabel->setText(
+ QString::fromStdString(beautify_fingerprint(key_fpr)));
}
void KeyPairDetailTab::createKeyServerOperaMenu() {
- keyServerOperaMenu = new QMenu(this);
-
- auto *uploadKeyPair = new QAction(tr("Upload Key Pair to Key Server"), this);
- connect(uploadKeyPair, SIGNAL(triggered()), this, SLOT(slotUploadKeyToServer()));
- auto *updateKeyPair = new QAction(tr("Update Key Pair"), this);
- connect(updateKeyPair, SIGNAL(triggered()), this, SLOT(slotUpdateKeyToServer()));
-
- keyServerOperaMenu->addAction(uploadKeyPair);
- // TODO Solve Refresh Problem
-// keyServerOperaMenu->addAction(updateKeyPair);
+ keyServerOperaMenu = new QMenu(this);
+
+ auto* uploadKeyPair = new QAction(tr("Upload Key Pair to Key Server"), this);
+ connect(uploadKeyPair, SIGNAL(triggered()), this,
+ SLOT(slotUploadKeyToServer()));
+ auto* updateKeyPair = new QAction(tr("Update Key Pair"), this);
+ connect(updateKeyPair, SIGNAL(triggered()), this,
+ SLOT(slotUpdateKeyToServer()));
+
+ keyServerOperaMenu->addAction(uploadKeyPair);
+ // TODO Solve Refresh Problem
+ // keyServerOperaMenu->addAction(updateKeyPair);
}
void KeyPairDetailTab::slotUploadKeyToServer() {
- QVector<GpgKey> keys;
- keys.append(mKey);
- auto *dialog = new KeyUploadDialog(mCtx, keys);
+ auto keys = std::make_unique<KeyIdArgsList>();
+ keys->push_back(mKey.id());
+ auto* dialog = new KeyUploadDialog(keys, this);
}
void KeyPairDetailTab::slotUpdateKeyToServer() {
- QVector<GpgKey> keys;
- keys.append(mKey);
- auto *dialog = new KeyServerImportDialog(mCtx, this);
- dialog->show();
- dialog->slotImportKey(keys);
+ auto keys = std::make_unique<KeyIdArgsList>();
+ keys->push_back(mKey.id());
+ auto* dialog = new KeyServerImportDialog(this);
+ dialog->show();
+ dialog->slotImportKey(keys);
}
void KeyPairDetailTab::slotGenRevokeCert() {
- auto mOutputFileName = QFileDialog::getSaveFileName(this, tr("Generate revocation certificate"),
- QString(),
- QStringLiteral("%1 (*.rev)").arg(
- tr("Revocation Certificates")));
-
- if (!mOutputFileName.isEmpty())
- mCtx->generateRevokeCert(mKey, mOutputFileName);
+ auto mOutputFileName = QFileDialog::getSaveFileName(
+ this, tr("Generate revocation certificate"), QString(),
+ QStringLiteral("%1 (*.rev)").arg(tr("Revocation Certificates")));
+ // if (!mOutputFileName.isEmpty())
+ // mCtx->generateRevokeCert(mKey, mOutputFileName);
}
+} // namespace GpgFrontend::UI
diff --git a/src/ui/keypair_details/KeyPairDetailTab.h b/src/ui/keypair_details/KeyPairDetailTab.h
new file mode 100644
index 00000000..a4978568
--- /dev/null
+++ b/src/ui/keypair_details/KeyPairDetailTab.h
@@ -0,0 +1,104 @@
+/**
+ * This file is part of GPGFrontend.
+ *
+ * GPGFrontend is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Foobar is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Foobar. If not, see <https://www.gnu.org/licenses/>.
+ *
+ * The initial version of the source code is inherited from gpg4usb-team.
+ * Their source code version also complies with GNU General Public License.
+ *
+ * The source code version of this software was modified and released
+ * by Saturneric<[email protected]><[email protected]> starting on May 12, 2021.
+ *
+ */
+
+#ifndef GPGFRONTEND_KEYPAIRDETAILTAB_H
+#define GPGFRONTEND_KEYPAIRDETAILTAB_H
+
+#include "gpg/GpgContext.h"
+#include "ui/GpgFrontendUI.h"
+
+#include "KeySetExpireDateDialog.h"
+#include "ui/KeyServerImportDialog.h"
+#include "ui/KeyUploadDialog.h"
+
+namespace GpgFrontend::UI {
+
+class KeyPairDetailTab : public QWidget {
+ Q_OBJECT
+
+ /**
+ * @details Return QString with a space inserted at every fourth character
+ *
+ * @param fingerprint The fingerprint to be beautified
+ */
+ static QString beautifyFingerprint(QString fingerprint);
+
+ void createKeyServerOperaMenu();
+
+ private slots:
+
+ /**
+ * @details Export the key to a file, which is choosen in a file dialog
+ */
+ void slotExportPrivateKey();
+
+ /**
+ * @details Copy the fingerprint to clipboard
+ */
+ void slotCopyFingerprint();
+
+ void slotModifyEditDatetime();
+
+ void slotRefreshKeyInfo();
+
+ void slotUploadKeyToServer();
+
+ void slotUpdateKeyToServer();
+
+ void slotGenRevokeCert();
+
+ private:
+ std::string keyid; /** The id of the key the details should be shown for */
+
+ GpgKey mKey;
+
+ QGroupBox* ownerBox; /** Groupbox containing owner information */
+ QGroupBox* keyBox; /** Groupbox containing key information */
+ QGroupBox* fingerprintBox; /** Groupbox containing fingerprint information */
+ QGroupBox* additionalUidBox; /** Groupbox containing information about
+ additional uids */
+
+ QLabel* nameVarLabel; /** Label containng the keys name */
+ QLabel* emailVarLabel; /** Label containng the keys email */
+ QLabel* commentVarLabel; /** Label containng the keys commment */
+ QLabel* keySizeVarLabel; /** Label containng the keys keysize */
+ QLabel* expireVarLabel; /** Label containng the keys expiration date */
+ QLabel* createdVarLabel; /** Label containng the keys creation date */
+ QLabel* algorithmVarLabel; /** Label containng the keys algorithm */
+ QLabel* keyidVarLabel; /** Label containng the keys keyid */
+ QLabel* fingerPrintVarLabel; /** Label containng the keys fingerprint */
+ QLabel* usageVarLabel;
+ QLabel* actualUsageVarLabel;
+ QLabel* masterKeyExistVarLabel;
+
+ QMenu* keyServerOperaMenu;
+
+ public:
+ explicit KeyPairDetailTab(const std::string& key_id,
+ QWidget* parent = nullptr);
+};
+
+} // namespace GpgFrontend::UI
+
+#endif // GPGFRONTEND_KEYPAIRDETAILTAB_H
diff --git a/src/ui/keypair_details/KeyPairSubkeyTab.cpp b/src/ui/keypair_details/KeyPairSubkeyTab.cpp
index e2714303..84d9f558 100644
--- a/src/ui/keypair_details/KeyPairSubkeyTab.cpp
+++ b/src/ui/keypair_details/KeyPairSubkeyTab.cpp
@@ -23,244 +23,262 @@
*/
#include "ui/keypair_details/KeyPairSubkeyTab.h"
-
-KeyPairSubkeyTab::KeyPairSubkeyTab(GpgFrontend::GpgContext *ctx, const GpgKey &key, QWidget *parent) : mCtx(ctx), mKey(key), QWidget(parent) {
-
- createSubkeyList();
- createSubkeyOperaMenu();
-
- listBox = new QGroupBox("Subkey List");
- detailBox = new QGroupBox("Detail of Selected Subkey");
-
- auto uidButtonsLayout = new QGridLayout();
-
- auto addSubkeyButton = new QPushButton(tr("Generate A New Subkey"));
- if(!mKey.is_private_key || !mKey.has_master_key) {
- addSubkeyButton->setDisabled(true);
- setHidden(addSubkeyButton);
- }
-
- uidButtonsLayout->addWidget(addSubkeyButton, 0, 1);
-
- auto *baseLayout = new QVBoxLayout();
-
- auto subkeyListLayout = new QGridLayout();
- subkeyListLayout->addWidget(subkeyList, 0, 0);
- subkeyListLayout->addLayout(uidButtonsLayout, 1, 0);
- subkeyListLayout->setContentsMargins(0, 10, 0, 0);
-
- auto *subkeyDetailLayout = new QGridLayout();
-
- subkeyDetailLayout->addWidget(new QLabel(tr("Key ID: ")), 0, 0);
- subkeyDetailLayout->addWidget(new QLabel(tr("Algorithm: ")), 1, 0);
- subkeyDetailLayout->addWidget(new QLabel(tr("Key Size:")), 2, 0);
- subkeyDetailLayout->addWidget(new QLabel(tr("Usage: ")), 3, 0);
- subkeyDetailLayout->addWidget(new QLabel(tr("Expires On ")), 4, 0);
- subkeyDetailLayout->addWidget(new QLabel(tr("Last Update: ")), 5, 0);
- subkeyDetailLayout->addWidget(new QLabel(tr("Existence: ")), 6, 0);
- subkeyDetailLayout->addWidget(new QLabel(tr("Fingerprint: ")), 7, 0);
-
-
- keyidVarLabel = new QLabel();
- keySizeVarLabel = new QLabel();
- expireVarLabel = new QLabel();
- algorithmVarLabel = new QLabel();
- createdVarLabel = new QLabel();
- usageVarLabel = new QLabel();
- masterKeyExistVarLabel = new QLabel();
- fingerPrintVarLabel = new QLabel();
-
- subkeyDetailLayout->addWidget(keyidVarLabel, 0, 1);
- subkeyDetailLayout->addWidget(keySizeVarLabel, 2, 1);
- subkeyDetailLayout->addWidget(expireVarLabel, 4, 1);
- subkeyDetailLayout->addWidget(algorithmVarLabel, 1, 1);
- subkeyDetailLayout->addWidget(createdVarLabel, 5, 1);
- subkeyDetailLayout->addWidget(usageVarLabel, 3, 1);
- subkeyDetailLayout->addWidget(masterKeyExistVarLabel, 6, 1);
- subkeyDetailLayout->addWidget(fingerPrintVarLabel, 7, 1);
-
- listBox->setLayout(subkeyListLayout);
- listBox->setContentsMargins(0, 5, 0, 0);
- detailBox->setLayout(subkeyDetailLayout);
-
- baseLayout->addWidget(listBox);
- baseLayout->addWidget(detailBox);
- baseLayout->addStretch();
-
- connect(addSubkeyButton, SIGNAL(clicked(bool)), this, SLOT(slotAddSubkey()));
- connect(mCtx, SIGNAL(signalKeyInfoChanged()), this, SLOT(slotRefreshSubkeyList()));
- connect(subkeyList, SIGNAL(itemSelectionChanged()), this, SLOT(slotRefreshSubkeyDetail()));
-
- baseLayout->setContentsMargins(0, 0, 0, 0);
-
- setLayout(baseLayout);
- setAttribute(Qt::WA_DeleteOnClose, true);
-
- slotRefreshSubkeyList();
-
+#include "gpg/function/GpgKeyGetter.h"
+
+namespace GpgFrontend::UI {
+
+KeyPairSubkeyTab::KeyPairSubkeyTab(const std::string& key_id, QWidget* parent)
+ : mKey(std::move(GpgKeyGetter::GetInstance().GetKey(key_id))),
+ QWidget(parent) {
+ createSubkeyList();
+ createSubkeyOperaMenu();
+
+ listBox = new QGroupBox("Subkey List");
+ detailBox = new QGroupBox("Detail of Selected Subkey");
+
+ auto uidButtonsLayout = new QGridLayout();
+
+ auto addSubkeyButton = new QPushButton(tr("Generate A New Subkey"));
+ if (!mKey.is_private_key() || !mKey.has_master_key()) {
+ addSubkeyButton->setDisabled(true);
+ setHidden(addSubkeyButton);
+ }
+
+ uidButtonsLayout->addWidget(addSubkeyButton, 0, 1);
+
+ auto* baseLayout = new QVBoxLayout();
+
+ auto subkeyListLayout = new QGridLayout();
+ subkeyListLayout->addWidget(subkeyList, 0, 0);
+ subkeyListLayout->addLayout(uidButtonsLayout, 1, 0);
+ subkeyListLayout->setContentsMargins(0, 10, 0, 0);
+
+ auto* subkeyDetailLayout = new QGridLayout();
+
+ subkeyDetailLayout->addWidget(new QLabel(tr("Key ID: ")), 0, 0);
+ subkeyDetailLayout->addWidget(new QLabel(tr("Algorithm: ")), 1, 0);
+ subkeyDetailLayout->addWidget(new QLabel(tr("Key Size:")), 2, 0);
+ subkeyDetailLayout->addWidget(new QLabel(tr("Usage: ")), 3, 0);
+ subkeyDetailLayout->addWidget(new QLabel(tr("Expires On ")), 4, 0);
+ subkeyDetailLayout->addWidget(new QLabel(tr("Last Update: ")), 5, 0);
+ subkeyDetailLayout->addWidget(new QLabel(tr("Existence: ")), 6, 0);
+ subkeyDetailLayout->addWidget(new QLabel(tr("Fingerprint: ")), 7, 0);
+
+ keyidVarLabel = new QLabel();
+ keySizeVarLabel = new QLabel();
+ expireVarLabel = new QLabel();
+ algorithmVarLabel = new QLabel();
+ createdVarLabel = new QLabel();
+ usageVarLabel = new QLabel();
+ masterKeyExistVarLabel = new QLabel();
+ fingerPrintVarLabel = new QLabel();
+
+ subkeyDetailLayout->addWidget(keyidVarLabel, 0, 1);
+ subkeyDetailLayout->addWidget(keySizeVarLabel, 2, 1);
+ subkeyDetailLayout->addWidget(expireVarLabel, 4, 1);
+ subkeyDetailLayout->addWidget(algorithmVarLabel, 1, 1);
+ subkeyDetailLayout->addWidget(createdVarLabel, 5, 1);
+ subkeyDetailLayout->addWidget(usageVarLabel, 3, 1);
+ subkeyDetailLayout->addWidget(masterKeyExistVarLabel, 6, 1);
+ subkeyDetailLayout->addWidget(fingerPrintVarLabel, 7, 1);
+
+ listBox->setLayout(subkeyListLayout);
+ listBox->setContentsMargins(0, 5, 0, 0);
+ detailBox->setLayout(subkeyDetailLayout);
+
+ baseLayout->addWidget(listBox);
+ baseLayout->addWidget(detailBox);
+ baseLayout->addStretch();
+
+ connect(addSubkeyButton, SIGNAL(clicked(bool)), this, SLOT(slotAddSubkey()));
+ connect(subkeyList, SIGNAL(itemSelectionChanged()), this,
+ SLOT(slotRefreshSubkeyDetail()));
+
+ baseLayout->setContentsMargins(0, 0, 0, 0);
+
+ setLayout(baseLayout);
+ setAttribute(Qt::WA_DeleteOnClose, true);
+
+ slotRefreshSubkeyList();
}
void KeyPairSubkeyTab::createSubkeyList() {
- subkeyList = new QTableWidget(this);
+ subkeyList = new QTableWidget(this);
- subkeyList->setColumnCount(5);
- subkeyList->horizontalHeader()->setSectionResizeMode(QHeaderView::ResizeToContents);
- subkeyList->verticalHeader()->hide();
- subkeyList->setShowGrid(false);
- subkeyList->setSelectionBehavior(QAbstractItemView::SelectRows);
+ subkeyList->setColumnCount(5);
+ subkeyList->horizontalHeader()->setSectionResizeMode(
+ QHeaderView::ResizeToContents);
+ subkeyList->verticalHeader()->hide();
+ subkeyList->setShowGrid(false);
+ subkeyList->setSelectionBehavior(QAbstractItemView::SelectRows);
- // tableitems not editable
- subkeyList->setEditTriggers(QAbstractItemView::NoEditTriggers);
+ // tableitems not editable
+ subkeyList->setEditTriggers(QAbstractItemView::NoEditTriggers);
- // no focus (rectangle around tableitems)
- // may be it should focus on whole row
- subkeyList->setFocusPolicy(Qt::NoFocus);
- subkeyList->setAlternatingRowColors(true);
+ // no focus (rectangle around tableitems)
+ // may be it should focus on whole row
+ subkeyList->setFocusPolicy(Qt::NoFocus);
+ subkeyList->setAlternatingRowColors(true);
- QStringList labels;
- labels << tr("Subkey ID") << tr("Key Size") << tr("Algo") << tr("Create Date") << tr("Expire Date");
+ QStringList labels;
+ labels << tr("Subkey ID") << tr("Key Size") << tr("Algo") << tr("Create Date")
+ << tr("Expire Date");
- subkeyList->setHorizontalHeaderLabels(labels);
- subkeyList->horizontalHeader()->setStretchLastSection(false);
+ subkeyList->setHorizontalHeaderLabels(labels);
+ subkeyList->horizontalHeader()->setStretchLastSection(false);
}
void KeyPairSubkeyTab::slotRefreshSubkeyList() {
- int row = 0;
-
- subkeyList->setSelectionMode(QAbstractItemView::SingleSelection);
-
- this->buffered_subkeys.clear();
-
- for(const auto &subkeys : mKey.subKeys) {
- if(subkeys.disabled || subkeys.revoked)
- continue;
- this->buffered_subkeys.push_back(&subkeys);
- }
-
- subkeyList->setRowCount(buffered_subkeys.size());
-
- for(const auto& subkeys : buffered_subkeys) {
-
- auto *tmp0 = new QTableWidgetItem(subkeys->id);
- tmp0->setTextAlignment(Qt::AlignCenter);
- subkeyList->setItem(row, 0, tmp0);
-
- auto *tmp1 = new QTableWidgetItem(QString::number(subkeys->length));
- tmp1->setTextAlignment(Qt::AlignCenter);
- subkeyList->setItem(row, 1, tmp1);
-
- auto *tmp2 = new QTableWidgetItem(subkeys->pubkey_algo);
- tmp2->setTextAlignment(Qt::AlignCenter);
- subkeyList->setItem(row, 2, tmp2);
-
- auto *tmp3= new QTableWidgetItem(subkeys->timestamp.toString());
- tmp3->setTextAlignment(Qt::AlignCenter);
- subkeyList->setItem(row, 3, tmp3);
-
- auto *tmp4= new QTableWidgetItem(subkeys->expires.toTime_t() == 0 ? tr("Never Expire") : subkeys->expires.toString());
- tmp4->setTextAlignment(Qt::AlignCenter);
- subkeyList->setItem(row, 4, tmp4);
-
- row++;
- }
-
- if(subkeyList->rowCount() > 0) {
- subkeyList->selectRow(0);
- }
+ int row = 0;
+
+ subkeyList->setSelectionMode(QAbstractItemView::SingleSelection);
+
+ this->buffered_subkeys.clear();
+ auto sub_keys = mKey.subKeys();
+ for (auto& sub_key : *sub_keys) {
+ if (sub_key.disabled() || sub_key.revoked())
+ continue;
+ this->buffered_subkeys.push_back(std::move(sub_key));
+ }
+
+ subkeyList->setRowCount(buffered_subkeys.size());
+
+ for (const auto& subkeys : buffered_subkeys) {
+ auto* tmp0 = new QTableWidgetItem(QString::fromStdString(subkeys.id()));
+ tmp0->setTextAlignment(Qt::AlignCenter);
+ subkeyList->setItem(row, 0, tmp0);
+
+ auto* tmp1 = new QTableWidgetItem(QString::number(subkeys.length()));
+ tmp1->setTextAlignment(Qt::AlignCenter);
+ subkeyList->setItem(row, 1, tmp1);
+
+ auto* tmp2 =
+ new QTableWidgetItem(QString::fromStdString(subkeys.pubkey_algo()));
+ tmp2->setTextAlignment(Qt::AlignCenter);
+ subkeyList->setItem(row, 2, tmp2);
+
+ auto* tmp3 = new QTableWidgetItem(
+ QString::fromStdString(to_iso_string(subkeys.timestamp())));
+ tmp3->setTextAlignment(Qt::AlignCenter);
+ subkeyList->setItem(row, 3, tmp3);
+
+ auto* tmp4 = new QTableWidgetItem(
+ boost::posix_time::to_time_t(
+ boost::posix_time::ptime(subkeys.expires())) == 0
+ ? tr("Never Expire")
+ : QString::fromStdString(to_iso_string(subkeys.expires())));
+ tmp4->setTextAlignment(Qt::AlignCenter);
+ subkeyList->setItem(row, 4, tmp4);
+
+ row++;
+ }
+
+ if (subkeyList->rowCount() > 0) {
+ subkeyList->selectRow(0);
+ }
}
void KeyPairSubkeyTab::slotAddSubkey() {
- auto dialog = new SubkeyGenerateDialog(mCtx, mKey, this);
- dialog->show();
+ auto dialog = new SubkeyGenerateDialog(mKey, this);
+ dialog->show();
}
void KeyPairSubkeyTab::slotRefreshSubkeyDetail() {
-
- auto key = getSelectedSubkey();
-
- keyidVarLabel->setText(key->id);
- keySizeVarLabel->setText(QString::number(key->length));
-
- expireVarLabel->setText(key->expires.toTime_t() == 0 ? tr("Never Expires") : key->expires.toString());
- if(key->expires.toTime_t() != 0 && key->expires < QDateTime::currentDateTime()) {
- auto paletteExpired = expireVarLabel->palette();
- paletteExpired.setColor(expireVarLabel->foregroundRole(), Qt::red);
- expireVarLabel->setPalette(paletteExpired);
- } else {
- auto paletteValid = expireVarLabel->palette();
- paletteValid.setColor(expireVarLabel->foregroundRole(), Qt::darkGreen);
- expireVarLabel->setPalette(paletteValid);
- }
-
- algorithmVarLabel->setText(key->pubkey_algo);
- createdVarLabel->setText(key->timestamp.toString());
-
- QString usage;
- QTextStream usage_steam(&usage);
-
- if(key->can_certify)
- usage_steam << "Cert ";
- if(key->can_encrypt)
- usage_steam << "Encr ";
- if(key->can_sign)
- usage_steam << "Sign ";
- if(key->can_authenticate)
- usage_steam << "Auth ";
-
- usageVarLabel->setText(usage);
-
- // Show the situation that master key not exists.
- masterKeyExistVarLabel->setText(key->secret ? "Exists" : "Not Exists");
- if(!key->secret){
- auto paletteExpired = masterKeyExistVarLabel->palette();
- paletteExpired.setColor(masterKeyExistVarLabel->foregroundRole(), Qt::red);
- masterKeyExistVarLabel->setPalette(paletteExpired);
- } else {
- auto paletteValid = masterKeyExistVarLabel->palette();
- paletteValid.setColor(masterKeyExistVarLabel->foregroundRole(), Qt::darkGreen);
- masterKeyExistVarLabel->setPalette(paletteValid);
- }
-
- fingerPrintVarLabel->setText(key->fpr);
+ auto& subkey = getSelectedSubkey();
+
+ keyidVarLabel->setText(QString::fromStdString(subkey.id()));
+ keySizeVarLabel->setText(QString::number(subkey.length()));
+
+ time_t subkey_time_t =
+ boost::posix_time::to_time_t(boost::posix_time::ptime(subkey.expires()));
+
+ expireVarLabel->setText(
+ subkey_time_t == 0
+ ? tr("Never Expires")
+ : QString::fromStdString(to_iso_string(subkey.expires())));
+ if (subkey_time_t != 0 &&
+ subkey.expires() < boost::posix_time::second_clock::local_time().date()) {
+ auto paletteExpired = expireVarLabel->palette();
+ paletteExpired.setColor(expireVarLabel->foregroundRole(), Qt::red);
+ expireVarLabel->setPalette(paletteExpired);
+ } else {
+ auto paletteValid = expireVarLabel->palette();
+ paletteValid.setColor(expireVarLabel->foregroundRole(), Qt::darkGreen);
+ expireVarLabel->setPalette(paletteValid);
+ }
+
+ algorithmVarLabel->setText(QString::fromStdString(subkey.pubkey_algo()));
+ createdVarLabel->setText(
+ QString::fromStdString(to_iso_string(subkey.timestamp())));
+
+ QString usage;
+ QTextStream usage_steam(&usage);
+
+ if (subkey.can_certify())
+ usage_steam << "Cert ";
+ if (subkey.can_encrypt())
+ usage_steam << "Encr ";
+ if (subkey.can_sign())
+ usage_steam << "Sign ";
+ if (subkey.can_authenticate())
+ usage_steam << "Auth ";
+
+ usageVarLabel->setText(usage);
+
+ // Show the situation that master key not exists.
+ masterKeyExistVarLabel->setText(subkey.secret() ? "Exists" : "Not Exists");
+ if (!subkey.secret()) {
+ auto paletteExpired = masterKeyExistVarLabel->palette();
+ paletteExpired.setColor(masterKeyExistVarLabel->foregroundRole(), Qt::red);
+ masterKeyExistVarLabel->setPalette(paletteExpired);
+ } else {
+ auto paletteValid = masterKeyExistVarLabel->palette();
+ paletteValid.setColor(masterKeyExistVarLabel->foregroundRole(),
+ Qt::darkGreen);
+ masterKeyExistVarLabel->setPalette(paletteValid);
+ }
+
+ fingerPrintVarLabel->setText(QString::fromStdString(subkey.fpr()));
}
void KeyPairSubkeyTab::createSubkeyOperaMenu() {
- subkeyOperaMenu = new QMenu(this);
- // auto *revokeSubkeyAct = new QAction(tr("Revoke Subkey"));
- auto *editSubkeyAct = new QAction(tr("Edit Expire Date"));
- connect(editSubkeyAct, SIGNAL(triggered(bool)), this, SLOT(slotEditSubkey()));
+ subkeyOperaMenu = new QMenu(this);
+ // auto *revokeSubkeyAct = new QAction(tr("Revoke Subkey"));
+ auto* editSubkeyAct = new QAction(tr("Edit Expire Date"));
+ connect(editSubkeyAct, SIGNAL(triggered(bool)), this, SLOT(slotEditSubkey()));
- // subkeyOperaMenu->addAction(revokeSubkeyAct);
- subkeyOperaMenu->addAction(editSubkeyAct);
+ // subkeyOperaMenu->addAction(revokeSubkeyAct);
+ subkeyOperaMenu->addAction(editSubkeyAct);
}
void KeyPairSubkeyTab::slotEditSubkey() {
- qDebug() << "Slot Edit Subkry";
- auto *subkey = getSelectedSubkey();
- if(subkey == buffered_subkeys[0]) {
- subkey = nullptr;
- }
- auto dialog = new KeySetExpireDateDialog(mCtx, mKey, subkey, this);
- dialog->show();
+ qDebug() << "Slot Edit Subkry";
+ auto subkey_id = std::make_unique<std::string>(getSelectedSubkey().id());
+ if (*subkey_id == buffered_subkeys[0].id()) {
+ subkey_id = nullptr;
+ }
+ auto dialog = new KeySetExpireDateDialog(mKey, subkey_id, this);
+ dialog->show();
}
-void KeyPairSubkeyTab::slotRevokeSubkey() {
-
-}
+void KeyPairSubkeyTab::slotRevokeSubkey() {}
-void KeyPairSubkeyTab::contextMenuEvent(QContextMenuEvent *event) {
- if (!subkeyList->selectedItems().isEmpty()) {
- subkeyOperaMenu->exec(event->globalPos());
- }
+void KeyPairSubkeyTab::contextMenuEvent(QContextMenuEvent* event) {
+ if (!subkeyList->selectedItems().isEmpty()) {
+ subkeyOperaMenu->exec(event->globalPos());
+ }
}
-const GpgSubKey *KeyPairSubkeyTab::getSelectedSubkey() {
- int row = 0;
+const GpgSubKey& KeyPairSubkeyTab::getSelectedSubkey() {
+ int row = 0;
- for(int i = 0 ; i < subkeyList->rowCount(); i++) {
- if(subkeyList->item(row, 0)->isSelected()) break;
- row++;
- }
+ for (int i = 0; i < subkeyList->rowCount(); i++) {
+ if (subkeyList->item(row, 0)->isSelected())
+ break;
+ row++;
+ }
- return buffered_subkeys[row];
+ return buffered_subkeys[row];
}
+
+} // namespace GpgFrontend::UI
diff --git a/src/ui/keypair_details/KeyPairSubkeyTab.h b/src/ui/keypair_details/KeyPairSubkeyTab.h
new file mode 100644
index 00000000..642d0cf4
--- /dev/null
+++ b/src/ui/keypair_details/KeyPairSubkeyTab.h
@@ -0,0 +1,85 @@
+/**
+ * This file is part of GPGFrontend.
+ *
+ * GPGFrontend is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Foobar is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Foobar. If not, see <https://www.gnu.org/licenses/>.
+ *
+ * The initial version of the source code is inherited from gpg4usb-team.
+ * Their source code version also complies with GNU General Public License.
+ *
+ * The source code version of this software was modified and released
+ * by Saturneric<[email protected]> starting on May 12, 2021.
+ *
+ */
+
+#ifndef GPGFRONTEND_KEYPAIRSUBKEYTAB_H
+#define GPGFRONTEND_KEYPAIRSUBKEYTAB_H
+
+#include "ui/GpgFrontendUI.h"
+
+#include "KeySetExpireDateDialog.h"
+#include "gpg/GpgContext.h"
+#include "ui/keygen/SubkeyGenerateDialog.h"
+
+namespace GpgFrontend::UI {
+
+class KeyPairSubkeyTab : public QWidget {
+ Q_OBJECT
+
+ public:
+ KeyPairSubkeyTab(const std::string& key, QWidget* parent);
+
+ private:
+ void createSubkeyList();
+
+ void createSubkeyOperaMenu();
+
+ const GpgSubKey& getSelectedSubkey();
+
+ GpgKey mKey;
+ QTableWidget* subkeyList{};
+ std::vector<GpgSubKey> buffered_subkeys;
+
+ QGroupBox* listBox;
+ QGroupBox* detailBox;
+
+ QMenu* subkeyOperaMenu{};
+
+ QLabel* keySizeVarLabel; /** Label containng the keys keysize */
+ QLabel* expireVarLabel; /** Label containng the keys expiration date */
+ QLabel* createdVarLabel; /** Label containng the keys creation date */
+ QLabel* algorithmVarLabel; /** Label containng the keys algorithm */
+ QLabel* keyidVarLabel; /** Label containng the keys keyid */
+ QLabel* fingerPrintVarLabel; /** Label containng the keys fingerprint */
+ QLabel* usageVarLabel;
+ QLabel* masterKeyExistVarLabel;
+
+ private slots:
+
+ void slotAddSubkey();
+
+ void slotRefreshSubkeyList();
+
+ void slotRefreshSubkeyDetail();
+
+ void slotEditSubkey();
+
+ void slotRevokeSubkey();
+
+ protected:
+ void contextMenuEvent(QContextMenuEvent* event) override;
+};
+
+} // namespace GpgFrontend::UI
+
+#endif // GPGFRONTEND_KEYPAIRSUBKEYTAB_H
diff --git a/src/ui/keypair_details/KeyPairUIDTab.cpp b/src/ui/keypair_details/KeyPairUIDTab.cpp
index fed500a4..075db08e 100644
--- a/src/ui/keypair_details/KeyPairUIDTab.cpp
+++ b/src/ui/keypair_details/KeyPairUIDTab.cpp
@@ -23,489 +23,483 @@
*/
#include "ui/keypair_details/KeyPairUIDTab.h"
+#include "gpg/function/GpgKeyGetter.h"
+#include "gpg/function/GpgKeyManager.h"
+#include "gpg/function/UidOperator.h"
-KeyPairUIDTab::KeyPairUIDTab(GpgFrontend::GpgContext *ctx, const GpgKey &key, QWidget *parent) : QWidget(parent), mKey(key) {
+namespace GpgFrontend::UI {
- mCtx = ctx;
+KeyPairUIDTab::KeyPairUIDTab(const std::string& key_id, QWidget* parent)
+ : QWidget(parent),
+ mKey(std::move(GpgKeyGetter::GetInstance().GetKey(key_id))) {
+ createUIDList();
+ createSignList();
+ createManageUIDMenu();
+ createUIDPopupMenu();
+ createSignPopupMenu();
- createUIDList();
- createSignList();
- createManageUIDMenu();
- createUIDPopupMenu();
- createSignPopupMenu();
+ auto uidButtonsLayout = new QGridLayout();
- auto uidButtonsLayout = new QGridLayout();
+ auto addUIDButton = new QPushButton(tr("New UID"));
+ auto manageUIDButton = new QPushButton(tr("UID Management"));
- auto addUIDButton = new QPushButton(tr("New UID"));
- auto manageUIDButton = new QPushButton(tr("UID Management"));
+ if (mKey.has_master_key()) {
+ manageUIDButton->setMenu(manageSelectedUIDMenu);
+ } else {
+ manageUIDButton->setDisabled(true);
+ }
- if(mKey.has_master_key) {
- manageUIDButton->setMenu(manageSelectedUIDMenu);
- } else {
- manageUIDButton->setDisabled(true);
- }
-
- uidButtonsLayout->addWidget(addUIDButton, 0, 1);
- uidButtonsLayout->addWidget(manageUIDButton, 0, 2);
+ uidButtonsLayout->addWidget(addUIDButton, 0, 1);
+ uidButtonsLayout->addWidget(manageUIDButton, 0, 2);
- auto gridLayout = new QGridLayout();
+ auto gridLayout = new QGridLayout();
- gridLayout->addWidget(uidList, 0, 0);
- gridLayout->addLayout(uidButtonsLayout, 1, 0);
- gridLayout->setContentsMargins(0, 10, 0, 0);
+ gridLayout->addWidget(uidList, 0, 0);
+ gridLayout->addLayout(uidButtonsLayout, 1, 0);
+ gridLayout->setContentsMargins(0, 10, 0, 0);
- auto uidGroupBox = new QGroupBox();
- uidGroupBox->setLayout(gridLayout);
- uidGroupBox->setTitle(tr("UIDs"));
+ auto uidGroupBox = new QGroupBox();
+ uidGroupBox->setLayout(gridLayout);
+ uidGroupBox->setTitle(tr("UIDs"));
- auto signGridLayout = new QGridLayout();
- signGridLayout->addWidget(sigList, 0, 0);
- signGridLayout->setContentsMargins(0, 10, 0, 0);
+ auto signGridLayout = new QGridLayout();
+ signGridLayout->addWidget(sigList, 0, 0);
+ signGridLayout->setContentsMargins(0, 10, 0, 0);
- auto signGroupBox = new QGroupBox();
- signGroupBox->setLayout(signGridLayout);
- signGroupBox->setTitle(tr("Signature of Selected UID"));
+ auto signGroupBox = new QGroupBox();
+ signGroupBox->setLayout(signGridLayout);
+ signGroupBox->setTitle(tr("Signature of Selected UID"));
- auto vboxLayout = new QVBoxLayout();
- vboxLayout->addWidget(uidGroupBox);
- vboxLayout->addWidget(signGroupBox);
- vboxLayout->setContentsMargins(0, 0, 0, 0);
+ auto vboxLayout = new QVBoxLayout();
+ vboxLayout->addWidget(uidGroupBox);
+ vboxLayout->addWidget(signGroupBox);
+ vboxLayout->setContentsMargins(0, 0, 0, 0);
- connect(addUIDButton, SIGNAL(clicked(bool)), this, SLOT(slotAddUID()));
- connect(mCtx, SIGNAL(signalKeyInfoChanged()), this, SLOT(slotRefreshUIDList()));
- connect(uidList, SIGNAL(itemSelectionChanged()), this, SLOT(slotRefreshSigList()));
+ connect(addUIDButton, SIGNAL(clicked(bool)), this, SLOT(slotAddUID()));
+ connect(uidList, SIGNAL(itemSelectionChanged()), this,
+ SLOT(slotRefreshSigList()));
- setLayout(vboxLayout);
- setAttribute(Qt::WA_DeleteOnClose, true);
+ setLayout(vboxLayout);
+ setAttribute(Qt::WA_DeleteOnClose, true);
- slotRefreshUIDList();
+ slotRefreshUIDList();
}
void KeyPairUIDTab::createUIDList() {
-
- uidList = new QTableWidget(this);
- uidList->setColumnCount(4);
- uidList->horizontalHeader()->setSectionResizeMode(QHeaderView::ResizeToContents);
- uidList->verticalHeader()->hide();
- uidList->setShowGrid(false);
- uidList->setSelectionBehavior(QAbstractItemView::SelectRows);
- uidList->setSelectionMode( QAbstractItemView::SingleSelection );
-
- // tableitems not editable
- uidList->setEditTriggers(QAbstractItemView::NoEditTriggers);
-
- // no focus (rectangle around tableitems)
- // may be it should focus on whole row
- uidList->setFocusPolicy(Qt::NoFocus);
- uidList->setAlternatingRowColors(true);
-
- QStringList labels;
- labels << tr("Select") << tr("Name") << tr("Email") << tr("Comment");
- uidList->setHorizontalHeaderLabels(labels);
- uidList->horizontalHeader()->setStretchLastSection(true);
+ uidList = new QTableWidget(this);
+ uidList->setColumnCount(4);
+ uidList->horizontalHeader()->setSectionResizeMode(
+ QHeaderView::ResizeToContents);
+ uidList->verticalHeader()->hide();
+ uidList->setShowGrid(false);
+ uidList->setSelectionBehavior(QAbstractItemView::SelectRows);
+ uidList->setSelectionMode(QAbstractItemView::SingleSelection);
+
+ // tableitems not editable
+ uidList->setEditTriggers(QAbstractItemView::NoEditTriggers);
+
+ // no focus (rectangle around tableitems)
+ // may be it should focus on whole row
+ uidList->setFocusPolicy(Qt::NoFocus);
+ uidList->setAlternatingRowColors(true);
+
+ QStringList labels;
+ labels << tr("Select") << tr("Name") << tr("Email") << tr("Comment");
+ uidList->setHorizontalHeaderLabels(labels);
+ uidList->horizontalHeader()->setStretchLastSection(true);
}
void KeyPairUIDTab::createSignList() {
-
- sigList = new QTableWidget(this);
- sigList->setColumnCount(5);
- sigList->horizontalHeader()->setSectionResizeMode(QHeaderView::ResizeToContents);
- sigList->verticalHeader()->hide();
- sigList->setShowGrid(false);
- sigList->setSelectionBehavior(QAbstractItemView::SelectRows);
-
- // table items not editable
- sigList->setEditTriggers(QAbstractItemView::NoEditTriggers);
-
- // no focus (rectangle around table items)
- // may be it should focus on whole row
- sigList->setFocusPolicy(Qt::NoFocus);
- sigList->setAlternatingRowColors(true);
-
- QStringList labels;
- labels << tr("Key ID") << tr("Name") << tr("Email") << tr("Create Date") << tr("Expired Date");
- sigList->setHorizontalHeaderLabels(labels);
- sigList->horizontalHeader()->setStretchLastSection(false);
-
+ sigList = new QTableWidget(this);
+ sigList->setColumnCount(5);
+ sigList->horizontalHeader()->setSectionResizeMode(
+ QHeaderView::ResizeToContents);
+ sigList->verticalHeader()->hide();
+ sigList->setShowGrid(false);
+ sigList->setSelectionBehavior(QAbstractItemView::SelectRows);
+
+ // table items not editable
+ sigList->setEditTriggers(QAbstractItemView::NoEditTriggers);
+
+ // no focus (rectangle around table items)
+ // may be it should focus on whole row
+ sigList->setFocusPolicy(Qt::NoFocus);
+ sigList->setAlternatingRowColors(true);
+
+ QStringList labels;
+ labels << tr("Key ID") << tr("Name") << tr("Email") << tr("Create Date")
+ << tr("Expired Date");
+ sigList->setHorizontalHeaderLabels(labels);
+ sigList->horizontalHeader()->setStretchLastSection(false);
}
void KeyPairUIDTab::slotRefreshUIDList() {
+ int row = 0;
- int row = 0;
-
- uidList->setSelectionMode(QAbstractItemView::SingleSelection);
+ uidList->setSelectionMode(QAbstractItemView::SingleSelection);
- this->buffered_uids.clear();
+ this->buffered_uids.clear();
- for(const auto &uid : mKey.uids) {
- if(uid.invalid || uid.revoked) {
- continue;
- }
- this->buffered_uids.push_back(&uid);
+ auto uids = mKey.uids();
+ for (auto& uid : *uids) {
+ if (uid.invalid() || uid.revoked()) {
+ continue;
}
+ this->buffered_uids.push_back(std::move(uid));
+ }
- uidList->setRowCount(buffered_uids.size());
+ uidList->setRowCount(buffered_uids.size());
- for(const auto& uid : buffered_uids) {
+ for (const auto& uid : buffered_uids) {
+ auto* tmp0 = new QTableWidgetItem(QString::fromStdString(uid.name()));
+ uidList->setItem(row, 1, tmp0);
- auto *tmp0 = new QTableWidgetItem(uid->name);
- uidList->setItem(row, 1, tmp0);
+ auto* tmp1 = new QTableWidgetItem(QString::fromStdString(uid.email()));
+ uidList->setItem(row, 2, tmp1);
- auto *tmp1 = new QTableWidgetItem(uid->email);
- uidList->setItem(row, 2, tmp1);
+ auto* tmp2 = new QTableWidgetItem(QString::fromStdString(uid.comment()));
+ uidList->setItem(row, 3, tmp2);
- auto *tmp2 = new QTableWidgetItem(uid->comment);
- uidList->setItem(row, 3, tmp2);
+ auto* tmp3 = new QTableWidgetItem(QString::number(row));
+ tmp3->setFlags(Qt::ItemIsUserCheckable | Qt::ItemIsEnabled |
+ Qt::ItemIsSelectable);
+ tmp3->setTextAlignment(Qt::AlignCenter);
+ tmp3->setCheckState(Qt::Unchecked);
+ uidList->setItem(row, 0, tmp3);
- auto *tmp3 = new QTableWidgetItem(QString::number(row));
- tmp3->setFlags(Qt::ItemIsUserCheckable | Qt::ItemIsEnabled | Qt::ItemIsSelectable);
- tmp3->setTextAlignment(Qt::AlignCenter);
- tmp3->setCheckState(Qt::Unchecked);
- uidList->setItem(row, 0, tmp3);
+ row++;
+ }
- row++;
- }
-
- if(uidList->rowCount() > 0) {
- uidList->selectRow(0);
- }
+ if (uidList->rowCount() > 0) {
+ uidList->selectRow(0);
+ }
- slotRefreshSigList();
+ slotRefreshSigList();
}
void KeyPairUIDTab::slotRefreshSigList() {
+ int uidRow = 0, sigRow = 0;
+ for (const auto& uid : buffered_uids) {
+ // Only Show Selected UID Signatures
+ if (!uidList->item(uidRow++, 0)->isSelected()) {
+ continue;
+ }
- int uidRow = 0, sigRow = 0;
- for(const auto& uid : buffered_uids) {
-
- // Only Show Selected UID Signatures
- if(!uidList->item(uidRow++, 0)->isSelected()) {
- continue;
- }
-
- buffered_signatures.clear();
-
- for(const auto &sig : uid->signatures) {
- if(sig.invalid || sig.revoked) {
- continue;
- }
- buffered_signatures.push_back(&sig);
- }
-
- sigList->setRowCount(buffered_signatures.size());
-
- for(const auto &sig : buffered_signatures) {
+ buffered_signatures.clear();
+ auto signatures = uid.signatures();
+ for (auto& sig : *signatures) {
+ if (sig.invalid() || sig.revoked()) {
+ continue;
+ }
+ buffered_signatures.push_back(std::move(sig));
+ }
- auto *tmp0 = new QTableWidgetItem(sig->keyid);
- sigList->setItem(sigRow, 0, tmp0);
+ sigList->setRowCount(buffered_signatures.size());
- if(gpgme_err_code(sig->status) == GPG_ERR_NO_PUBKEY) {
- auto *tmp2 = new QTableWidgetItem("<Unknown>");
- sigList->setItem(sigRow, 1, tmp2);
+ for (const auto& sig : buffered_signatures) {
+ auto* tmp0 = new QTableWidgetItem(QString::fromStdString(sig.keyid()));
+ sigList->setItem(sigRow, 0, tmp0);
- auto *tmp3 = new QTableWidgetItem("<Unknown>");
- sigList->setItem(sigRow, 2, tmp3);
- } else {
- auto *tmp2 = new QTableWidgetItem(sig->name);
- sigList->setItem(sigRow, 1, tmp2);
+ if (gpgme_err_code(sig.status()) == GPG_ERR_NO_PUBKEY) {
+ auto* tmp2 = new QTableWidgetItem("<Unknown>");
+ sigList->setItem(sigRow, 1, tmp2);
- auto *tmp3 = new QTableWidgetItem(sig->email);
- sigList->setItem(sigRow, 2, tmp3);
- }
+ auto* tmp3 = new QTableWidgetItem("<Unknown>");
+ sigList->setItem(sigRow, 2, tmp3);
+ } else {
+ auto* tmp2 = new QTableWidgetItem(QString::fromStdString(sig.name()));
+ sigList->setItem(sigRow, 1, tmp2);
- auto *tmp4 = new QTableWidgetItem(sig->create_time.toString());
- sigList->setItem(sigRow, 3, tmp4);
+ auto* tmp3 = new QTableWidgetItem(QString::fromStdString(sig.email()));
+ sigList->setItem(sigRow, 2, tmp3);
+ }
- auto *tmp5 = new QTableWidgetItem(sig->expire_time.toTime_t() == 0 ? tr("Never Expires") : sig->expire_time.toString());
- tmp5->setTextAlignment(Qt::AlignCenter);
- sigList->setItem(sigRow, 4, tmp5);
+ auto* tmp4 = new QTableWidgetItem(QString::fromStdString(
+ boost::gregorian::to_iso_string(sig.create_time())));
+ sigList->setItem(sigRow, 3, tmp4);
- sigRow++;
- }
+ auto* tmp5 = new QTableWidgetItem(
+ boost::posix_time::to_time_t(
+ boost::posix_time::ptime(sig.expire_time())) == 0
+ ? tr("Never Expires")
+ : QString::fromStdString(
+ boost::gregorian::to_iso_string(sig.expire_time())));
+ tmp5->setTextAlignment(Qt::AlignCenter);
+ sigList->setItem(sigRow, 4, tmp5);
- break;
+ sigRow++;
}
+
+ break;
+ }
}
void KeyPairUIDTab::slotAddSign() {
+ auto selected_uids = getUIDChecked();
- QVector<GpgUID> selected_uids;
- getUIDChecked(selected_uids);
+ if (selected_uids->empty()) {
+ QMessageBox::information(
+ nullptr, tr("Invalid Operation"),
+ tr("Please select one or more UIDs before doing this operation."));
+ return;
+ }
- if(selected_uids.isEmpty()) {
- QMessageBox::information(nullptr,
- tr("Invalid Operation"),
- tr("Please select one or more UIDs before doing this operation."));
- return;
- }
-
- auto keySignDialog = new KeyUIDSignDialog(mCtx, mKey, selected_uids, this);
- keySignDialog->show();
+ auto keySignDialog = new KeyUIDSignDialog(mKey, selected_uids, this);
+ keySignDialog->show();
}
-
-
-void KeyPairUIDTab::getUIDChecked(QVector<GpgUID> &selected_uids) {
-
- auto &uids = buffered_uids;
-
- for (int i = 0; i < uidList->rowCount(); i++) {
- if (uidList->item(i, 0)->checkState() == Qt::Checked) {
- selected_uids.push_back(*uids[i]);
- }
- }
+UIDArgsListPtr KeyPairUIDTab::getUIDChecked() {
+ auto selected_uids = std::make_unique<UIDArgsList>();
+ for (int i = 0; i < uidList->rowCount(); i++) {
+ if (uidList->item(i, 0)->checkState() == Qt::Checked)
+ selected_uids->push_back(buffered_uids[i].uid());
+ }
+ return selected_uids;
}
void KeyPairUIDTab::createManageUIDMenu() {
+ manageSelectedUIDMenu = new QMenu(this);
- manageSelectedUIDMenu = new QMenu(this);
+ auto* signUIDAct = new QAction(tr("Sign Selected UID(s)"), this);
+ connect(signUIDAct, SIGNAL(triggered()), this, SLOT(slotAddSign()));
+ auto* delUIDAct = new QAction(tr("Delete Selected UID(s)"), this);
+ connect(delUIDAct, SIGNAL(triggered()), this, SLOT(slotDelUID()));
- auto *signUIDAct = new QAction(tr("Sign Selected UID(s)"), this);
- connect(signUIDAct, SIGNAL(triggered()), this, SLOT(slotAddSign()));
- auto *delUIDAct = new QAction(tr("Delete Selected UID(s)"), this);
- connect(delUIDAct, SIGNAL(triggered()), this, SLOT(slotDelUID()));
-
- if(mKey.has_master_key) {
- manageSelectedUIDMenu->addAction(signUIDAct);
- manageSelectedUIDMenu->addAction(delUIDAct);
- }
+ if (mKey.has_master_key()) {
+ manageSelectedUIDMenu->addAction(signUIDAct);
+ manageSelectedUIDMenu->addAction(delUIDAct);
+ }
}
void KeyPairUIDTab::slotAddUID() {
- auto keyNewUIDDialog = new KeyNewUIDDialog(mCtx, mKey, this);
- connect(keyNewUIDDialog, SIGNAL(finished(int)), this, SLOT(slotAddUIDResult(int)));
- connect(keyNewUIDDialog, SIGNAL(finished(int)), keyNewUIDDialog, SLOT(deleteLater()));
- keyNewUIDDialog->show();
+ auto keyNewUIDDialog = new KeyNewUIDDialog(mKey.id(), this);
+ connect(keyNewUIDDialog, SIGNAL(finished(int)), this,
+ SLOT(slotAddUIDResult(int)));
+ connect(keyNewUIDDialog, SIGNAL(finished(int)), keyNewUIDDialog,
+ SLOT(deleteLater()));
+ keyNewUIDDialog->show();
}
void KeyPairUIDTab::slotAddUIDResult(int result) {
- if(result == 1) {
- QMessageBox::information(nullptr,
- tr("Successful Operation"),
- tr("Successfully added a new UID."));
- } else if (result == -1) {
- QMessageBox::critical(nullptr,
- tr("Operation Failed"),
- tr("An error occurred during the operation."));
- }
+ if (result == 1) {
+ QMessageBox::information(nullptr, tr("Successful Operation"),
+ tr("Successfully added a new UID."));
+ } else if (result == -1) {
+ QMessageBox::critical(nullptr, tr("Operation Failed"),
+ tr("An error occurred during the operation."));
+ }
}
void KeyPairUIDTab::slotDelUID() {
-
- QVector<GpgUID> selected_uids;
- getUIDChecked(selected_uids);
-
- if(selected_uids.isEmpty()) {
- QMessageBox::information(nullptr,
- tr("Invalid Operation"),
- tr("Please select one or more UIDs before doing this operation."));
- return;
+ auto selected_uids = getUIDChecked();
+
+ if (selected_uids->empty()) {
+ QMessageBox::information(
+ nullptr, tr("Invalid Operation"),
+ tr("Please select one or more UIDs before doing this operation."));
+ return;
+ }
+
+ QString keynames;
+ for (auto& uid : *selected_uids) {
+ keynames.append(QString::fromStdString(uid));
+ keynames.append("<br/>");
+ }
+
+ int ret = QMessageBox::warning(
+ this, tr("Deleting UIDs"),
+ "<b>" + tr("Are you sure that you want to delete the following uids?") +
+ "</b><br/><br/>" + keynames + +"<br/>" +
+ tr("The action can not be undone."),
+ QMessageBox::No | QMessageBox::Yes);
+
+ bool if_success = true;
+
+ if (ret == QMessageBox::Yes) {
+ for (const auto& uid : *selected_uids) {
+ if (UidOperator::GetInstance().revUID(mKey, uid)) {
+ if_success = false;
+ }
}
- QString keynames;
- for (const auto &uid : selected_uids) {
- keynames.append(uid.name);
- keynames.append("<i> &lt;");
- keynames.append(uid.email);
- keynames.append("&gt; </i><br/>");
- }
-
- int ret = QMessageBox::warning(this, tr("Deleting UIDs"),
- "<b>"+tr("Are you sure that you want to delete the following uids?")+"</b><br/><br/>"+keynames+
- +"<br/>"+tr("The action can not be undone."),
- QMessageBox::No | QMessageBox::Yes);
-
-
- bool if_success = true;
-
- if (ret == QMessageBox::Yes) {
- for(const auto &uid : selected_uids) {
- if(!mCtx->revUID(mKey, uid)) {
- if_success = false;
- }
- }
-
- if(!if_success) {
- QMessageBox::critical(nullptr,
- tr("Operation Failed"),
- tr("An error occurred during the operation."));
- }
-
+ if (!if_success) {
+ QMessageBox::critical(nullptr, tr("Operation Failed"),
+ tr("An error occurred during the operation."));
}
+ }
}
void KeyPairUIDTab::slotSetPrimaryUID() {
-
- GpgUID selected_uid;
-
- if(!getUIDSelected(selected_uid)) {
- auto emptyUIDMsg = new QMessageBox();
- emptyUIDMsg->setText("Please select one UID before doing this operation.");
- emptyUIDMsg->exec();
- return;
- }
-
- QString keynames;
-
- keynames.append(selected_uid.name);
- keynames.append("<i> &lt;");
- keynames.append(selected_uid.email);
- keynames.append("&gt; </i><br/>");
-
- int ret = QMessageBox::warning(this, tr("Set Primary UID"),
- "<b>"+tr("Are you sure that you want to set the Primary UID to?")+"</b><br/><br/>"+keynames+
- +"<br/>"+tr("The action can not be undone."),
- QMessageBox::No | QMessageBox::Yes);
-
- if (ret == QMessageBox::Yes) {
- if(!mCtx->setPrimaryUID(mKey, selected_uid)) {
- QMessageBox::critical(nullptr,
- tr("Operation Failed"),
- tr("An error occurred during the operation."));
- }
+ auto selected_uids = getUIDSelected();
+
+ if (selected_uids->empty()) {
+ auto emptyUIDMsg = new QMessageBox();
+ emptyUIDMsg->setText("Please select one UID before doing this operation.");
+ emptyUIDMsg->exec();
+ return;
+ }
+
+ QString keynames;
+
+ keynames.append(QString::fromStdString(selected_uids->front()));
+ keynames.append("<br/>");
+
+ int ret = QMessageBox::warning(
+ this, tr("Set Primary UID"),
+ "<b>" + tr("Are you sure that you want to set the Primary UID to?") +
+ "</b><br/><br/>" + keynames + +"<br/>" +
+ tr("The action can not be undone."),
+ QMessageBox::No | QMessageBox::Yes);
+
+ if (ret == QMessageBox::Yes) {
+ if (!UidOperator::GetInstance().setPrimaryUID(mKey,
+ selected_uids->front())) {
+ QMessageBox::critical(nullptr, tr("Operation Failed"),
+ tr("An error occurred during the operation."));
}
+ }
}
-bool KeyPairUIDTab::getUIDSelected(GpgUID &uid) {
- auto &uids = buffered_uids;
- for (int i = 0; i < uidList->rowCount(); i++) {
- if (uidList->item(i, 0)->isSelected()) {
- uid = *uids[i];
- return true;
- }
+UIDArgsListPtr KeyPairUIDTab::getUIDSelected() {
+ auto uids = std::make_unique<UIDArgsList>();
+ for (int i = 0; i < uidList->rowCount(); i++) {
+ if (uidList->item(i, 0)->isSelected()) {
+ uids->push_back(buffered_uids[i].uid());
}
- return false;
+ }
+ return std::move(uids);
}
-bool KeyPairUIDTab::getSignSelected(GpgKeySignature &signature) {
- auto &signatures = buffered_signatures;
- for (int i = 0; i < sigList->rowCount(); i++) {
- if (sigList->item(i, 0)->isSelected()) {
- signature = *signatures[i];
- return true;
- }
+SignIdArgsListPtr KeyPairUIDTab::getSignSelected() {
+ auto signatures = std::make_unique<SignIdArgsList>();
+ for (int i = 0; i < sigList->rowCount(); i++) {
+ if (sigList->item(i, 0)->isSelected()) {
+ auto& sign = buffered_signatures[i];
+ signatures->push_back({sign.keyid(), sign.uid()});
}
- return false;
+ }
+ return signatures;
}
void KeyPairUIDTab::createUIDPopupMenu() {
-
- uidPopupMenu = new QMenu(this);
-
- auto *serPrimaryUIDAct = new QAction(tr("Set As Primary"), this);
- connect(serPrimaryUIDAct, SIGNAL(triggered()), this, SLOT(slotSetPrimaryUID()));
- auto *signUIDAct = new QAction(tr("Sign UID"), this);
- connect(signUIDAct, SIGNAL(triggered()), this, SLOT(slotAddSignSingle()));
- auto *delUIDAct = new QAction(tr("Delete UID"), this);
- connect(delUIDAct, SIGNAL(triggered()), this, SLOT(slotDelUIDSingle()));
-
- if(mKey.has_master_key) {
- uidPopupMenu->addAction(serPrimaryUIDAct);
- uidPopupMenu->addAction(signUIDAct);
- uidPopupMenu->addAction(delUIDAct);
- }
+ uidPopupMenu = new QMenu(this);
+
+ auto* serPrimaryUIDAct = new QAction(tr("Set As Primary"), this);
+ connect(serPrimaryUIDAct, SIGNAL(triggered()), this,
+ SLOT(slotSetPrimaryUID()));
+ auto* signUIDAct = new QAction(tr("Sign UID"), this);
+ connect(signUIDAct, SIGNAL(triggered()), this, SLOT(slotAddSignSingle()));
+ auto* delUIDAct = new QAction(tr("Delete UID"), this);
+ connect(delUIDAct, SIGNAL(triggered()), this, SLOT(slotDelUIDSingle()));
+
+ if (mKey.has_master_key()) {
+ uidPopupMenu->addAction(serPrimaryUIDAct);
+ uidPopupMenu->addAction(signUIDAct);
+ uidPopupMenu->addAction(delUIDAct);
+ }
}
-void KeyPairUIDTab::contextMenuEvent(QContextMenuEvent *event) {
- if (uidList->selectedItems().length() > 0 && sigList->selectedItems().isEmpty()) {
- uidPopupMenu->exec(event->globalPos());
- }
+void KeyPairUIDTab::contextMenuEvent(QContextMenuEvent* event) {
+ if (uidList->selectedItems().length() > 0 &&
+ sigList->selectedItems().isEmpty()) {
+ uidPopupMenu->exec(event->globalPos());
+ }
- if (!sigList->selectedItems().isEmpty()) {
- signPopupMenu->exec(event->globalPos());
- }
+ if (!sigList->selectedItems().isEmpty()) {
+ signPopupMenu->exec(event->globalPos());
+ }
}
void KeyPairUIDTab::slotAddSignSingle() {
+ auto selected_uids = getUIDSelected();
- GpgUID selected_uid;
+ if (selected_uids->empty()) {
+ QMessageBox::information(
+ nullptr, tr("Invalid Operation"),
+ tr("Please select one UID before doing this operation."));
+ return;
+ }
- if(!getUIDSelected(selected_uid)) {
- QMessageBox::information(nullptr,
- tr("Invalid Operation"),
- tr("Please select one UID before doing this operation."));
- return;
- }
-
- auto selected_uids = QVector<GpgUID>({selected_uid });
- auto keySignDialog = new KeyUIDSignDialog(mCtx, mKey, selected_uids, this);
- keySignDialog->show();
+ auto keySignDialog = new KeyUIDSignDialog(mKey, selected_uids, this);
+ keySignDialog->show();
}
void KeyPairUIDTab::slotDelUIDSingle() {
- GpgUID selected_uid;
-
- if(!getUIDSelected(selected_uid)) {
- QMessageBox::information(nullptr,
- tr("Invalid Operation"),
- tr("Please select one UID before doing this operation."));
- return;
- }
-
- QString keynames;
-
- keynames.append(selected_uid.name);
- keynames.append("<i> &lt;");
- keynames.append(selected_uid.email);
- keynames.append("&gt; </i><br/>");
-
- int ret = QMessageBox::warning(this, tr("Deleting UID"),
- "<b>"+tr("Are you sure that you want to delete the following uid?")+"</b><br/><br/>"+keynames+
- +"<br/>"+tr("The action can not be undone."),
- QMessageBox::No | QMessageBox::Yes);
-
- if (ret == QMessageBox::Yes) {
- if(!mCtx->revUID(mKey, selected_uid)) {
- QMessageBox::critical(nullptr,
- tr("Operation Failed"),
- tr("An error occurred during the operation."));
- }
+ auto selected_uids = getUIDSelected();
+ if (selected_uids->empty()) {
+ QMessageBox::information(
+ nullptr, tr("Invalid Operation"),
+ tr("Please select one UID before doing this operation."));
+ return;
+ }
+
+ QString keynames;
+
+ keynames.append(QString::fromStdString(selected_uids->front()));
+ keynames.append("<br/>");
+
+ int ret = QMessageBox::warning(
+ this, tr("Deleting UID"),
+ "<b>" + tr("Are you sure that you want to delete the following uid?") +
+ "</b><br/><br/>" + keynames + +"<br/>" +
+ tr("The action can not be undone."),
+ QMessageBox::No | QMessageBox::Yes);
+
+ if (ret == QMessageBox::Yes) {
+ if (!UidOperator::GetInstance().revUID(mKey, selected_uids->front())) {
+ QMessageBox::critical(nullptr, tr("Operation Failed"),
+ tr("An error occurred during the operation."));
}
+ }
}
void KeyPairUIDTab::createSignPopupMenu() {
- signPopupMenu = new QMenu(this);
+ signPopupMenu = new QMenu(this);
- auto *delSignAct = new QAction(tr("Delete(Revoke) Key Signature"), this);
- connect(delSignAct, SIGNAL(triggered()), this, SLOT(slotDelSign()));
+ auto* delSignAct = new QAction(tr("Delete(Revoke) Key Signature"), this);
+ connect(delSignAct, SIGNAL(triggered()), this, SLOT(slotDelSign()));
- signPopupMenu->addAction(delSignAct);
+ signPopupMenu->addAction(delSignAct);
}
void KeyPairUIDTab::slotDelSign() {
- GpgKeySignature selected_sign;
-
- if(!getSignSelected(selected_sign)) {
- QMessageBox::information(nullptr,
- tr("Invalid Operation"),
- tr("Please select one Key Signature before doing this operation."));
- return;
- }
-
- if(gpgme_err_code(selected_sign.status) == GPG_ERR_NO_PUBKEY) {
- QMessageBox::critical(nullptr,
- tr("Invalid Operation"),
- tr("To delete the signature, you need to have its corresponding public key in the local database."));
- return;
- }
-
- QString keynames;
-
- keynames.append(selected_sign.name);
- keynames.append("<i> &lt;");
- keynames.append(selected_sign.email);
- keynames.append("&gt; </i><br/>");
-
- int ret = QMessageBox::warning(this, tr("Deleting Key Signature"),
- "<b>"+tr("Are you sure that you want to delete the following signature?")+"</b><br/><br/>"+keynames+
- +"<br/>"+tr("The action can not be undone."),
- QMessageBox::No | QMessageBox::Yes);
-
- if (ret == QMessageBox::Yes) {
- if(!mCtx->revSign(mKey, selected_sign)) {
- QMessageBox::critical(nullptr,
- tr("Operation Failed"),
- tr("An error occurred during the operation."));
- }
+ auto selected_signs = getSignSelected();
+ if (selected_signs->empty()) {
+ QMessageBox::information(
+ nullptr, tr("Invalid Operation"),
+ tr("Please select one Key Signature before doing this operation."));
+ return;
+ }
+
+ if (!GpgKeyGetter::GetInstance()
+ .GetKey(selected_signs->front().first)
+ .good()) {
+ QMessageBox::critical(
+ nullptr, tr("Invalid Operation"),
+ tr("To delete the signature, you need to have its corresponding public "
+ "key in the local database."));
+ return;
+ }
+
+ QString keynames;
+
+ keynames.append(QString::fromStdString(selected_signs->front().second));
+ keynames.append("<br/>");
+
+ int ret = QMessageBox::warning(
+ this, tr("Deleting Key Signature"),
+ "<b>" +
+ tr("Are you sure that you want to delete the following signature?") +
+ "</b><br/><br/>" + keynames + +"<br/>" +
+ tr("The action can not be undone."),
+ QMessageBox::No | QMessageBox::Yes);
+
+ if (ret == QMessageBox::Yes) {
+ if (!GpgKeyManager::GetInstance().revSign(mKey, selected_signs)) {
+ QMessageBox::critical(nullptr, tr("Operation Failed"),
+ tr("An error occurred during the operation."));
}
+ }
}
+
+} // namespace GpgFrontend::UI
diff --git a/include/ui/keypair_details/KeyPairUIDTab.h b/src/ui/keypair_details/KeyPairUIDTab.h
index 3056687d..0246ead2 100644
--- a/include/ui/keypair_details/KeyPairUIDTab.h
+++ b/src/ui/keypair_details/KeyPairUIDTab.h
@@ -25,74 +25,72 @@
#ifndef GPGFRONTEND_KEYPAIRUIDTAB_H
#define GPGFRONTEND_KEYPAIRUIDTAB_H
-#include "GpgFrontend.h"
#include "gpg/GpgContext.h"
+#include "ui/GpgFrontendUI.h"
-#include "KeyUIDSignDialog.h"
#include "KeyNewUIDDialog.h"
+#include "KeyUIDSignDialog.h"
-class KeyPairUIDTab : public QWidget {
-Q_OBJECT
-
-public:
-
- KeyPairUIDTab(GpgFrontend::GpgContext *ctx, const GpgKey &key, QWidget *parent);
-
-private:
+namespace GpgFrontend::UI {
- void createUIDList();
+class KeyPairUIDTab : public QWidget {
+ Q_OBJECT
- void createSignList();
+ public:
+ KeyPairUIDTab(const std::string& key_id, QWidget* parent);
- void createManageUIDMenu();
+ private:
+ GpgKey mKey;
+ QTableWidget* uidList{};
+ QTableWidget* sigList{};
+ QMenu* manageSelectedUIDMenu{};
+ QMenu* uidPopupMenu{};
+ QMenu* signPopupMenu{};
+ std::vector<GpgUID> buffered_uids;
+ std::vector<GpgKeySignature> buffered_signatures;
- void createUIDPopupMenu();
+ void createUIDList();
- void createSignPopupMenu();
+ void createSignList();
- void getUIDChecked(QVector<GpgUID> &uids);
+ void createManageUIDMenu();
- bool getUIDSelected(GpgUID &uid);
+ void createUIDPopupMenu();
- bool getSignSelected(GpgKeySignature &signature);
+ void createSignPopupMenu();
- GpgFrontend::GpgContext *mCtx;
- const GpgKey &mKey;
- QTableWidget *uidList{};
- QTableWidget *sigList{};
- QMenu *manageSelectedUIDMenu;
- QMenu *uidPopupMenu;
- QMenu *signPopupMenu;
- QVector<const GpgUID *> buffered_uids;
- QVector<const GpgKeySignature *> buffered_signatures;
+ UIDArgsListPtr getUIDChecked();
-private slots:
+ UIDArgsListPtr getUIDSelected();
- void slotRefreshUIDList();
+ SignIdArgsListPtr getSignSelected();
- void slotRefreshSigList();
+ private slots:
- void slotAddSign();
+ void slotRefreshUIDList();
- void slotAddSignSingle();
+ void slotRefreshSigList();
- void slotAddUID();
+ void slotAddSign();
- void slotDelUID();
+ void slotAddSignSingle();
- void slotDelUIDSingle();
+ void slotAddUID();
- void slotSetPrimaryUID();
+ void slotDelUID();
- void slotDelSign();
+ void slotDelUIDSingle();
- static void slotAddUIDResult(int result);
+ void slotSetPrimaryUID();
-protected:
+ void slotDelSign();
- void contextMenuEvent(QContextMenuEvent *event) override;
+ static void slotAddUIDResult(int result);
+ protected:
+ void contextMenuEvent(QContextMenuEvent* event) override;
};
+} // namespace GpgFrontend::UI
-#endif //GPGFRONTEND_KEYPAIRUIDTAB_H
+#endif // GPGFRONTEND_KEYPAIRUIDTAB_H
diff --git a/src/ui/keypair_details/KeySetExpireDateDialog.cpp b/src/ui/keypair_details/KeySetExpireDateDialog.cpp
index da4f63cf..788adf44 100644
--- a/src/ui/keypair_details/KeySetExpireDateDialog.cpp
+++ b/src/ui/keypair_details/KeySetExpireDateDialog.cpp
@@ -24,51 +24,69 @@
#include "ui/keypair_details/KeySetExpireDateDialog.h"
-KeySetExpireDateDialog::KeySetExpireDateDialog(GpgFrontend::GpgContext *ctx, const GpgKey &key, const GpgSubKey *subkey, QWidget *parent) :
-QDialog(parent), mKey(key), mSubkey(subkey), mCtx(ctx) {
+#include "gpg/function/GpgKeyGetter.h"
+#include "gpg/function/GpgKeyOpera.h"
- QDateTime maxDateTime = QDateTime::currentDateTime().addYears(2);
- dateTimeEdit = new QDateTimeEdit(maxDateTime);
- dateTimeEdit->setMinimumDateTime(QDateTime::currentDateTime().addSecs(1));
- dateTimeEdit->setMaximumDateTime(maxDateTime);
- nonExpiredCheck = new QCheckBox();
- nonExpiredCheck->setTristate(false);
- confirmButton = new QPushButton(tr("Confirm"));
+namespace GpgFrontend::UI {
- auto *gridLayout = new QGridLayout();
- gridLayout->addWidget(dateTimeEdit, 0, 0, 1, 2);
- gridLayout->addWidget(nonExpiredCheck, 0, 2, 1, 1, Qt::AlignRight);
- gridLayout->addWidget(new QLabel(tr("Never Expire")), 0, 3);
- gridLayout->addWidget(confirmButton, 1, 3);
-
- connect(nonExpiredCheck, SIGNAL(stateChanged(int)), this, SLOT(slotNonExpiredChecked(int)));
- connect(confirmButton, SIGNAL(clicked(bool)), this, SLOT(slotConfirm()));
+KeySetExpireDateDialog::KeySetExpireDateDialog(const KeyId& key_id,
+ QWidget* parent)
+ : QDialog(parent), mKey(GpgKeyGetter::GetInstance().GetKey(key_id)) {
+ init();
+}
- this->setLayout(gridLayout);
- this->setWindowTitle("Edit Expire Datetime");
- this->setModal(true);
- this->setAttribute(Qt::WA_DeleteOnClose, true);
+KeySetExpireDateDialog::KeySetExpireDateDialog(const KeyId& key_id,
+ const std::string& subkey_id,
+ QWidget* parent)
+ : QDialog(parent),
+ mKey(GpgKeyGetter::GetInstance().GetKey(key_id)),
+ mSubkey(subkey_id) {
+ init();
}
void KeySetExpireDateDialog::slotConfirm() {
- QDateTime *expires = nullptr;
- if(this->nonExpiredCheck->checkState() == Qt::Unchecked) {
- expires = new QDateTime(this->dateTimeEdit->dateTime());
- }
+ std::unique_ptr<boost::gregorian::date> expires = nullptr;
+ if (this->nonExpiredCheck->checkState() == Qt::Unchecked) {
+ expires = std::make_unique<boost::gregorian::date>(
+ boost::posix_time::from_time_t(
+ this->dateTimeEdit->dateTime().toTime_t())
+ .date());
+ }
+ GpgKeyOpera::GetInstance().SetExpire(mKey, mSubkey, expires);
+ this->close();
+}
+
+void KeySetExpireDateDialog::init() {
+ QDateTime maxDateTime = QDateTime::currentDateTime().addYears(2);
+ dateTimeEdit = new QDateTimeEdit(maxDateTime);
+ dateTimeEdit->setMinimumDateTime(QDateTime::currentDateTime().addSecs(1));
+ dateTimeEdit->setMaximumDateTime(maxDateTime);
+ nonExpiredCheck = new QCheckBox();
+ nonExpiredCheck->setTristate(false);
+ confirmButton = new QPushButton(tr("Confirm"));
- if(!mCtx->setExpire(mKey, mSubkey, expires)) {
- QMessageBox::critical(nullptr,
- tr("Operation Failed"),
- tr("An error occurred during the operation."));
- }
- delete expires;
- this->close();
+ auto* gridLayout = new QGridLayout();
+ gridLayout->addWidget(dateTimeEdit, 0, 0, 1, 2);
+ gridLayout->addWidget(nonExpiredCheck, 0, 2, 1, 1, Qt::AlignRight);
+ gridLayout->addWidget(new QLabel(tr("Never Expire")), 0, 3);
+ gridLayout->addWidget(confirmButton, 1, 3);
+
+ connect(nonExpiredCheck, SIGNAL(stateChanged(int)), this,
+ SLOT(slotNonExpiredChecked(int)));
+ connect(confirmButton, SIGNAL(clicked(bool)), this, SLOT(slotConfirm()));
+
+ this->setLayout(gridLayout);
+ this->setWindowTitle("Edit Expire Datetime");
+ this->setModal(true);
+ this->setAttribute(Qt::WA_DeleteOnClose, true);
}
void KeySetExpireDateDialog::slotNonExpiredChecked(int state) {
- if(state == 0) {
- this->dateTimeEdit->setDisabled(false);
- } else {
- this->dateTimeEdit->setDisabled(true);
- }
+ if (state == 0) {
+ this->dateTimeEdit->setDisabled(false);
+ } else {
+ this->dateTimeEdit->setDisabled(true);
+ }
}
+
+} // namespace GpgFrontend::UI
diff --git a/include/ui/keypair_details/KeySetExpireDateDialog.h b/src/ui/keypair_details/KeySetExpireDateDialog.h
index 11f2a560..d7c19eaa 100644
--- a/include/ui/keypair_details/KeySetExpireDateDialog.h
+++ b/src/ui/keypair_details/KeySetExpireDateDialog.h
@@ -25,29 +25,39 @@
#ifndef GPGFRONTEND_KEYSETEXPIREDATEDIALOG_H
#define GPGFRONTEND_KEYSETEXPIREDATEDIALOG_H
-#include "GpgFrontend.h"
#include "gpg/GpgContext.h"
#include "gpg/model/GpgKey.h"
#include "gpg/model/GpgSubKey.h"
+#include "ui/GpgFrontendUI.h"
+
+namespace GpgFrontend::UI {
class KeySetExpireDateDialog : public QDialog {
-Q_OBJECT
-public:
- explicit KeySetExpireDateDialog(GpgFrontend::GpgContext *ctx, const GpgKey &key, const GpgSubKey *subkey, QWidget *parent = nullptr);
-
-private:
- GpgFrontend::GpgContext *mCtx;
- const GpgKey &mKey;
- const GpgSubKey *mSubkey;
-
- QDateTimeEdit *dateTimeEdit{};
- QPushButton *confirmButton{};
- QCheckBox *nonExpiredCheck{};
-
-private slots:
- void slotConfirm();
- void slotNonExpiredChecked(int state);
+ Q_OBJECT
+ public:
+ explicit KeySetExpireDateDialog(const KeyId& key_id,
+ QWidget* parent = nullptr);
+
+ explicit KeySetExpireDateDialog(const KeyId& key_id,
+ const std::string& subkey_id,
+ QWidget* parent = nullptr);
+
+ private:
+
+ void init();
+
+ const GpgKey mKey;
+ const SubkeyId mSubkey;
+
+ QDateTimeEdit* dateTimeEdit{};
+ QPushButton* confirmButton{};
+ QCheckBox* nonExpiredCheck{};
+
+ private slots:
+ void slotConfirm();
+ void slotNonExpiredChecked(int state);
};
+} // namespace GpgFrontend::UI
-#endif //GPGFRONTEND_KEYSETEXPIREDATEDIALOG_H
+#endif // GPGFRONTEND_KEYSETEXPIREDATEDIALOG_H
diff --git a/src/ui/keypair_details/KeyUIDSignDialog.cpp b/src/ui/keypair_details/KeyUIDSignDialog.cpp
index 90b2033c..f49a16bc 100644
--- a/src/ui/keypair_details/KeyUIDSignDialog.cpp
+++ b/src/ui/keypair_details/KeyUIDSignDialog.cpp
@@ -23,89 +23,99 @@
*/
#include "ui/keypair_details/KeyUIDSignDialog.h"
-
-KeyUIDSignDialog::KeyUIDSignDialog(GpgFrontend::GpgContext *ctx, const GpgKey &key, const QVector<GpgUID> &uid, QWidget *parent) :
- mKey(key), mCtx(ctx), mUids(uid), QDialog(parent) {
-
- mKeyList = new KeyList(ctx,
- KeyListRow::ONLY_SECRET_KEY,
- KeyListColumn::NAME | KeyListColumn::EmailAddress,
- this);
-
- mKeyList->setFilter([](const GpgKey &key) -> bool {
- if(key.disabled || !key.can_certify || !key.has_master_key || key.expired || key.revoked) return false;
- else return true;
- });
- mKeyList->setExcludeKeys({key.id});
- mKeyList->slotRefresh();
-
- signKeyButton = new QPushButton("Sign");
-
- /**
- * A DateTime after 5 Years is recommend.
- */
- expiresEdit = new QDateTimeEdit(QDateTime::currentDateTime().addYears(5));
- expiresEdit->setMinimumDateTime(QDateTime::currentDateTime());
-
- /**
- * Note further that the OpenPGP protocol uses 32 bit values for timestamps
- * and thus can only encode dates up to the year 2106.
- */
- expiresEdit->setMaximumDate(QDate(2106, 1, 1));
-
- nonExpireCheck = new QCheckBox("Non Expired");
- nonExpireCheck->setTristate(false);
-
- connect(nonExpireCheck, &QCheckBox::stateChanged, this, [this] (int state) -> void {
- if(state == 0)
- expiresEdit->setDisabled(false);
- else
- expiresEdit->setDisabled(true);
- });
-
- auto layout = new QGridLayout();
-
- auto timeLayout = new QGridLayout();
-
- layout->addWidget(mKeyList, 0, 0);
- layout->addWidget(signKeyButton, 2, 0, Qt::AlignRight);
- timeLayout->addWidget(new QLabel(tr("Expire Date")), 0, 0);
- timeLayout->addWidget(expiresEdit, 0, 1);
- timeLayout->addWidget(nonExpireCheck, 0, 2);
- layout->addLayout(timeLayout, 1, 0);
-
- connect(signKeyButton, SIGNAL(clicked(bool)), this, SLOT(slotSignKey(bool)));
-
- this->setLayout(layout);
- this->setModal(true);
- this->setWindowTitle(tr("Sign For Key's UID(s)"));
- this->adjustSize();
-
- setAttribute(Qt::WA_DeleteOnClose, true);
+#include "gpg/function/GpgKeyGetter.h"
+#include "gpg/function/GpgKeyManager.h"
+
+namespace GpgFrontend::UI {
+
+KeyUIDSignDialog::KeyUIDSignDialog(const GpgKey& key,
+ const UIDArgsListPtr& uid,
+ QWidget* parent)
+ : mKey(key), mUids(uid), QDialog(parent) {
+ mKeyList =
+ new KeyList(KeyListRow::ONLY_SECRET_KEY,
+ KeyListColumn::NAME | KeyListColumn::EmailAddress, this);
+
+ mKeyList->setFilter([](const GpgKey& key) -> bool {
+ if (key.disabled() || !key.can_certify() || !key.has_master_key() ||
+ key.expired() || key.revoked())
+ return false;
+ else
+ return true;
+ });
+ mKeyList->setExcludeKeys({key.id()});
+ mKeyList->slotRefresh();
+
+ signKeyButton = new QPushButton("Sign");
+
+ /**
+ * A DateTime after 5 Years is recommend.
+ */
+ expiresEdit = new QDateTimeEdit(QDateTime::currentDateTime().addYears(5));
+ expiresEdit->setMinimumDateTime(QDateTime::currentDateTime());
+
+ /**
+ * Note further that the OpenPGP protocol uses 32 bit values for timestamps
+ * and thus can only encode dates up to the year 2106.
+ */
+ expiresEdit->setMaximumDate(QDate(2106, 1, 1));
+
+ nonExpireCheck = new QCheckBox("Non Expired");
+ nonExpireCheck->setTristate(false);
+
+ connect(nonExpireCheck, &QCheckBox::stateChanged, this,
+ [this](int state) -> void {
+ if (state == 0)
+ expiresEdit->setDisabled(false);
+ else
+ expiresEdit->setDisabled(true);
+ });
+
+ auto layout = new QGridLayout();
+
+ auto timeLayout = new QGridLayout();
+
+ layout->addWidget(mKeyList, 0, 0);
+ layout->addWidget(signKeyButton, 2, 0, Qt::AlignRight);
+ timeLayout->addWidget(new QLabel(tr("Expire Date")), 0, 0);
+ timeLayout->addWidget(expiresEdit, 0, 1);
+ timeLayout->addWidget(nonExpireCheck, 0, 2);
+ layout->addLayout(timeLayout, 1, 0);
+
+ connect(signKeyButton, SIGNAL(clicked(bool)), this, SLOT(slotSignKey(bool)));
+
+ this->setLayout(layout);
+ this->setModal(true);
+ this->setWindowTitle(tr("Sign For Key's UID(s)"));
+ this->adjustSize();
+
+ setAttribute(Qt::WA_DeleteOnClose, true);
}
void KeyUIDSignDialog::slotSignKey(bool clicked) {
-
- // Set Signers
- QVector<GpgKey> keys;
- mKeyList->getCheckedKeys(keys);
-
- const auto expires = expiresEdit->dateTime();
-
- for(const auto &uid : mUids) {
- // Sign For mKey
- if (!mCtx->signKey(mKey, keys, uid.uid, &expires)) {
- QMessageBox::critical(nullptr,
- tr("Unsuccessful Operation"),
- QString(tr("Signature operation failed for UID ") + "%1")
- .arg(uid.uid));
- }
-
+ // Set Signers
+ auto key_ids = mKeyList->getChecked();
+ auto keys = GpgKeyGetter::GetInstance().GetKeys(std::move(key_ids));
+
+ auto expires = std::make_unique<boost::gregorian::date>(
+ boost::posix_time::from_time_t(expiresEdit->dateTime().toTime_t())
+ .date());
+
+ for (const auto& uid : *mUids) {
+ // Sign For mKey
+ if (!GpgKeyManager::GetInstance().signKey(mKey, *keys, uid, expires)) {
+ QMessageBox::critical(
+ nullptr, tr("Unsuccessful Operation"),
+ QString(tr("Signature operation failed for UID ") + "%1")
+ .arg(uid.c_str()));
}
+ }
- QMessageBox::information(nullptr,
- tr("Operation Complete"),
- tr("The signature operation of the UID is complete"));
+ QMessageBox::information(
+ nullptr, tr("Operation Complete"),
+ tr("The signature operation of the UID is complete"));
- this->close();
+ this->close();
}
+
+} // namespace GpgFrontend::UI
diff --git a/include/ui/keypair_details/KeyUIDSignDialog.h b/src/ui/keypair_details/KeyUIDSignDialog.h
index fcbb4fbd..cd35c4e6 100644
--- a/include/ui/keypair_details/KeyUIDSignDialog.h
+++ b/src/ui/keypair_details/KeyUIDSignDialog.h
@@ -25,40 +25,38 @@
#ifndef GPGFRONTEND_KEYUIDSIGNDIALOG_H
#define GPGFRONTEND_KEYUIDSIGNDIALOG_H
-#include "GpgFrontend.h"
-
#include "gpg/GpgContext.h"
+#include "ui/GpgFrontendUI.h"
#include "ui/widgets/KeyList.h"
-class KeyUIDSignDialog : public QDialog {
- Q_OBJECT
-
-public:
-
- explicit KeyUIDSignDialog(GpgFrontend::GpgContext *ctx, const GpgKey &key, const QVector<GpgUID> &uid, QWidget *parent = nullptr);
+namespace GpgFrontend::UI {
-private:
-
- GpgFrontend::GpgContext *mCtx;
-
- KeyList *mKeyList;
+class KeyUIDSignDialog : public QDialog {
+ Q_OBJECT
- QPushButton *signKeyButton;
+ public:
+ explicit KeyUIDSignDialog(const GpgKey& key,
+ const UIDArgsListPtr& uid,
+ QWidget* parent = nullptr);
- QDateTimeEdit *expiresEdit;
+ private:
+ KeyList* mKeyList;
- QCheckBox *nonExpireCheck;
+ QPushButton* signKeyButton;
- const QVector<GpgUID> mUids;
+ QDateTimeEdit* expiresEdit;
- const GpgKey &mKey;
+ QCheckBox* nonExpireCheck;
+ const UIDArgsListPtr& mUids;
-private slots:
+ const GpgKey& mKey;
- void slotSignKey(bool clicked);
+ private slots:
+ void slotSignKey(bool clicked);
};
+} // namespace GpgFrontend::UI
-#endif //GPGFRONTEND_KEYUIDSIGNDIALOG_H
+#endif // GPGFRONTEND_KEYUIDSIGNDIALOG_H
diff --git a/src/ui/main_window/MainWindowFileSlotFunction.cpp b/src/ui/main_window/MainWindowFileSlotFunction.cpp
index eff84fcf..2719b103 100644
--- a/src/ui/main_window/MainWindowFileSlotFunction.cpp
+++ b/src/ui/main_window/MainWindowFileSlotFunction.cpp
@@ -24,587 +24,503 @@
#include "MainWindow.h"
-void MainWindow::slotFileEncrypt() {
-
- auto fileTreeView = edit->slotCurPageFileTreeView();
- auto path = fileTreeView->getSelected();
-
- QFileInfo fileInfo(path);
- QFileInfo pathInfo(fileInfo.absolutePath());
-
- if (!fileInfo.isFile()) {
- QMessageBox::critical(this, tr("Error"), tr("Select a file before doing it."));
- return;
- }
- if (!fileInfo.isReadable()) {
- QMessageBox::critical(this, tr("Error"), tr("No permission to read this file."));
- return;
- }
- if (!pathInfo.isWritable()) {
- QMessageBox::critical(this, tr("Error"), tr("No permission to create file."));
- return;
- }
- if (QFile::exists(path + ".asc")) {
- auto ret = QMessageBox::warning(this,
- tr("Warning"),
- tr("The target file already exists, do you need to overwrite it?"),
- QMessageBox::Ok | QMessageBox::Cancel);
-
- if (ret == QMessageBox::Cancel)
- return;
- }
-
- QVector<GpgKey> keys;
-
- mKeyList->getCheckedKeys(keys);
+#include "gpg/function/GpgFileOpera.h"
+#include "gpg/function/GpgKeyGetter.h"
+
+namespace GpgFrontend::UI {
+
+void refresh_info_board(InfoBoardWidget* info_board,
+ int status,
+ const std::string& report_text) {
+ if (status < 0)
+ info_board->slotRefresh(QString::fromStdString(report_text),
+ INFO_ERROR_CRITICAL);
+ else if (status > 0)
+ info_board->slotRefresh(QString::fromStdString(report_text), INFO_ERROR_OK);
+ else
+ info_board->slotRefresh(QString::fromStdString(report_text),
+ INFO_ERROR_WARN);
+}
- if (keys.empty()) {
- QMessageBox::critical(this, tr("No Key Selected"), tr("No Key Selected"));
- return;
- }
+void process_result_analyse(TextEdit* edit,
+ InfoBoardWidget* info_board,
+ const ResultAnalyse& result_analyse) {
+ info_board->associateTabWidget(edit->tabWidget);
+ info_board->associateFileTreeView(edit->curFilePage());
+ refresh_info_board(info_board, result_analyse.getStatus(),
+ result_analyse.getResultReport());
+}
- for (const auto &key : keys) {
- if (!GpgFrontend::GpgContext::checkIfKeyCanEncr(key)) {
- QMessageBox::information(this,
- tr("Invalid Operation"),
- tr("The selected key contains a key that does not actually have a encrypt usage.<br/>")
- + tr("<br/>For example the Following Key: <br/>") + key.uids.first().uid);
- return;
+void process_result_analyse(TextEdit* edit,
+ InfoBoardWidget* info_board,
+ const ResultAnalyse& result_analyse_a,
+ const ResultAnalyse& result_analyse_b) {
+ info_board->associateTabWidget(edit->tabWidget);
+ info_board->associateFileTreeView(edit->curFilePage());
+
+ refresh_info_board(
+ info_board,
+ std::min(result_analyse_a.getStatus(), result_analyse_a.getStatus()),
+ result_analyse_a.getResultReport() + result_analyse_a.getResultReport());
+}
- }
- }
+bool file_pre_check(QWidget* parent, const QString& path) {
+ QFileInfo file_info(path);
+ QFileInfo path_info(file_info.absolutePath());
+ if (!file_info.isFile()) {
+ QMessageBox::critical(parent, QApplication::tr("Error"),
+ QApplication::tr("Select a file before doing it."));
+ return false;
+ }
+ if (!file_info.isReadable()) {
+ QMessageBox::critical(parent, QApplication::tr("Error"),
+ QApplication::tr("No permission to read this file."));
+ return false;
+ }
+ if (!path_info.isWritable()) {
+ QMessageBox::critical(parent, QApplication::tr("Error"),
+ QApplication::tr("No permission to create file."));
+ return false;
+ }
+ return true;
+}
- gpgme_encrypt_result_t result;
-
- gpgme_error_t error;
- bool if_error = false;
- auto thread = QThread::create([&]() {
- try {
- error = GpgFileOpera::encryptFile(mCtx, keys, path, &result);
- } catch (const std::runtime_error &e) {
- if_error = true;
- }
- });
- connect(thread, SIGNAL(finished()), thread, SLOT(deleteLater()));
- thread->start();
-
- auto *dialog = new WaitingDialog(tr("Encrypting"), this);
- while (thread->isRunning()) {
- QApplication::processEvents();
- }
+void process_operation(QWidget* parent,
+ std::string waiting_title,
+ std::function<void()> func) {
+ GpgEncrResult result = nullptr;
+
+ gpgme_error_t error;
+ bool if_error = false;
+ auto thread = QThread::create(func);
+ QApplication::connect(thread, SIGNAL(finished()), thread,
+ SLOT(deleteLater()));
+ thread->start();
+
+ auto* dialog =
+ new WaitingDialog(QString::fromStdString(waiting_title), parent);
+ while (thread->isRunning()) {
+ QApplication::processEvents();
+ }
+ dialog->close();
+}
- dialog->close();
- if (!if_error) {
- auto resultAnalyse = new EncryptResultAnalyse(error, result);
- auto &reportText = resultAnalyse->getResultReport();
- infoBoard->associateTabWidget(edit->tabWidget);
- infoBoard->associateFileTreeView(edit->curFilePage());
-
- if (resultAnalyse->getStatus() < 0)
- infoBoard->slotRefresh(reportText, INFO_ERROR_CRITICAL);
- else if (resultAnalyse->getStatus() > 0)
- infoBoard->slotRefresh(reportText, INFO_ERROR_OK);
- else
- infoBoard->slotRefresh(reportText, INFO_ERROR_WARN);
-
- delete resultAnalyse;
-
- fileTreeView->update();
- } else {
- QMessageBox::critical(this, tr("Error"), tr("An error occurred during operation."));
- return;
- }
+void MainWindow::slotFileEncrypt() {
+ auto fileTreeView = edit->slotCurPageFileTreeView();
+ auto path = fileTreeView->getSelected();
+
+ if (!file_pre_check(this, path))
+ return;
+
+ if (QFile::exists(path + ".asc")) {
+ auto ret = QMessageBox::warning(
+ this, tr("Warning"),
+ tr("The target file already exists, do you need to overwrite it?"),
+ QMessageBox::Ok | QMessageBox::Cancel);
+
+ if (ret == QMessageBox::Cancel)
+ return;
+ }
+
+ auto key_ids = mKeyList->getChecked();
+ auto keys = GpgKeyGetter::GetInstance().GetKeys(key_ids);
+ if (keys->empty()) {
+ QMessageBox::critical(this, tr("No Key Selected"), tr("No Key Selected"));
+ return;
+ }
+
+ for (const auto& key : *keys) {
+ if (!key.CanEncrActual()) {
+ QMessageBox::information(
+ this, tr("Invalid Operation"),
+ tr("The selected key contains a key that does not actually have a "
+ "encrypt usage.<br/>") +
+ tr("<br/>For example the Following Key: <br/>") +
+ QString::fromStdString(key.uids()->front().uid()));
+ return;
+ }
+ }
+
+ GpgEncrResult result = nullptr;
+ GpgError error;
+ bool if_error = false;
+ process_operation(this, tr("Encrypting").toStdString(), [&]() {
+ try {
+ error = GpgFileOpera::GetInstance().EncryptFile(
+ std::move(*keys), path.toStdString(), result);
+ } catch (const std::runtime_error& e) {
+ if_error = true;
+ }
+ });
+
+ if (!if_error) {
+ auto resultAnalyse = EncryptResultAnalyse(error, std::move(result));
+ resultAnalyse.analyse();
+ process_result_analyse(edit, infoBoard, resultAnalyse);
+ fileTreeView->update();
+ } else {
+ QMessageBox::critical(this, tr("Error"),
+ tr("An error occurred during operation."));
+ return;
+ }
}
void MainWindow::slotFileDecrypt() {
+ auto fileTreeView = edit->slotCurPageFileTreeView();
+ auto path = fileTreeView->getSelected();
+
+ if (!file_pre_check(this, path))
+ return;
+
+ QString outFileName, fileExtension = QFileInfo(path).suffix();
+
+ if (fileExtension == "asc" || fileExtension == "gpg") {
+ int pos = path.lastIndexOf(QChar('.'));
+ outFileName = path.left(pos);
+ } else {
+ outFileName = path + ".out";
+ }
+
+ if (QFile::exists(outFileName)) {
+ auto ret = QMessageBox::warning(
+ this, tr("Warning"),
+ tr("The target file already exists, do you need to overwrite it?"),
+ QMessageBox::Ok | QMessageBox::Cancel);
+
+ if (ret == QMessageBox::Cancel)
+ return;
+ }
+
+ GpgDecrResult result = nullptr;
+ gpgme_error_t error;
+ bool if_error = false;
+ process_operation(this, tr("Decrypting").toStdString(), [&]() {
+ try {
+ error =
+ GpgFileOpera::GetInstance().DecryptFile(path.toStdString(), result);
+ } catch (const std::runtime_error& e) {
+ if_error = true;
+ }
+ });
+
+ if (!if_error) {
+ auto resultAnalyse = DecryptResultAnalyse(error, std::move(result));
+ resultAnalyse.analyse();
+ process_result_analyse(edit, infoBoard, resultAnalyse);
- auto fileTreeView = edit->slotCurPageFileTreeView();
- auto path = fileTreeView->getSelected();
-
- QFileInfo fileInfo(path);
- QFileInfo pathInfo(fileInfo.absolutePath());
- if (!fileInfo.isFile()) {
- QMessageBox::critical(this, tr("Error"), tr("Select a file before doing it."));
- return;
- }
- if (!fileInfo.isReadable()) {
- QMessageBox::critical(this, tr("Error"), tr("No permission to read this file."));
- return;
- }
- if (!pathInfo.isWritable()) {
- QMessageBox::critical(this, tr("Error"), tr("No permission to create file."));
- return;
- }
-
- QString outFileName, fileExtension = fileInfo.suffix();
-
- if (fileExtension == "asc" || fileExtension == "gpg") {
- int pos = path.lastIndexOf(QChar('.'));
- outFileName = path.left(pos);
- } else {
- outFileName = path + ".out";
- }
-
- if (QFile::exists(outFileName)) {
- auto ret = QMessageBox::warning(this,
- tr("Warning"),
- tr("The target file already exists, do you need to overwrite it?"),
- QMessageBox::Ok | QMessageBox::Cancel);
-
- if (ret == QMessageBox::Cancel)
- return;
- }
-
- gpgme_decrypt_result_t result;
- gpgme_error_t error;
- bool if_error = false;
-
- auto thread = QThread::create([&]() {
- try {
- error = GpgFileOpera::decryptFile(mCtx, path, &result);
- } catch (const std::runtime_error &e) {
- if_error = true;
- }
- });
- connect(thread, SIGNAL(finished()), thread, SLOT(deleteLater()));
- thread->start();
-
- auto *dialog = new WaitingDialog("Decrypting", this);
- while (thread->isRunning()) {
- QApplication::processEvents();
- }
-
- dialog->close();
-
- if (!if_error) {
- auto resultAnalyse = new DecryptResultAnalyse(mCtx, error, result);
- auto &reportText = resultAnalyse->getResultReport();
- infoBoard->associateTabWidget(edit->tabWidget);
- infoBoard->associateFileTreeView(edit->curFilePage());
-
- if (resultAnalyse->getStatus() < 0)
- infoBoard->slotRefresh(reportText, INFO_ERROR_CRITICAL);
- else if (resultAnalyse->getStatus() > 0)
- infoBoard->slotRefresh(reportText, INFO_ERROR_OK);
- else
- infoBoard->slotRefresh(reportText, INFO_ERROR_WARN);
-
- delete resultAnalyse;
-
- fileTreeView->update();
- } else {
- QMessageBox::critical(this, tr("Error"), tr("An error occurred during operation."));
- return;
- }
-
-
+ fileTreeView->update();
+ } else {
+ QMessageBox::critical(this, tr("Error"),
+ tr("An error occurred during operation."));
+ return;
+ }
}
void MainWindow::slotFileSign() {
-
- auto fileTreeView = edit->slotCurPageFileTreeView();
- auto path = fileTreeView->getSelected();
-
- QFileInfo fileInfo(path);
- QFileInfo pathInfo(fileInfo.absolutePath());
-
- if (!fileInfo.isFile()) {
- QMessageBox::critical(this, tr("Error"), tr("Select a file before doing it."));
- return;
- }
- if (!fileInfo.isReadable()) {
- QMessageBox::critical(this, tr("Error"), tr("No permission to read this file."));
- return;
- }
- if (!pathInfo.isWritable()) {
- QMessageBox::critical(this, tr("Error"), tr("No permission to create file."));
- return;
- }
-
- if (QFile::exists(path + ".sig")) {
- auto ret = QMessageBox::warning(this,
- tr("Warning"),
- tr("The target file already exists, do you need to overwrite it?"),
- QMessageBox::Ok | QMessageBox::Cancel);
-
- if (ret == QMessageBox::Cancel)
- return;
- }
-
- QVector<GpgKey> keys;
-
- mKeyList->getCheckedKeys(keys);
-
- if (keys.empty()) {
- QMessageBox::critical(this, tr("No Key Selected"), tr("No Key Selected"));
- return;
- }
-
- for (const auto &key : keys) {
- if (!GpgFrontend::GpgContext::checkIfKeyCanEncr(key)) {
- QMessageBox::information(this,
- tr("Invalid Operation"),
- tr("The selected key contains a key that does not actually have a encrypt usage.<br/>")
- + tr("<br/>For example the Following Key: <br/>") + key.uids.first().uid);
- return;
-
- }
- }
-
- gpgme_sign_result_t result;
- gpgme_error_t error;
- bool if_error = false;
-
- auto thread = QThread::create([&]() {
- try {
- error = GpgFileOpera::signFile(mCtx, keys, path, &result);
- } catch (const std::runtime_error &e) {
- if_error = true;
- }
- });
- connect(thread, SIGNAL(finished()), thread, SLOT(deleteLater()));
- thread->start();
-
- auto *dialog = new WaitingDialog(tr("Signing"), this);
- while (thread->isRunning()) {
- QApplication::processEvents();
- }
-
- dialog->close();
-
- if (!if_error) {
-
- auto resultAnalyse = new SignResultAnalyse(mCtx, error, result);
- auto &reportText = resultAnalyse->getResultReport();
- infoBoard->associateTabWidget(edit->tabWidget);
- infoBoard->associateFileTreeView(edit->curFilePage());
-
- if (resultAnalyse->getStatus() < 0)
- infoBoard->slotRefresh(reportText, INFO_ERROR_CRITICAL);
- else if (resultAnalyse->getStatus() > 0)
- infoBoard->slotRefresh(reportText, INFO_ERROR_OK);
- else
- infoBoard->slotRefresh(reportText, INFO_ERROR_WARN);
-
- delete resultAnalyse;
-
- fileTreeView->update();
-
- } else {
- QMessageBox::critical(this, tr("Error"), tr("An error occurred during operation."));
- return;
- }
+ auto fileTreeView = edit->slotCurPageFileTreeView();
+ auto path = fileTreeView->getSelected();
+
+ if (!file_pre_check(this, path))
+ return;
+
+ if (QFile::exists(path + ".sig")) {
+ auto ret = QMessageBox::warning(
+ this, tr("Warning"),
+ tr("The target file already exists, do you need to overwrite it?"),
+ QMessageBox::Ok | QMessageBox::Cancel);
+
+ if (ret == QMessageBox::Cancel)
+ return;
+ }
+
+ auto key_ids = mKeyList->getChecked();
+ auto keys = GpgKeyGetter::GetInstance().GetKeys(key_ids);
+
+ if (keys->empty()) {
+ QMessageBox::critical(this, tr("No Key Selected"), tr("No Key Selected"));
+ return;
+ }
+
+ for (const auto& key : *keys) {
+ if (!key.CanSignActual()) {
+ QMessageBox::information(
+ this, tr("Invalid Operation"),
+ tr("The selected key contains a key that does not actually have a "
+ "sign usage.<br/>") +
+ tr("<br/>For example the Following Key: <br/>") +
+ QString::fromStdString(key.uids()->front().uid()));
+ return;
+ }
+ }
+
+ GpgSignResult result = nullptr;
+ gpgme_error_t error;
+ bool if_error = false;
+
+ process_operation(this, tr("Signing").toStdString(), [&]() {
+ try {
+ error = GpgFileOpera::GetInstance().SignFile(std::move(*keys),
+ path.toStdString(), result);
+ } catch (const std::runtime_error& e) {
+ if_error = true;
+ }
+ });
+
+ if (!if_error) {
+ auto resultAnalyse = SignResultAnalyse(error, std::move(result));
+ resultAnalyse.analyse();
+ process_result_analyse(edit, infoBoard, resultAnalyse);
fileTreeView->update();
+ } else {
+ QMessageBox::critical(this, tr("Error"),
+ tr("An error occurred during operation."));
+ return;
+ }
+
+ fileTreeView->update();
}
void MainWindow::slotFileVerify() {
+ auto fileTreeView = edit->slotCurPageFileTreeView();
+ auto path = fileTreeView->getSelected();
+
+ QFileInfo fileInfo(path);
+
+ QString signFilePath, dataFilePath;
+
+ if (fileInfo.suffix() == "gpg") {
+ dataFilePath = path;
+ signFilePath = path;
+ } else if (fileInfo.suffix() == "sig") {
+ int pos = path.lastIndexOf(QChar('.'));
+ dataFilePath = path.left(pos);
+ signFilePath = path;
+ } else {
+ dataFilePath = path;
+ signFilePath = path + ".sig";
+ }
+
+ QFileInfo dataFileInfo(dataFilePath), signFileInfo(signFilePath);
+
+ if (!dataFileInfo.isFile() || !signFileInfo.isFile()) {
+ QMessageBox::critical(
+ this, tr("Error"),
+ tr("Please select the appropriate target file or signature file. "
+ "Ensure that both are in this directory."));
+ return;
+ }
+ if (!dataFileInfo.isReadable()) {
+ QMessageBox::critical(this, tr("Error"),
+ tr("No permission to read target file."));
+ return;
+ }
+ if (!fileInfo.isReadable()) {
+ QMessageBox::critical(this, tr("Error"),
+ tr("No permission to read signature file."));
+ return;
+ }
+
+ GpgVerifyResult result = nullptr;
+ gpgme_error_t error;
+ bool if_error = false;
+ process_operation(this, tr("Verifying").toStdString(), [&]() {
+ try {
+ error = GpgFileOpera::GetInstance().VerifyFile(dataFilePath.toStdString(),
+ result);
+ } catch (const std::runtime_error& e) {
+ if_error = true;
+ }
+ });
+
+ if (!if_error) {
+ auto resultAnalyse = VerifyResultAnalyse(error, std::move(result));
+ resultAnalyse.analyse();
+ process_result_analyse(edit, infoBoard, resultAnalyse);
+
+ // if (resultAnalyse->getStatus() >= 0) {
+ // infoBoard->resetOptionActionsMenu();
+ // infoBoard->addOptionalAction(
+ // "Show Verify Details", [this, error, result]() {
+ // VerifyDetailsDialog(this, mCtx, mKeyList, error, result);
+ // });
+ // }
- auto fileTreeView = edit->slotCurPageFileTreeView();
- auto path = fileTreeView->getSelected();
-
- QFileInfo fileInfo(path);
-
- QString signFilePath, dataFilePath;
-
- if (fileInfo.suffix() == "gpg") {
- dataFilePath = path;
- signFilePath = path;
- } else if (fileInfo.suffix() == "sig") {
- int pos = path.lastIndexOf(QChar('.'));
- dataFilePath = path.left(pos);
- signFilePath = path;
- } else {
- dataFilePath = path;
- signFilePath = path + ".sig";
- }
-
- QFileInfo dataFileInfo(dataFilePath), signFileInfo(signFilePath);
-
- if (!dataFileInfo.isFile() || !signFileInfo.isFile()) {
- QMessageBox::critical(this, tr("Error"),
- tr("Please select the appropriate target file or signature file. Ensure that both are in this directory."));
- return;
- }
- if (!dataFileInfo.isReadable()) {
- QMessageBox::critical(this, tr("Error"), tr("No permission to read target file."));
- return;
- }
- if (!fileInfo.isReadable()) {
- QMessageBox::critical(this, tr("Error"), tr("No permission to read signature file."));
- return;
- }
-
- gpgme_verify_result_t result;
-
- gpgme_error_t error;
- bool if_error = false;
- auto thread = QThread::create([&]() {
- try {
- error = GpgFileOpera::verifyFile(mCtx, dataFilePath, &result);
- } catch (const std::runtime_error &e) {
- if_error = true;
- }
- });
- connect(thread, SIGNAL(finished()), thread, SLOT(deleteLater()));
- thread->start();
-
- auto *dialog = new WaitingDialog(tr("Verifying"), this);
- while (thread->isRunning()) {
- QApplication::processEvents();
- }
- dialog->close();
-
- if (!if_error) {
- auto resultAnalyse = new VerifyResultAnalyse(mCtx, error, result);
- auto &reportText = resultAnalyse->getResultReport();
- infoBoard->associateTabWidget(edit->tabWidget);
- infoBoard->associateFileTreeView(edit->curFilePage());
-
- if (resultAnalyse->getStatus() < 0)
- infoBoard->slotRefresh(reportText, INFO_ERROR_CRITICAL);
- else if (resultAnalyse->getStatus() > 0)
- infoBoard->slotRefresh(reportText, INFO_ERROR_OK);
- else
- infoBoard->slotRefresh(reportText, INFO_ERROR_WARN);
-
- if (resultAnalyse->getStatus() >= 0) {
- infoBoard->resetOptionActionsMenu();
- infoBoard->addOptionalAction("Show Verify Details", [this, error, result]() {
- VerifyDetailsDialog(this, mCtx, mKeyList, error, result);
- });
- }
-
- delete resultAnalyse;
-
- fileTreeView->update();
- } else {
- QMessageBox::critical(this, tr("Error"), tr("An error occurred during operation."));
- return;
- }
+ fileTreeView->update();
+ } else {
+ QMessageBox::critical(this, tr("Error"),
+ tr("An error occurred during operation."));
+ return;
+ }
}
void MainWindow::slotFileEncryptSign() {
- auto fileTreeView = edit->slotCurPageFileTreeView();
- auto path = fileTreeView->getSelected();
-
- QFileInfo fileInfo(path);
- QFileInfo pathInfo(fileInfo.absolutePath());
-
- if (!fileInfo.isFile()) {
- QMessageBox::critical(this, tr("Error"), tr("Select a file before doing it."));
- return;
- }
- if (!fileInfo.isReadable()) {
- QMessageBox::critical(this, tr("Error"), tr("No permission to read this file."));
- return;
- }
- if (!pathInfo.isWritable()) {
- QMessageBox::critical(this, tr("Error"), tr("No permission to create file."));
- return;
- }
- if (QFile::exists(path + ".gpg")) {
- auto ret = QMessageBox::warning(this,
- tr("Warning"),
- tr("The target file already exists, do you need to overwrite it?"),
- QMessageBox::Ok | QMessageBox::Cancel);
-
- if (ret == QMessageBox::Cancel)
- return;
- }
-
- QVector<GpgKey> keys;
-
- mKeyList->getCheckedKeys(keys);
-
- if (keys.empty()) {
- QMessageBox::critical(this, tr("No Key Selected"), tr("No Key Selected"));
- return;
- }
-
- bool can_sign = false, can_encr = false;
+ auto fileTreeView = edit->slotCurPageFileTreeView();
+ auto path = fileTreeView->getSelected();
+
+ if (!file_pre_check(this, path))
+ return;
+
+ if (QFile::exists(path + ".gpg")) {
+ auto ret = QMessageBox::warning(
+ this, tr("Warning"),
+ tr("The target file already exists, do you need to overwrite it?"),
+ QMessageBox::Ok | QMessageBox::Cancel);
+
+ if (ret == QMessageBox::Cancel)
+ return;
+ }
+
+ auto key_ids = mKeyList->getChecked();
+ auto keys = GpgKeyGetter::GetInstance().GetKeys(key_ids);
+
+ if (keys->empty()) {
+ QMessageBox::critical(this, tr("No Key Selected"), tr("No Key Selected"));
+ return;
+ }
+
+ bool can_sign = false, can_encr = false;
+
+ for (const auto& key : *keys) {
+ bool key_can_sign = key.CanSignActual();
+ bool key_can_encr = key.CanEncrActual();
+
+ if (!key_can_sign && !key_can_encr) {
+ QMessageBox::critical(
+ nullptr, tr("Invalid KeyPair"),
+ tr("The selected keypair cannot be used for signing and encryption "
+ "at the same time.<br/>") +
+ tr("<br/>For example the Following Key: <br/>") +
+ QString::fromStdString(key.uids()->front().uid()));
+ return;
+ }
+
+ if (key_can_sign)
+ can_sign = true;
+ if (key_can_encr)
+ can_encr = true;
+ }
+
+ if (!can_encr) {
+ QMessageBox::critical(nullptr, tr("Incomplete Operation"),
+ tr("None of the selected key pairs can provide the "
+ "encryption function."));
+ return;
+ }
+
+ if (!can_sign) {
+ QMessageBox::warning(nullptr, tr("Incomplete Operation"),
+ tr("None of the selected key pairs can provide the "
+ "signature function."));
+ }
+
+ GpgEncrResult encr_result = nullptr;
+ GpgSignResult sign_result = nullptr;
+
+ gpgme_error_t error;
+ bool if_error = false;
+
+ process_operation(this, tr("Encrypting and Signing").toStdString(), [&]() {
+ try {
+ error = GpgFileOpera::GetInstance().EncryptSignFile(
+ std::move(*keys), path.toStdString(), encr_result, sign_result);
+ } catch (const std::runtime_error& e) {
+ if_error = true;
+ }
+ });
+
+ if (!if_error) {
+ auto encrypt_res = EncryptResultAnalyse(error, std::move(encr_result));
+ auto sign_res = SignResultAnalyse(error, std::move(sign_result));
+ encrypt_res.analyse();
+ sign_res.analyse();
+ process_result_analyse(edit, infoBoard, encrypt_res, sign_res);
- for (const auto &key : keys) {
- bool key_can_sign = GpgFrontend::GpgContext::checkIfKeyCanSign(key);
- bool key_can_encr = GpgFrontend::GpgContext::checkIfKeyCanEncr(key);
-
- if (!key_can_sign && !key_can_encr) {
- QMessageBox::critical(nullptr,
- tr("Invalid KeyPair"),
- tr("The selected keypair cannot be used for signing and encryption at the same time.<br/>")
- + tr("<br/>For example the Following Key: <br/>") + key.uids.first().uid);
- return;
- }
-
- if (key_can_sign) can_sign = true;
- if (key_can_encr) can_encr = true;
- }
-
- if (!can_encr) {
- QMessageBox::critical(nullptr,
- tr("Incomplete Operation"),
- tr("None of the selected key pairs can provide the encryption function."));
- return;
- }
-
- if (!can_sign) {
- QMessageBox::warning(nullptr,
- tr("Incomplete Operation"),
- tr("None of the selected key pairs can provide the signature function."));
- }
-
- gpgme_encrypt_result_t encr_result = nullptr;
- gpgme_sign_result_t sign_result = nullptr;
-
- gpgme_error_t error;
- bool if_error = false;
-
- auto thread = QThread::create([&]() {
- try {
- error = GpgFileOpera::encryptSignFile(mCtx, keys, path, &encr_result, &sign_result);
- } catch (const std::runtime_error &e) {
- if_error = true;
- }
- });
- connect(thread, SIGNAL(finished()), thread, SLOT(deleteLater()));
- thread->start();
-
- auto *dialog = new WaitingDialog(tr("Encrypting and Signing"), this);
- while (thread->isRunning()) {
- QApplication::processEvents();
- }
- dialog->close();
-
- if (!if_error) {
-
- auto resultAnalyseEncr = new EncryptResultAnalyse(error, encr_result);
- auto resultAnalyseSign = new SignResultAnalyse(mCtx, error, sign_result);
- int status = std::min(resultAnalyseEncr->getStatus(), resultAnalyseSign->getStatus());
- auto reportText = resultAnalyseEncr->getResultReport() + resultAnalyseSign->getResultReport();
-
- infoBoard->associateFileTreeView(edit->curFilePage());
-
- if (status < 0)
- infoBoard->slotRefresh(reportText, INFO_ERROR_CRITICAL);
- else if (status > 0)
- infoBoard->slotRefresh(reportText, INFO_ERROR_OK);
- else
- infoBoard->slotRefresh(reportText, INFO_ERROR_WARN);
-
- delete resultAnalyseEncr;
- delete resultAnalyseSign;
-
- fileTreeView->update();
+ fileTreeView->update();
- } else {
- QMessageBox::critical(this, tr("Error"), tr("An error occurred during operation."));
- return;
- }
+ } else {
+ QMessageBox::critical(this, tr("Error"),
+ tr("An error occurred during operation."));
+ return;
+ }
}
void MainWindow::slotFileDecryptVerify() {
- auto fileTreeView = edit->slotCurPageFileTreeView();
- auto path = fileTreeView->getSelected();
-
- QFileInfo fileInfo(path);
- QFileInfo pathInfo(fileInfo.absolutePath());
- if (!fileInfo.isFile()) {
- QMessageBox::critical(this, tr("Error"), tr("Select a file(.gpg/.asc) before doing it."));
- return;
- }
- if (!fileInfo.isReadable()) {
- QMessageBox::critical(this, tr("Error"), tr("No permission to read this file."));
- return;
- }
- if (!pathInfo.isWritable()) {
- QMessageBox::critical(this, tr("Error"), tr("No permission to create file."));
- return;
- }
-
- QString outFileName, fileExtension = fileInfo.suffix();
-
- if (fileExtension == "asc" || fileExtension == "gpg") {
- int pos = path.lastIndexOf(QChar('.'));
- outFileName = path.left(pos);
- } else {
- outFileName = path + ".out";
- }
-
- gpgme_decrypt_result_t d_result = nullptr;
- gpgme_verify_result_t v_result = nullptr;
+ auto fileTreeView = edit->slotCurPageFileTreeView();
+ auto path = fileTreeView->getSelected();
+
+ if (!file_pre_check(this, path))
+ return;
+
+ QString outFileName, fileExtension = QFileInfo(path).suffix();
+
+ if (fileExtension == "asc" || fileExtension == "gpg") {
+ int pos = path.lastIndexOf(QChar('.'));
+ outFileName = path.left(pos);
+ } else {
+ outFileName = path + ".out";
+ }
+
+ GpgDecrResult d_result = nullptr;
+ GpgVerifyResult v_result = nullptr;
+ gpgme_error_t error;
+ bool if_error = false;
+ process_operation(this, tr("Decrypting and Verifying").toStdString(), [&]() {
+ try {
+ error = GpgFileOpera::GetInstance().DecryptVerifyFile(path.toStdString(),
+ d_result, v_result);
+ } catch (const std::runtime_error& e) {
+ if_error = true;
+ }
+ });
+
+ if (!if_error) {
+ infoBoard->associateFileTreeView(edit->curFilePage());
+
+ auto decrypt_res = DecryptResultAnalyse(error, std::move(d_result));
+ auto verify_res = VerifyResultAnalyse(error, std::move(v_result));
+ decrypt_res.analyse();
+ verify_res.analyse();
+ process_result_analyse(edit, infoBoard, decrypt_res, verify_res);
+
+ // if (verify_res.getStatus() >= 0) {
+ // infoBoard->resetOptionActionsMenu();
+ // infoBoard->addOptionalAction(
+ // "Show Verify Details", [this, error, v_result]() {
+ // VerifyDetailsDialog(this, mCtx, mKeyList, error, v_result);
+ // });
+ // }
- gpgme_error_t error;
- bool if_error = false;
-
- auto thread = QThread::create([&]() {
- try {
- error = GpgFileOpera::decryptVerifyFile(mCtx, path, &d_result, &v_result);
- } catch (const std::runtime_error &e) {
- if_error = true;
- }
- });
- connect(thread, SIGNAL(finished()), thread, SLOT(deleteLater()));
- thread->start();
-
-
- auto *dialog = new WaitingDialog(tr("Decrypting and Verifying"), this);
- while (thread->isRunning()) {
- QApplication::processEvents();
- }
- dialog->close();
-
- if (!if_error) {
- infoBoard->associateFileTreeView(edit->curFilePage());
-
- auto resultAnalyseDecrypt = new DecryptResultAnalyse(mCtx, error, d_result);
- auto resultAnalyseVerify = new VerifyResultAnalyse(mCtx, error, v_result);
-
- int status = std::min(resultAnalyseDecrypt->getStatus(), resultAnalyseVerify->getStatus());
- auto &reportText = resultAnalyseDecrypt->getResultReport() + resultAnalyseVerify->getResultReport();
- if (status < 0)
- infoBoard->slotRefresh(reportText, INFO_ERROR_CRITICAL);
- else if (status > 0)
- infoBoard->slotRefresh(reportText, INFO_ERROR_OK);
- else
- infoBoard->slotRefresh(reportText, INFO_ERROR_WARN);
-
- if (resultAnalyseVerify->getStatus() >= 0) {
- infoBoard->resetOptionActionsMenu();
- infoBoard->addOptionalAction("Show Verify Details", [this, error, v_result]() {
- VerifyDetailsDialog(this, mCtx, mKeyList, error, v_result);
- });
- }
- delete resultAnalyseDecrypt;
- delete resultAnalyseVerify;
-
- fileTreeView->update();
- } else {
- QMessageBox::critical(this, tr("Error"), tr("An error occurred during operation."));
- return;
- }
+ fileTreeView->update();
+ } else {
+ QMessageBox::critical(this, tr("Error"),
+ tr("An error occurred during operation."));
+ return;
+ }
}
void MainWindow::slotFileEncryptCustom() {
- QStringList *keyList;
- keyList = mKeyList->getChecked();
- new FileEncryptionDialog(mCtx, *keyList, FileEncryptionDialog::Encrypt, this);
+ new FileEncryptionDialog(mKeyList->getChecked(),
+ FileEncryptionDialog::Encrypt, this);
}
void MainWindow::slotFileDecryptCustom() {
- QStringList *keyList;
- keyList = mKeyList->getChecked();
- new FileEncryptionDialog(mCtx, *keyList, FileEncryptionDialog::Decrypt, this);
+ auto key_ids = mKeyList->getChecked();
+ new FileEncryptionDialog(mKeyList->getChecked(),
+ FileEncryptionDialog::Decrypt, this);
}
void MainWindow::slotFileSignCustom() {
- QStringList *keyList;
- keyList = mKeyList->getChecked();
- new FileEncryptionDialog(mCtx, *keyList, FileEncryptionDialog::Sign, this);
+ auto key_ids = mKeyList->getChecked();
+ new FileEncryptionDialog(mKeyList->getChecked(), FileEncryptionDialog::Sign,
+ this);
}
void MainWindow::slotFileVerifyCustom() {
- QStringList *keyList;
- keyList = mKeyList->getChecked();
- new FileEncryptionDialog(mCtx, *keyList, FileEncryptionDialog::Verify, this);
+ auto key_ids = mKeyList->getChecked();
+ new FileEncryptionDialog(mKeyList->getChecked(), FileEncryptionDialog::Verify,
+ this);
}
+
+} // namespace GpgFrontend::UI
diff --git a/src/ui/main_window/MainWindowServerSlotFunction.cpp b/src/ui/main_window/MainWindowServerSlotFunction.cpp
index dbbf178a..6266efda 100644
--- a/src/ui/main_window/MainWindowServerSlotFunction.cpp
+++ b/src/ui/main_window/MainWindowServerSlotFunction.cpp
@@ -23,216 +23,242 @@
*/
#include "MainWindow.h"
-#include "server/ComUtils.h"
-#include "ui/ShowCopyDialog.h"
+#ifdef SERVER_SUPPORT
#include "rapidjson/document.h"
#include "rapidjson/prettywriter.h"
+#include "server/ComUtils.h"
+#endif
+#include "ui/ShowCopyDialog.h"
+
+namespace GpgFrontend::UI {
+
+#ifdef SERVER_SUPPORT
/**
* get full size crypt text from server using short crypto text
* @param shortenCryptoText short crypto text([GpgFrontend_ShortCrypto]://)
* @return
*/
-QString MainWindow::getCryptText(const QString &shortenCryptoText) {
-
- QString ownKeyId = settings.value("general/ownKeyId").toString();
-
- GpgKey key = mCtx->getKeyRefById(ownKeyId);
- if (!key.good) {
- QMessageBox::critical(this, tr("Invalid Own Key"),
- tr("Own Key can not be use to do any operation. "
- "Please go to the setting interface to select an OwnKey and get a ServiceToken."));
- return {};
- }
-
- auto utils = new ComUtils(this);
+QString MainWindow::getCryptText(const QString& shortenCryptoText) {
+ QString ownKeyId = settings.value("general/ownKeyId").toString();
+
+ GpgKey key = mCtx->getKeyRefById(ownKeyId);
+ if (!key.good) {
+ QMessageBox::critical(this, tr("Invalid Own Key"),
+ tr("Own Key can not be use to do any operation. "
+ "Please go to the setting interface to select an "
+ "OwnKey and get a ServiceToken."));
+ return {};
+ }
- QString serviceToken = settings.value("general/serviceToken").toString();
- if (serviceToken.isEmpty() || !utils->checkServiceTokenFormat(serviceToken)) {
- QMessageBox::critical(this, tr("Error"),
- tr("Please obtain a Service Token from the server in the settings."));
- return {};
- }
+ auto utils = new ComUtils(this);
- QUrl reqUrl(utils->getUrl(ComUtils::GetFullCryptText));
- QNetworkRequest request(reqUrl);
- request.setHeader(QNetworkRequest::ContentTypeHeader, "application/json");
+ QString serviceToken = settings.value("general/serviceToken").toString();
+ if (serviceToken.isEmpty() || !utils->checkServiceTokenFormat(serviceToken)) {
+ QMessageBox::critical(
+ this, tr("Error"),
+ tr("Please obtain a Service Token from the server in the settings."));
+ return {};
+ }
- // Sign Shorten Text
- auto outSignTextBase64 = ComUtils::getSignStringBase64(mCtx, shortenCryptoText, key);
+ QUrl reqUrl(utils->getUrl(ComUtils::GetFullCryptText));
+ QNetworkRequest request(reqUrl);
+ request.setHeader(QNetworkRequest::ContentTypeHeader, "application/json");
- rapidjson::Document doc;
- doc.SetObject();
+ // Sign Shorten Text
+ auto outSignTextBase64 =
+ ComUtils::getSignStringBase64(mCtx, shortenCryptoText, key);
- rapidjson::Value s, t;
+ rapidjson::Document doc;
+ doc.SetObject();
- // Signature
- s.SetString(outSignTextBase64.constData(), outSignTextBase64.count());
- // Service Token
- const auto t_byte_array = serviceToken.toUtf8();
- t.SetString(t_byte_array.constData(), t_byte_array.count());
+ rapidjson::Value s, t;
- rapidjson::Document::AllocatorType &allocator = doc.GetAllocator();
+ // Signature
+ s.SetString(outSignTextBase64.constData(), outSignTextBase64.count());
+ // Service Token
+ const auto t_byte_array = serviceToken.toUtf8();
+ t.SetString(t_byte_array.constData(), t_byte_array.count());
- doc.AddMember("signature", s, allocator);
- doc.AddMember("serviceToken", t, allocator);
+ rapidjson::Document::AllocatorType& allocator = doc.GetAllocator();
- rapidjson::StringBuffer sb;
- rapidjson::PrettyWriter<rapidjson::StringBuffer> writer(sb);
- doc.Accept(writer);
+ doc.AddMember("signature", s, allocator);
+ doc.AddMember("serviceToken", t, allocator);
- QByteArray postData(sb.GetString());
- qDebug() << "postData" << QString::fromUtf8(postData);
+ rapidjson::StringBuffer sb;
+ rapidjson::PrettyWriter<rapidjson::StringBuffer> writer(sb);
+ doc.Accept(writer);
- QNetworkReply *reply = utils->getNetworkManager().post(request, postData);
+ QByteArray postData(sb.GetString());
+ qDebug() << "postData" << QString::fromUtf8(postData);
- auto dialog = new WaitingDialog(tr("Getting Cpt From Server"), this);
- dialog->show();
+ QNetworkReply* reply = utils->getNetworkManager().post(request, postData);
- while (reply->isRunning()) QApplication::processEvents();
+ auto dialog = new WaitingDialog(tr("Getting Cpt From Server"), this);
+ dialog->show();
- dialog->close();
+ while (reply->isRunning())
+ QApplication::processEvents();
- QByteArray replyData = reply->readAll().constData();
- if (utils->checkServerReply(replyData)) {
- /**
- * {
- * "cryptoText" : ...
- * "sha": ...
- * "serviceToken": ...
- * "date": ...
- * }
- */
+ dialog->close();
- if (!utils->checkDataValueStr("cryptoText")
- || !utils->checkDataValueStr("sha")
- || !utils->checkDataValueStr("serviceToken")) {
- QMessageBox::critical(this, tr("Error"),
- tr("The communication content with the server does not meet the requirements"));
- return {};
- }
+ QByteArray replyData = reply->readAll().constData();
+ if (utils->checkServerReply(replyData)) {
+ /**
+ * {
+ * "cryptoText" : ...
+ * "sha": ...
+ * "serviceToken": ...
+ * "date": ...
+ * }
+ */
- auto cryptoText = utils->getDataValueStr("cryptoText");
- auto sha = utils->getDataValueStr("sha");
- auto serviceTokenFromServer = utils->getDataValueStr("serviceToken");
+ if (!utils->checkDataValueStr("cryptoText") ||
+ !utils->checkDataValueStr("sha") ||
+ !utils->checkDataValueStr("serviceToken")) {
+ QMessageBox::critical(this, tr("Error"),
+ tr("The communication content with the server does "
+ "not meet the requirements"));
+ return {};
+ }
- QCryptographicHash sha_generator(QCryptographicHash::Sha256);
- sha_generator.addData(cryptoText.toUtf8());
+ auto cryptoText = utils->getDataValueStr("cryptoText");
+ auto sha = utils->getDataValueStr("sha");
+ auto serviceTokenFromServer = utils->getDataValueStr("serviceToken");
- if (sha_generator.result().toHex() == sha && serviceToken == serviceTokenFromServer) {
- return cryptoText;
- } else QMessageBox::critical(this, tr("Error"), tr("Invalid short ciphertext"));
+ QCryptographicHash sha_generator(QCryptographicHash::Sha256);
+ sha_generator.addData(cryptoText.toUtf8());
- return {};
- }
+ if (sha_generator.result().toHex() == sha &&
+ serviceToken == serviceTokenFromServer) {
+ return cryptoText;
+ } else
+ QMessageBox::critical(this, tr("Error"), tr("Invalid short ciphertext"));
return {};
-}
+ }
-void MainWindow::shortenCryptText() {
+ return {};
+}
- // gather information
- QString serviceToken = settings.value("general/serviceToken").toString();
- QString ownKeyId = settings.value("general/ownKeyId").toString();
- QByteArray cryptoText = edit->curTextPage()->toPlainText().toUtf8();
+#endif
- auto utils = new ComUtils(this);
+#ifdef SERVER_SUPPORT
- if (serviceToken.isEmpty() || !utils->checkServiceTokenFormat(serviceToken)) {
- QMessageBox::critical(this, tr("Invalid Service Token"),
- tr("Please go to the setting interface to get a ServiceToken."));
- return;
+void MainWindow::shortenCryptText() {
+ // gather information
+ QString serviceToken = settings.value("general/serviceToken").toString();
+ QString ownKeyId = settings.value("general/ownKeyId").toString();
+ QByteArray cryptoText = edit->curTextPage()->toPlainText().toUtf8();
+
+ auto utils = new ComUtils(this);
+
+ if (serviceToken.isEmpty() || !utils->checkServiceTokenFormat(serviceToken)) {
+ QMessageBox::critical(
+ this, tr("Invalid Service Token"),
+ tr("Please go to the setting interface to get a ServiceToken."));
+ return;
+ }
+
+ QUrl reqUrl(utils->getUrl(ComUtils::ShortenCryptText));
+ QNetworkRequest request(reqUrl);
+ request.setHeader(QNetworkRequest::ContentTypeHeader, "application/json");
+
+ GpgKey key = mCtx->getKeyRefById(ownKeyId);
+ if (!key.good) {
+ QMessageBox::critical(this, tr("Invalid Own Key"),
+ tr("Own Key can not be use to do any operation."));
+ return;
+ }
+
+ QCryptographicHash ch(QCryptographicHash::Md5);
+ ch.addData(cryptoText);
+ QString md5 = ch.result().toHex();
+
+ qDebug() << "md5" << md5;
+
+ QByteArray signText = QString("[%1][%2]").arg(serviceToken, md5).toUtf8();
+
+ QCryptographicHash sha(QCryptographicHash::Sha256);
+ sha.addData(signText);
+ QString shaText = sha.result().toHex();
+
+ qDebug() << "shaText" << shaText;
+
+ QByteArray outSignTextBase64 =
+ ComUtils::getSignStringBase64(mCtx, signText, key);
+
+ rapidjson::Value c, s, m, t;
+
+ rapidjson::Document doc;
+ doc.SetObject();
+
+ c.SetString(cryptoText.constData(), cryptoText.count());
+ auto m_byte_array = shaText.toUtf8();
+ m.SetString(m_byte_array.constData(), m_byte_array.count());
+ s.SetString(outSignTextBase64.constData(), outSignTextBase64.count());
+ auto t_byte_array = serviceToken.toUtf8();
+ t.SetString(t_byte_array.constData(), t_byte_array.count());
+
+ rapidjson::Document::AllocatorType& allocator = doc.GetAllocator();
+
+ doc.AddMember("cryptoText", c, allocator);
+ doc.AddMember("sha", m, allocator);
+ doc.AddMember("sign", s, allocator);
+ doc.AddMember("serviceToken", t, allocator);
+
+ rapidjson::StringBuffer sb;
+ rapidjson::PrettyWriter<rapidjson::StringBuffer> writer(sb);
+ doc.Accept(writer);
+
+ QByteArray postData(sb.GetString());
+ qDebug() << "postData" << QString::fromUtf8(postData);
+
+ QNetworkReply* reply = networkAccessManager->post(request, postData);
+
+ auto* dialog = new WaitingDialog(tr("Getting Scpt From Server"), this);
+ dialog->show();
+ while (reply->isRunning())
+ QApplication::processEvents();
+ dialog->close();
+
+ if (utils->checkServerReply(reply->readAll().constData())) {
+ /**
+ * {
+ * "shortenText" : ...
+ * "md5": ...
+ * }
+ */
+
+ if (!utils->checkDataValueStr("shortenText") ||
+ !utils->checkDataValueStr("md5")) {
+ QMessageBox::critical(this, tr("Error"),
+ tr("The communication content with the server does "
+ "not meet the requirements"));
+ return;
}
- QUrl reqUrl(utils->getUrl(ComUtils::ShortenCryptText));
- QNetworkRequest request(reqUrl);
- request.setHeader(QNetworkRequest::ContentTypeHeader, "application/json");
-
- GpgKey key = mCtx->getKeyRefById(ownKeyId);
- if (!key.good) {
- QMessageBox::critical(this, tr("Invalid Own Key"), tr("Own Key can not be use to do any operation."));
- return;
+ QString shortenText = utils->getDataValueStr("shortenText");
+
+ QCryptographicHash md5_generator(QCryptographicHash::Md5);
+ md5_generator.addData(shortenText.toUtf8());
+ if (md5_generator.result().toHex() == utils->getDataValueStr("md5")) {
+ auto* dialog =
+ new ShowCopyDialog(shortenText,
+ tr("Notice: Use Decrypt & Verify operation to "
+ "decrypt this short crypto text."),
+ this);
+ dialog->show();
+ } else {
+ QMessageBox::critical(
+ this, tr("Error"),
+ tr("There is a problem with the communication with the server"));
+ return;
}
-
- QCryptographicHash ch(QCryptographicHash::Md5);
- ch.addData(cryptoText);
- QString md5 = ch.result().toHex();
-
- qDebug() << "md5" << md5;
-
- QByteArray signText = QString("[%1][%2]").arg(serviceToken, md5).toUtf8();
-
- QCryptographicHash sha(QCryptographicHash::Sha256);
- sha.addData(signText);
- QString shaText = sha.result().toHex();
-
- qDebug() << "shaText" << shaText;
-
- QByteArray outSignTextBase64 = ComUtils::getSignStringBase64(mCtx, signText, key);
-
- rapidjson::Value c, s, m, t;
-
- rapidjson::Document doc;
- doc.SetObject();
-
- c.SetString(cryptoText.constData(), cryptoText.count());
- auto m_byte_array = shaText.toUtf8();
- m.SetString(m_byte_array.constData(), m_byte_array.count());
- s.SetString(outSignTextBase64.constData(), outSignTextBase64.count());
- auto t_byte_array = serviceToken.toUtf8();
- t.SetString(t_byte_array.constData(), t_byte_array.count());
-
- rapidjson::Document::AllocatorType &allocator = doc.GetAllocator();
-
- doc.AddMember("cryptoText", c, allocator);
- doc.AddMember("sha", m, allocator);
- doc.AddMember("sign", s, allocator);
- doc.AddMember("serviceToken", t, allocator);
-
- rapidjson::StringBuffer sb;
- rapidjson::PrettyWriter<rapidjson::StringBuffer> writer(sb);
- doc.Accept(writer);
-
- QByteArray postData(sb.GetString());
- qDebug() << "postData" << QString::fromUtf8(postData);
-
- QNetworkReply *reply = networkAccessManager->post(request, postData);
-
- auto *dialog = new WaitingDialog(tr("Getting Scpt From Server"), this);
- dialog->show();
- while (reply->isRunning()) QApplication::processEvents();
- dialog->close();
-
- if (utils->checkServerReply(reply->readAll().constData())) {
-
- /**
- * {
- * "shortenText" : ...
- * "md5": ...
- * }
- */
-
- if (!utils->checkDataValueStr("shortenText") || !utils->checkDataValueStr("md5")) {
- QMessageBox::critical(this, tr("Error"),
- tr("The communication content with the server does not meet the requirements"));
- return;
- }
-
- QString shortenText = utils->getDataValueStr("shortenText");
-
- QCryptographicHash md5_generator(QCryptographicHash::Md5);
- md5_generator.addData(shortenText.toUtf8());
- if (md5_generator.result().toHex() == utils->getDataValueStr("md5")) {
- auto *dialog = new ShowCopyDialog(shortenText,
- tr("Notice: Use Decrypt & Verify operation to decrypt this short crypto text."),
- this);
- dialog->show();
- } else {
- QMessageBox::critical(this, tr("Error"), tr("There is a problem with the communication with the server"));
- return;
- }
- }
-
+ }
}
+#endif
+
+} // namespace GpgFrontend::UI
diff --git a/src/ui/main_window/MainWindowSlotFunction.cpp b/src/ui/main_window/MainWindowSlotFunction.cpp
index 347cf412..0dcbd506 100644
--- a/src/ui/main_window/MainWindowSlotFunction.cpp
+++ b/src/ui/main_window/MainWindowSlotFunction.cpp
@@ -23,559 +23,576 @@
*/
#include "MainWindow.h"
-#include "ui/SendMailDialog.h"
-#include "ui/widgets/SignersPicker.h"
-#include "server/api/PubkeyUploader.h"
+
+#ifdef ADVANCE_SUPPORT
#include "advance/UnknownSignersChecker.h"
+#endif
+#ifdef SERVER_SUPPORT
+#include "server/api/PubkeyUploader.h"
+#endif
+#include "ui/SendMailDialog.h"
+#include "ui/widgets/SignersPicker.h"
+namespace GpgFrontend::UI {
/**
* Encrypt Entry(Text & File)
*/
void MainWindow::slotEncrypt() {
+ if (edit->tabCount() == 0)
+ return;
- if (edit->tabCount() == 0) return;
+ if (edit->slotCurPageTextEdit() != nullptr) {
+ auto keys = mKeyList->getChecked(keys);
- if (edit->slotCurPageTextEdit() != nullptr) {
-
- QVector<GpgKey> keys;
- mKeyList->getCheckedKeys(keys);
-
- if (keys.count() == 0) {
- QMessageBox::critical(nullptr, tr("No Key Selected"), tr("No Key Selected"));
- return;
- }
-
- for (const auto &key : keys) {
- if (!GpgFrontend::GpgContext::checkIfKeyCanEncr(key)) {
- QMessageBox::information(nullptr,
- tr("Invalid Operation"),
- tr("The selected key contains a key that does not actually have a encrypt usage.<br/>")
- + tr("<br/>For example the Following Key: <br/>") + key.uids.first().uid);
- return;
+ if (keys.count() == 0) {
+ QMessageBox::critical(nullptr, tr("No Key Selected"),
+ tr("No Key Selected"));
+ return;
+ }
- }
- }
+ for (const auto& key : keys) {
+ if (!GpgFrontend::GpgContext::checkIfKeyCanEncr(key)) {
+ QMessageBox::information(
+ nullptr, tr("Invalid Operation"),
+ tr("The selected key contains a key that does not actually have a "
+ "encrypt usage.<br/>") +
+ tr("<br/>For example the Following Key: <br/>") +
+ key.uids.first().uid);
+ return;
+ }
+ }
- auto tmp = QByteArray();
+ auto tmp = QByteArray();
- gpgme_encrypt_result_t result = nullptr;
+ gpgme_encrypt_result_t result = nullptr;
- gpgme_error_t error;
+ gpgme_error_t error;
- auto thread = QThread::create([&]() {
- error = mCtx->encrypt(keys, edit->curTextPage()->toPlainText().toUtf8(), &tmp, &result);
- });
- connect(thread, SIGNAL(finished()), thread, SLOT(deleteLater()));
- thread->start();
+ auto thread = QThread::create([&]() {
+ error = mCtx->encrypt(keys, edit->curTextPage()->toPlainText().toUtf8(),
+ &tmp, &result);
+ });
+ connect(thread, SIGNAL(finished()), thread, SLOT(deleteLater()));
+ thread->start();
- auto *dialog = new WaitingDialog(tr("Encrypting"), this);
+ auto* dialog = new WaitingDialog(tr("Encrypting"), this);
- while (thread->isRunning())
- QApplication::processEvents();
+ while (thread->isRunning())
+ QApplication::processEvents();
- dialog->close();
+ dialog->close();
- auto resultAnalyse = new EncryptResultAnalyse(error, result);
- auto &reportText = resultAnalyse->getResultReport();
+ auto resultAnalyse = new EncryptResultAnalyse(error, result);
+ auto& reportText = resultAnalyse->getResultReport();
- auto tmp2 = QString(tmp);
- edit->slotFillTextEditWithText(tmp2);
- infoBoard->associateTextEdit(edit->curTextPage());
+ auto tmp2 = QString(tmp);
+ edit->slotFillTextEditWithText(tmp2);
+ infoBoard->associateTextEdit(edit->curTextPage());
- // check result analyse status
- if (resultAnalyse->getStatus() < 0)
- infoBoard->slotRefresh(reportText, INFO_ERROR_CRITICAL);
- else if (resultAnalyse->getStatus() > 0)
- infoBoard->slotRefresh(reportText, INFO_ERROR_OK);
- else
- infoBoard->slotRefresh(reportText, INFO_ERROR_WARN);
+ // check result analyse status
+ if (resultAnalyse->getStatus() < 0)
+ infoBoard->slotRefresh(reportText, INFO_ERROR_CRITICAL);
+ else if (resultAnalyse->getStatus() > 0)
+ infoBoard->slotRefresh(reportText, INFO_ERROR_OK);
+ else
+ infoBoard->slotRefresh(reportText, INFO_ERROR_WARN);
- // set optional actions
- if (resultAnalyse->getStatus() >= 0) {
- infoBoard->resetOptionActionsMenu();
- infoBoard->addOptionalAction("Send Mail", [this]() {
- if (settings.value("sendMail/enable", false).toBool())
- new SendMailDialog(edit->curTextPage()->toPlainText(), this);
- else {
- QMessageBox::warning(nullptr,
- tr("Function Disabled"),
- tr("Please go to the settings interface to enable and configure this function."));
- }
- });
+ // set optional actions
+ if (resultAnalyse->getStatus() >= 0) {
+ infoBoard->resetOptionActionsMenu();
+ infoBoard->addOptionalAction("Send Mail", [this]() {
+ if (settings.value("sendMail/enable", false).toBool())
+ new SendMailDialog(edit->curTextPage()->toPlainText(), this);
+ else {
+ QMessageBox::warning(nullptr, tr("Function Disabled"),
+ tr("Please go to the settings interface to "
+ "enable and configure this function."));
}
-
- delete resultAnalyse;
- } else if (edit->slotCurPageFileTreeView() != nullptr) {
- this->slotFileEncrypt();
+ });
}
+
+ delete resultAnalyse;
+ } else if (edit->slotCurPageFileTreeView() != nullptr) {
+ this->slotFileEncrypt();
+ }
}
void MainWindow::slotSign() {
+ if (edit->tabCount() == 0)
+ return;
- if (edit->tabCount() == 0) return;
-
- if (edit->slotCurPageTextEdit() != nullptr) {
-
- QVector<GpgKey> keys;
+ if (edit->slotCurPageTextEdit() != nullptr) {
+ QVector<GpgKey> keys;
- mKeyList->getPrivateCheckedKeys(keys);
+ mKeyList->getPrivateCheckedKeys(keys);
- if (keys.isEmpty()) {
- QMessageBox::critical(this, tr("No Key Selected"), tr("No Key Selected"));
- return;
- }
+ if (keys.isEmpty()) {
+ QMessageBox::critical(this, tr("No Key Selected"), tr("No Key Selected"));
+ return;
+ }
- for (const auto &key : keys) {
- if (!GpgFrontend::GpgContext::checkIfKeyCanSign(key)) {
- QMessageBox::information(this,
- tr("Invalid Operation"),
- tr("The selected key contains a key that does not actually have a signature usage.<br/>")
- + tr("<br/>For example the Following Key: <br/>") + key.uids.first().uid);
- return;
- }
- }
+ for (const auto& key : keys) {
+ if (!GpgFrontend::GpgContext::checkIfKeyCanSign(key)) {
+ QMessageBox::information(
+ this, tr("Invalid Operation"),
+ tr("The selected key contains a key that does not actually have a "
+ "signature usage.<br/>") +
+ tr("<br/>For example the Following Key: <br/>") +
+ key.uids.first().uid);
+ return;
+ }
+ }
- auto tmp = QByteArray();
+ auto tmp = QByteArray();
- gpgme_sign_result_t result = nullptr;
+ gpgme_sign_result_t result = nullptr;
- gpgme_error_t error;
- auto thread = QThread::create([&]() {
- error = mCtx->sign(keys, edit->curTextPage()->toPlainText().toUtf8(), &tmp, GPGME_SIG_MODE_CLEAR, &result);
- });
- connect(thread, SIGNAL(finished()), thread, SLOT(deleteLater()));
- thread->start();
+ gpgme_error_t error;
+ auto thread = QThread::create([&]() {
+ error = mCtx->sign(keys, edit->curTextPage()->toPlainText().toUtf8(),
+ &tmp, GPGME_SIG_MODE_CLEAR, &result);
+ });
+ connect(thread, SIGNAL(finished()), thread, SLOT(deleteLater()));
+ thread->start();
- auto *dialog = new WaitingDialog(tr("Signing"), this);
- while (thread->isRunning()) {
- QApplication::processEvents();
- }
- dialog->close();
+ auto* dialog = new WaitingDialog(tr("Signing"), this);
+ while (thread->isRunning()) {
+ QApplication::processEvents();
+ }
+ dialog->close();
- infoBoard->associateTextEdit(edit->curTextPage());
- edit->slotFillTextEditWithText(QString::fromUtf8(tmp));
+ infoBoard->associateTextEdit(edit->curTextPage());
+ edit->slotFillTextEditWithText(QString::fromUtf8(tmp));
- auto resultAnalyse = new SignResultAnalyse(mCtx, error, result);
+ auto resultAnalyse = new SignResultAnalyse(mCtx, error, result);
- auto &reportText = resultAnalyse->getResultReport();
- if (resultAnalyse->getStatus() < 0)
- infoBoard->slotRefresh(reportText, INFO_ERROR_CRITICAL);
- else if (resultAnalyse->getStatus() > 0)
- infoBoard->slotRefresh(reportText, INFO_ERROR_OK);
- else
- infoBoard->slotRefresh(reportText, INFO_ERROR_WARN);
+ auto& reportText = resultAnalyse->getResultReport();
+ if (resultAnalyse->getStatus() < 0)
+ infoBoard->slotRefresh(reportText, INFO_ERROR_CRITICAL);
+ else if (resultAnalyse->getStatus() > 0)
+ infoBoard->slotRefresh(reportText, INFO_ERROR_OK);
+ else
+ infoBoard->slotRefresh(reportText, INFO_ERROR_WARN);
- delete resultAnalyse;
- } else if (edit->slotCurPageFileTreeView() != nullptr) {
- this->slotFileSign();
- }
+ delete resultAnalyse;
+ } else if (edit->slotCurPageFileTreeView() != nullptr) {
+ this->slotFileSign();
+ }
}
void MainWindow::slotDecrypt() {
- if (edit->tabCount() == 0) return;
-
- if (edit->slotCurPageTextEdit() != nullptr) {
-
- auto decrypted = QByteArray();
- QByteArray text = edit->curTextPage()->toPlainText().toUtf8();
- GpgFrontend::GpgContext::preventNoDataErr(&text);
-
- if (text.trimmed().startsWith(GpgConstants::GPG_FRONTEND_SHORT_CRYPTO_HEAD)) {
- QMessageBox::critical(this, tr("Notice"), tr("Short Crypto Text only supports Decrypt & Verify."));
- return;
- }
+ if (edit->tabCount() == 0)
+ return;
+
+ if (edit->slotCurPageTextEdit() != nullptr) {
+ auto decrypted = QByteArray();
+ QByteArray text = edit->curTextPage()->toPlainText().toUtf8();
+ GpgFrontend::GpgContext::preventNoDataErr(&text);
+
+ if (text.trimmed().startsWith(
+ GpgConstants::GPG_FRONTEND_SHORT_CRYPTO_HEAD)) {
+ QMessageBox::critical(
+ this, tr("Notice"),
+ tr("Short Crypto Text only supports Decrypt & Verify."));
+ return;
+ }
- gpgme_decrypt_result_t result = nullptr;
+ gpgme_decrypt_result_t result = nullptr;
- gpgme_error_t error;
- auto thread = QThread::create([&]() {
- // try decrypt, if fail do nothing, especially don't replace text
- error = mCtx->decrypt(text, &decrypted, &result);
- });
- connect(thread, SIGNAL(finished()), thread, SLOT(deleteLater()));
- thread->start();
+ gpgme_error_t error;
+ auto thread = QThread::create([&]() {
+ // try decrypt, if fail do nothing, especially don't replace text
+ error = mCtx->decrypt(text, &decrypted, &result);
+ });
+ connect(thread, SIGNAL(finished()), thread, SLOT(deleteLater()));
+ thread->start();
- auto *dialog = new WaitingDialog(tr("Decrypting"), this);
- while (thread->isRunning()) {
- QApplication::processEvents();
- }
+ auto* dialog = new WaitingDialog(tr("Decrypting"), this);
+ while (thread->isRunning()) {
+ QApplication::processEvents();
+ }
- dialog->close();
+ dialog->close();
- infoBoard->associateTextEdit(edit->curTextPage());
+ infoBoard->associateTextEdit(edit->curTextPage());
- if (gpgme_err_code(error) == GPG_ERR_NO_ERROR)
- edit->slotFillTextEditWithText(QString::fromUtf8(decrypted));
+ if (gpgme_err_code(error) == GPG_ERR_NO_ERROR)
+ edit->slotFillTextEditWithText(QString::fromUtf8(decrypted));
- auto resultAnalyse = new DecryptResultAnalyse(mCtx, error, result);
+ auto resultAnalyse = new DecryptResultAnalyse(mCtx, error, result);
- auto &reportText = resultAnalyse->getResultReport();
- if (resultAnalyse->getStatus() < 0)
- infoBoard->slotRefresh(reportText, INFO_ERROR_CRITICAL);
- else if (resultAnalyse->getStatus() > 0)
- infoBoard->slotRefresh(reportText, INFO_ERROR_OK);
- else
- infoBoard->slotRefresh(reportText, INFO_ERROR_WARN);
+ auto& reportText = resultAnalyse->getResultReport();
+ if (resultAnalyse->getStatus() < 0)
+ infoBoard->slotRefresh(reportText, INFO_ERROR_CRITICAL);
+ else if (resultAnalyse->getStatus() > 0)
+ infoBoard->slotRefresh(reportText, INFO_ERROR_OK);
+ else
+ infoBoard->slotRefresh(reportText, INFO_ERROR_WARN);
- delete resultAnalyse;
- } else if (edit->slotCurPageFileTreeView() != nullptr) {
- this->slotFileDecrypt();
- }
+ delete resultAnalyse;
+ } else if (edit->slotCurPageFileTreeView() != nullptr) {
+ this->slotFileDecrypt();
+ }
}
void MainWindow::slotFind() {
- if (edit->tabCount() == 0 || edit->curTextPage() == nullptr) {
- return;
- }
-
- // At first close verifynotification, if existing
- edit->slotCurPageTextEdit()->closeNoteByClass("findwidget");
+ if (edit->tabCount() == 0 || edit->curTextPage() == nullptr) {
+ return;
+ }
- auto *fw = new FindWidget(this, edit->curTextPage());
- edit->slotCurPageTextEdit()->showNotificationWidget(fw, "findWidget");
+ // At first close verifynotification, if existing
+ edit->slotCurPageTextEdit()->closeNoteByClass("findwidget");
+ auto* fw = new FindWidget(this, edit->curTextPage());
+ edit->slotCurPageTextEdit()->showNotificationWidget(fw, "findWidget");
}
void MainWindow::slotVerify() {
-
- if (edit->tabCount() == 0) return;
-
- if (edit->slotCurPageTextEdit() != nullptr) {
-
- QByteArray text = edit->curTextPage()->toPlainText().toUtf8();
- GpgFrontend::GpgContext::preventNoDataErr(&text);
-
- gpgme_verify_result_t result;
-
- gpgme_error_t error;
- auto thread = QThread::create([&]() {
- error = mCtx->verify(&text, nullptr, &result);
- });
- connect(thread, SIGNAL(finished()), thread, SLOT(deleteLater()));
- thread->start();
-
- auto *dialog = new WaitingDialog(tr("Verifying"), this);
- while (thread->isRunning())
- QApplication::processEvents();
- dialog->close();
-
- auto resultAnalyse = new VerifyResultAnalyse(mCtx, error, result);
- infoBoard->associateTextEdit(edit->curTextPage());
-
- auto &reportText = resultAnalyse->getResultReport();
- if (resultAnalyse->getStatus() < 0)
- infoBoard->slotRefresh(reportText, INFO_ERROR_CRITICAL);
- else if (resultAnalyse->getStatus() > 0)
- infoBoard->slotRefresh(reportText, INFO_ERROR_OK);
- else
- infoBoard->slotRefresh(reportText, INFO_ERROR_WARN);
-
- if (resultAnalyse->getStatus() >= 0) {
- infoBoard->resetOptionActionsMenu();
- infoBoard->addOptionalAction("Show Verify Details", [this, error, result]() {
- VerifyDetailsDialog(this, mCtx, mKeyList, error, result);
- });
- }
- delete resultAnalyse;
- } else if (edit->slotCurPageFileTreeView() != nullptr) {
- this->slotFileVerify();
+ if (edit->tabCount() == 0)
+ return;
+
+ if (edit->slotCurPageTextEdit() != nullptr) {
+ QByteArray text = edit->curTextPage()->toPlainText().toUtf8();
+ GpgFrontend::GpgContext::preventNoDataErr(&text);
+
+ gpgme_verify_result_t result;
+
+ gpgme_error_t error;
+ auto thread = QThread::create(
+ [&]() { error = mCtx->verify(&text, nullptr, &result); });
+ connect(thread, SIGNAL(finished()), thread, SLOT(deleteLater()));
+ thread->start();
+
+ auto* dialog = new WaitingDialog(tr("Verifying"), this);
+ while (thread->isRunning())
+ QApplication::processEvents();
+ dialog->close();
+
+ auto resultAnalyse = new VerifyResultAnalyse(mCtx, error, result);
+ infoBoard->associateTextEdit(edit->curTextPage());
+
+ auto& reportText = resultAnalyse->getResultReport();
+ if (resultAnalyse->getStatus() < 0)
+ infoBoard->slotRefresh(reportText, INFO_ERROR_CRITICAL);
+ else if (resultAnalyse->getStatus() > 0)
+ infoBoard->slotRefresh(reportText, INFO_ERROR_OK);
+ else
+ infoBoard->slotRefresh(reportText, INFO_ERROR_WARN);
+
+ if (resultAnalyse->getStatus() >= 0) {
+ infoBoard->resetOptionActionsMenu();
+ infoBoard->addOptionalAction(
+ "Show Verify Details", [this, error, result]() {
+ VerifyDetailsDialog(this, mCtx, mKeyList, error, result);
+ });
}
+ delete resultAnalyse;
+ } else if (edit->slotCurPageFileTreeView() != nullptr) {
+ this->slotFileVerify();
+ }
}
void MainWindow::slotEncryptSign() {
+ if (edit->tabCount() == 0)
+ return;
- if (edit->tabCount() == 0) return;
-
- if (edit->slotCurPageTextEdit() != nullptr) {
-
- QVector<GpgKey> keys;
- mKeyList->getCheckedKeys(keys);
-
- if (keys.empty()) {
- QMessageBox::critical(nullptr, tr("No Key Selected"), tr("No Key Selected"));
- return;
- }
-
- for (const auto &key : keys) {
- bool key_can_encr = GpgFrontend::GpgContext::checkIfKeyCanEncr(key);
-
- if (!key_can_encr) {
- QMessageBox::critical(nullptr,
- tr("Invalid KeyPair"),
- tr("The selected keypair cannot be used for encryption.<br/>")
- + tr("<br/>For example the Following Key: <br/>") + key.uids.first().uid);
- return;
- }
+ if (edit->slotCurPageTextEdit() != nullptr) {
+ QVector<GpgKey> keys;
+ mKeyList->getCheckedKeys(keys);
- }
+ if (keys.empty()) {
+ QMessageBox::critical(nullptr, tr("No Key Selected"),
+ tr("No Key Selected"));
+ return;
+ }
- QVector<GpgKey> signerKeys;
+ for (const auto& key : keys) {
+ bool key_can_encr = GpgFrontend::GpgContext::checkIfKeyCanEncr(key);
- auto signersPicker = new SignersPicker(mCtx, this);
+ if (!key_can_encr) {
+ QMessageBox::critical(
+ nullptr, tr("Invalid KeyPair"),
+ tr("The selected keypair cannot be used for encryption.<br/>") +
+ tr("<br/>For example the Following Key: <br/>") +
+ key.uids.first().uid);
+ return;
+ }
+ }
- QEventLoop loop;
- connect(signersPicker, SIGNAL(finished(int)), &loop, SLOT(quit()));
- loop.exec();
+ QVector<GpgKey> signerKeys;
- signersPicker->getCheckedSigners(signerKeys);
+ auto signersPicker = new SignersPicker(mCtx, this);
- for (const auto &key : keys) {
- qDebug() << "Keys " << key.email;
- }
+ QEventLoop loop;
+ connect(signersPicker, SIGNAL(finished(int)), &loop, SLOT(quit()));
+ loop.exec();
- for (const auto &signer : signerKeys) {
- qDebug() << "Signers " << signer.email;
- }
+ signersPicker->getCheckedSigners(signerKeys);
+ for (const auto& key : keys) {
+ qDebug() << "Keys " << key.email;
+ }
- auto tmp = QByteArray();
- gpgme_encrypt_result_t encr_result = nullptr;
- gpgme_sign_result_t sign_result = nullptr;
+ for (const auto& signer : signerKeys) {
+ qDebug() << "Signers " << signer.email;
+ }
- gpgme_error_t error;
- auto thread = QThread::create([&]() {
- error = mCtx->encryptSign(keys, signerKeys, edit->curTextPage()->toPlainText().toUtf8(), &tmp,
- &encr_result,
- &sign_result);
- });
- connect(thread, SIGNAL(finished()), thread, SLOT(deleteLater()));
- thread->start();
+ auto tmp = QByteArray();
+ gpgme_encrypt_result_t encr_result = nullptr;
+ gpgme_sign_result_t sign_result = nullptr;
+
+ gpgme_error_t error;
+ auto thread = QThread::create([&]() {
+ error = mCtx->encryptSign(keys, signerKeys,
+ edit->curTextPage()->toPlainText().toUtf8(),
+ &tmp, &encr_result, &sign_result);
+ });
+ connect(thread, SIGNAL(finished()), thread, SLOT(deleteLater()));
+ thread->start();
+
+ auto* dialog = new WaitingDialog(tr("Encrypting and Signing"), this);
+ while (thread->isRunning()) {
+ QApplication::processEvents();
+ }
- auto *dialog = new WaitingDialog(tr("Encrypting and Signing"), this);
- while (thread->isRunning()) {
- QApplication::processEvents();
- }
+ if (settings.value("advanced/autoPubkeyExchange").toBool()) {
+ PubkeyUploader pubkeyUploader(mCtx, signerKeys);
+ pubkeyUploader.start();
+ if (!pubkeyUploader.result()) {
+ QMessageBox::warning(nullptr, tr("Automatic Key Exchange Warning"),
+ tr("Part of the automatic key exchange failed, "
+ "which may be related to your key.") +
+ tr("If possible, try to use the RSA algorithm "
+ "compatible with the server for signing."));
+ }
+ }
- if (settings.value("advanced/autoPubkeyExchange").toBool()) {
- PubkeyUploader pubkeyUploader(mCtx, signerKeys);
- pubkeyUploader.start();
- if (!pubkeyUploader.result()) {
- QMessageBox::warning(nullptr,
- tr("Automatic Key Exchange Warning"),
- tr("Part of the automatic key exchange failed, which may be related to your key.")
- +
- tr("If possible, try to use the RSA algorithm compatible with the server for signing."));
- }
- }
+ dialog->close();
- dialog->close();
+ if (gpgme_err_code(error) == GPG_ERR_NO_ERROR) {
+ auto tmp2 = QString(tmp);
+ edit->slotFillTextEditWithText(tmp2);
+ }
- if (gpgme_err_code(error) == GPG_ERR_NO_ERROR) {
- auto tmp2 = QString(tmp);
- edit->slotFillTextEditWithText(tmp2);
+ qDebug() << "Start Analyse Result";
+
+ auto resultAnalyseEncr = new EncryptResultAnalyse(error, encr_result);
+ auto resultAnalyseSign = new SignResultAnalyse(mCtx, error, sign_result);
+ int status = std::min(resultAnalyseEncr->getStatus(),
+ resultAnalyseSign->getStatus());
+ auto reportText = resultAnalyseEncr->getResultReport() +
+ resultAnalyseSign->getResultReport();
+
+ infoBoard->associateTextEdit(edit->curTextPage());
+
+ if (status < 0)
+ infoBoard->slotRefresh(reportText, INFO_ERROR_CRITICAL);
+ else if (status > 0)
+ infoBoard->slotRefresh(reportText, INFO_ERROR_OK);
+ else
+ infoBoard->slotRefresh(reportText, INFO_ERROR_WARN);
+
+ qDebug() << "End Analyse Result";
+
+ if (status >= 0) {
+ infoBoard->resetOptionActionsMenu();
+ infoBoard->addOptionalAction("Send Mail", [this]() {
+ if (settings.value("sendMail/enable", false).toBool())
+ new SendMailDialog(edit->curTextPage()->toPlainText(), this);
+ else {
+ QMessageBox::warning(nullptr, tr("Function Disabled"),
+ tr("Please go to the settings interface to "
+ "enable and configure this function."));
}
-
- qDebug() << "Start Analyse Result";
-
- auto resultAnalyseEncr = new EncryptResultAnalyse(error, encr_result);
- auto resultAnalyseSign = new SignResultAnalyse(mCtx, error, sign_result);
- int status = std::min(resultAnalyseEncr->getStatus(), resultAnalyseSign->getStatus());
- auto reportText = resultAnalyseEncr->getResultReport() + resultAnalyseSign->getResultReport();
-
- infoBoard->associateTextEdit(edit->curTextPage());
-
- if (status < 0)
- infoBoard->slotRefresh(reportText, INFO_ERROR_CRITICAL);
- else if (status > 0)
- infoBoard->slotRefresh(reportText, INFO_ERROR_OK);
- else
- infoBoard->slotRefresh(reportText, INFO_ERROR_WARN);
-
- qDebug() << "End Analyse Result";
-
- if (status >= 0) {
- infoBoard->resetOptionActionsMenu();
- infoBoard->addOptionalAction("Send Mail", [this]() {
- if (settings.value("sendMail/enable", false).toBool())
- new SendMailDialog(edit->curTextPage()->toPlainText(), this);
- else {
- QMessageBox::warning(nullptr,
- tr("Function Disabled"),
- tr("Please go to the settings interface to enable and configure this function."));
- }
- });
- infoBoard->addOptionalAction("Shorten Ciphertext", [this]() {
- if (settings.value("general/serviceToken").toString().isEmpty())
- QMessageBox::warning(nullptr,
- tr("Service Token Empty"),
- tr("Please go to the settings interface to set Own Key and get Service Token."));
- else {
- shortenCryptText();
- }
- });
+ });
+ infoBoard->addOptionalAction("Shorten Ciphertext", [this]() {
+ if (settings.value("general/serviceToken").toString().isEmpty())
+ QMessageBox::warning(nullptr, tr("Service Token Empty"),
+ tr("Please go to the settings interface to set "
+ "Own Key and get Service Token."));
+ else {
+ shortenCryptText();
}
-
- delete resultAnalyseEncr;
- delete resultAnalyseSign;
- } else if (edit->slotCurPageFileTreeView() != nullptr) {
- this->slotFileEncryptSign();
+ });
}
+
+ delete resultAnalyseEncr;
+ delete resultAnalyseSign;
+ } else if (edit->slotCurPageFileTreeView() != nullptr) {
+ this->slotFileEncryptSign();
+ }
}
void MainWindow::slotDecryptVerify() {
+ if (edit->tabCount() == 0)
+ return;
+
+ if (edit->slotCurPageTextEdit() != nullptr) {
+ auto decrypted = QByteArray();
+ QString plainText = edit->curTextPage()->toPlainText();
+
+ if (plainText.trimmed().startsWith(
+ GpgConstants::GPG_FRONTEND_SHORT_CRYPTO_HEAD)) {
+ auto cryptoText = getCryptText(plainText);
+ if (!cryptoText.isEmpty()) {
+ plainText = cryptoText;
+ }
+ }
- if (edit->tabCount() == 0) return;
-
- if (edit->slotCurPageTextEdit() != nullptr) {
-
- auto decrypted = QByteArray();
- QString plainText = edit->curTextPage()->toPlainText();
-
-
- if (plainText.trimmed().startsWith(GpgConstants::GPG_FRONTEND_SHORT_CRYPTO_HEAD)) {
- auto cryptoText = getCryptText(plainText);
- if (!cryptoText.isEmpty()) {
- plainText = cryptoText;
- }
- }
-
- QByteArray text = plainText.toUtf8();
-
- GpgFrontend::GpgContext::preventNoDataErr(&text);
-
- gpgme_decrypt_result_t d_result = nullptr;
- gpgme_verify_result_t v_result = nullptr;
-
- auto *dialog = new WaitingDialog(tr("Decrypting and Verifying"), this);
-
- // Automatically import public keys that are not stored locally
- if (settings.value("advanced/autoPubkeyExchange").toBool()) {
- gpgme_verify_result_t tmp_v_result = nullptr;
- auto thread = QThread::create([&]() {
- mCtx->verify(&text, nullptr, &tmp_v_result);
- });
- thread->start();
- while (thread->isRunning()) QApplication::processEvents();
- auto *checker = new UnknownSignersChecker(mCtx, tmp_v_result);
- checker->start();
- checker->deleteLater();
- }
-
- gpgme_error_t error;
- auto thread = QThread::create([&]() {
- error = mCtx->decryptVerify(text, &decrypted, &d_result, &v_result);
- });
- connect(thread, SIGNAL(finished()), thread, SLOT(deleteLater()));
- thread->start();
-
- while (thread->isRunning()) QApplication::processEvents();
-
- dialog->close();
-
- qDebug() << "Start Analyse Result";
+ QByteArray text = plainText.toUtf8();
- infoBoard->associateTextEdit(edit->curTextPage());
+ GpgFrontend::GpgContext::preventNoDataErr(&text);
- if (gpgme_err_code(error) == GPG_ERR_NO_ERROR)
- edit->slotFillTextEditWithText(QString::fromUtf8(decrypted));
+ gpgme_decrypt_result_t d_result = nullptr;
+ gpgme_verify_result_t v_result = nullptr;
- auto resultAnalyseDecrypt = new DecryptResultAnalyse(mCtx, error, d_result);
- auto resultAnalyseVerify = new VerifyResultAnalyse(mCtx, error, v_result);
+ auto* dialog = new WaitingDialog(tr("Decrypting and Verifying"), this);
- int status = std::min(resultAnalyseDecrypt->getStatus(), resultAnalyseVerify->getStatus());
- auto &reportText = resultAnalyseDecrypt->getResultReport() + resultAnalyseVerify->getResultReport();
- if (status < 0)
- infoBoard->slotRefresh(reportText, INFO_ERROR_CRITICAL);
- else if (status > 0)
- infoBoard->slotRefresh(reportText, INFO_ERROR_OK);
- else
- infoBoard->slotRefresh(reportText, INFO_ERROR_WARN);
+ // Automatically import public keys that are not stored locally
+ if (settings.value("advanced/autoPubkeyExchange").toBool()) {
+ gpgme_verify_result_t tmp_v_result = nullptr;
+ auto thread = QThread::create(
+ [&]() { mCtx->verify(&text, nullptr, &tmp_v_result); });
+ thread->start();
+ while (thread->isRunning())
+ QApplication::processEvents();
+ auto* checker = new UnknownSignersChecker(mCtx, tmp_v_result);
+ checker->start();
+ checker->deleteLater();
+ }
- if (resultAnalyseVerify->getStatus() >= 0) {
- infoBoard->resetOptionActionsMenu();
- infoBoard->addOptionalAction("Show Verify Details", [this, error, v_result]() {
- VerifyDetailsDialog(this, mCtx, mKeyList, error, v_result);
- });
- }
- delete resultAnalyseDecrypt;
- delete resultAnalyseVerify;
+ gpgme_error_t error;
+ auto thread = QThread::create([&]() {
+ error = mCtx->decryptVerify(text, &decrypted, &d_result, &v_result);
+ });
+ connect(thread, SIGNAL(finished()), thread, SLOT(deleteLater()));
+ thread->start();
+
+ while (thread->isRunning())
+ QApplication::processEvents();
+
+ dialog->close();
+
+ qDebug() << "Start Analyse Result";
+
+ infoBoard->associateTextEdit(edit->curTextPage());
+
+ if (gpgme_err_code(error) == GPG_ERR_NO_ERROR)
+ edit->slotFillTextEditWithText(QString::fromUtf8(decrypted));
+
+ auto resultAnalyseDecrypt = new DecryptResultAnalyse(mCtx, error, d_result);
+ auto resultAnalyseVerify = new VerifyResultAnalyse(mCtx, error, v_result);
+
+ int status = std::min(resultAnalyseDecrypt->getStatus(),
+ resultAnalyseVerify->getStatus());
+ auto& reportText = resultAnalyseDecrypt->getResultReport() +
+ resultAnalyseVerify->getResultReport();
+ if (status < 0)
+ infoBoard->slotRefresh(reportText, INFO_ERROR_CRITICAL);
+ else if (status > 0)
+ infoBoard->slotRefresh(reportText, INFO_ERROR_OK);
+ else
+ infoBoard->slotRefresh(reportText, INFO_ERROR_WARN);
+
+ if (resultAnalyseVerify->getStatus() >= 0) {
+ infoBoard->resetOptionActionsMenu();
+ infoBoard->addOptionalAction(
+ "Show Verify Details", [this, error, v_result]() {
+ VerifyDetailsDialog(this, mCtx, mKeyList, error, v_result);
+ });
+ }
+ delete resultAnalyseDecrypt;
+ delete resultAnalyseVerify;
- qDebug() << "End Analyse Result";
+ qDebug() << "End Analyse Result";
- } else if (edit->slotCurPageFileTreeView() != nullptr) {
- this->slotFileDecryptVerify();
- }
+ } else if (edit->slotCurPageFileTreeView() != nullptr) {
+ this->slotFileDecryptVerify();
+ }
}
-
/*
* Append the selected (not checked!) Key(s) To Textedit
*/
void MainWindow::slotAppendSelectedKeys() {
- if (edit->tabCount() == 0 || edit->slotCurPageTextEdit() == nullptr) {
- return;
- }
+ if (edit->tabCount() == 0 || edit->slotCurPageTextEdit() == nullptr) {
+ return;
+ }
- auto *keyArray = new QByteArray();
- mCtx->exportKeys(mKeyList->getSelected(), keyArray);
- edit->curTextPage()->append(*keyArray);
+ auto* keyArray = new QByteArray();
+ mCtx->exportKeys(mKeyList->getSelected(), keyArray);
+ edit->curTextPage()->append(*keyArray);
}
void MainWindow::slotCopyMailAddressToClipboard() {
- if (mKeyList->getSelected()->isEmpty()) {
- return;
- }
- auto key = mCtx->getKeyRefById(mKeyList->getSelected()->first());
- if (!key.good) {
- QMessageBox::critical(nullptr, tr("Error"), tr("Key Not Found."));
- return;
- }
- QClipboard *cb = QApplication::clipboard();
- QString mail = key.email;
- cb->setText(mail);
+ if (mKeyList->getSelected()->isEmpty()) {
+ return;
+ }
+ auto key = mCtx->getKeyRefById(mKeyList->getSelected()->first());
+ if (!key.good) {
+ QMessageBox::critical(nullptr, tr("Error"), tr("Key Not Found."));
+ return;
+ }
+ QClipboard* cb = QApplication::clipboard();
+ QString mail = key.email;
+ cb->setText(mail);
}
void MainWindow::slotShowKeyDetails() {
- if (mKeyList->getSelected()->isEmpty()) {
- return;
- }
- auto key = mCtx->getKeyRefById(mKeyList->getSelected()->first());
- if (key.good) {
- new KeyDetailsDialog(mCtx, key, this);
- } else {
- QMessageBox::critical(nullptr, tr("Error"), tr("Key Not Found."));
- }
+ if (mKeyList->getSelected()->isEmpty()) {
+ return;
+ }
+ auto key = mCtx->getKeyRefById(mKeyList->getSelected()->first());
+ if (key.good) {
+ new KeyDetailsDialog(mCtx, key, this);
+ } else {
+ QMessageBox::critical(nullptr, tr("Error"), tr("Key Not Found."));
+ }
}
void MainWindow::refreshKeysFromKeyserver() {
- if (mKeyList->getSelected()->isEmpty()) {
- return;
- }
-
- auto *dialog = new KeyServerImportDialog(mCtx, mKeyList, true, this);
- dialog->show();
- dialog->slotImport(*mKeyList->getSelected());
+ if (mKeyList->getSelected()->isEmpty()) {
+ return;
+ }
+ auto* dialog = new KeyServerImportDialog(mCtx, mKeyList, true, this);
+ dialog->show();
+ dialog->slotImport(*mKeyList->getSelected());
}
void MainWindow::uploadKeyToServer() {
- QVector<GpgKey> keys;
- keys.append(mKeyList->getSelectedKey());
- auto *dialog = new KeyUploadDialog(mCtx, keys, this);
- dialog->show();
- dialog->slotUpload();
+ QVector<GpgKey> keys;
+ keys.append(mKeyList->getSelectedKey());
+ auto* dialog = new KeyUploadDialog(mCtx, keys, this);
+ dialog->show();
+ dialog->slotUpload();
}
-
-void MainWindow::slotOpenFile(QString &path) {
- edit->slotOpenFile(path);
+void MainWindow::slotOpenFile(QString& path) {
+ edit->slotOpenFile(path);
}
-void MainWindow::slotVersionUpgrade(const QString &currentVersion, const QString &latestVersion) {
- if (currentVersion < latestVersion) {
- QMessageBox::warning(this,
- tr("Outdated Version"),
- tr("This version(%1) is out of date, please update the latest version in time. ").arg(
- currentVersion)
- + tr("You can download the latest version(%1) on Github Releases Page.<br/>").arg(
- latestVersion));
- } else if (currentVersion > latestVersion) {
- QMessageBox::warning(this,
- tr("Unreleased Version"),
- tr("This version(%1) has not been officially released and is not recommended for use in a production environment. <br/>").arg(
- currentVersion)
- + tr("You can download the latest version(%1) on Github Releases Page.<br/>").arg(
- latestVersion));
- }
+void MainWindow::slotVersionUpgrade(const QString& currentVersion,
+ const QString& latestVersion) {
+ if (currentVersion < latestVersion) {
+ QMessageBox::warning(this, tr("Outdated Version"),
+ tr("This version(%1) is out of date, please update "
+ "the latest version in time. ")
+ .arg(currentVersion) +
+ tr("You can download the latest version(%1) on "
+ "Github Releases Page.<br/>")
+ .arg(latestVersion));
+ } else if (currentVersion > latestVersion) {
+ QMessageBox::warning(
+ this, tr("Unreleased Version"),
+ tr("This version(%1) has not been officially released and is not "
+ "recommended for use in a production environment. <br/>")
+ .arg(currentVersion) +
+ tr("You can download the latest version(%1) on Github Releases "
+ "Page.<br/>")
+ .arg(latestVersion));
+ }
}
+
+} // namespace GpgFrontend::UI
diff --git a/src/ui/main_window/MainWindowSlotUI.cpp b/src/ui/main_window/MainWindowSlotUI.cpp
index 7065e41c..982c9efb 100644
--- a/src/ui/main_window/MainWindowSlotUI.cpp
+++ b/src/ui/main_window/MainWindowSlotUI.cpp
@@ -24,197 +24,200 @@
#include "MainWindow.h"
+namespace GpgFrontend::UI {
+
void MainWindow::slotAbout() {
- new AboutDialog(0, this);
+ new AboutDialog(0, this);
}
void MainWindow::slotCheckUpdate() {
- new AboutDialog(2, this);
+ new AboutDialog(2, this);
}
-void MainWindow::slotSetStatusBarText(const QString &text) {
- statusBar()->showMessage(text, 20000);
+void MainWindow::slotSetStatusBarText(const QString& text) {
+ statusBar()->showMessage(text, 20000);
}
void MainWindow::slotStartWizard() {
- auto *wizard = new Wizard(mCtx, keyMgmt, this);
- wizard->show();
- wizard->setModal(true);
+ auto* wizard = new Wizard(keyMgmt, this);
+ wizard->show();
+ wizard->setModal(true);
}
-
void MainWindow::slotCheckAttachmentFolder() {
- // TODO: always check?
- if (!settings.value("mime/parseMime").toBool()) {
- return;
- }
-
- QString attachmentDir = qApp->applicationDirPath() + "/attachments/";
- // filenum minus . and ..
- uint filenum = QDir(attachmentDir).count() - 2;
- if (filenum > 0) {
- QString statusText;
- if (filenum == 1) {
- statusText = tr("There is one unencrypted file in attachment folder");
- } else {
- statusText = tr("There are ") + QString::number(filenum) + tr(" unencrypted files in attachment folder");
- }
- statusBarIcon->setStatusTip(statusText);
- statusBarIcon->show();
+ // TODO: always check?
+ if (!settings.value("mime/parseMime").toBool()) {
+ return;
+ }
+
+ QString attachmentDir = qApp->applicationDirPath() + "/attachments/";
+ // filenum minus . and ..
+ uint filenum = QDir(attachmentDir).count() - 2;
+ if (filenum > 0) {
+ QString statusText;
+ if (filenum == 1) {
+ statusText = tr("There is one unencrypted file in attachment folder");
} else {
- statusBarIcon->hide();
+ statusText = tr("There are ") + QString::number(filenum) +
+ tr(" unencrypted files in attachment folder");
}
+ statusBarIcon->setStatusTip(statusText);
+ statusBarIcon->show();
+ } else {
+ statusBarIcon->hide();
+ }
}
void MainWindow::slotImportKeyFromEdit() {
- if (edit->tabCount() == 0 || edit->slotCurPageTextEdit() == nullptr)
- return;
- keyMgmt->slotImportKeys(edit->curTextPage()->toPlainText().toUtf8());
+ if (edit->tabCount() == 0 || edit->slotCurPageTextEdit() == nullptr)
+ return;
+ keyMgmt->slotImportKeys(std::make_unique<ByteArray>(
+ edit->curTextPage()->toPlainText().toStdString()));
}
void MainWindow::slotOpenKeyManagement() {
- keyMgmt->show();
- keyMgmt->raise();
- keyMgmt->activateWindow();
+ keyMgmt->show();
+ keyMgmt->raise();
+ keyMgmt->activateWindow();
}
void MainWindow::slotOpenFileTab() {
- edit->slotNewFileTab();
+ edit->slotNewFileTab();
}
void MainWindow::slotDisableTabActions(int number) {
- bool disable;
-
- if (number == -1)
- disable = true;
- else
- disable = false;
-
- if(edit->curFilePage() != nullptr) {
- disable = true;
- }
-
- printAct->setDisabled(disable);
- saveAct->setDisabled(disable);
- saveAsAct->setDisabled(disable);
- quoteAct->setDisabled(disable);
- cutAct->setDisabled(disable);
- copyAct->setDisabled(disable);
- pasteAct->setDisabled(disable);
- closeTabAct->setDisabled(disable);
- selectAllAct->setDisabled(disable);
- findAct->setDisabled(disable);
- verifyAct->setDisabled(disable);
- signAct->setDisabled(disable);
- encryptAct->setDisabled(disable);
- encryptSignAct->setDisabled(disable);
- decryptAct->setDisabled(disable);
- decryptVerifyAct->setDisabled(disable);
-
- redoAct->setDisabled(disable);
- undoAct->setDisabled(disable);
- zoomOutAct->setDisabled(disable);
- zoomInAct->setDisabled(disable);
- cleanDoubleLinebreaksAct->setDisabled(disable);
- quoteAct->setDisabled(disable);
- appendSelectedKeysAct->setDisabled(disable);
- importKeyFromEditAct->setDisabled(disable);
-
- cutPgpHeaderAct->setDisabled(disable);
- addPgpHeaderAct->setDisabled(disable);
+ bool disable;
+
+ if (number == -1)
+ disable = true;
+ else
+ disable = false;
+
+ if (edit->curFilePage() != nullptr) {
+ disable = true;
+ }
+
+ printAct->setDisabled(disable);
+ saveAct->setDisabled(disable);
+ saveAsAct->setDisabled(disable);
+ quoteAct->setDisabled(disable);
+ cutAct->setDisabled(disable);
+ copyAct->setDisabled(disable);
+ pasteAct->setDisabled(disable);
+ closeTabAct->setDisabled(disable);
+ selectAllAct->setDisabled(disable);
+ findAct->setDisabled(disable);
+ verifyAct->setDisabled(disable);
+ signAct->setDisabled(disable);
+ encryptAct->setDisabled(disable);
+ encryptSignAct->setDisabled(disable);
+ decryptAct->setDisabled(disable);
+ decryptVerifyAct->setDisabled(disable);
+
+ redoAct->setDisabled(disable);
+ undoAct->setDisabled(disable);
+ zoomOutAct->setDisabled(disable);
+ zoomInAct->setDisabled(disable);
+ cleanDoubleLinebreaksAct->setDisabled(disable);
+ quoteAct->setDisabled(disable);
+ appendSelectedKeysAct->setDisabled(disable);
+ importKeyFromEditAct->setDisabled(disable);
+
+ cutPgpHeaderAct->setDisabled(disable);
+ addPgpHeaderAct->setDisabled(disable);
}
void MainWindow::slotOpenSettingsDialog() {
+ auto dialog = new SettingsDialog(this);
+
+ connect(dialog, &SettingsDialog::finished, this, [&]() -> void {
+ qDebug() << "Setting Dialog Finished";
+
+ // Iconsize
+ QSize iconSize = settings.value("toolbar/iconsize", QSize(32, 32)).toSize();
+ this->setIconSize(iconSize);
+ importButton->setIconSize(iconSize);
+ fileEncButton->setIconSize(iconSize);
+
+ // Iconstyle
+ Qt::ToolButtonStyle buttonStyle = static_cast<Qt::ToolButtonStyle>(
+ settings.value("toolbar/iconstyle", Qt::ToolButtonTextUnderIcon)
+ .toUInt());
+ this->setToolButtonStyle(buttonStyle);
+ importButton->setToolButtonStyle(buttonStyle);
+ fileEncButton->setToolButtonStyle(buttonStyle);
+
+ // restart mainwindow if necessary
+ if (getRestartNeeded()) {
+ if (edit->maybeSaveAnyTab()) {
+ saveSettings();
+ qApp->exit(RESTART_CODE);
+ }
+ }
- auto dialog = new SettingsDialog(mCtx, this);
-
- connect(dialog, &SettingsDialog::finished, this, [&] () -> void {
-
- qDebug() << "Setting Dialog Finished";
-
- // Iconsize
- QSize iconSize = settings.value("toolbar/iconsize", QSize(32, 32)).toSize();
- this->setIconSize(iconSize);
- importButton->setIconSize(iconSize);
- fileEncButton->setIconSize(iconSize);
-
- // Iconstyle
- Qt::ToolButtonStyle buttonStyle = static_cast<Qt::ToolButtonStyle>(settings.value("toolbar/iconstyle",
- Qt::ToolButtonTextUnderIcon).toUInt());
- this->setToolButtonStyle(buttonStyle);
- importButton->setToolButtonStyle(buttonStyle);
- fileEncButton->setToolButtonStyle(buttonStyle);
-
- // restart mainwindow if necessary
- if (getRestartNeeded()) {
- if (edit->maybeSaveAnyTab()) {
- saveSettings();
- qApp->exit(RESTART_CODE);
- }
- }
-
- // steganography hide/show
- if (!settings.value("advanced/steganography").toBool()) {
- this->menuBar()->removeAction(steganoMenu->menuAction());
- } else {
- this->menuBar()->insertAction(viewMenu->menuAction(), steganoMenu->menuAction());
- }
- });
-
+ // steganography hide/show
+ if (!settings.value("advanced/steganography").toBool()) {
+ this->menuBar()->removeAction(steganoMenu->menuAction());
+ } else {
+ this->menuBar()->insertAction(viewMenu->menuAction(),
+ steganoMenu->menuAction());
+ }
+ });
}
void MainWindow::slotCleanDoubleLinebreaks() {
- if (edit->tabCount() == 0 || edit->slotCurPageTextEdit() == nullptr) {
- return;
- }
+ if (edit->tabCount() == 0 || edit->slotCurPageTextEdit() == nullptr) {
+ return;
+ }
- QString content = edit->curTextPage()->toPlainText();
- content.replace("\n\n", "\n");
- edit->slotFillTextEditWithText(content);
+ QString content = edit->curTextPage()->toPlainText();
+ content.replace("\n\n", "\n");
+ edit->slotFillTextEditWithText(content);
}
void MainWindow::slotAddPgpHeader() {
- if (edit->tabCount() == 0 || edit->slotCurPageTextEdit() == nullptr) {
- return;
- }
+ if (edit->tabCount() == 0 || edit->slotCurPageTextEdit() == nullptr) {
+ return;
+ }
- QString content = edit->curTextPage()->toPlainText().trimmed();
+ QString content = edit->curTextPage()->toPlainText().trimmed();
- content.prepend("\n\n").prepend(GpgConstants::PGP_CRYPT_BEGIN);
- content.append("\n").append(GpgConstants::PGP_CRYPT_END);
+ content.prepend("\n\n").prepend(GpgConstants::PGP_CRYPT_BEGIN);
+ content.append("\n").append(GpgConstants::PGP_CRYPT_END);
- edit->slotFillTextEditWithText(content);
+ edit->slotFillTextEditWithText(content);
}
void MainWindow::slotCutPgpHeader() {
+ if (edit->tabCount() == 0 || edit->slotCurPageTextEdit() == nullptr) {
+ return;
+ }
- if (edit->tabCount() == 0 || edit->slotCurPageTextEdit() == nullptr) {
- return;
- }
-
- QString content = edit->curTextPage()->toPlainText();
- int start = content.indexOf(GpgConstants::PGP_CRYPT_BEGIN);
- int end = content.indexOf(GpgConstants::PGP_CRYPT_END);
+ QString content = edit->curTextPage()->toPlainText();
+ int start = content.indexOf(GpgConstants::PGP_CRYPT_BEGIN);
+ int end = content.indexOf(GpgConstants::PGP_CRYPT_END);
- if (start < 0 || end < 0) {
- return;
- }
+ if (start < 0 || end < 0) {
+ return;
+ }
- // remove head
- int headEnd = content.indexOf("\n\n", start) + 2;
- content.remove(start, headEnd - start);
+ // remove head
+ int headEnd = content.indexOf("\n\n", start) + 2;
+ content.remove(start, headEnd - start);
- // remove tail
- end = content.indexOf(GpgConstants::PGP_CRYPT_END);
- content.remove(end, QString(GpgConstants::PGP_CRYPT_END).size());
+ // remove tail
+ end = content.indexOf(GpgConstants::PGP_CRYPT_END);
+ content.remove(end, QString(GpgConstants::PGP_CRYPT_END).size());
- edit->slotFillTextEditWithText(content.trimmed());
+ edit->slotFillTextEditWithText(content.trimmed());
}
void MainWindow::slotSetRestartNeeded(bool needed) {
- this->restartNeeded = needed;
+ this->restartNeeded = needed;
}
bool MainWindow::getRestartNeeded() const {
- return this->restartNeeded;
+ return this->restartNeeded;
}
+
+} // namespace GpgFrontend::UI
diff --git a/src/ui/main_window/MainWindowUI.cpp b/src/ui/main_window/MainWindowUI.cpp
index 21f6e3b7..44fed8dc 100644
--- a/src/ui/main_window/MainWindowUI.cpp
+++ b/src/ui/main_window/MainWindowUI.cpp
@@ -24,427 +24,454 @@
#include "MainWindow.h"
+namespace GpgFrontend::UI {
+
void MainWindow::createActions() {
- /* Main Menu
- */
- newTabAct = new QAction(tr("&New"), this);
- newTabAct->setIcon(QIcon(":misc_doc.png"));
- QList<QKeySequence> newTabActShortcutList;
- newTabActShortcutList.append(QKeySequence(Qt::CTRL + Qt::Key_N));
- newTabActShortcutList.append(QKeySequence(Qt::CTRL + Qt::Key_T));
- newTabAct->setShortcuts(newTabActShortcutList);
- newTabAct->setToolTip(tr("Open a new file"));
- connect(newTabAct, SIGNAL(triggered()), edit, SLOT(slotNewTab()));
-
- openAct = new QAction(tr("&Open..."), this);
- openAct->setIcon(QIcon(":fileopen.png"));
- openAct->setShortcut(QKeySequence::Open);
- openAct->setToolTip(tr("Open an existing file"));
- connect(openAct, SIGNAL(triggered()), edit, SLOT(slotOpen()));
-
- browserAct = new QAction(tr("&Browser"), this);
- browserAct->setShortcut(QKeySequence(Qt::CTRL + Qt::Key_B));
- browserAct->setToolTip(tr("Open a file browser"));
- connect(browserAct, SIGNAL(triggered()), this, SLOT(slotOpenFileTab()));
-
- saveAct = new QAction(tr("&Save"), this);
- saveAct->setIcon(QIcon(":filesave.png"));
- saveAct->setShortcut(QKeySequence::Save);
- saveAct->setToolTip(tr("Save the current File"));
- connect(saveAct, SIGNAL(triggered()), edit, SLOT(slotSave()));
-
- saveAsAct = new QAction(tr("Save &As") + "...", this);
- saveAsAct->setIcon(QIcon(":filesaveas.png"));
- saveAsAct->setShortcut(QKeySequence::SaveAs);
- saveAsAct->setToolTip(tr("Save the current File as..."));
- connect(saveAsAct, SIGNAL(triggered()), edit, SLOT(slotSaveAs()));
-
- printAct = new QAction(tr("&Print"), this);
- printAct->setIcon(QIcon(":fileprint.png"));
- printAct->setShortcut(QKeySequence::Print);
- printAct->setToolTip(tr("Print Document"));
- connect(printAct, SIGNAL(triggered()), edit, SLOT(slotPrint()));
-
- closeTabAct = new QAction(tr("&Close"), this);
- closeTabAct->setShortcut(QKeySequence::Close);
- closeTabAct->setToolTip(tr("Close file"));
- connect(closeTabAct, SIGNAL(triggered()), edit, SLOT(slotCloseTab()));
-
- quitAct = new QAction(tr("&Quit"), this);
- quitAct->setShortcut(QKeySequence::Quit);
- quitAct->setIcon(QIcon(":exit.png"));
- quitAct->setToolTip(tr("Quit Program"));
- connect(quitAct, SIGNAL(triggered()), this, SLOT(close()));
-
- /* Edit Menu
- */
- undoAct = new QAction(tr("&Undo"), this);
- undoAct->setShortcut(QKeySequence::Undo);
- undoAct->setToolTip(tr("Undo Last Edit Action"));
- connect(undoAct, SIGNAL(triggered()), edit, SLOT(slotUndo()));
-
- redoAct = new QAction(tr("&Redo"), this);
- redoAct->setShortcut(QKeySequence::Redo);
- redoAct->setToolTip(tr("Redo Last Edit Action"));
- connect(redoAct, SIGNAL(triggered()), edit, SLOT(slotRedo()));
-
- zoomInAct = new QAction(tr("Zoom In"), this);
- zoomInAct->setShortcut(QKeySequence::ZoomIn);
- connect(zoomInAct, SIGNAL(triggered()), edit, SLOT(slotZoomIn()));
-
- zoomOutAct = new QAction(tr("Zoom Out"), this);
- zoomOutAct->setShortcut(QKeySequence::ZoomOut);
- connect(zoomOutAct, SIGNAL(triggered()), edit, SLOT(slotZoomOut()));
-
- pasteAct = new QAction(tr("&Paste"), this);
- pasteAct->setIcon(QIcon(":button_paste.png"));
- pasteAct->setShortcut(QKeySequence::Paste);
- pasteAct->setToolTip(tr("Paste Text From Clipboard"));
- connect(pasteAct, SIGNAL(triggered()), edit, SLOT(slotPaste()));
-
- cutAct = new QAction(tr("Cu&t"), this);
- cutAct->setIcon(QIcon(":button_cut.png"));
- cutAct->setShortcut(QKeySequence::Cut);
- cutAct->setToolTip(tr("Cut the current selection's contents to the "
- "clipboard"));
- connect(cutAct, SIGNAL(triggered()), edit, SLOT(slotCut()));
-
- copyAct = new QAction(tr("&Copy"), this);
- copyAct->setIcon(QIcon(":button_copy.png"));
- copyAct->setShortcut(QKeySequence::Copy);
- copyAct->setToolTip(tr("Copy the current selection's contents to the "
- "clipboard"));
- connect(copyAct, SIGNAL(triggered()), edit, SLOT(slotCopy()));
-
- quoteAct = new QAction(tr("&Quote"), this);
- quoteAct->setIcon(QIcon(":quote.png"));
- quoteAct->setToolTip(tr("Quote whole text"));
- connect(quoteAct, SIGNAL(triggered()), edit, SLOT(slotQuote()));
-
- selectAllAct = new QAction(tr("Select &All"), this);
- selectAllAct->setIcon(QIcon(":edit.png"));
- selectAllAct->setShortcut(QKeySequence::SelectAll);
- selectAllAct->setToolTip(tr("Select the whole text"));
- connect(selectAllAct, SIGNAL(triggered()), edit, SLOT(slotSelectAll()));
-
- findAct = new QAction(tr("&Find"), this);
- findAct->setShortcut(QKeySequence::Find);
- findAct->setToolTip(tr("Find a word"));
- connect(findAct, SIGNAL(triggered()), this, SLOT(slotFind()));
-
- cleanDoubleLinebreaksAct = new QAction(tr("Remove &spacing"), this);
- cleanDoubleLinebreaksAct->setIcon(QIcon(":format-line-spacing-triple.png"));
- //cleanDoubleLineBreaksAct->setShortcut(QKeySequence::SelectAll);
- cleanDoubleLinebreaksAct->setToolTip(tr("Remove double linebreaks, e.g. in pasted text from webmailer"));
- connect(cleanDoubleLinebreaksAct, SIGNAL(triggered()), this, SLOT(slotCleanDoubleLinebreaks()));
-
- openSettingsAct = new QAction(tr("Se&ttings"), this);
- openSettingsAct->setToolTip(tr("Open settings dialog"));
- openSettingsAct->setShortcut(QKeySequence::Preferences);
- connect(openSettingsAct, SIGNAL(triggered()), this, SLOT(slotOpenSettingsDialog()));
-
- /* Crypt Menu
- */
- encryptAct = new QAction(tr("&Encrypt"), this);
- encryptAct->setIcon(QIcon(":encrypted.png"));
- encryptAct->setShortcut(QKeySequence(Qt::CTRL + Qt::Key_E));
- encryptAct->setToolTip(tr("Encrypt Message"));
- connect(encryptAct, SIGNAL(triggered()), this, SLOT(slotEncrypt()));
-
- encryptSignAct = new QAction(tr("&Encrypt &Sign"), this);
- encryptSignAct->setIcon(QIcon(":encrypted_signed.png"));
- encryptSignAct->setShortcut(QKeySequence(Qt::CTRL + Qt::SHIFT + Qt::Key_E));
- encryptSignAct->setToolTip(tr("Encrypt and Sign Message"));
- connect(encryptSignAct, SIGNAL(triggered()), this, SLOT(slotEncryptSign()));
-
- decryptAct = new QAction(tr("&Decrypt"), this);
- decryptAct->setIcon(QIcon(":decrypted.png"));
- decryptAct->setShortcut(QKeySequence(Qt::CTRL + Qt::Key_D));
- decryptAct->setToolTip(tr("Decrypt Message"));
- connect(decryptAct, SIGNAL(triggered()), this, SLOT(slotDecrypt()));
-
- decryptVerifyAct = new QAction(tr("&Decrypt &Verify"), this);
- decryptVerifyAct->setIcon(QIcon(":decrypted_verified.png"));
- decryptVerifyAct->setShortcut(QKeySequence(Qt::CTRL + Qt::SHIFT + Qt::Key_D));
- decryptVerifyAct->setToolTip(tr("Decrypt and Verify Message"));
- connect(decryptVerifyAct, SIGNAL(triggered()), this, SLOT(slotDecryptVerify()));
-
- /*
- * File encryption submenu
- */
- fileEncryptAct = new QAction(tr("&Encrypt File"), this);
- fileEncryptAct->setToolTip(tr("Encrypt File"));
- connect(fileEncryptAct, SIGNAL(triggered()), this, SLOT(slotFileEncryptCustom()));
-
- fileDecryptAct = new QAction(tr("&Decrypt File"), this);
- fileDecryptAct->setToolTip(tr("Decrypt File"));
- connect(fileDecryptAct, SIGNAL(triggered()), this, SLOT(slotFileDecryptCustom()));
-
- fileSignAct = new QAction(tr("&Sign File"), this);
- fileSignAct->setToolTip(tr("Sign File"));
- connect(fileSignAct, SIGNAL(triggered()), this, SLOT(slotFileSignCustom()));
-
- fileVerifyAct = new QAction(tr("&Verify File"), this);
- fileVerifyAct->setToolTip(tr("Verify File"));
- connect(fileVerifyAct, SIGNAL(triggered()), this, SLOT(slotFileVerifyCustom()));
-
-
- signAct = new QAction(tr("&Sign"), this);
- signAct->setIcon(QIcon(":signature.png"));
- signAct->setShortcut(QKeySequence(Qt::CTRL + Qt::SHIFT + Qt::Key_I));
- signAct->setToolTip(tr("Sign Message"));
- connect(signAct, SIGNAL(triggered()), this, SLOT(slotSign()));
-
- verifyAct = new QAction(tr("&Verify"), this);
- verifyAct->setIcon(QIcon(":verify.png"));
- verifyAct->setShortcut(QKeySequence(Qt::CTRL + Qt::SHIFT + Qt::Key_V));
- verifyAct->setToolTip(tr("Verify Message"));
- connect(verifyAct, SIGNAL(triggered()), this, SLOT(slotVerify()));
-
- /* Key Menu
- */
-
- importKeyFromEditAct = new QAction(tr("&Editor"), this);
- importKeyFromEditAct->setIcon(QIcon(":txt.png"));
- importKeyFromEditAct->setToolTip(tr("Import New Key From Editor"));
- connect(importKeyFromEditAct, SIGNAL(triggered()), this, SLOT(slotImportKeyFromEdit()));
-
- openKeyManagementAct = new QAction(tr("Manage &Keys"), this);
- openKeyManagementAct->setIcon(QIcon(":keymgmt.png"));
- openKeyManagementAct->setToolTip(tr("Open Keymanagement"));
- connect(openKeyManagementAct, SIGNAL(triggered()), this, SLOT(slotOpenKeyManagement()));
-
- /*
- * About Menu
- */
- aboutAct = new QAction(tr("&About"), this);
- aboutAct->setIcon(QIcon(":help.png"));
- aboutAct->setToolTip(tr("Show the application's About box"));
- connect(aboutAct, SIGNAL(triggered()), this, SLOT(slotAbout()));
-
- /*
- * Check Update Menu
- */
- checkUpdateAct = new QAction(tr("&Check for Updates"), this);
- checkUpdateAct->setIcon(QIcon(":help.png"));
- checkUpdateAct->setToolTip(tr("Check for updates"));
- connect(checkUpdateAct, SIGNAL(triggered()), this, SLOT(slotCheckUpdate()));
-
- startWizardAct = new QAction(tr("Open &Wizard"), this);
- startWizardAct->setToolTip(tr("Open the wizard"));
- connect(startWizardAct, SIGNAL(triggered()), this, SLOT(slotStartWizard()));
-
- /* Popup-Menu-Action for KeyList
- */
- appendSelectedKeysAct = new QAction(tr("Append Selected Key(s) To Text"), this);
- appendSelectedKeysAct->setToolTip(tr("Append The Selected Keys To Text in Editor"));
- connect(appendSelectedKeysAct, SIGNAL(triggered()), this, SLOT(slotAppendSelectedKeys()));
-
- copyMailAddressToClipboardAct = new QAction(tr("Copy Email"), this);
- copyMailAddressToClipboardAct->setToolTip(tr("Copy selected Email to clipboard"));
- connect(copyMailAddressToClipboardAct, SIGNAL(triggered()), this, SLOT(slotCopyMailAddressToClipboard()));
-
- // TODO: find central place for shared actions, to avoid code-duplication with keymgmt.cpp
- showKeyDetailsAct = new QAction(tr("Show Key Details"), this);
- showKeyDetailsAct->setToolTip(tr("Show Details for this Key"));
- connect(showKeyDetailsAct, SIGNAL(triggered()), this, SLOT(slotShowKeyDetails()));
-
- refreshKeysFromKeyserverAct = new QAction(tr("Refresh Key From Key Server"), this);
- refreshKeysFromKeyserverAct->setToolTip(tr("Refresh key from default key server"));
- connect(refreshKeysFromKeyserverAct, SIGNAL(triggered()), this, SLOT(refreshKeysFromKeyserver()));
-
- uploadKeyToServerAct = new QAction(tr("Upload Public Key(s) To Server"), this);
- uploadKeyToServerAct->setToolTip(tr("Upload The Selected Public Keys To Server"));
- connect(uploadKeyToServerAct, SIGNAL(triggered()), this, SLOT(uploadKeyToServer()));
-
- /* Key-Shortcuts for Tab-Switchung-Action
- */
- switchTabUpAct = new QAction(this);
- switchTabUpAct->setShortcut(QKeySequence::NextChild);
- connect(switchTabUpAct, SIGNAL(triggered()), edit, SLOT(slotSwitchTabUp()));
- this->addAction(switchTabUpAct);
-
- switchTabDownAct = new QAction(this);
- switchTabDownAct->setShortcut(QKeySequence::PreviousChild);
- connect(switchTabDownAct, SIGNAL(triggered()), edit, SLOT(slotSwitchTabDown()));
- this->addAction(switchTabDownAct);
-
- cutPgpHeaderAct = new QAction(tr("Remove PGP Header"), this);
- connect(cutPgpHeaderAct, SIGNAL(triggered()), this, SLOT(slotCutPgpHeader()));
-
- addPgpHeaderAct = new QAction(tr("Add PGP Header"), this);
- connect(addPgpHeaderAct, SIGNAL(triggered()), this, SLOT(slotAddPgpHeader()));
+ /* Main Menu
+ */
+ newTabAct = new QAction(tr("&New"), this);
+ newTabAct->setIcon(QIcon(":misc_doc.png"));
+ QList<QKeySequence> newTabActShortcutList;
+ newTabActShortcutList.append(QKeySequence(Qt::CTRL + Qt::Key_N));
+ newTabActShortcutList.append(QKeySequence(Qt::CTRL + Qt::Key_T));
+ newTabAct->setShortcuts(newTabActShortcutList);
+ newTabAct->setToolTip(tr("Open a new file"));
+ connect(newTabAct, SIGNAL(triggered()), edit, SLOT(slotNewTab()));
+
+ openAct = new QAction(tr("&Open..."), this);
+ openAct->setIcon(QIcon(":fileopen.png"));
+ openAct->setShortcut(QKeySequence::Open);
+ openAct->setToolTip(tr("Open an existing file"));
+ connect(openAct, SIGNAL(triggered()), edit, SLOT(slotOpen()));
+
+ browserAct = new QAction(tr("&Browser"), this);
+ browserAct->setShortcut(QKeySequence(Qt::CTRL + Qt::Key_B));
+ browserAct->setToolTip(tr("Open a file browser"));
+ connect(browserAct, SIGNAL(triggered()), this, SLOT(slotOpenFileTab()));
+
+ saveAct = new QAction(tr("&Save"), this);
+ saveAct->setIcon(QIcon(":filesave.png"));
+ saveAct->setShortcut(QKeySequence::Save);
+ saveAct->setToolTip(tr("Save the current File"));
+ connect(saveAct, SIGNAL(triggered()), edit, SLOT(slotSave()));
+
+ saveAsAct = new QAction(tr("Save &As") + "...", this);
+ saveAsAct->setIcon(QIcon(":filesaveas.png"));
+ saveAsAct->setShortcut(QKeySequence::SaveAs);
+ saveAsAct->setToolTip(tr("Save the current File as..."));
+ connect(saveAsAct, SIGNAL(triggered()), edit, SLOT(slotSaveAs()));
+
+ printAct = new QAction(tr("&Print"), this);
+ printAct->setIcon(QIcon(":fileprint.png"));
+ printAct->setShortcut(QKeySequence::Print);
+ printAct->setToolTip(tr("Print Document"));
+ connect(printAct, SIGNAL(triggered()), edit, SLOT(slotPrint()));
+
+ closeTabAct = new QAction(tr("&Close"), this);
+ closeTabAct->setShortcut(QKeySequence::Close);
+ closeTabAct->setToolTip(tr("Close file"));
+ connect(closeTabAct, SIGNAL(triggered()), edit, SLOT(slotCloseTab()));
+
+ quitAct = new QAction(tr("&Quit"), this);
+ quitAct->setShortcut(QKeySequence::Quit);
+ quitAct->setIcon(QIcon(":exit.png"));
+ quitAct->setToolTip(tr("Quit Program"));
+ connect(quitAct, SIGNAL(triggered()), this, SLOT(close()));
+
+ /* Edit Menu
+ */
+ undoAct = new QAction(tr("&Undo"), this);
+ undoAct->setShortcut(QKeySequence::Undo);
+ undoAct->setToolTip(tr("Undo Last Edit Action"));
+ connect(undoAct, SIGNAL(triggered()), edit, SLOT(slotUndo()));
+
+ redoAct = new QAction(tr("&Redo"), this);
+ redoAct->setShortcut(QKeySequence::Redo);
+ redoAct->setToolTip(tr("Redo Last Edit Action"));
+ connect(redoAct, SIGNAL(triggered()), edit, SLOT(slotRedo()));
+
+ zoomInAct = new QAction(tr("Zoom In"), this);
+ zoomInAct->setShortcut(QKeySequence::ZoomIn);
+ connect(zoomInAct, SIGNAL(triggered()), edit, SLOT(slotZoomIn()));
+
+ zoomOutAct = new QAction(tr("Zoom Out"), this);
+ zoomOutAct->setShortcut(QKeySequence::ZoomOut);
+ connect(zoomOutAct, SIGNAL(triggered()), edit, SLOT(slotZoomOut()));
+
+ pasteAct = new QAction(tr("&Paste"), this);
+ pasteAct->setIcon(QIcon(":button_paste.png"));
+ pasteAct->setShortcut(QKeySequence::Paste);
+ pasteAct->setToolTip(tr("Paste Text From Clipboard"));
+ connect(pasteAct, SIGNAL(triggered()), edit, SLOT(slotPaste()));
+
+ cutAct = new QAction(tr("Cu&t"), this);
+ cutAct->setIcon(QIcon(":button_cut.png"));
+ cutAct->setShortcut(QKeySequence::Cut);
+ cutAct->setToolTip(
+ tr("Cut the current selection's contents to the "
+ "clipboard"));
+ connect(cutAct, SIGNAL(triggered()), edit, SLOT(slotCut()));
+
+ copyAct = new QAction(tr("&Copy"), this);
+ copyAct->setIcon(QIcon(":button_copy.png"));
+ copyAct->setShortcut(QKeySequence::Copy);
+ copyAct->setToolTip(
+ tr("Copy the current selection's contents to the "
+ "clipboard"));
+ connect(copyAct, SIGNAL(triggered()), edit, SLOT(slotCopy()));
+
+ quoteAct = new QAction(tr("&Quote"), this);
+ quoteAct->setIcon(QIcon(":quote.png"));
+ quoteAct->setToolTip(tr("Quote whole text"));
+ connect(quoteAct, SIGNAL(triggered()), edit, SLOT(slotQuote()));
+
+ selectAllAct = new QAction(tr("Select &All"), this);
+ selectAllAct->setIcon(QIcon(":edit.png"));
+ selectAllAct->setShortcut(QKeySequence::SelectAll);
+ selectAllAct->setToolTip(tr("Select the whole text"));
+ connect(selectAllAct, SIGNAL(triggered()), edit, SLOT(slotSelectAll()));
+
+ findAct = new QAction(tr("&Find"), this);
+ findAct->setShortcut(QKeySequence::Find);
+ findAct->setToolTip(tr("Find a word"));
+ connect(findAct, SIGNAL(triggered()), this, SLOT(slotFind()));
+
+ cleanDoubleLinebreaksAct = new QAction(tr("Remove &spacing"), this);
+ cleanDoubleLinebreaksAct->setIcon(QIcon(":format-line-spacing-triple.png"));
+ // cleanDoubleLineBreaksAct->setShortcut(QKeySequence::SelectAll);
+ cleanDoubleLinebreaksAct->setToolTip(
+ tr("Remove double linebreaks, e.g. in pasted text from webmailer"));
+ connect(cleanDoubleLinebreaksAct, SIGNAL(triggered()), this,
+ SLOT(slotCleanDoubleLinebreaks()));
+
+ openSettingsAct = new QAction(tr("Se&ttings"), this);
+ openSettingsAct->setToolTip(tr("Open settings dialog"));
+ openSettingsAct->setShortcut(QKeySequence::Preferences);
+ connect(openSettingsAct, SIGNAL(triggered()), this,
+ SLOT(slotOpenSettingsDialog()));
+
+ /* Crypt Menu
+ */
+ encryptAct = new QAction(tr("&Encrypt"), this);
+ encryptAct->setIcon(QIcon(":encrypted.png"));
+ encryptAct->setShortcut(QKeySequence(Qt::CTRL + Qt::Key_E));
+ encryptAct->setToolTip(tr("Encrypt Message"));
+ connect(encryptAct, SIGNAL(triggered()), this, SLOT(slotEncrypt()));
+
+ encryptSignAct = new QAction(tr("&Encrypt &Sign"), this);
+ encryptSignAct->setIcon(QIcon(":encrypted_signed.png"));
+ encryptSignAct->setShortcut(QKeySequence(Qt::CTRL + Qt::SHIFT + Qt::Key_E));
+ encryptSignAct->setToolTip(tr("Encrypt and Sign Message"));
+ connect(encryptSignAct, SIGNAL(triggered()), this, SLOT(slotEncryptSign()));
+
+ decryptAct = new QAction(tr("&Decrypt"), this);
+ decryptAct->setIcon(QIcon(":decrypted.png"));
+ decryptAct->setShortcut(QKeySequence(Qt::CTRL + Qt::Key_D));
+ decryptAct->setToolTip(tr("Decrypt Message"));
+ connect(decryptAct, SIGNAL(triggered()), this, SLOT(slotDecrypt()));
+
+ decryptVerifyAct = new QAction(tr("&Decrypt &Verify"), this);
+ decryptVerifyAct->setIcon(QIcon(":decrypted_verified.png"));
+ decryptVerifyAct->setShortcut(QKeySequence(Qt::CTRL + Qt::SHIFT + Qt::Key_D));
+ decryptVerifyAct->setToolTip(tr("Decrypt and Verify Message"));
+ connect(decryptVerifyAct, SIGNAL(triggered()), this,
+ SLOT(slotDecryptVerify()));
+
+ /*
+ * File encryption submenu
+ */
+ fileEncryptAct = new QAction(tr("&Encrypt File"), this);
+ fileEncryptAct->setToolTip(tr("Encrypt File"));
+ connect(fileEncryptAct, SIGNAL(triggered()), this,
+ SLOT(slotFileEncryptCustom()));
+
+ fileDecryptAct = new QAction(tr("&Decrypt File"), this);
+ fileDecryptAct->setToolTip(tr("Decrypt File"));
+ connect(fileDecryptAct, SIGNAL(triggered()), this,
+ SLOT(slotFileDecryptCustom()));
+
+ fileSignAct = new QAction(tr("&Sign File"), this);
+ fileSignAct->setToolTip(tr("Sign File"));
+ connect(fileSignAct, SIGNAL(triggered()), this, SLOT(slotFileSignCustom()));
+
+ fileVerifyAct = new QAction(tr("&Verify File"), this);
+ fileVerifyAct->setToolTip(tr("Verify File"));
+ connect(fileVerifyAct, SIGNAL(triggered()), this,
+ SLOT(slotFileVerifyCustom()));
+
+ signAct = new QAction(tr("&Sign"), this);
+ signAct->setIcon(QIcon(":signature.png"));
+ signAct->setShortcut(QKeySequence(Qt::CTRL + Qt::SHIFT + Qt::Key_I));
+ signAct->setToolTip(tr("Sign Message"));
+ connect(signAct, SIGNAL(triggered()), this, SLOT(slotSign()));
+
+ verifyAct = new QAction(tr("&Verify"), this);
+ verifyAct->setIcon(QIcon(":verify.png"));
+ verifyAct->setShortcut(QKeySequence(Qt::CTRL + Qt::SHIFT + Qt::Key_V));
+ verifyAct->setToolTip(tr("Verify Message"));
+ connect(verifyAct, SIGNAL(triggered()), this, SLOT(slotVerify()));
+
+ /* Key Menu
+ */
+
+ importKeyFromEditAct = new QAction(tr("&Editor"), this);
+ importKeyFromEditAct->setIcon(QIcon(":txt.png"));
+ importKeyFromEditAct->setToolTip(tr("Import New Key From Editor"));
+ connect(importKeyFromEditAct, SIGNAL(triggered()), this,
+ SLOT(slotImportKeyFromEdit()));
+
+ openKeyManagementAct = new QAction(tr("Manage &Keys"), this);
+ openKeyManagementAct->setIcon(QIcon(":keymgmt.png"));
+ openKeyManagementAct->setToolTip(tr("Open Keymanagement"));
+ connect(openKeyManagementAct, SIGNAL(triggered()), this,
+ SLOT(slotOpenKeyManagement()));
+
+ /*
+ * About Menu
+ */
+ aboutAct = new QAction(tr("&About"), this);
+ aboutAct->setIcon(QIcon(":help.png"));
+ aboutAct->setToolTip(tr("Show the application's About box"));
+ connect(aboutAct, SIGNAL(triggered()), this, SLOT(slotAbout()));
+
+ /*
+ * Check Update Menu
+ */
+ checkUpdateAct = new QAction(tr("&Check for Updates"), this);
+ checkUpdateAct->setIcon(QIcon(":help.png"));
+ checkUpdateAct->setToolTip(tr("Check for updates"));
+ connect(checkUpdateAct, SIGNAL(triggered()), this, SLOT(slotCheckUpdate()));
+
+ startWizardAct = new QAction(tr("Open &Wizard"), this);
+ startWizardAct->setToolTip(tr("Open the wizard"));
+ connect(startWizardAct, SIGNAL(triggered()), this, SLOT(slotStartWizard()));
+
+ /* Popup-Menu-Action for KeyList
+ */
+ appendSelectedKeysAct =
+ new QAction(tr("Append Selected Key(s) To Text"), this);
+ appendSelectedKeysAct->setToolTip(
+ tr("Append The Selected Keys To Text in Editor"));
+ connect(appendSelectedKeysAct, SIGNAL(triggered()), this,
+ SLOT(slotAppendSelectedKeys()));
+
+ copyMailAddressToClipboardAct = new QAction(tr("Copy Email"), this);
+ copyMailAddressToClipboardAct->setToolTip(
+ tr("Copy selected Email to clipboard"));
+ connect(copyMailAddressToClipboardAct, SIGNAL(triggered()), this,
+ SLOT(slotCopyMailAddressToClipboard()));
+
+ // TODO: find central place for shared actions, to avoid code-duplication with
+ // keymgmt.cpp
+ showKeyDetailsAct = new QAction(tr("Show Key Details"), this);
+ showKeyDetailsAct->setToolTip(tr("Show Details for this Key"));
+ connect(showKeyDetailsAct, SIGNAL(triggered()), this,
+ SLOT(slotShowKeyDetails()));
+
+ refreshKeysFromKeyserverAct =
+ new QAction(tr("Refresh Key From Key Server"), this);
+ refreshKeysFromKeyserverAct->setToolTip(
+ tr("Refresh key from default key server"));
+ connect(refreshKeysFromKeyserverAct, SIGNAL(triggered()), this,
+ SLOT(refreshKeysFromKeyserver()));
+
+ uploadKeyToServerAct =
+ new QAction(tr("Upload Public Key(s) To Server"), this);
+ uploadKeyToServerAct->setToolTip(
+ tr("Upload The Selected Public Keys To Server"));
+ connect(uploadKeyToServerAct, SIGNAL(triggered()), this,
+ SLOT(uploadKeyToServer()));
+
+ /* Key-Shortcuts for Tab-Switchung-Action
+ */
+ switchTabUpAct = new QAction(this);
+ switchTabUpAct->setShortcut(QKeySequence::NextChild);
+ connect(switchTabUpAct, SIGNAL(triggered()), edit, SLOT(slotSwitchTabUp()));
+ this->addAction(switchTabUpAct);
+
+ switchTabDownAct = new QAction(this);
+ switchTabDownAct->setShortcut(QKeySequence::PreviousChild);
+ connect(switchTabDownAct, SIGNAL(triggered()), edit,
+ SLOT(slotSwitchTabDown()));
+ this->addAction(switchTabDownAct);
+
+ cutPgpHeaderAct = new QAction(tr("Remove PGP Header"), this);
+ connect(cutPgpHeaderAct, SIGNAL(triggered()), this, SLOT(slotCutPgpHeader()));
+
+ addPgpHeaderAct = new QAction(tr("Add PGP Header"), this);
+ connect(addPgpHeaderAct, SIGNAL(triggered()), this, SLOT(slotAddPgpHeader()));
}
void MainWindow::createMenus() {
- fileMenu = menuBar()->addMenu(tr("&File"));
- fileMenu->addAction(newTabAct);
- fileMenu->addAction(browserAct);
- fileMenu->addAction(openAct);
- fileMenu->addSeparator();
- fileMenu->addAction(saveAct);
- fileMenu->addAction(saveAsAct);
- fileMenu->addSeparator();
- fileMenu->addAction(printAct);
- fileMenu->addSeparator();
- fileMenu->addAction(closeTabAct);
- fileMenu->addAction(quitAct);
-
- editMenu = menuBar()->addMenu(tr("&Edit"));
- editMenu->addAction(undoAct);
- editMenu->addAction(redoAct);
- editMenu->addSeparator();
- editMenu->addAction(zoomInAct);
- editMenu->addAction(zoomOutAct);
- editMenu->addSeparator();
- editMenu->addAction(copyAct);
- editMenu->addAction(cutAct);
- editMenu->addAction(pasteAct);
- editMenu->addAction(selectAllAct);
- editMenu->addAction(findAct);
- editMenu->addSeparator();
- editMenu->addAction(quoteAct);
- editMenu->addAction(cleanDoubleLinebreaksAct);
- editMenu->addSeparator();
- editMenu->addAction(openSettingsAct);
-
- fileEncMenu = new QMenu(tr("&File..."));
- fileEncMenu->addAction(fileEncryptAct);
- fileEncMenu->addAction(fileDecryptAct);
- fileEncMenu->addAction(fileSignAct);
- fileEncMenu->addAction(fileVerifyAct);
-
- cryptMenu = menuBar()->addMenu(tr("&Crypt"));
- cryptMenu->addAction(encryptAct);
- cryptMenu->addAction(encryptSignAct);
- cryptMenu->addAction(decryptAct);
- cryptMenu->addAction(decryptVerifyAct);
- cryptMenu->addSeparator();
- cryptMenu->addAction(signAct);
- cryptMenu->addAction(verifyAct);
- cryptMenu->addSeparator();
- cryptMenu->addMenu(fileEncMenu);
-
- keyMenu = menuBar()->addMenu(tr("&Keys"));
- importKeyMenu = keyMenu->addMenu(tr("&Import Key"));
- importKeyMenu->setIcon(QIcon(":key_import.png"));
- importKeyMenu->addAction(keyMgmt->importKeyFromFileAct);
- importKeyMenu->addAction(importKeyFromEditAct);
- importKeyMenu->addAction(keyMgmt->importKeyFromClipboardAct);
- importKeyMenu->addAction(keyMgmt->importKeyFromKeyServerAct);
- importKeyMenu->addAction(keyMgmt->importKeyFromKeyServerAct);
- keyMenu->addAction(openKeyManagementAct);
-
- steganoMenu = menuBar()->addMenu(tr("&Steganography"));
- steganoMenu->addAction(cutPgpHeaderAct);
- steganoMenu->addAction(addPgpHeaderAct);
-
- // Hide menu, when steganography menu is disabled in settings
- if (!settings.value("advanced/steganography").toBool()) {
- this->menuBar()->removeAction(steganoMenu->menuAction());
- }
-
- viewMenu = menuBar()->addMenu(tr("&View"));
-
- helpMenu = menuBar()->addMenu(tr("&Help"));
- helpMenu->addAction(startWizardAct);
- helpMenu->addSeparator();
- helpMenu->addAction(checkUpdateAct);
- helpMenu->addAction(aboutAct);
-
+ fileMenu = menuBar()->addMenu(tr("&File"));
+ fileMenu->addAction(newTabAct);
+ fileMenu->addAction(browserAct);
+ fileMenu->addAction(openAct);
+ fileMenu->addSeparator();
+ fileMenu->addAction(saveAct);
+ fileMenu->addAction(saveAsAct);
+ fileMenu->addSeparator();
+ fileMenu->addAction(printAct);
+ fileMenu->addSeparator();
+ fileMenu->addAction(closeTabAct);
+ fileMenu->addAction(quitAct);
+
+ editMenu = menuBar()->addMenu(tr("&Edit"));
+ editMenu->addAction(undoAct);
+ editMenu->addAction(redoAct);
+ editMenu->addSeparator();
+ editMenu->addAction(zoomInAct);
+ editMenu->addAction(zoomOutAct);
+ editMenu->addSeparator();
+ editMenu->addAction(copyAct);
+ editMenu->addAction(cutAct);
+ editMenu->addAction(pasteAct);
+ editMenu->addAction(selectAllAct);
+ editMenu->addAction(findAct);
+ editMenu->addSeparator();
+ editMenu->addAction(quoteAct);
+ editMenu->addAction(cleanDoubleLinebreaksAct);
+ editMenu->addSeparator();
+ editMenu->addAction(openSettingsAct);
+
+ fileEncMenu = new QMenu(tr("&File..."));
+ fileEncMenu->addAction(fileEncryptAct);
+ fileEncMenu->addAction(fileDecryptAct);
+ fileEncMenu->addAction(fileSignAct);
+ fileEncMenu->addAction(fileVerifyAct);
+
+ cryptMenu = menuBar()->addMenu(tr("&Crypt"));
+ cryptMenu->addAction(encryptAct);
+ cryptMenu->addAction(encryptSignAct);
+ cryptMenu->addAction(decryptAct);
+ cryptMenu->addAction(decryptVerifyAct);
+ cryptMenu->addSeparator();
+ cryptMenu->addAction(signAct);
+ cryptMenu->addAction(verifyAct);
+ cryptMenu->addSeparator();
+ cryptMenu->addMenu(fileEncMenu);
+
+ keyMenu = menuBar()->addMenu(tr("&Keys"));
+ importKeyMenu = keyMenu->addMenu(tr("&Import Key"));
+ importKeyMenu->setIcon(QIcon(":key_import.png"));
+ importKeyMenu->addAction(keyMgmt->importKeyFromFileAct);
+ importKeyMenu->addAction(importKeyFromEditAct);
+ importKeyMenu->addAction(keyMgmt->importKeyFromClipboardAct);
+ importKeyMenu->addAction(keyMgmt->importKeyFromKeyServerAct);
+ importKeyMenu->addAction(keyMgmt->importKeyFromKeyServerAct);
+ keyMenu->addAction(openKeyManagementAct);
+
+ steganoMenu = menuBar()->addMenu(tr("&Steganography"));
+ steganoMenu->addAction(cutPgpHeaderAct);
+ steganoMenu->addAction(addPgpHeaderAct);
+
+ // Hide menu, when steganography menu is disabled in settings
+ if (!settings.value("advanced/steganography").toBool()) {
+ this->menuBar()->removeAction(steganoMenu->menuAction());
+ }
+
+ viewMenu = menuBar()->addMenu(tr("&View"));
+
+ helpMenu = menuBar()->addMenu(tr("&Help"));
+ helpMenu->addAction(startWizardAct);
+ helpMenu->addSeparator();
+ helpMenu->addAction(checkUpdateAct);
+ helpMenu->addAction(aboutAct);
}
void MainWindow::createToolBars() {
- fileToolBar = addToolBar(tr("File"));
- fileToolBar->setObjectName("fileToolBar");
- fileToolBar->addAction(newTabAct);
- fileToolBar->addAction(openAct);
- fileToolBar->addAction(saveAct);
- fileToolBar->hide();
- viewMenu->addAction(fileToolBar->toggleViewAction());
-
- cryptToolBar = addToolBar(tr("Crypt"));
- cryptToolBar->setObjectName("cryptToolBar");
- cryptToolBar->addAction(encryptAct);
- cryptToolBar->addAction(encryptSignAct);
- cryptToolBar->addAction(decryptAct);
- cryptToolBar->addAction(decryptVerifyAct);
- cryptToolBar->addAction(signAct);
- cryptToolBar->addAction(verifyAct);
- viewMenu->addAction(cryptToolBar->toggleViewAction());
-
- keyToolBar = addToolBar(tr("Key"));
- keyToolBar->setObjectName("keyToolBar");
- keyToolBar->addAction(openKeyManagementAct);
- viewMenu->addAction(keyToolBar->toggleViewAction());
-
- editToolBar = addToolBar(tr("Edit"));
- editToolBar->setObjectName("editToolBar");
- editToolBar->addAction(copyAct);
- editToolBar->addAction(pasteAct);
- editToolBar->addAction(selectAllAct);
- viewMenu->addAction(editToolBar->toggleViewAction());
-
- specialEditToolBar = addToolBar(tr("Special Edit"));
- specialEditToolBar->setObjectName("specialEditToolBar");
- specialEditToolBar->addAction(quoteAct);
- specialEditToolBar->addAction(cleanDoubleLinebreaksAct);
- specialEditToolBar->hide();
- viewMenu->addAction(specialEditToolBar->toggleViewAction());
-
- // Add dropdown menu for key import to keytoolbar
- importButton = new QToolButton();
- importButton->setMenu(importKeyMenu);
- importButton->setPopupMode(QToolButton::InstantPopup);
- importButton->setIcon(QIcon(":key_import.png"));
- importButton->setToolTip(tr("Import key from..."));
- importButton->setText(tr("Import key"));
- keyToolBar->addWidget(importButton);
-
- // Add dropdown menu for file encryption/decryption to crypttoolbar
- fileEncButton = new QToolButton();
- connect(fileEncButton, SIGNAL(clicked(bool)), this, SLOT(slotOpenFileTab()));
- fileEncButton->setPopupMode(QToolButton::InstantPopup);
- fileEncButton->setIcon(QIcon(":fileencryption.png"));
- fileEncButton->setToolTip(tr("Browser to view and operate file"));
- fileEncButton->setText(tr("Browser"));
- fileToolBar->addWidget(fileEncButton);
-
+ fileToolBar = addToolBar(tr("File"));
+ fileToolBar->setObjectName("fileToolBar");
+ fileToolBar->addAction(newTabAct);
+ fileToolBar->addAction(openAct);
+ fileToolBar->addAction(saveAct);
+ fileToolBar->hide();
+ viewMenu->addAction(fileToolBar->toggleViewAction());
+
+ cryptToolBar = addToolBar(tr("Crypt"));
+ cryptToolBar->setObjectName("cryptToolBar");
+ cryptToolBar->addAction(encryptAct);
+ cryptToolBar->addAction(encryptSignAct);
+ cryptToolBar->addAction(decryptAct);
+ cryptToolBar->addAction(decryptVerifyAct);
+ cryptToolBar->addAction(signAct);
+ cryptToolBar->addAction(verifyAct);
+ viewMenu->addAction(cryptToolBar->toggleViewAction());
+
+ keyToolBar = addToolBar(tr("Key"));
+ keyToolBar->setObjectName("keyToolBar");
+ keyToolBar->addAction(openKeyManagementAct);
+ viewMenu->addAction(keyToolBar->toggleViewAction());
+
+ editToolBar = addToolBar(tr("Edit"));
+ editToolBar->setObjectName("editToolBar");
+ editToolBar->addAction(copyAct);
+ editToolBar->addAction(pasteAct);
+ editToolBar->addAction(selectAllAct);
+ viewMenu->addAction(editToolBar->toggleViewAction());
+
+ specialEditToolBar = addToolBar(tr("Special Edit"));
+ specialEditToolBar->setObjectName("specialEditToolBar");
+ specialEditToolBar->addAction(quoteAct);
+ specialEditToolBar->addAction(cleanDoubleLinebreaksAct);
+ specialEditToolBar->hide();
+ viewMenu->addAction(specialEditToolBar->toggleViewAction());
+
+ // Add dropdown menu for key import to keytoolbar
+ importButton = new QToolButton();
+ importButton->setMenu(importKeyMenu);
+ importButton->setPopupMode(QToolButton::InstantPopup);
+ importButton->setIcon(QIcon(":key_import.png"));
+ importButton->setToolTip(tr("Import key from..."));
+ importButton->setText(tr("Import key"));
+ keyToolBar->addWidget(importButton);
+
+ // Add dropdown menu for file encryption/decryption to crypttoolbar
+ fileEncButton = new QToolButton();
+ connect(fileEncButton, SIGNAL(clicked(bool)), this, SLOT(slotOpenFileTab()));
+ fileEncButton->setPopupMode(QToolButton::InstantPopup);
+ fileEncButton->setIcon(QIcon(":fileencryption.png"));
+ fileEncButton->setToolTip(tr("Browser to view and operate file"));
+ fileEncButton->setText(tr("Browser"));
+ fileToolBar->addWidget(fileEncButton);
}
void MainWindow::createStatusBar() {
- auto *statusBarBox = new QWidget();
- auto *statusBarBoxLayout = new QHBoxLayout();
- QPixmap *pixmap;
-
- // icon which should be shown if there are files in attachments-folder
- pixmap = new QPixmap(":statusbar_icon.png");
- statusBarIcon = new QLabel();
- statusBar()->addWidget(statusBarIcon);
-
- statusBarIcon->setPixmap(*pixmap);
- statusBar()->insertPermanentWidget(0, statusBarIcon, 0);
- statusBarIcon->hide();
- statusBar()->showMessage(tr("Ready"), 2000);
- statusBarBox->setLayout(statusBarBoxLayout);
+ auto* statusBarBox = new QWidget();
+ auto* statusBarBoxLayout = new QHBoxLayout();
+ QPixmap* pixmap;
+
+ // icon which should be shown if there are files in attachments-folder
+ pixmap = new QPixmap(":statusbar_icon.png");
+ statusBarIcon = new QLabel();
+ statusBar()->addWidget(statusBarIcon);
+
+ statusBarIcon->setPixmap(*pixmap);
+ statusBar()->insertPermanentWidget(0, statusBarIcon, 0);
+ statusBarIcon->hide();
+ statusBar()->showMessage(tr("Ready"), 2000);
+ statusBarBox->setLayout(statusBarBoxLayout);
}
void MainWindow::createDockWindows() {
- /* KeyList-Dockwindow
- */
- keyListDock = new QDockWidget(tr("Key ToolBox"), this);
- keyListDock->setObjectName("EncryptDock");
- keyListDock->setAllowedAreas(Qt::LeftDockWidgetArea | Qt::RightDockWidgetArea);
- keyListDock->setMinimumWidth(460);
- addDockWidget(Qt::RightDockWidgetArea, keyListDock);
- keyListDock->setWidget(mKeyList);
- viewMenu->addAction(keyListDock->toggleViewAction());
-
- infoBoardDock = new QDockWidget(tr("Information Board"), this);
- infoBoardDock->setObjectName("Information Board");
- infoBoardDock->setAllowedAreas(Qt::BottomDockWidgetArea);
- addDockWidget(Qt::BottomDockWidgetArea, infoBoardDock);
- infoBoardDock->setWidget(infoBoard);
- infoBoardDock->widget()->layout()->setContentsMargins(0, 0, 0, 0);
- viewMenu->addAction(infoBoardDock->toggleViewAction());
+ /* KeyList-Dockwindow
+ */
+ keyListDock = new QDockWidget(tr("Key ToolBox"), this);
+ keyListDock->setObjectName("EncryptDock");
+ keyListDock->setAllowedAreas(Qt::LeftDockWidgetArea |
+ Qt::RightDockWidgetArea);
+ keyListDock->setMinimumWidth(460);
+ addDockWidget(Qt::RightDockWidgetArea, keyListDock);
+ keyListDock->setWidget(mKeyList);
+ viewMenu->addAction(keyListDock->toggleViewAction());
+
+ infoBoardDock = new QDockWidget(tr("Information Board"), this);
+ infoBoardDock->setObjectName("Information Board");
+ infoBoardDock->setAllowedAreas(Qt::BottomDockWidgetArea);
+ addDockWidget(Qt::BottomDockWidgetArea, infoBoardDock);
+ infoBoardDock->setWidget(infoBoard);
+ infoBoardDock->widget()->layout()->setContentsMargins(0, 0, 0, 0);
+ viewMenu->addAction(infoBoardDock->toggleViewAction());
}
+
+} // namespace GpgFrontend::UI
diff --git a/src/ui/settings/SettingsAdvanced.cpp b/src/ui/settings/SettingsAdvanced.cpp
index 30414250..90e588e9 100644
--- a/src/ui/settings/SettingsAdvanced.cpp
+++ b/src/ui/settings/SettingsAdvanced.cpp
@@ -24,44 +24,49 @@
#include "ui/SettingsDialog.h"
-AdvancedTab::AdvancedTab(QWidget *parent)
-: QWidget(parent), appPath(qApp->applicationDirPath()),
-settings(RESOURCE_DIR(appPath) + "/conf/gpgfrontend.ini",
- QSettings::IniFormat) {
- /*****************************************
- * Steganography Box
- *****************************************/
- auto *steganoBox = new QGroupBox(tr("Show Steganography Options"));
- auto *steganoBoxLayout = new QHBoxLayout();
- steganoCheckBox = new QCheckBox(tr("Show Steganographic Options."), this);
- steganoBoxLayout->addWidget(steganoCheckBox);
- steganoBox->setLayout(steganoBoxLayout);
+namespace GpgFrontend::UI {
- auto *pubkeyExchangeBox = new QGroupBox(tr("Pubkey Exchange"));
- auto *pubkeyExchangeBoxLayout = new QHBoxLayout();
- autoPubkeyExchangeCheckBox = new QCheckBox(tr("Auto Pubkey Exchange"), this);
- pubkeyExchangeBoxLayout->addWidget(autoPubkeyExchangeCheckBox);
- pubkeyExchangeBox->setLayout(pubkeyExchangeBoxLayout);
+AdvancedTab::AdvancedTab(QWidget* parent)
+ : QWidget(parent),
+ appPath(qApp->applicationDirPath()),
+ settings(RESOURCE_DIR(appPath) + "/conf/gpgfrontend.ini",
+ QSettings::IniFormat) {
+ /*****************************************
+ * Steganography Box
+ *****************************************/
+ auto* steganoBox = new QGroupBox(tr("Show Steganography Options"));
+ auto* steganoBoxLayout = new QHBoxLayout();
+ steganoCheckBox = new QCheckBox(tr("Show Steganographic Options."), this);
+ steganoBoxLayout->addWidget(steganoCheckBox);
+ steganoBox->setLayout(steganoBoxLayout);
- auto *mainLayout = new QVBoxLayout;
- mainLayout->addWidget(steganoBox);
- mainLayout->addWidget(pubkeyExchangeBox);
- setSettings();
- mainLayout->addStretch(1);
- setLayout(mainLayout);
+ auto* pubkeyExchangeBox = new QGroupBox(tr("Pubkey Exchange"));
+ auto* pubkeyExchangeBoxLayout = new QHBoxLayout();
+ autoPubkeyExchangeCheckBox = new QCheckBox(tr("Auto Pubkey Exchange"), this);
+ pubkeyExchangeBoxLayout->addWidget(autoPubkeyExchangeCheckBox);
+ pubkeyExchangeBox->setLayout(pubkeyExchangeBoxLayout);
+
+ auto* mainLayout = new QVBoxLayout;
+ mainLayout->addWidget(steganoBox);
+ mainLayout->addWidget(pubkeyExchangeBox);
+ setSettings();
+ mainLayout->addStretch(1);
+ setLayout(mainLayout);
}
void AdvancedTab::setSettings() {
- if (settings.value("advanced/steganography").toBool()) {
- steganoCheckBox->setCheckState(Qt::Checked);
- }
- if (settings.value("advanced/autoPubkeyExchange").toBool()) {
- autoPubkeyExchangeCheckBox->setCheckState(Qt::Checked);
- }
+ if (settings.value("advanced/steganography").toBool()) {
+ steganoCheckBox->setCheckState(Qt::Checked);
+ }
+ if (settings.value("advanced/autoPubkeyExchange").toBool()) {
+ autoPubkeyExchangeCheckBox->setCheckState(Qt::Checked);
+ }
}
void AdvancedTab::applySettings() {
- settings.setValue("advanced/steganography", steganoCheckBox->isChecked());
- settings.setValue("advanced/autoPubkeyExchange", autoPubkeyExchangeCheckBox->isChecked());
+ settings.setValue("advanced/steganography", steganoCheckBox->isChecked());
+ settings.setValue("advanced/autoPubkeyExchange",
+ autoPubkeyExchangeCheckBox->isChecked());
}
+} // namespace GpgFrontend::UI
diff --git a/src/ui/settings/SettingsAppearance.cpp b/src/ui/settings/SettingsAppearance.cpp
index aeb7ed70..79bfe5d8 100644
--- a/src/ui/settings/SettingsAppearance.cpp
+++ b/src/ui/settings/SettingsAppearance.cpp
@@ -24,82 +24,85 @@
#include "ui/SettingsDialog.h"
-AppearanceTab::AppearanceTab(QWidget *parent)
-: QWidget(parent), appPath(qApp->applicationDirPath()),
-settings(RESOURCE_DIR(appPath) + "/conf/gpgfrontend.ini",
- QSettings::IniFormat) {
- /*****************************************
- * Icon-Size-Box
- *****************************************/
- auto *iconSizeBox = new QGroupBox(tr("Iconsize"));
- iconSizeGroup = new QButtonGroup();
- iconSizeSmall = new QRadioButton(tr("small"));
- iconSizeMedium = new QRadioButton(tr("medium"));
- iconSizeLarge = new QRadioButton(tr("large"));
-
- iconSizeGroup->addButton(iconSizeSmall, 1);
- iconSizeGroup->addButton(iconSizeMedium, 2);
- iconSizeGroup->addButton(iconSizeLarge, 3);
-
- auto *iconSizeBoxLayout = new QHBoxLayout();
- iconSizeBoxLayout->addWidget(iconSizeSmall);
- iconSizeBoxLayout->addWidget(iconSizeMedium);
- iconSizeBoxLayout->addWidget(iconSizeLarge);
-
- iconSizeBox->setLayout(iconSizeBoxLayout);
-
- /*****************************************
- * Icon-Style-Box
- *****************************************/
- auto *iconStyleBox = new QGroupBox(tr("Iconstyle"));
- iconStyleGroup = new QButtonGroup();
- iconTextButton = new QRadioButton(tr("just text"));
- iconIconsButton = new QRadioButton(tr("just icons"));
- iconAllButton = new QRadioButton(tr("text and icons"));
-
- iconStyleGroup->addButton(iconTextButton, 1);
- iconStyleGroup->addButton(iconIconsButton, 2);
- iconStyleGroup->addButton(iconAllButton, 3);
-
- auto *iconStyleBoxLayout = new QHBoxLayout();
- iconStyleBoxLayout->addWidget(iconTextButton);
- iconStyleBoxLayout->addWidget(iconIconsButton);
- iconStyleBoxLayout->addWidget(iconAllButton);
-
- iconStyleBox->setLayout(iconStyleBoxLayout);
-
- /*****************************************
- * Window-Size-Box
- *****************************************/
- auto *windowSizeBox = new QGroupBox(tr("Windowstate"));
- auto *windowSizeBoxLayout = new QHBoxLayout();
- windowSizeCheckBox =
- new QCheckBox(tr("Save window size and position on exit."), this);
- windowSizeBoxLayout->addWidget(windowSizeCheckBox);
- windowSizeBox->setLayout(windowSizeBoxLayout);
-
- /*****************************************
- * Info-Board-Font-Size-Box
- *****************************************/
-
- auto *infoBoardBox = new QGroupBox(tr("Information Board"));
- auto *infoBoardLayout = new QHBoxLayout();
- infoBoardFontSizeSpin = new QSpinBox();
- infoBoardFontSizeSpin->setRange(9, 18);
- infoBoardFontSizeSpin->setValue(10);
- infoBoardFontSizeSpin->setSingleStep(1);
- infoBoardLayout->addWidget(new QLabel(tr(" Front Size")));
- infoBoardLayout->addWidget(infoBoardFontSizeSpin);
- infoBoardBox->setLayout(infoBoardLayout);
-
- auto *mainLayout = new QVBoxLayout;
- mainLayout->addWidget(iconSizeBox);
- mainLayout->addWidget(iconStyleBox);
- mainLayout->addWidget(windowSizeBox);
- mainLayout->addWidget(infoBoardBox);
- mainLayout->addStretch(1);
- setSettings();
- setLayout(mainLayout);
+namespace GpgFrontend::UI {
+
+AppearanceTab::AppearanceTab(QWidget* parent)
+ : QWidget(parent),
+ appPath(qApp->applicationDirPath()),
+ settings(RESOURCE_DIR(appPath) + "/conf/gpgfrontend.ini",
+ QSettings::IniFormat) {
+ /*****************************************
+ * Icon-Size-Box
+ *****************************************/
+ auto* iconSizeBox = new QGroupBox(tr("Iconsize"));
+ iconSizeGroup = new QButtonGroup();
+ iconSizeSmall = new QRadioButton(tr("small"));
+ iconSizeMedium = new QRadioButton(tr("medium"));
+ iconSizeLarge = new QRadioButton(tr("large"));
+
+ iconSizeGroup->addButton(iconSizeSmall, 1);
+ iconSizeGroup->addButton(iconSizeMedium, 2);
+ iconSizeGroup->addButton(iconSizeLarge, 3);
+
+ auto* iconSizeBoxLayout = new QHBoxLayout();
+ iconSizeBoxLayout->addWidget(iconSizeSmall);
+ iconSizeBoxLayout->addWidget(iconSizeMedium);
+ iconSizeBoxLayout->addWidget(iconSizeLarge);
+
+ iconSizeBox->setLayout(iconSizeBoxLayout);
+
+ /*****************************************
+ * Icon-Style-Box
+ *****************************************/
+ auto* iconStyleBox = new QGroupBox(tr("Iconstyle"));
+ iconStyleGroup = new QButtonGroup();
+ iconTextButton = new QRadioButton(tr("just text"));
+ iconIconsButton = new QRadioButton(tr("just icons"));
+ iconAllButton = new QRadioButton(tr("text and icons"));
+
+ iconStyleGroup->addButton(iconTextButton, 1);
+ iconStyleGroup->addButton(iconIconsButton, 2);
+ iconStyleGroup->addButton(iconAllButton, 3);
+
+ auto* iconStyleBoxLayout = new QHBoxLayout();
+ iconStyleBoxLayout->addWidget(iconTextButton);
+ iconStyleBoxLayout->addWidget(iconIconsButton);
+ iconStyleBoxLayout->addWidget(iconAllButton);
+
+ iconStyleBox->setLayout(iconStyleBoxLayout);
+
+ /*****************************************
+ * Window-Size-Box
+ *****************************************/
+ auto* windowSizeBox = new QGroupBox(tr("Windowstate"));
+ auto* windowSizeBoxLayout = new QHBoxLayout();
+ windowSizeCheckBox =
+ new QCheckBox(tr("Save window size and position on exit."), this);
+ windowSizeBoxLayout->addWidget(windowSizeCheckBox);
+ windowSizeBox->setLayout(windowSizeBoxLayout);
+
+ /*****************************************
+ * Info-Board-Font-Size-Box
+ *****************************************/
+
+ auto* infoBoardBox = new QGroupBox(tr("Information Board"));
+ auto* infoBoardLayout = new QHBoxLayout();
+ infoBoardFontSizeSpin = new QSpinBox();
+ infoBoardFontSizeSpin->setRange(9, 18);
+ infoBoardFontSizeSpin->setValue(10);
+ infoBoardFontSizeSpin->setSingleStep(1);
+ infoBoardLayout->addWidget(new QLabel(tr(" Front Size")));
+ infoBoardLayout->addWidget(infoBoardFontSizeSpin);
+ infoBoardBox->setLayout(infoBoardLayout);
+
+ auto* mainLayout = new QVBoxLayout;
+ mainLayout->addWidget(iconSizeBox);
+ mainLayout->addWidget(iconStyleBox);
+ mainLayout->addWidget(windowSizeBox);
+ mainLayout->addWidget(infoBoardBox);
+ mainLayout->addStretch(1);
+ setSettings();
+ setLayout(mainLayout);
}
/**********************************
@@ -108,47 +111,47 @@ settings(RESOURCE_DIR(appPath) + "/conf/gpgfrontend.ini",
* appropriately
**********************************/
void AppearanceTab::setSettings() {
-
- // Iconsize
- QSize iconSize = settings.value("toolbar/iconsize", QSize(24, 24)).toSize();
- switch (iconSize.height()) {
- case 12:
- iconSizeSmall->setChecked(true);
- break;
- case 24:
- iconSizeMedium->setChecked(true);
- break;
- case 32:
- iconSizeLarge->setChecked(true);
- break;
- }
- // Iconstyle
- Qt::ToolButtonStyle iconStyle = static_cast<Qt::ToolButtonStyle>(
- settings.value("toolbar/iconstyle", Qt::ToolButtonTextUnderIcon)
- .toUInt());
- switch (iconStyle) {
- case Qt::ToolButtonTextOnly:
- iconTextButton->setChecked(true);
- break;
- case Qt::ToolButtonIconOnly:
- iconIconsButton->setChecked(true);
- break;
- case Qt::ToolButtonTextUnderIcon:
- iconAllButton->setChecked(true);
- break;
- default:
- break;
- }
-
- // Window Save and Position
- if (settings.value("window/windowSave").toBool())
- windowSizeCheckBox->setCheckState(Qt::Checked);
-
- // infoBoardFontSize
- auto infoBoardFontSize = settings.value("informationBoard/fontSize", 10).toInt();
- if (infoBoardFontSize < 9 || infoBoardFontSize > 18)
- infoBoardFontSize = 10;
- infoBoardFontSizeSpin->setValue(infoBoardFontSize);
+ // Iconsize
+ QSize iconSize = settings.value("toolbar/iconsize", QSize(24, 24)).toSize();
+ switch (iconSize.height()) {
+ case 12:
+ iconSizeSmall->setChecked(true);
+ break;
+ case 24:
+ iconSizeMedium->setChecked(true);
+ break;
+ case 32:
+ iconSizeLarge->setChecked(true);
+ break;
+ }
+ // Iconstyle
+ Qt::ToolButtonStyle iconStyle = static_cast<Qt::ToolButtonStyle>(
+ settings.value("toolbar/iconstyle", Qt::ToolButtonTextUnderIcon)
+ .toUInt());
+ switch (iconStyle) {
+ case Qt::ToolButtonTextOnly:
+ iconTextButton->setChecked(true);
+ break;
+ case Qt::ToolButtonIconOnly:
+ iconIconsButton->setChecked(true);
+ break;
+ case Qt::ToolButtonTextUnderIcon:
+ iconAllButton->setChecked(true);
+ break;
+ default:
+ break;
+ }
+
+ // Window Save and Position
+ if (settings.value("window/windowSave").toBool())
+ windowSizeCheckBox->setCheckState(Qt::Checked);
+
+ // infoBoardFontSize
+ auto infoBoardFontSize =
+ settings.value("informationBoard/fontSize", 10).toInt();
+ if (infoBoardFontSize < 9 || infoBoardFontSize > 18)
+ infoBoardFontSize = 10;
+ infoBoardFontSizeSpin->setValue(infoBoardFontSize);
}
/***********************************
@@ -156,32 +159,34 @@ void AppearanceTab::setSettings() {
* write them to settings-file
*************************************/
void AppearanceTab::applySettings() {
- switch (iconSizeGroup->checkedId()) {
- case 1:
- settings.setValue("toolbar/iconsize", QSize(12, 12));
- break;
- case 2:
- settings.setValue("toolbar/iconsize", QSize(24, 24));
- break;
- case 3:
- settings.setValue("toolbar/iconsize", QSize(32, 32));
- break;
- }
-
- switch (iconStyleGroup->checkedId()) {
- case 1:
- settings.setValue("toolbar/iconstyle", Qt::ToolButtonTextOnly);
- break;
- case 2:
- settings.setValue("toolbar/iconstyle", Qt::ToolButtonIconOnly);
- break;
- case 3:
- settings.setValue("toolbar/iconstyle", Qt::ToolButtonTextUnderIcon);
- break;
- }
-
- settings.setValue("window/windowSave", windowSizeCheckBox->isChecked());
-
- settings.setValue("informationBoard/fontSize", infoBoardFontSizeSpin->value());
+ switch (iconSizeGroup->checkedId()) {
+ case 1:
+ settings.setValue("toolbar/iconsize", QSize(12, 12));
+ break;
+ case 2:
+ settings.setValue("toolbar/iconsize", QSize(24, 24));
+ break;
+ case 3:
+ settings.setValue("toolbar/iconsize", QSize(32, 32));
+ break;
+ }
+
+ switch (iconStyleGroup->checkedId()) {
+ case 1:
+ settings.setValue("toolbar/iconstyle", Qt::ToolButtonTextOnly);
+ break;
+ case 2:
+ settings.setValue("toolbar/iconstyle", Qt::ToolButtonIconOnly);
+ break;
+ case 3:
+ settings.setValue("toolbar/iconstyle", Qt::ToolButtonTextUnderIcon);
+ break;
+ }
+
+ settings.setValue("window/windowSave", windowSizeCheckBox->isChecked());
+
+ settings.setValue("informationBoard/fontSize",
+ infoBoardFontSizeSpin->value());
}
+} // namespace GpgFrontend::UI
diff --git a/src/ui/settings/SettingsDialog.cpp b/src/ui/settings/SettingsDialog.cpp
index 33595b25..9a423dfd 100644
--- a/src/ui/settings/SettingsDialog.cpp
+++ b/src/ui/settings/SettingsDialog.cpp
@@ -25,181 +25,186 @@
#include "ui/SettingsDialog.h"
#include "ui/WaitingDialog.h"
-SettingsDialog::SettingsDialog(GpgFrontend::GpgContext *ctx, QWidget *parent)
- : QDialog(parent) {
- mCtx = ctx;
- tabWidget = new QTabWidget;
- generalTab = new GeneralTab(mCtx);
- appearanceTab = new AppearanceTab;
- sendMailTab = new SendMailTab;
- keyserverTab = new KeyserverTab;
- advancedTab = new AdvancedTab;
- gpgPathsTab = new GpgPathsTab;
-
- tabWidget->addTab(generalTab, tr("General"));
- tabWidget->addTab(appearanceTab, tr("Appearance"));
- tabWidget->addTab(sendMailTab, tr("Send Mail"));
- tabWidget->addTab(keyserverTab, tr("Key Server"));
- // tabWidget->addTab(gpgPathsTab, tr("Gpg paths"));
- tabWidget->addTab(advancedTab, tr("Advanced"));
-
- buttonBox =
- new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel);
-
- connect(buttonBox, SIGNAL(accepted()), this, SLOT(slotAccept()));
- connect(buttonBox, SIGNAL(rejected()), this, SLOT(reject()));
-
- auto *mainLayout = new QVBoxLayout;
- mainLayout->addWidget(tabWidget);
- mainLayout->stretch(0);
- mainLayout->addWidget(buttonBox);
- mainLayout->stretch(0);
- setLayout(mainLayout);
-
- setWindowTitle(tr("Settings"));
-
- // slots for handling the restartneeded member
- this->slotSetRestartNeeded(false);
- connect(generalTab, SIGNAL(signalRestartNeeded(bool)), this,
- SLOT(slotSetRestartNeeded(bool)));
- connect(appearanceTab, SIGNAL(signalRestartNeeded(bool)), this,
- SLOT(slotSetRestartNeeded(bool)));
- connect(sendMailTab, SIGNAL(signalRestartNeeded(bool)), this,
- SLOT(slotSetRestartNeeded(bool)));
- connect(keyserverTab, SIGNAL(signalRestartNeeded(bool)), this,
- SLOT(slotSetRestartNeeded(bool)));
- connect(advancedTab, SIGNAL(signalRestartNeeded(bool)), this,
- SLOT(slotSetRestartNeeded(bool)));
-
- connect(this, SIGNAL(signalRestartNeeded(bool)), parent,
- SLOT(slotSetRestartNeeded(bool)));
-
- this->resize(480, 640);
- this->show();
+namespace GpgFrontend::UI {
+
+SettingsDialog::SettingsDialog(QWidget* parent) : QDialog(parent) {
+ tabWidget = new QTabWidget;
+ generalTab = new GeneralTab();
+ appearanceTab = new AppearanceTab;
+ sendMailTab = new SendMailTab;
+ keyserverTab = new KeyserverTab;
+ advancedTab = new AdvancedTab;
+ gpgPathsTab = new GpgPathsTab;
+
+ tabWidget->addTab(generalTab, tr("General"));
+ tabWidget->addTab(appearanceTab, tr("Appearance"));
+ tabWidget->addTab(sendMailTab, tr("Send Mail"));
+ tabWidget->addTab(keyserverTab, tr("Key Server"));
+ // tabWidget->addTab(gpgPathsTab, tr("Gpg paths"));
+ tabWidget->addTab(advancedTab, tr("Advanced"));
+
+ buttonBox =
+ new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel);
+
+ connect(buttonBox, SIGNAL(accepted()), this, SLOT(slotAccept()));
+ connect(buttonBox, SIGNAL(rejected()), this, SLOT(reject()));
+
+ auto* mainLayout = new QVBoxLayout;
+ mainLayout->addWidget(tabWidget);
+ mainLayout->stretch(0);
+ mainLayout->addWidget(buttonBox);
+ mainLayout->stretch(0);
+ setLayout(mainLayout);
+
+ setWindowTitle(tr("Settings"));
+
+ // slots for handling the restartneeded member
+ this->slotSetRestartNeeded(false);
+ connect(generalTab, SIGNAL(signalRestartNeeded(bool)), this,
+ SLOT(slotSetRestartNeeded(bool)));
+ connect(appearanceTab, SIGNAL(signalRestartNeeded(bool)), this,
+ SLOT(slotSetRestartNeeded(bool)));
+ connect(sendMailTab, SIGNAL(signalRestartNeeded(bool)), this,
+ SLOT(slotSetRestartNeeded(bool)));
+ connect(keyserverTab, SIGNAL(signalRestartNeeded(bool)), this,
+ SLOT(slotSetRestartNeeded(bool)));
+ connect(advancedTab, SIGNAL(signalRestartNeeded(bool)), this,
+ SLOT(slotSetRestartNeeded(bool)));
+
+ connect(this, SIGNAL(signalRestartNeeded(bool)), parent,
+ SLOT(slotSetRestartNeeded(bool)));
+
+ this->resize(480, 640);
+ this->show();
}
-bool SettingsDialog::getRestartNeeded() const { return this->restartNeeded; }
+bool SettingsDialog::getRestartNeeded() const {
+ return this->restartNeeded;
+}
void SettingsDialog::slotSetRestartNeeded(bool needed) {
- this->restartNeeded = needed;
+ this->restartNeeded = needed;
}
void SettingsDialog::slotAccept() {
- generalTab->applySettings();
- sendMailTab->applySettings();
- appearanceTab->applySettings();
- keyserverTab->applySettings();
- advancedTab->applySettings();
- gpgPathsTab->applySettings();
- if (getRestartNeeded()) {
- emit signalRestartNeeded(true);
- }
- close();
+ generalTab->applySettings();
+ sendMailTab->applySettings();
+ appearanceTab->applySettings();
+ keyserverTab->applySettings();
+ advancedTab->applySettings();
+ gpgPathsTab->applySettings();
+ if (getRestartNeeded()) {
+ emit signalRestartNeeded(true);
+ }
+ close();
}
// http://www.informit.com/articles/article.aspx?p=1405555&seqNum=3
// http://developer.qt.nokia.com/wiki/How_to_create_a_multi_language_application
QHash<QString, QString> SettingsDialog::listLanguages() {
- QHash<QString, QString> languages;
+ QHash<QString, QString> languages;
- languages.insert("", tr("System Default"));
+ languages.insert("", tr("System Default"));
- QString appPath = qApp->applicationDirPath();
- QDir qmDir = QDir(RESOURCE_DIR(appPath) + "/ts/");
- QStringList fileNames = qmDir.entryList(QStringList("gpgfrontend_*.qm"));
+ QString appPath = qApp->applicationDirPath();
+ QDir qmDir = QDir(RESOURCE_DIR(appPath) + "/ts/");
+ QStringList fileNames = qmDir.entryList(QStringList("gpgfrontend_*.qm"));
- for (int i = 0; i < fileNames.size(); ++i) {
- QString locale = fileNames[i];
- locale.truncate(locale.lastIndexOf('.'));
- locale.remove(0, locale.indexOf('_') + 1);
+ for (int i = 0; i < fileNames.size(); ++i) {
+ QString locale = fileNames[i];
+ locale.truncate(locale.lastIndexOf('.'));
+ locale.remove(0, locale.indexOf('_') + 1);
- // this works in qt 4.8
- QLocale qloc(locale);
+ // this works in qt 4.8
+ QLocale qloc(locale);
#if QT_VERSION < 0x040800
- QString language =
- QLocale::languageToString(qloc.language()) + " (" + locale +
- ")"; //+ " (" + QLocale::languageToString(qloc.language()) + ")";
+ QString language =
+ QLocale::languageToString(qloc.language()) + " (" + locale +
+ ")"; //+ " (" + QLocale::languageToString(qloc.language()) + ")";
#else
- QString language = qloc.nativeLanguageName() + " (" + locale + ")";
+ QString language = qloc.nativeLanguageName() + " (" + locale + ")";
#endif
- languages.insert(locale, language);
- }
- return languages;
+ languages.insert(locale, language);
+ }
+ return languages;
}
-GpgPathsTab::GpgPathsTab(QWidget *parent)
- : QWidget(parent), appPath(qApp->applicationDirPath()),
- settings(RESOURCE_DIR(appPath) + "/conf/gpgfrontend.ini",
- QSettings::IniFormat) {
- setSettings();
-
- /*****************************************
- * Keydb Box
- *****************************************/
- auto *keydbBox = new QGroupBox(tr("Relative path to keydb"));
- auto *keydbBoxLayout = new QGridLayout();
-
- // Label containing the current keydbpath relative to default keydb path
- keydbLabel = new QLabel(accKeydbPath, this);
-
- auto *keydbButton = new QPushButton("Change keydb path", this);
- connect(keydbButton, SIGNAL(clicked()), this, SLOT(chooseKeydbDir()));
- auto *keydbDefaultButton = new QPushButton("Set keydb to default path", this);
- connect(keydbDefaultButton, SIGNAL(clicked()), this,
- SLOT(setKeydbPathToDefault()));
-
- keydbBox->setLayout(keydbBoxLayout);
- keydbBoxLayout->addWidget(new QLabel(tr("Current keydb path: ")), 1, 1);
- keydbBoxLayout->addWidget(keydbLabel, 1, 2);
- keydbBoxLayout->addWidget(keydbButton, 1, 3);
- keydbBoxLayout->addWidget(keydbDefaultButton, 2, 3);
- keydbBoxLayout->addWidget(
- new QLabel(tr("<b>NOTE: </b> Gpg4usb will restart automatically if you "
- "change the keydb path!")),
- 3, 1, 1, 3);
-
- auto *mainLayout = new QVBoxLayout;
- mainLayout->addWidget(keydbBox);
- mainLayout->addStretch(1);
- setLayout(mainLayout);
+GpgPathsTab::GpgPathsTab(QWidget* parent)
+ : QWidget(parent),
+ appPath(qApp->applicationDirPath()),
+ settings(RESOURCE_DIR(appPath) + "/conf/gpgfrontend.ini",
+ QSettings::IniFormat) {
+ setSettings();
+
+ /*****************************************
+ * Keydb Box
+ *****************************************/
+ auto* keydbBox = new QGroupBox(tr("Relative path to keydb"));
+ auto* keydbBoxLayout = new QGridLayout();
+
+ // Label containing the current keydbpath relative to default keydb path
+ keydbLabel = new QLabel(accKeydbPath, this);
+
+ auto* keydbButton = new QPushButton("Change keydb path", this);
+ connect(keydbButton, SIGNAL(clicked()), this, SLOT(chooseKeydbDir()));
+ auto* keydbDefaultButton = new QPushButton("Set keydb to default path", this);
+ connect(keydbDefaultButton, SIGNAL(clicked()), this,
+ SLOT(setKeydbPathToDefault()));
+
+ keydbBox->setLayout(keydbBoxLayout);
+ keydbBoxLayout->addWidget(new QLabel(tr("Current keydb path: ")), 1, 1);
+ keydbBoxLayout->addWidget(keydbLabel, 1, 2);
+ keydbBoxLayout->addWidget(keydbButton, 1, 3);
+ keydbBoxLayout->addWidget(keydbDefaultButton, 2, 3);
+ keydbBoxLayout->addWidget(
+ new QLabel(tr("<b>NOTE: </b> Gpg4usb will restart automatically if you "
+ "change the keydb path!")),
+ 3, 1, 1, 3);
+
+ auto* mainLayout = new QVBoxLayout;
+ mainLayout->addWidget(keydbBox);
+ mainLayout->addStretch(1);
+ setLayout(mainLayout);
}
-QString GpgPathsTab::getRelativePath(const QString &dir1, const QString &dir2) {
- QDir dir(dir1);
- QString s;
+QString GpgPathsTab::getRelativePath(const QString& dir1, const QString& dir2) {
+ QDir dir(dir1);
+ QString s;
- s = dir.relativeFilePath(dir2);
- qDebug() << "relative path: " << s;
- if (s.isEmpty()) {
- s = ".";
- }
- return s;
+ s = dir.relativeFilePath(dir2);
+ qDebug() << "relative path: " << s;
+ if (s.isEmpty()) {
+ s = ".";
+ }
+ return s;
}
void GpgPathsTab::setKeydbPathToDefault() {
- accKeydbPath = ".";
- keydbLabel->setText(".");
+ accKeydbPath = ".";
+ keydbLabel->setText(".");
}
QString GpgPathsTab::chooseKeydbDir() {
- QString dir = QFileDialog::getExistingDirectory(
- this, tr("Choose keydb directory"), accKeydbPath,
- QFileDialog::ShowDirsOnly);
+ QString dir = QFileDialog::getExistingDirectory(
+ this, tr("Choose keydb directory"), accKeydbPath,
+ QFileDialog::ShowDirsOnly);
- accKeydbPath = getRelativePath(defKeydbPath, dir);
- keydbLabel->setText(accKeydbPath);
- return "";
+ accKeydbPath = getRelativePath(defKeydbPath, dir);
+ keydbLabel->setText(accKeydbPath);
+ return "";
}
void GpgPathsTab::setSettings() {
- defKeydbPath = qApp->applicationDirPath() + "/keydb";
+ defKeydbPath = qApp->applicationDirPath() + "/keydb";
- accKeydbPath = settings.value("gpgpaths/keydbpath").toString();
- if (accKeydbPath.isEmpty()) {
- accKeydbPath = ".";
- }
+ accKeydbPath = settings.value("gpgpaths/keydbpath").toString();
+ if (accKeydbPath.isEmpty()) {
+ accKeydbPath = ".";
+ }
}
void GpgPathsTab::applySettings() {
- settings.setValue("gpgpaths/keydbpath", accKeydbPath);
+ settings.setValue("gpgpaths/keydbpath", accKeydbPath);
}
+
+} // namespace GpgFrontend::UI
diff --git a/src/ui/settings/SettingsGeneral.cpp b/src/ui/settings/SettingsGeneral.cpp
index 666556a0..dab0bb5d 100644
--- a/src/ui/settings/SettingsGeneral.cpp
+++ b/src/ui/settings/SettingsGeneral.cpp
@@ -23,121 +23,131 @@
*/
#include "ui/SettingsDialog.h"
-#include "ui/WaitingDialog.h"
-#include "server/ComUtils.h"
#include "rapidjson/prettywriter.h"
-GeneralTab::GeneralTab(GpgFrontend::GpgContext *ctx, QWidget *parent)
- : QWidget(parent), appPath(qApp->applicationDirPath()),
- settings(RESOURCE_DIR(appPath) + "/conf/gpgfrontend.ini",
- QSettings::IniFormat) {
- mCtx = ctx;
-
- /*****************************************
- * GpgFrontend Server
- *****************************************/
- auto *serverBox = new QGroupBox(tr("GpgFrontend Server"));
- auto *serverBoxLayout = new QVBoxLayout();
- serverSelectBox = new QComboBox();
- serverBoxLayout->addWidget(serverSelectBox);
- serverBoxLayout->addWidget(new QLabel(
- tr("Server that provides short key and key exchange services")));
-
- serverBox->setLayout(serverBoxLayout);
-
- /*****************************************
- * Save-Checked-Keys-Box
- *****************************************/
- auto *saveCheckedKeysBox = new QGroupBox(tr("Save Checked Keys"));
- auto *saveCheckedKeysBoxLayout = new QHBoxLayout();
- saveCheckedKeysCheckBox = new QCheckBox(
- tr("Save checked private keys on exit and restore them on next start."),
- this);
- saveCheckedKeysBoxLayout->addWidget(saveCheckedKeysCheckBox);
- saveCheckedKeysBox->setLayout(saveCheckedKeysBoxLayout);
-
- /*****************************************
- * Key-Impport-Confirmation Box
- *****************************************/
- auto *importConfirmationBox =
- new QGroupBox(tr("Confirm drag'n'drop key import"));
- auto *importConfirmationBoxLayout = new QHBoxLayout();
- importConfirmationCheckBox = new QCheckBox(
- tr("Import files dropped on the keylist without confirmation."), this);
- importConfirmationBoxLayout->addWidget(importConfirmationCheckBox);
- importConfirmationBox->setLayout(importConfirmationBoxLayout);
-
- /*****************************************
- * Language Select Box
- *****************************************/
- auto *langBox = new QGroupBox(tr("Language"));
- auto *langBoxLayout = new QVBoxLayout();
- langSelectBox = new QComboBox;
- lang = SettingsDialog::listLanguages();
-
- for (const auto &l: lang) { langSelectBox->addItem(l); }
-
- langBoxLayout->addWidget(langSelectBox);
- langBoxLayout->addWidget(
- new QLabel(tr("<b>NOTE: </b> GpgFrontend will restart automatically if "
- "you change the language!")));
- langBox->setLayout(langBoxLayout);
- connect(langSelectBox, SIGNAL(currentIndexChanged(int)), this,
- SLOT(slotLanguageChanged()));
-
- /*****************************************
- * Own Key Select Box
- *****************************************/
- auto *ownKeyBox = new QGroupBox(tr("Own key"));
- auto *ownKeyBoxLayout = new QVBoxLayout();
- auto *ownKeyServiceTokenLayout = new QHBoxLayout();
- ownKeySelectBox = new QComboBox;
- getServiceTokenButton = new QPushButton(tr("Get Service Token"));
- serviceTokenLabel = new QLabel(tr("No Service Token Found"));
- serviceTokenLabel->setAlignment(Qt::AlignCenter);
-
- ownKeyBox->setLayout(ownKeyBoxLayout);
- mKeyList = new KeyList(mCtx);
-
- // Fill the keyid hashmap
- keyIds.insert("", tr("<none>"));
-
- for (const auto &keyid : *mKeyList->getAllPrivateKeys()) {
- auto key = mCtx->getKeyRefById(keyid);
- if (!key.good) continue;
- keyIds.insert(key.id, key.uids.first().uid);
- }
- for (const auto &k : keyIds.keys()) {
- ownKeySelectBox->addItem(keyIds.find(k).value());
- keyIdsList.append(k);
- }
- connect(ownKeySelectBox, SIGNAL(currentIndexChanged(int)), this,
- SLOT(slotOwnKeyIdChanged()));
- connect(getServiceTokenButton, SIGNAL(clicked(bool)), this,
- SLOT(slotGetServiceToken()));
-
- ownKeyBoxLayout->addWidget(new QLabel(
- tr("Key pair for synchronization and identity authentication")));
- ownKeyBoxLayout->addWidget(ownKeySelectBox);
- ownKeyBoxLayout->addLayout(ownKeyServiceTokenLayout);
- ownKeyServiceTokenLayout->addWidget(getServiceTokenButton);
- ownKeyServiceTokenLayout->addWidget(serviceTokenLabel);
- ownKeyServiceTokenLayout->stretch(0);
-
- /*****************************************
- * Mainlayout
- *****************************************/
- auto *mainLayout = new QVBoxLayout;
- mainLayout->addWidget(serverBox);
- mainLayout->addWidget(saveCheckedKeysBox);
- mainLayout->addWidget(importConfirmationBox);
- mainLayout->addWidget(langBox);
- mainLayout->addWidget(ownKeyBox);
-
- setSettings();
- mainLayout->addStretch(1);
- setLayout(mainLayout);
+#ifdef SERVER_SUPPORT
+#include "server/ComUtils.h"
+#endif
+#include "gpg/function/GpgKeyGetter.h"
+#include "ui/WaitingDialog.h"
+
+namespace GpgFrontend::UI {
+
+GeneralTab::GeneralTab(QWidget* parent)
+ : QWidget(parent),
+ appPath(qApp->applicationDirPath()),
+ settings(RESOURCE_DIR(appPath) + "/conf/gpgfrontend.ini",
+ QSettings::IniFormat) {
+ /*****************************************
+ * GpgFrontend Server
+ *****************************************/
+ auto* serverBox = new QGroupBox(tr("GpgFrontend Server"));
+ auto* serverBoxLayout = new QVBoxLayout();
+ serverSelectBox = new QComboBox();
+ serverBoxLayout->addWidget(serverSelectBox);
+ serverBoxLayout->addWidget(new QLabel(
+ tr("Server that provides short key and key exchange services")));
+
+ serverBox->setLayout(serverBoxLayout);
+
+ /*****************************************
+ * Save-Checked-Keys-Box
+ *****************************************/
+ auto* saveCheckedKeysBox = new QGroupBox(tr("Save Checked Keys"));
+ auto* saveCheckedKeysBoxLayout = new QHBoxLayout();
+ saveCheckedKeysCheckBox = new QCheckBox(
+ tr("Save checked private keys on exit and restore them on next start."),
+ this);
+ saveCheckedKeysBoxLayout->addWidget(saveCheckedKeysCheckBox);
+ saveCheckedKeysBox->setLayout(saveCheckedKeysBoxLayout);
+
+ /*****************************************
+ * Key-Impport-Confirmation Box
+ *****************************************/
+ auto* importConfirmationBox =
+ new QGroupBox(tr("Confirm drag'n'drop key import"));
+ auto* importConfirmationBoxLayout = new QHBoxLayout();
+ importConfirmationCheckBox = new QCheckBox(
+ tr("Import files dropped on the keylist without confirmation."), this);
+ importConfirmationBoxLayout->addWidget(importConfirmationCheckBox);
+ importConfirmationBox->setLayout(importConfirmationBoxLayout);
+
+ /*****************************************
+ * Language Select Box
+ *****************************************/
+ auto* langBox = new QGroupBox(tr("Language"));
+ auto* langBoxLayout = new QVBoxLayout();
+ langSelectBox = new QComboBox;
+ lang = SettingsDialog::listLanguages();
+
+ for (const auto& l : lang) {
+ langSelectBox->addItem(l);
+ }
+
+ langBoxLayout->addWidget(langSelectBox);
+ langBoxLayout->addWidget(
+ new QLabel(tr("<b>NOTE: </b> GpgFrontend will restart automatically if "
+ "you change the language!")));
+ langBox->setLayout(langBoxLayout);
+ connect(langSelectBox, SIGNAL(currentIndexChanged(int)), this,
+ SLOT(slotLanguageChanged()));
+
+ /*****************************************
+ * Own Key Select Box
+ *****************************************/
+ auto* ownKeyBox = new QGroupBox(tr("Own key"));
+ auto* ownKeyBoxLayout = new QVBoxLayout();
+ auto* ownKeyServiceTokenLayout = new QHBoxLayout();
+ ownKeySelectBox = new QComboBox;
+ getServiceTokenButton = new QPushButton(tr("Get Service Token"));
+ serviceTokenLabel = new QLabel(tr("No Service Token Found"));
+ serviceTokenLabel->setAlignment(Qt::AlignCenter);
+
+ ownKeyBox->setLayout(ownKeyBoxLayout);
+ mKeyList = new KeyList();
+
+ // Fill the keyid hashmap
+ keyIds.insert({"", "<none>"});
+
+ auto private_keys = mKeyList->getAllPrivateKeys();
+
+ for (const auto& keyid : *private_keys) {
+ auto key = GpgKeyGetter::GetInstance().GetKey(keyid);
+ if (!key.good())
+ continue;
+ keyIds.insert({key.id(), key.uids()->front().uid()});
+ }
+ for (const auto& k : keyIds) {
+ ownKeySelectBox->addItem(QString::fromStdString(k.second));
+ keyIdsList.push_back(k.first);
+ }
+ connect(ownKeySelectBox, SIGNAL(currentIndexChanged(int)), this,
+ SLOT(slotOwnKeyIdChanged()));
+ connect(getServiceTokenButton, SIGNAL(clicked(bool)), this,
+ SLOT(slotGetServiceToken()));
+
+ ownKeyBoxLayout->addWidget(new QLabel(
+ tr("Key pair for synchronization and identity authentication")));
+ ownKeyBoxLayout->addWidget(ownKeySelectBox);
+ ownKeyBoxLayout->addLayout(ownKeyServiceTokenLayout);
+ ownKeyServiceTokenLayout->addWidget(getServiceTokenButton);
+ ownKeyServiceTokenLayout->addWidget(serviceTokenLabel);
+ ownKeyServiceTokenLayout->stretch(0);
+
+ /*****************************************
+ * Mainlayout
+ *****************************************/
+ auto* mainLayout = new QVBoxLayout;
+ mainLayout->addWidget(serverBox);
+ mainLayout->addWidget(saveCheckedKeysBox);
+ mainLayout->addWidget(importConfirmationBox);
+ mainLayout->addWidget(langBox);
+ mainLayout->addWidget(ownKeyBox);
+
+ setSettings();
+ mainLayout->addStretch(1);
+ setLayout(mainLayout);
}
/**********************************
@@ -146,55 +156,58 @@ GeneralTab::GeneralTab(GpgFrontend::GpgContext *ctx, QWidget *parent)
* appropriately
**********************************/
void GeneralTab::setSettings() {
- // Keysaving
- if (settings.value("keys/saveKeyChecked").toBool()) {
- saveCheckedKeysCheckBox->setCheckState(Qt::Checked);
- }
-
- auto serverList = settings.value("general/gpgfrontendServerList").toStringList();
- if (serverList.empty()) {
- serverList.append("service.gpgfrontend.pub");
- serverList.append("localhost");
- }
- for (const auto &s : serverList)
- serverSelectBox->addItem(s);
-
- qDebug() << "Current Gpgfrontend Server" << settings.value("general/currentGpgfrontendServer").toString();
- serverSelectBox->setCurrentText(settings.value("general/currentGpgfrontendServer",
- "service.gpgfrontend.pub").toString());
-
- connect(serverSelectBox, QOverload<const QString &>::of(&QComboBox::currentTextChanged),
- this, [&](const QString &current) -> void {
- settings.setValue("general/currentGpgfrontendServer", current);
- });
-
- // Language setting
- QString langKey = settings.value("int/lang").toString();
- QString langValue = lang.value(langKey);
- if (langKey != "") {
- langSelectBox->setCurrentIndex(langSelectBox->findText(langValue));
- }
-
- QString own_key_id = settings.value("general/ownKeyId").toString();
- qDebug() << "OwnKeyId" << own_key_id;
- if (own_key_id.isEmpty()) {
- ownKeySelectBox->setCurrentText("<none>");
- } else {
- const auto text = keyIds.find(own_key_id).value();
- qDebug() << "OwnKey" << own_key_id << text;
- ownKeySelectBox->setCurrentText(text);
- }
-
- serviceToken = settings.value("general/serviceToken").toString();
- qDebug() << "Load Service Token" << serviceToken;
- if (!serviceToken.isEmpty()) {
- serviceTokenLabel->setText(serviceToken);
- }
-
- // Get own key information from keydb/gpg.conf (if contained)
- if (settings.value("general/confirmImportKeys", Qt::Checked).toBool()) {
- importConfirmationCheckBox->setCheckState(Qt::Checked);
- }
+ // Keysaving
+ if (settings.value("keys/saveKeyChecked").toBool()) {
+ saveCheckedKeysCheckBox->setCheckState(Qt::Checked);
+ }
+
+ auto serverList =
+ settings.value("general/gpgfrontendServerList").toStringList();
+ if (serverList.empty()) {
+ serverList.append("service.gpgfrontend.pub");
+ serverList.append("localhost");
+ }
+ for (const auto& s : serverList)
+ serverSelectBox->addItem(s);
+
+ qDebug() << "Current Gpgfrontend Server"
+ << settings.value("general/currentGpgfrontendServer").toString();
+ serverSelectBox->setCurrentText(
+ settings
+ .value("general/currentGpgfrontendServer", "service.gpgfrontend.pub")
+ .toString());
+
+ connect(serverSelectBox,
+ QOverload<const QString&>::of(&QComboBox::currentTextChanged), this,
+ [&](const QString& current) -> void {
+ settings.setValue("general/currentGpgfrontendServer", current);
+ });
+
+ // Language setting
+ QString langKey = settings.value("int/lang").toString();
+ QString langValue = lang.value(langKey);
+ if (langKey != "") {
+ langSelectBox->setCurrentIndex(langSelectBox->findText(langValue));
+ }
+
+ auto own_key_id = settings.value("general/ownKeyId").toString().toStdString();
+ if (own_key_id.empty()) {
+ ownKeySelectBox->setCurrentText("<none>");
+ } else {
+ const auto uid = keyIds.find(own_key_id)->second;
+ ownKeySelectBox->setCurrentText(QString::fromStdString(uid));
+ }
+
+ serviceToken =
+ settings.value("general/serviceToken").toString().toStdString();
+ if (!serviceToken.empty()) {
+ serviceTokenLabel->setText(QString::fromStdString(serviceToken));
+ }
+
+ // Get own key information from keydb/gpg.conf (if contained)
+ if (settings.value("general/confirmImportKeys", Qt::Checked).toBool()) {
+ importConfirmationCheckBox->setCheckState(Qt::Checked);
+ }
}
/***********************************
@@ -202,157 +215,164 @@ void GeneralTab::setSettings() {
* write them to settings-file
*************************************/
void GeneralTab::applySettings() {
- settings.setValue("keys/saveKeyChecked",
- saveCheckedKeysCheckBox->isChecked());
+ settings.setValue("keys/saveKeyChecked",
+ saveCheckedKeysCheckBox->isChecked());
- qDebug() << "serverSelectBox currentText" << serverSelectBox->currentText();
- settings.setValue("general/currentGpgfrontendServer",
- serverSelectBox->currentText());
+ qDebug() << "serverSelectBox currentText" << serverSelectBox->currentText();
+ settings.setValue("general/currentGpgfrontendServer",
+ serverSelectBox->currentText());
- auto *serverList = new QStringList();
- for (int i = 0; i < serverSelectBox->count(); i++)
- serverList->append(serverSelectBox->itemText(i));
- settings.setValue("general/gpgfrontendServerList",
- *serverList);
- delete serverList;
+ auto* serverList = new QStringList();
+ for (int i = 0; i < serverSelectBox->count(); i++)
+ serverList->append(serverSelectBox->itemText(i));
+ settings.setValue("general/gpgfrontendServerList", *serverList);
+ delete serverList;
- settings.setValue("int/lang", lang.key(langSelectBox->currentText()));
+ settings.setValue("int/lang", lang.key(langSelectBox->currentText()));
- settings.setValue("general/ownKeyId",
- keyIdsList[ownKeySelectBox->currentIndex()]);
+ settings.setValue(
+ "general/ownKeyId",
+ QString::fromStdString(keyIdsList[ownKeySelectBox->currentIndex()]));
- settings.setValue("general/serviceToken",
- serviceToken);
+ settings.setValue("general/serviceToken",
+ QString::fromStdString(serviceToken));
- settings.setValue("general/confirmImportKeys",
- importConfirmationCheckBox->isChecked());
+ settings.setValue("general/confirmImportKeys",
+ importConfirmationCheckBox->isChecked());
}
-void GeneralTab::slotLanguageChanged() { emit signalRestartNeeded(true); }
+void GeneralTab::slotLanguageChanged() {
+ emit signalRestartNeeded(true);
+}
void GeneralTab::slotOwnKeyIdChanged() {
- // Set ownKeyId to currently selected
- this->serviceTokenLabel->setText(tr("No Service Token Found"));
- serviceToken.clear();
+ // Set ownKeyId to currently selected
+ this->serviceTokenLabel->setText(tr("No Service Token Found"));
+ serviceToken.clear();
}
+#ifdef SERVER_SUPPORT
void GeneralTab::slotGetServiceToken() {
+ auto utils = new ComUtils(this);
- auto utils = new ComUtils(this);
+ QUrl reqUrl(utils->getUrl(ComUtils::GetServiceToken));
+ QNetworkRequest request(reqUrl);
+ request.setHeader(QNetworkRequest::ContentTypeHeader, "application/json");
- QUrl reqUrl(utils->getUrl(ComUtils::GetServiceToken));
- QNetworkRequest request(reqUrl);
- request.setHeader(QNetworkRequest::ContentTypeHeader, "application/json");
+ const auto keyId = keyIdsList[ownKeySelectBox->currentIndex()];
+ qDebug() << "KeyId" << keyIdsList[ownKeySelectBox->currentIndex()];
- const auto keyId = keyIdsList[ownKeySelectBox->currentIndex()];
+ if (keyId.isEmpty()) {
+ QMessageBox::critical(
+ this, tr("Invalid Operation"),
+ tr("Own Key can not be None while getting service token."));
+ return;
+ }
- qDebug() << "KeyId" << keyIdsList[ownKeySelectBox->currentIndex()];
+ QStringList selectedKeyIds(keyIdsList[ownKeySelectBox->currentIndex()]);
- if (keyId.isEmpty()) {
- QMessageBox::critical(this, tr("Invalid Operation"),
- tr("Own Key can not be None while getting service token."));
- return;
- }
+ QByteArray keyDataBuf;
+ mCtx->exportKeys(&selectedKeyIds, &keyDataBuf);
- QStringList selectedKeyIds(keyIdsList[ownKeySelectBox->currentIndex()]);
+ GpgKey key = mCtx->getKeyRefById(keyId);
- QByteArray keyDataBuf;
- mCtx->exportKeys(&selectedKeyIds, &keyDataBuf);
+ if (!key.good) {
+ QMessageBox::critical(this, tr("Error"), tr("Key Not Exists"));
+ return;
+ }
- GpgKey key = mCtx->getKeyRefById(keyId);
+ qDebug() << "keyDataBuf" << keyDataBuf;
- if (!key.good) {
- QMessageBox::critical(this, tr("Error"),
- tr("Key Not Exists"));
- return;
- }
+ /**
+ * {
+ * "publicKey" : ...
+ * "sha": ...
+ * "signedFpr": ...
+ * "version": ...
+ * }
+ */
- qDebug() << "keyDataBuf" << keyDataBuf;
+ QCryptographicHash shaGen(QCryptographicHash::Sha256);
+ shaGen.addData(keyDataBuf);
- /**
- * {
- * "publicKey" : ...
- * "sha": ...
- * "signedFpr": ...
- * "version": ...
- * }
- */
+ auto shaStr = shaGen.result().toHex();
- QCryptographicHash shaGen(QCryptographicHash::Sha256);
- shaGen.addData(keyDataBuf);
+ auto signFprStr = ComUtils::getSignStringBase64(mCtx, key.fpr, key);
- auto shaStr = shaGen.result().toHex();
+ rapidjson::Value pubkey, ver, sha, signFpr;
- auto signFprStr = ComUtils::getSignStringBase64(mCtx, key.fpr, key);
+ rapidjson::Document doc;
+ doc.SetObject();
- rapidjson::Value pubkey, ver, sha, signFpr;
+ pubkey.SetString(keyDataBuf.constData(), keyDataBuf.count());
- rapidjson::Document doc;
- doc.SetObject();
+ auto version = qApp->applicationVersion();
+ ver.SetString(version.toUtf8().constData(),
+ qApp->applicationVersion().count());
- pubkey.SetString(keyDataBuf.constData(), keyDataBuf.count());
+ sha.SetString(shaStr.constData(), shaStr.count());
+ signFpr.SetString(signFprStr.constData(), signFprStr.count());
- auto version = qApp->applicationVersion();
- ver.SetString(version.toUtf8().constData(), qApp->applicationVersion().count());
+ rapidjson::Document::AllocatorType& allocator = doc.GetAllocator();
- sha.SetString(shaStr.constData(), shaStr.count());
- signFpr.SetString(signFprStr.constData(), signFprStr.count());
+ doc.AddMember("publicKey", pubkey, allocator);
+ doc.AddMember("sha", sha, allocator);
+ doc.AddMember("signedFpr", signFpr, allocator);
+ doc.AddMember("version", ver, allocator);
- rapidjson::Document::AllocatorType &allocator = doc.GetAllocator();
+ rapidjson::StringBuffer sb;
+ rapidjson::PrettyWriter<rapidjson::StringBuffer> writer(sb);
+ doc.Accept(writer);
- doc.AddMember("publicKey", pubkey, allocator);
- doc.AddMember("sha", sha, allocator);
- doc.AddMember("signedFpr", signFpr, allocator);
- doc.AddMember("version", ver, allocator);
+ QByteArray postData(sb.GetString());
- rapidjson::StringBuffer sb;
- rapidjson::PrettyWriter<rapidjson::StringBuffer> writer(sb);
- doc.Accept(writer);
+ QNetworkReply* reply = utils->getNetworkManager().post(request, postData);
- QByteArray postData(sb.GetString());
+ // Show Waiting Dailog
+ auto dialog = new WaitingDialog("Getting Token From Server", this);
+ dialog->show();
- QNetworkReply *reply = utils->getNetworkManager().post(request, postData);
+ while (reply->isRunning()) {
+ QApplication::processEvents();
+ }
- // Show Waiting Dailog
- auto dialog = new WaitingDialog("Getting Token From Server", this);
- dialog->show();
+ dialog->close();
- while (reply->isRunning()) {
- QApplication::processEvents();
- }
+ if (utils->checkServerReply(reply->readAll().constData())) {
+ /**
+ * {
+ * "serviceToken" : ...
+ * "fpr": ...
+ * }
+ */
- dialog->close();
-
- if (utils->checkServerReply(reply->readAll().constData())) {
-
- /**
- * {
- * "serviceToken" : ...
- * "fpr": ...
- * }
- */
-
- if (!utils->checkDataValueStr("serviceToken") || !utils->checkDataValueStr("fpr")) {
- QMessageBox::critical(this, tr("Error"),
- tr("The communication content with the server does not meet the requirements"));
- return;
- }
-
- QString serviceTokenTemp = utils->getDataValueStr("serviceToken");
- QString fpr = utils->getDataValueStr("fpr");
- auto key = mCtx->getKeyRefByFpr(fpr);
- if (utils->checkServiceTokenFormat(serviceTokenTemp) && key.good) {
- serviceToken = serviceTokenTemp;
- qDebug() << "Get Service Token" << serviceToken;
- // Auto update settings
- settings.setValue("general/serviceToken", serviceToken);
- serviceTokenLabel->setText(serviceToken);
- QMessageBox::information(this, tr("Notice"),
- tr("Succeed in getting service token"));
- } else {
- QMessageBox::critical(this, tr("Error"), tr("There is a problem with the communication with the server"));
- }
+ if (!utils->checkDataValueStr("serviceToken") ||
+ !utils->checkDataValueStr("fpr")) {
+ QMessageBox::critical(this, tr("Error"),
+ tr("The communication content with the server does "
+ "not meet the requirements"));
+ return;
}
+ QString serviceTokenTemp = utils->getDataValueStr("serviceToken");
+ QString fpr = utils->getDataValueStr("fpr");
+ auto key = mCtx->getKeyRefByFpr(fpr);
+ if (utils->checkServiceTokenFormat(serviceTokenTemp) && key.good) {
+ serviceToken = serviceTokenTemp;
+ qDebug() << "Get Service Token" << serviceToken;
+ // Auto update settings
+ settings.setValue("general/serviceToken", serviceToken);
+ serviceTokenLabel->setText(serviceToken);
+ QMessageBox::information(this, tr("Notice"),
+ tr("Succeed in getting service token"));
+ } else {
+ QMessageBox::critical(
+ this, tr("Error"),
+ tr("There is a problem with the communication with the server"));
+ }
+ }
}
+#endif
+
+} // namespace GpgFrontend::UI
diff --git a/src/ui/settings/SettingsKeyServer.cpp b/src/ui/settings/SettingsKeyServer.cpp
index b49eb9e0..e11115c1 100644
--- a/src/ui/settings/SettingsKeyServer.cpp
+++ b/src/ui/settings/SettingsKeyServer.cpp
@@ -24,66 +24,69 @@
#include "ui/SettingsDialog.h"
-KeyserverTab::KeyserverTab(QWidget *parent)
- : QWidget(parent), appPath(qApp->applicationDirPath()),
- settings(RESOURCE_DIR(appPath) + "/conf/gpgfrontend.ini",
- QSettings::IniFormat) {
-
- auto generalGroupBox = new QGroupBox(tr("General"));
- auto generalLayout = new QVBoxLayout();
-
- keyServerTable = new QTableWidget();
- keyServerTable->setColumnCount(3);
- keyServerTable->horizontalHeader()->setSectionResizeMode(QHeaderView::ResizeToContents);
- keyServerTable->horizontalHeader()->setStretchLastSection(false);
- keyServerTable->verticalHeader()->hide();
- keyServerTable->setShowGrid(false);
- keyServerTable->sortByColumn(0, Qt::AscendingOrder);
- keyServerTable->setSelectionBehavior(QAbstractItemView::SelectRows);
- keyServerTable->setSelectionMode(QAbstractItemView::SingleSelection);
-
- // tableitems not editable
- keyServerTable->setEditTriggers(QAbstractItemView::NoEditTriggers);
- // no focus (rectangle around tableitems)
- // may be it should focus on whole row
- keyServerTable->setFocusPolicy(Qt::NoFocus);
- keyServerTable->setAlternatingRowColors(true);
-
- QStringList labels;
- labels << tr("No.") << tr("Address") << tr("Available");
- keyServerTable->setHorizontalHeaderLabels(labels);
-
- auto *mainLayout = new QVBoxLayout(this);
- auto *label = new QLabel(tr("Default Key Server for Import:"));
-
- comboBox = new QComboBox;
- comboBox->setEditable(false);
- comboBox->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Preferred);
-
- auto *addKeyServerBox = new QWidget(this);
- auto *addKeyServerLayout = new QHBoxLayout(addKeyServerBox);
- auto *http = new QLabel("URL: ");
- newKeyServerEdit = new QLineEdit(this);
- auto *newKeyServerButton = new QPushButton(tr("Add"), this);
- connect(newKeyServerButton, SIGNAL(clicked()), this, SLOT(addKeyServer()));
- addKeyServerLayout->addWidget(http);
- addKeyServerLayout->addWidget(newKeyServerEdit);
- addKeyServerLayout->addWidget(newKeyServerButton);
-
- generalLayout->addWidget(label);
- generalLayout->addWidget(comboBox);
- generalLayout->addWidget(keyServerTable);
- generalLayout->addWidget(addKeyServerBox);
- generalLayout->addStretch(0);
-
- generalGroupBox->setLayout(generalLayout);
- mainLayout->addWidget(generalGroupBox);
- mainLayout->addStretch(0);
-
- setLayout(mainLayout);
- // Read keylist from ini-file and fill it into combobox
- setSettings();
- refreshTable();
+namespace GpgFrontend::UI {
+
+KeyserverTab::KeyserverTab(QWidget* parent)
+ : QWidget(parent),
+ appPath(qApp->applicationDirPath()),
+ settings(RESOURCE_DIR(appPath) + "/conf/gpgfrontend.ini",
+ QSettings::IniFormat) {
+ auto generalGroupBox = new QGroupBox(tr("General"));
+ auto generalLayout = new QVBoxLayout();
+
+ keyServerTable = new QTableWidget();
+ keyServerTable->setColumnCount(3);
+ keyServerTable->horizontalHeader()->setSectionResizeMode(
+ QHeaderView::ResizeToContents);
+ keyServerTable->horizontalHeader()->setStretchLastSection(false);
+ keyServerTable->verticalHeader()->hide();
+ keyServerTable->setShowGrid(false);
+ keyServerTable->sortByColumn(0, Qt::AscendingOrder);
+ keyServerTable->setSelectionBehavior(QAbstractItemView::SelectRows);
+ keyServerTable->setSelectionMode(QAbstractItemView::SingleSelection);
+
+ // tableitems not editable
+ keyServerTable->setEditTriggers(QAbstractItemView::NoEditTriggers);
+ // no focus (rectangle around tableitems)
+ // may be it should focus on whole row
+ keyServerTable->setFocusPolicy(Qt::NoFocus);
+ keyServerTable->setAlternatingRowColors(true);
+
+ QStringList labels;
+ labels << tr("No.") << tr("Address") << tr("Available");
+ keyServerTable->setHorizontalHeaderLabels(labels);
+
+ auto* mainLayout = new QVBoxLayout(this);
+ auto* label = new QLabel(tr("Default Key Server for Import:"));
+
+ comboBox = new QComboBox;
+ comboBox->setEditable(false);
+ comboBox->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Preferred);
+
+ auto* addKeyServerBox = new QWidget(this);
+ auto* addKeyServerLayout = new QHBoxLayout(addKeyServerBox);
+ auto* http = new QLabel("URL: ");
+ newKeyServerEdit = new QLineEdit(this);
+ auto* newKeyServerButton = new QPushButton(tr("Add"), this);
+ connect(newKeyServerButton, SIGNAL(clicked()), this, SLOT(addKeyServer()));
+ addKeyServerLayout->addWidget(http);
+ addKeyServerLayout->addWidget(newKeyServerEdit);
+ addKeyServerLayout->addWidget(newKeyServerButton);
+
+ generalLayout->addWidget(label);
+ generalLayout->addWidget(comboBox);
+ generalLayout->addWidget(keyServerTable);
+ generalLayout->addWidget(addKeyServerBox);
+ generalLayout->addStretch(0);
+
+ generalGroupBox->setLayout(generalLayout);
+ mainLayout->addWidget(generalGroupBox);
+ mainLayout->addStretch(0);
+
+ setLayout(mainLayout);
+ // Read keylist from ini-file and fill it into combobox
+ setSettings();
+ refreshTable();
}
/**********************************
@@ -92,29 +95,27 @@ KeyserverTab::KeyserverTab(QWidget *parent)
* appropriately
**********************************/
void KeyserverTab::setSettings() {
+ keyServerStrList = settings.value("keyserver/keyServerList").toStringList();
- keyServerStrList = settings.value("keyserver/keyServerList").toStringList();
-
- for (const auto &keyServer : keyServerStrList) {
- comboBox->addItem(keyServer);
- qDebug() << "KeyserverTab Get ListItemText" << keyServer;
- }
-
- comboBox->setCurrentText(
- settings.value("keyserver/defaultKeyServer").toString());
+ for (const auto& keyServer : keyServerStrList) {
+ comboBox->addItem(keyServer);
+ qDebug() << "KeyserverTab Get ListItemText" << keyServer;
+ }
+ comboBox->setCurrentText(
+ settings.value("keyserver/defaultKeyServer").toString());
}
void KeyserverTab::addKeyServer() {
- QString targetUrl;
- if (newKeyServerEdit->text().startsWith("http://") ||
- newKeyServerEdit->text().startsWith("https://"))
- targetUrl = newKeyServerEdit->text();
- else
- targetUrl = "http://" + newKeyServerEdit->text();
- keyServerStrList.append(targetUrl);
- comboBox->addItem(targetUrl);
- refreshTable();
+ QString targetUrl;
+ if (newKeyServerEdit->text().startsWith("http://") ||
+ newKeyServerEdit->text().startsWith("https://"))
+ targetUrl = newKeyServerEdit->text();
+ else
+ targetUrl = "http://" + newKeyServerEdit->text();
+ keyServerStrList.append(targetUrl);
+ comboBox->addItem(targetUrl);
+ refreshTable();
}
/***********************************
@@ -122,27 +123,28 @@ void KeyserverTab::addKeyServer() {
* write them to settings-file
*************************************/
void KeyserverTab::applySettings() {
- settings.setValue("keyserver/keyServerList", keyServerStrList);
- settings.setValue("keyserver/defaultKeyServer", comboBox->currentText());
+ settings.setValue("keyserver/keyServerList", keyServerStrList);
+ settings.setValue("keyserver/defaultKeyServer", comboBox->currentText());
}
void KeyserverTab::refreshTable() {
-
- qDebug() << "Start Refreshing Key Server Table";
-
- keyServerTable->setRowCount(keyServerStrList.size());
-
- int index = 0;
- for (const auto &server : keyServerStrList) {
- auto *tmp1 = new QTableWidgetItem(QString::number(index));
- tmp1->setTextAlignment(Qt::AlignCenter);
- keyServerTable->setItem(index, 0, tmp1);
- auto *tmp2 = new QTableWidgetItem(server);
- tmp2->setTextAlignment(Qt::AlignCenter);
- keyServerTable->setItem(index, 1, tmp2);
- auto *tmp3 = new QTableWidgetItem("");
- tmp3->setTextAlignment(Qt::AlignCenter);
- keyServerTable->setItem(index, 2, tmp3);
- index++;
- }
+ qDebug() << "Start Refreshing Key Server Table";
+
+ keyServerTable->setRowCount(keyServerStrList.size());
+
+ int index = 0;
+ for (const auto& server : keyServerStrList) {
+ auto* tmp1 = new QTableWidgetItem(QString::number(index));
+ tmp1->setTextAlignment(Qt::AlignCenter);
+ keyServerTable->setItem(index, 0, tmp1);
+ auto* tmp2 = new QTableWidgetItem(server);
+ tmp2->setTextAlignment(Qt::AlignCenter);
+ keyServerTable->setItem(index, 1, tmp2);
+ auto* tmp3 = new QTableWidgetItem("");
+ tmp3->setTextAlignment(Qt::AlignCenter);
+ keyServerTable->setItem(index, 2, tmp3);
+ index++;
+ }
}
+
+} // namespace GpgFrontend::UI
diff --git a/src/ui/settings/SettingsSendMail.cpp b/src/ui/settings/SettingsSendMail.cpp
index a5e3274f..8db3cd0a 100644
--- a/src/ui/settings/SettingsSendMail.cpp
+++ b/src/ui/settings/SettingsSendMail.cpp
@@ -22,75 +22,81 @@
*
*/
-#include "ui/SettingsDialog.h"
+#ifdef SMTP_SUPPORT
#include "smtp/SmtpMime"
+#endif
+#include "ui/SettingsDialog.h"
-SendMailTab::SendMailTab(QWidget *parent)
- : QWidget(parent), appPath(qApp->applicationDirPath()),
- settings(RESOURCE_DIR(appPath) + "/conf/gpgfrontend.ini",
- QSettings::IniFormat) {
-
- enableCheckBox = new QCheckBox(tr("Enable"));
- enableCheckBox->setTristate(false);
-
- smtpAddress = new QLineEdit();
- username = new QLineEdit();
- password = new QLineEdit();
- password->setEchoMode(QLineEdit::Password);
-
- portSpin = new QSpinBox();
- portSpin->setMinimum(1);
- portSpin->setMaximum(65535);
- connectionTypeComboBox = new QComboBox();
- connectionTypeComboBox->addItem("None");
- connectionTypeComboBox->addItem("SSL");
- connectionTypeComboBox->addItem("TLS");
- connectionTypeComboBox->addItem("STARTTLS");
-
- defaultSender = new QLineEdit();;
- checkConnectionButton = new QPushButton(tr("Check Connection"));
-
- auto generalGroupBox = new QGroupBox(tr("General"));
- auto connectGroupBox = new QGroupBox(tr("Connection"));
- auto preferenceGroupBox = new QGroupBox(tr("Preference"));
-
- auto generalLayout = new QGridLayout();
- generalLayout->addWidget(enableCheckBox);
-
- auto connectLayout = new QGridLayout();
- connectLayout->addWidget(new QLabel(tr("SMTP Address")), 1, 0);
- connectLayout->addWidget(smtpAddress, 1, 1, 1, 4);
- connectLayout->addWidget(new QLabel(tr("Username")), 2, 0);
- connectLayout->addWidget(username, 2, 1, 1, 4);
- connectLayout->addWidget(new QLabel(tr("Password")), 3, 0);
- connectLayout->addWidget(password, 3, 1, 1, 4);
- connectLayout->addWidget(new QLabel(tr("Port")), 4, 0);
- connectLayout->addWidget(portSpin, 4, 1, 1, 1);
- connectLayout->addWidget(new QLabel(tr("Connection Security")), 5, 0);
- connectLayout->addWidget(connectionTypeComboBox, 5, 1, 1, 1);
- connectLayout->addWidget(checkConnectionButton, 6, 0);
-
- auto preferenceLayout = new QGridLayout();
-
- preferenceLayout->addWidget(new QLabel(tr("Default Sender")), 0, 0);
- preferenceLayout->addWidget(defaultSender, 0, 1, 1, 4);
-
- generalGroupBox->setLayout(generalLayout);
- connectGroupBox->setLayout(connectLayout);
- preferenceGroupBox->setLayout(preferenceLayout);
-
- auto vBox = new QVBoxLayout();
- vBox->addWidget(generalGroupBox);
- vBox->addWidget(connectGroupBox);
- vBox->addWidget(preferenceGroupBox);
- vBox->addStretch(0);
-
- connect(enableCheckBox, SIGNAL(stateChanged(int)), this, SLOT(slotCheckBoxSetEnableDisable(int)));
- connect(checkConnectionButton, SIGNAL(clicked(bool)), this, SLOT(slotCheckConnection()));
-
-
- this->setLayout(vBox);
- setSettings();
+namespace GpgFrontend::UI {
+
+SendMailTab::SendMailTab(QWidget* parent)
+ : QWidget(parent),
+ appPath(qApp->applicationDirPath()),
+ settings(RESOURCE_DIR(appPath) + "/conf/gpgfrontend.ini",
+ QSettings::IniFormat) {
+ enableCheckBox = new QCheckBox(tr("Enable"));
+ enableCheckBox->setTristate(false);
+
+ smtpAddress = new QLineEdit();
+ username = new QLineEdit();
+ password = new QLineEdit();
+ password->setEchoMode(QLineEdit::Password);
+
+ portSpin = new QSpinBox();
+ portSpin->setMinimum(1);
+ portSpin->setMaximum(65535);
+ connectionTypeComboBox = new QComboBox();
+ connectionTypeComboBox->addItem("None");
+ connectionTypeComboBox->addItem("SSL");
+ connectionTypeComboBox->addItem("TLS");
+ connectionTypeComboBox->addItem("STARTTLS");
+
+ defaultSender = new QLineEdit();
+ ;
+ checkConnectionButton = new QPushButton(tr("Check Connection"));
+
+ auto generalGroupBox = new QGroupBox(tr("General"));
+ auto connectGroupBox = new QGroupBox(tr("Connection"));
+ auto preferenceGroupBox = new QGroupBox(tr("Preference"));
+
+ auto generalLayout = new QGridLayout();
+ generalLayout->addWidget(enableCheckBox);
+
+ auto connectLayout = new QGridLayout();
+ connectLayout->addWidget(new QLabel(tr("SMTP Address")), 1, 0);
+ connectLayout->addWidget(smtpAddress, 1, 1, 1, 4);
+ connectLayout->addWidget(new QLabel(tr("Username")), 2, 0);
+ connectLayout->addWidget(username, 2, 1, 1, 4);
+ connectLayout->addWidget(new QLabel(tr("Password")), 3, 0);
+ connectLayout->addWidget(password, 3, 1, 1, 4);
+ connectLayout->addWidget(new QLabel(tr("Port")), 4, 0);
+ connectLayout->addWidget(portSpin, 4, 1, 1, 1);
+ connectLayout->addWidget(new QLabel(tr("Connection Security")), 5, 0);
+ connectLayout->addWidget(connectionTypeComboBox, 5, 1, 1, 1);
+ connectLayout->addWidget(checkConnectionButton, 6, 0);
+
+ auto preferenceLayout = new QGridLayout();
+
+ preferenceLayout->addWidget(new QLabel(tr("Default Sender")), 0, 0);
+ preferenceLayout->addWidget(defaultSender, 0, 1, 1, 4);
+
+ generalGroupBox->setLayout(generalLayout);
+ connectGroupBox->setLayout(connectLayout);
+ preferenceGroupBox->setLayout(preferenceLayout);
+
+ auto vBox = new QVBoxLayout();
+ vBox->addWidget(generalGroupBox);
+ vBox->addWidget(connectGroupBox);
+ vBox->addWidget(preferenceGroupBox);
+ vBox->addStretch(0);
+
+ connect(enableCheckBox, SIGNAL(stateChanged(int)), this,
+ SLOT(slotCheckBoxSetEnableDisable(int)));
+ connect(checkConnectionButton, SIGNAL(clicked(bool)), this,
+ SLOT(slotCheckConnection()));
+
+ this->setLayout(vBox);
+ setSettings();
}
/**********************************
@@ -99,27 +105,28 @@ SendMailTab::SendMailTab(QWidget *parent)
* appropriately
**********************************/
void SendMailTab::setSettings() {
-
- if (settings.value("sendMail/enable", false).toBool())
- enableCheckBox->setCheckState(Qt::Checked);
- else {
- enableCheckBox->setCheckState(Qt::Unchecked);
- smtpAddress->setDisabled(true);
- username->setDisabled(true);
- password->setDisabled(true);
- portSpin->setDisabled(true);
- connectionTypeComboBox->setDisabled(true);
- defaultSender->setDisabled(true);
- checkConnectionButton->setDisabled(true);
- }
-
- smtpAddress->setText(settings.value("sendMail/smtpAddress", QString()).toString());
- username->setText(settings.value("sendMail/username", QString()).toString());
- password->setText(settings.value("sendMail/password", QString()).toString());
- portSpin->setValue(settings.value("sendMail/port", 25).toInt());
- connectionTypeComboBox->setCurrentText(settings.value("sendMail/connectionType", "None").toString());
- defaultSender->setText(settings.value("sendMail/defaultSender", QString()).toString());
-
+ if (settings.value("sendMail/enable", false).toBool())
+ enableCheckBox->setCheckState(Qt::Checked);
+ else {
+ enableCheckBox->setCheckState(Qt::Unchecked);
+ smtpAddress->setDisabled(true);
+ username->setDisabled(true);
+ password->setDisabled(true);
+ portSpin->setDisabled(true);
+ connectionTypeComboBox->setDisabled(true);
+ defaultSender->setDisabled(true);
+ checkConnectionButton->setDisabled(true);
+ }
+
+ smtpAddress->setText(
+ settings.value("sendMail/smtpAddress", QString()).toString());
+ username->setText(settings.value("sendMail/username", QString()).toString());
+ password->setText(settings.value("sendMail/password", QString()).toString());
+ portSpin->setValue(settings.value("sendMail/port", 25).toInt());
+ connectionTypeComboBox->setCurrentText(
+ settings.value("sendMail/connectionType", "None").toString());
+ defaultSender->setText(
+ settings.value("sendMail/defaultSender", QString()).toString());
}
/***********************************
@@ -127,67 +134,69 @@ void SendMailTab::setSettings() {
* write them to settings-file
*************************************/
void SendMailTab::applySettings() {
-
- settings.setValue("sendMail/smtpAddress", smtpAddress->text());
- settings.setValue("sendMail/username", username->text());
- settings.setValue("sendMail/password", password->text());
- settings.setValue("sendMail/port", portSpin->value());
- settings.setValue("sendMail/connectionType", connectionTypeComboBox->currentText());
- settings.setValue("sendMail/defaultSender", defaultSender->text());
-
- settings.setValue("sendMail/enable", enableCheckBox->isChecked());
+ settings.setValue("sendMail/smtpAddress", smtpAddress->text());
+ settings.setValue("sendMail/username", username->text());
+ settings.setValue("sendMail/password", password->text());
+ settings.setValue("sendMail/port", portSpin->value());
+ settings.setValue("sendMail/connectionType",
+ connectionTypeComboBox->currentText());
+ settings.setValue("sendMail/defaultSender", defaultSender->text());
+
+ settings.setValue("sendMail/enable", enableCheckBox->isChecked());
}
+#ifdef SMTP_SUPPORT
void SendMailTab::slotCheckConnection() {
-
- SmtpClient::ConnectionType connectionType;
- const auto selectedConnType = connectionTypeComboBox->currentText();
- if (selectedConnType == "SSL") {
- connectionType = SmtpClient::ConnectionType::SslConnection;
- } else if (selectedConnType == "TLS" || selectedConnType == "STARTTLS") {
- connectionType = SmtpClient::ConnectionType::TlsConnection;
- } else {
- connectionType = SmtpClient::ConnectionType::TcpConnection;
- }
-
- SmtpClient smtp(smtpAddress->text(), portSpin->value(), connectionType);
-
- smtp.setUser(username->text());
- smtp.setPassword(password->text());
-
- bool if_success = true;
-
- if (!smtp.connectToHost()) {
- QMessageBox::critical(this, tr("Fail"), tr("Fail to Connect SMTP Server"));
- if_success = false;
- }
- if (if_success && !smtp.login()) {
- QMessageBox::critical(this, tr("Fail"), tr("Fail to Login"));
- if_success = false;
- }
-
- if (if_success)
- QMessageBox::information(this, tr("Success"), tr("Succeed in connecting and login"));
-
+ SmtpClient::ConnectionType connectionType;
+ const auto selectedConnType = connectionTypeComboBox->currentText();
+ if (selectedConnType == "SSL") {
+ connectionType = SmtpClient::ConnectionType::SslConnection;
+ } else if (selectedConnType == "TLS" || selectedConnType == "STARTTLS") {
+ connectionType = SmtpClient::ConnectionType::TlsConnection;
+ } else {
+ connectionType = SmtpClient::ConnectionType::TcpConnection;
+ }
+
+ SmtpClient smtp(smtpAddress->text(), portSpin->value(), connectionType);
+
+ smtp.setUser(username->text());
+ smtp.setPassword(password->text());
+
+ bool if_success = true;
+
+ if (!smtp.connectToHost()) {
+ QMessageBox::critical(this, tr("Fail"), tr("Fail to Connect SMTP Server"));
+ if_success = false;
+ }
+ if (if_success && !smtp.login()) {
+ QMessageBox::critical(this, tr("Fail"), tr("Fail to Login"));
+ if_success = false;
+ }
+
+ if (if_success)
+ QMessageBox::information(this, tr("Success"),
+ tr("Succeed in connecting and login"));
}
+#endif
void SendMailTab::slotCheckBoxSetEnableDisable(int state) {
- if (state == Qt::Checked) {
- smtpAddress->setEnabled(true);
- username->setEnabled(true);
- password->setEnabled(true);
- portSpin->setEnabled(true);
- connectionTypeComboBox->setEnabled(true);
- defaultSender->setEnabled(true);
- checkConnectionButton->setEnabled(true);
- } else {
- smtpAddress->setDisabled(true);
- username->setDisabled(true);
- password->setDisabled(true);
- portSpin->setDisabled(true);
- connectionTypeComboBox->setDisabled(true);
- defaultSender->setDisabled(true);
- checkConnectionButton->setDisabled(true);
- }
+ if (state == Qt::Checked) {
+ smtpAddress->setEnabled(true);
+ username->setEnabled(true);
+ password->setEnabled(true);
+ portSpin->setEnabled(true);
+ connectionTypeComboBox->setEnabled(true);
+ defaultSender->setEnabled(true);
+ checkConnectionButton->setEnabled(true);
+ } else {
+ smtpAddress->setDisabled(true);
+ username->setDisabled(true);
+ password->setDisabled(true);
+ portSpin->setDisabled(true);
+ connectionTypeComboBox->setDisabled(true);
+ defaultSender->setDisabled(true);
+ checkConnectionButton->setDisabled(true);
+ }
}
+} // namespace GpgFrontend::UI
diff --git a/src/ui/widgets/EditorPage.cpp b/src/ui/widgets/EditorPage.cpp
index beb37b96..76db1b0b 100644
--- a/src/ui/widgets/EditorPage.cpp
+++ b/src/ui/widgets/EditorPage.cpp
@@ -26,82 +26,86 @@
#include <utility>
-EditorPage::EditorPage(QString filePath, QWidget *parent) : QWidget(parent),
- fullFilePath(std::move(filePath)) {
- // Set the Textedit properties
- textPage = new QTextEdit();
- textPage->setAcceptRichText(false);
-
- // Set the layout style
- mainLayout = new QVBoxLayout();
- mainLayout->setSpacing(0);
- mainLayout->addWidget(textPage);
- mainLayout->setContentsMargins(0, 0, 0, 0);
- setLayout(mainLayout);
-
- setAttribute(Qt::WA_DeleteOnClose);
- textPage->setFocus();
-
- // Front in same width
- this->setFont({"Courier"});
+namespace GpgFrontend::UI {
+
+EditorPage::EditorPage(QString filePath, QWidget* parent)
+ : QWidget(parent), fullFilePath(std::move(filePath)) {
+ // Set the Textedit properties
+ textPage = new QTextEdit();
+ textPage->setAcceptRichText(false);
+
+ // Set the layout style
+ mainLayout = new QVBoxLayout();
+ mainLayout->setSpacing(0);
+ mainLayout->addWidget(textPage);
+ mainLayout->setContentsMargins(0, 0, 0, 0);
+ setLayout(mainLayout);
+
+ setAttribute(Qt::WA_DeleteOnClose);
+ textPage->setFocus();
+
+ // Front in same width
+ this->setFont({"Courier"});
}
-const QString &EditorPage::getFilePath() const {
- return fullFilePath;
+const QString& EditorPage::getFilePath() const {
+ return fullFilePath;
}
-QTextEdit *EditorPage::getTextPage() {
- return textPage;
+QTextEdit* EditorPage::getTextPage() {
+ return textPage;
}
-void EditorPage::setFilePath(const QString &filePath) {
- fullFilePath = filePath;
+void EditorPage::setFilePath(const QString& filePath) {
+ fullFilePath = filePath;
}
-void EditorPage::showNotificationWidget(QWidget *widget, const char *className) {
- widget->setProperty(className, true);
- mainLayout->addWidget(widget);
+void EditorPage::showNotificationWidget(QWidget* widget,
+ const char* className) {
+ widget->setProperty(className, true);
+ mainLayout->addWidget(widget);
}
-void EditorPage::closeNoteByClass(const char *className) {
- QList<QWidget *> widgets = findChildren<QWidget *>();
- for (QWidget *widget: widgets) {
- if (widget->property(className) == true) {
- widget->close();
- }
+void EditorPage::closeNoteByClass(const char* className) {
+ QList<QWidget*> widgets = findChildren<QWidget*>();
+ for (QWidget* widget : widgets) {
+ if (widget->property(className) == true) {
+ widget->close();
}
+ }
}
void EditorPage::slotFormatGpgHeader() {
-
- QString content = textPage->toPlainText();
-
- // Get positions of the gpg-headers, if they exist
- int start = content.indexOf(GpgConstants::PGP_SIGNED_BEGIN);
- int startSig = content.indexOf(GpgConstants::PGP_SIGNATURE_BEGIN);
- int endSig = content.indexOf(GpgConstants::PGP_SIGNATURE_END);
-
- if (start < 0 || startSig < 0 || endSig < 0 || signMarked) {
- return;
- }
-
- signMarked = true;
-
- // Set the fontstyle for the header
- QTextCharFormat signFormat;
- signFormat.setForeground(QBrush(QColor::fromRgb(80, 80, 80)));
- signFormat.setFontPointSize(9);
-
- // set font style for the signature
- QTextCursor cursor(textPage->document());
- cursor.setPosition(startSig, QTextCursor::MoveAnchor);
- cursor.movePosition(QTextCursor::Right, QTextCursor::KeepAnchor, endSig);
- cursor.setCharFormat(signFormat);
-
- // set the font style for the header
- int headEnd = content.indexOf("\n\n", start);
- cursor.setPosition(start, QTextCursor::MoveAnchor);
- cursor.movePosition(QTextCursor::Right, QTextCursor::KeepAnchor, headEnd);
- cursor.setCharFormat(signFormat);
-
+ QString content = textPage->toPlainText();
+
+ // Get positions of the gpg-headers, if they exist
+ int start = content.indexOf(GpgFrontend::GpgConstants::PGP_SIGNED_BEGIN);
+ int startSig =
+ content.indexOf(GpgFrontend::GpgConstants::PGP_SIGNATURE_BEGIN);
+ int endSig = content.indexOf(GpgFrontend::GpgConstants::PGP_SIGNATURE_END);
+
+ if (start < 0 || startSig < 0 || endSig < 0 || signMarked) {
+ return;
+ }
+
+ signMarked = true;
+
+ // Set the fontstyle for the header
+ QTextCharFormat signFormat;
+ signFormat.setForeground(QBrush(QColor::fromRgb(80, 80, 80)));
+ signFormat.setFontPointSize(9);
+
+ // set font style for the signature
+ QTextCursor cursor(textPage->document());
+ cursor.setPosition(startSig, QTextCursor::MoveAnchor);
+ cursor.movePosition(QTextCursor::Right, QTextCursor::KeepAnchor, endSig);
+ cursor.setCharFormat(signFormat);
+
+ // set the font style for the header
+ int headEnd = content.indexOf("\n\n", start);
+ cursor.setPosition(start, QTextCursor::MoveAnchor);
+ cursor.movePosition(QTextCursor::Right, QTextCursor::KeepAnchor, headEnd);
+ cursor.setCharFormat(signFormat);
}
+
+} // namespace GpgFrontend::UI
diff --git a/src/ui/widgets/EditorPage.h b/src/ui/widgets/EditorPage.h
new file mode 100644
index 00000000..4d7d7ab6
--- /dev/null
+++ b/src/ui/widgets/EditorPage.h
@@ -0,0 +1,108 @@
+/**
+ * This file is part of GPGFrontend.
+ *
+ * GPGFrontend is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Foobar is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Foobar. If not, see <https://www.gnu.org/licenses/>.
+ *
+ * The initial version of the source code is inherited from gpg4usb-team.
+ * Their source code version also complies with GNU General Public License.
+ *
+ * The source code version of this software was modified and released
+ * by Saturneric<[email protected]> starting on May 12, 2021.
+ *
+ */
+
+#ifndef __EDITORPAGE_H__
+#define __EDITORPAGE_H__
+
+#include "gpg/GpgConstants.h"
+#include "ui/GpgFrontendUI.h"
+
+QT_BEGIN_NAMESPACE
+class QVBoxLayout;
+
+class QHBoxLayout;
+
+class QString;
+
+class QLabel;
+QT_END_NAMESPACE
+
+namespace GpgFrontend::UI {
+
+/**
+ * @brief Class for handling a single tab of the tabwidget
+ *
+ */
+class EditorPage : public QWidget {
+ Q_OBJECT
+ public:
+ /**
+ * @details Add layout and add plaintextedit
+ *
+ * @param filePath Path of the file handled in this tab
+ * @param parent Pointer to the parent widget
+ */
+ explicit EditorPage(QString filePath = "", QWidget* parent = nullptr);
+
+ /**
+ * @details Get the filepath of the currently activated tab.
+ */
+ const QString& getFilePath() const;
+
+ /**
+ * @details Set filepath of currently activated tab.
+ *
+ * @param filePath The path to be set
+ */
+ void setFilePath(const QString& filePath);
+
+ /**
+ * @details Return pointer tp the textedit of the currently activated tab.
+ */
+ QTextEdit* getTextPage();
+
+ /**
+ * @details Show additional widget at buttom of currently active tab
+ *
+ * @param widget The widget to be added
+ * @param className The name to handle the added widget
+ */
+ void showNotificationWidget(QWidget* widget, const char* className);
+
+ /**
+ * @details Hide all widgets with the given className
+ *
+ * @param className The classname of the widgets to hide
+ */
+ void closeNoteByClass(const char* className);
+
+ const QString uuid = QUuid::createUuid().toString();
+
+ private:
+ QTextEdit* textPage; /** The textedit of the tab */
+ QVBoxLayout* mainLayout; /** The layout for the tab */
+ QString fullFilePath; /** The path to the file handled in the tab */
+ bool signMarked{}; /** true, if the signed header is marked, false if not */
+
+ private slots:
+
+ /**
+ * @details Format the gpg header in another font-style
+ */
+ void slotFormatGpgHeader();
+};
+
+} // namespace GpgFrontend::UI
+
+#endif // __EDITORPAGE_H__
diff --git a/src/ui/widgets/FilePage.cpp b/src/ui/widgets/FilePage.cpp
index b9602d58..07d3b762 100644
--- a/src/ui/widgets/FilePage.cpp
+++ b/src/ui/widgets/FilePage.cpp
@@ -26,242 +26,251 @@
#include "MainWindow.h"
-FilePage::FilePage(QWidget *parent) : QWidget(parent) {
-
- qDebug() << "First Parent" << parent;
- firstParent = parent;
-
- qDebug() << "New File Page";
-
- dirModel = new QFileSystemModel();
- dirModel->setRootPath(QDir::currentPath());
-
- dirTreeView = new QTreeView();
- dirTreeView->setModel(dirModel);
- dirTreeView->setAnimated(true);
- dirTreeView->setIndentation(20);
- dirTreeView->setRootIndex(dirModel->index(QDir::currentPath()));
- dirTreeView->setContextMenuPolicy(Qt::CustomContextMenu);
- mPath = dirModel->rootPath();
-
- createPopupMenu();
-
-
- upLevelButton = new QPushButton();
- connect(upLevelButton, SIGNAL(clicked(bool)), this, SLOT(slotUpLevel()));
-
- QString buttonStyle = "QPushButton{border:none;background-color:rgba(255, 255, 255,100);}";
-
-
- auto upPixmap = QPixmap(":up.png");
- upPixmap = upPixmap.scaled(18, 18, Qt::KeepAspectRatio, Qt::SmoothTransformation);
- QIcon upButtonIcon(upPixmap);
- upLevelButton->setIcon(upButtonIcon);
- upLevelButton->setIconSize(upPixmap.rect().size());
- upLevelButton->setStyleSheet(buttonStyle);
-
- refreshButton = new QPushButton("Refresh");
- connect(refreshButton, SIGNAL(clicked(bool)), this, SLOT(slotGoPath()));
-
- goPathButton = new QPushButton();
- connect(goPathButton, SIGNAL(clicked(bool)), this, SLOT(slotGoPath()));
-
- auto updatePixmap = QPixmap(":refresh.png");
- updatePixmap = updatePixmap.scaled(18, 18, Qt::KeepAspectRatio, Qt::SmoothTransformation);
- QIcon updateButtonIcon(updatePixmap);
- goPathButton->setIcon(updateButtonIcon);
- goPathButton->setIconSize(updatePixmap.rect().size());
- goPathButton->setStyleSheet(buttonStyle);
-
- pathEdit = new QLineEdit();
- pathEdit->setText(dirModel->rootPath());
-
- auto *menuLayout = new QHBoxLayout();
- menuLayout->addWidget(upLevelButton);
- menuLayout->setStretchFactor(upLevelButton, 1);
- menuLayout->addWidget(pathEdit);
- menuLayout->setStretchFactor(pathEdit, 10);
- menuLayout->addWidget(goPathButton);
- menuLayout->setStretchFactor(goPathButton, 1);
- // menuLayout->addWidget(refreshButton);
- // menuLayout->setStretchFactor(refreshButton, 1);
-
- auto *layout = new QVBoxLayout();
- layout->setContentsMargins(0, 0, 0, 0);
- layout->setSpacing(0);
- layout->addLayout(menuLayout);
- layout->setStretchFactor(menuLayout, 1);
- layout->addWidget(dirTreeView);
- layout->setStretchFactor(dirTreeView, 8);
-
- this->setLayout(layout);
-
- connect(dirTreeView, SIGNAL(clicked(const QModelIndex &)), this, SLOT(fileTreeViewItemClicked(const QModelIndex &)));
- connect(dirTreeView, SIGNAL(doubleClicked(const QModelIndex &)), this, SLOT(fileTreeViewItemDoubleClicked(const QModelIndex &)));
- connect(dirTreeView, SIGNAL(customContextMenuRequested(const QPoint &)), this, SLOT(onCustomContextMenu(const QPoint &)));
-
- emit pathChanged(mPath);
-
+namespace GpgFrontend::UI {
+
+FilePage::FilePage(QWidget* parent) : QWidget(parent) {
+ qDebug() << "First Parent" << parent;
+ firstParent = parent;
+
+ qDebug() << "New File Page";
+
+ dirModel = new QFileSystemModel();
+ dirModel->setRootPath(QDir::currentPath());
+
+ dirTreeView = new QTreeView();
+ dirTreeView->setModel(dirModel);
+ dirTreeView->setAnimated(true);
+ dirTreeView->setIndentation(20);
+ dirTreeView->setRootIndex(dirModel->index(QDir::currentPath()));
+ dirTreeView->setContextMenuPolicy(Qt::CustomContextMenu);
+ mPath = dirModel->rootPath();
+
+ createPopupMenu();
+
+ upLevelButton = new QPushButton();
+ connect(upLevelButton, SIGNAL(clicked(bool)), this, SLOT(slotUpLevel()));
+
+ QString buttonStyle =
+ "QPushButton{border:none;background-color:rgba(255, 255, 255,100);}";
+
+ auto upPixmap = QPixmap(":up.png");
+ upPixmap =
+ upPixmap.scaled(18, 18, Qt::KeepAspectRatio, Qt::SmoothTransformation);
+ QIcon upButtonIcon(upPixmap);
+ upLevelButton->setIcon(upButtonIcon);
+ upLevelButton->setIconSize(upPixmap.rect().size());
+ upLevelButton->setStyleSheet(buttonStyle);
+
+ refreshButton = new QPushButton("Refresh");
+ connect(refreshButton, SIGNAL(clicked(bool)), this, SLOT(slotGoPath()));
+
+ goPathButton = new QPushButton();
+ connect(goPathButton, SIGNAL(clicked(bool)), this, SLOT(slotGoPath()));
+
+ auto updatePixmap = QPixmap(":refresh.png");
+ updatePixmap = updatePixmap.scaled(18, 18, Qt::KeepAspectRatio,
+ Qt::SmoothTransformation);
+ QIcon updateButtonIcon(updatePixmap);
+ goPathButton->setIcon(updateButtonIcon);
+ goPathButton->setIconSize(updatePixmap.rect().size());
+ goPathButton->setStyleSheet(buttonStyle);
+
+ pathEdit = new QLineEdit();
+ pathEdit->setText(dirModel->rootPath());
+
+ auto* menuLayout = new QHBoxLayout();
+ menuLayout->addWidget(upLevelButton);
+ menuLayout->setStretchFactor(upLevelButton, 1);
+ menuLayout->addWidget(pathEdit);
+ menuLayout->setStretchFactor(pathEdit, 10);
+ menuLayout->addWidget(goPathButton);
+ menuLayout->setStretchFactor(goPathButton, 1);
+ // menuLayout->addWidget(refreshButton);
+ // menuLayout->setStretchFactor(refreshButton, 1);
+
+ auto* layout = new QVBoxLayout();
+ layout->setContentsMargins(0, 0, 0, 0);
+ layout->setSpacing(0);
+ layout->addLayout(menuLayout);
+ layout->setStretchFactor(menuLayout, 1);
+ layout->addWidget(dirTreeView);
+ layout->setStretchFactor(dirTreeView, 8);
+
+ this->setLayout(layout);
+
+ connect(dirTreeView, SIGNAL(clicked(const QModelIndex&)), this,
+ SLOT(fileTreeViewItemClicked(const QModelIndex&)));
+ connect(dirTreeView, SIGNAL(doubleClicked(const QModelIndex&)), this,
+ SLOT(fileTreeViewItemDoubleClicked(const QModelIndex&)));
+ connect(dirTreeView, SIGNAL(customContextMenuRequested(const QPoint&)), this,
+ SLOT(onCustomContextMenu(const QPoint&)));
+
+ emit pathChanged(mPath);
}
-void FilePage::fileTreeViewItemClicked(const QModelIndex &index) {
- selectedPath = dirModel->fileInfo(index).absoluteFilePath();
- qDebug() << "selectedPath" << selectedPath;
+void FilePage::fileTreeViewItemClicked(const QModelIndex& index) {
+ selectedPath = dirModel->fileInfo(index).absoluteFilePath();
+ qDebug() << "selectedPath" << selectedPath;
}
void FilePage::slotUpLevel() {
- QModelIndex currentRoot = dirTreeView->rootIndex();
-
- mPath = dirModel->fileInfo(currentRoot).absoluteFilePath();
- QDir dir(mPath);
- dir.makeAbsolute();
- dir.setPath(QDir::cleanPath(dir.filePath(QStringLiteral(".."))));
- mPath = dir.absolutePath();
- auto fileInfo = QFileInfo(dir.absolutePath());
- if(fileInfo.isDir() && fileInfo.isReadable() && fileInfo.isExecutable()) {
- pathEdit->setText(mPath);
- slotGoPath();
- }
- qDebug() << "Current Root mPath" << mPath;
- emit pathChanged(mPath);
+ QModelIndex currentRoot = dirTreeView->rootIndex();
+
+ mPath = dirModel->fileInfo(currentRoot).absoluteFilePath();
+ QDir dir(mPath);
+ dir.makeAbsolute();
+ dir.setPath(QDir::cleanPath(dir.filePath(QStringLiteral(".."))));
+ mPath = dir.absolutePath();
+ auto fileInfo = QFileInfo(dir.absolutePath());
+ if (fileInfo.isDir() && fileInfo.isReadable() && fileInfo.isExecutable()) {
+ pathEdit->setText(mPath);
+ slotGoPath();
+ }
+ qDebug() << "Current Root mPath" << mPath;
+ emit pathChanged(mPath);
}
-void FilePage::fileTreeViewItemDoubleClicked(const QModelIndex &index) {
- mPath = dirModel->fileInfo(index).absoluteFilePath();
- auto fileInfo = QFileInfo(mPath);
- auto targetModelIndex = dirTreeView->model()->index(index.row(), 0, index.parent());
- if(fileInfo.isDir() && fileInfo.isReadable() && fileInfo.isExecutable()) {
- dirTreeView->setRootIndex(targetModelIndex);
- pathEdit->setText(mPath);
- }
- qDebug() << "Index mPath" << mPath;
- emit pathChanged(mPath);
+void FilePage::fileTreeViewItemDoubleClicked(const QModelIndex& index) {
+ mPath = dirModel->fileInfo(index).absoluteFilePath();
+ auto fileInfo = QFileInfo(mPath);
+ auto targetModelIndex =
+ dirTreeView->model()->index(index.row(), 0, index.parent());
+ if (fileInfo.isDir() && fileInfo.isReadable() && fileInfo.isExecutable()) {
+ dirTreeView->setRootIndex(targetModelIndex);
+ pathEdit->setText(mPath);
+ }
+ qDebug() << "Index mPath" << mPath;
+ emit pathChanged(mPath);
}
QString FilePage::getSelected() const {
- return selectedPath;
+ return selectedPath;
}
void FilePage::slotGoPath() {
- qDebug() << "getSelected" << pathEdit->text();
- auto fileInfo = QFileInfo(pathEdit->text());
- if(fileInfo.isDir() && fileInfo.isReadable() && fileInfo.isExecutable()) {
- mPath = fileInfo.filePath();
- qDebug() << "Set Path" << mPath;
- dirTreeView->setRootIndex(dirModel->index(fileInfo.filePath()));
- } else {
- QMessageBox::critical(this, "Error", "The path is unprivileged or unreachable.");
- }
- emit pathChanged(mPath);
+ qDebug() << "getSelected" << pathEdit->text();
+ auto fileInfo = QFileInfo(pathEdit->text());
+ if (fileInfo.isDir() && fileInfo.isReadable() && fileInfo.isExecutable()) {
+ mPath = fileInfo.filePath();
+ qDebug() << "Set Path" << mPath;
+ dirTreeView->setRootIndex(dirModel->index(fileInfo.filePath()));
+ } else {
+ QMessageBox::critical(this, "Error",
+ "The path is unprivileged or unreachable.");
+ }
+ emit pathChanged(mPath);
}
void FilePage::createPopupMenu() {
- popUpMenu = new QMenu();
-
- auto openItemAct = new QAction(tr("Open"), this);
- connect(openItemAct, SIGNAL(triggered()), this, SLOT(slotOpenItem()));
- auto deleteItemAct = new QAction(tr("Delete"), this);
- connect(deleteItemAct, SIGNAL(triggered()), this, SLOT(slotDeleteItem()));
- encryptItemAct = new QAction(tr("Encrypt and Sign"), this);
- connect(encryptItemAct, SIGNAL(triggered()), this, SLOT(slotEncryptItem()));
- decryptItemAct = new QAction(tr("Decrypt and Verify"), this);
- connect(decryptItemAct, SIGNAL(triggered()), this, SLOT(slotDecryptItem()));
- signItemAct = new QAction(tr("Only Sign"), this);
- connect(signItemAct, SIGNAL(triggered()), this, SLOT(slotSignItem()));
- verifyItemAct = new QAction(tr("Only Verify"), this);
- connect(verifyItemAct, SIGNAL(triggered()), this, SLOT(slotVerifyItem()));
-
- popUpMenu->addAction(openItemAct);
- popUpMenu->addAction(deleteItemAct);
- popUpMenu->addSeparator();
- popUpMenu->addAction(encryptItemAct);
- popUpMenu->addAction(decryptItemAct);
- popUpMenu->addAction(signItemAct);
- popUpMenu->addAction(verifyItemAct);
-
+ popUpMenu = new QMenu();
+
+ auto openItemAct = new QAction(tr("Open"), this);
+ connect(openItemAct, SIGNAL(triggered()), this, SLOT(slotOpenItem()));
+ auto deleteItemAct = new QAction(tr("Delete"), this);
+ connect(deleteItemAct, SIGNAL(triggered()), this, SLOT(slotDeleteItem()));
+ encryptItemAct = new QAction(tr("Encrypt and Sign"), this);
+ connect(encryptItemAct, SIGNAL(triggered()), this, SLOT(slotEncryptItem()));
+ decryptItemAct = new QAction(tr("Decrypt and Verify"), this);
+ connect(decryptItemAct, SIGNAL(triggered()), this, SLOT(slotDecryptItem()));
+ signItemAct = new QAction(tr("Only Sign"), this);
+ connect(signItemAct, SIGNAL(triggered()), this, SLOT(slotSignItem()));
+ verifyItemAct = new QAction(tr("Only Verify"), this);
+ connect(verifyItemAct, SIGNAL(triggered()), this, SLOT(slotVerifyItem()));
+
+ popUpMenu->addAction(openItemAct);
+ popUpMenu->addAction(deleteItemAct);
+ popUpMenu->addSeparator();
+ popUpMenu->addAction(encryptItemAct);
+ popUpMenu->addAction(decryptItemAct);
+ popUpMenu->addAction(signItemAct);
+ popUpMenu->addAction(verifyItemAct);
}
-void FilePage::onCustomContextMenu(const QPoint &point) {
- QModelIndex index = dirTreeView->indexAt(point);
- selectedPath = dirModel->fileInfo(index).absoluteFilePath();
- qDebug() << "Right Click" << selectedPath;
- if (index.isValid()) {
- QFileInfo info(selectedPath);
- encryptItemAct->setEnabled(info.isFile() && (info.suffix() != "gpg" && info.suffix() != "sig"));
- decryptItemAct->setEnabled(info.isFile() && info.suffix() == "gpg");
- signItemAct->setEnabled(info.isFile() && (info.suffix() != "gpg" && info.suffix() != "sig"));
- verifyItemAct->setEnabled(info.isFile() && (info.suffix() == "sig" || info.suffix() == "gpg"));
-
- popUpMenu->exec(dirTreeView->viewport()->mapToGlobal(point));
- }
+void FilePage::onCustomContextMenu(const QPoint& point) {
+ QModelIndex index = dirTreeView->indexAt(point);
+ selectedPath = dirModel->fileInfo(index).absoluteFilePath();
+ qDebug() << "Right Click" << selectedPath;
+ if (index.isValid()) {
+ QFileInfo info(selectedPath);
+ encryptItemAct->setEnabled(
+ info.isFile() && (info.suffix() != "gpg" && info.suffix() != "sig"));
+ decryptItemAct->setEnabled(info.isFile() && info.suffix() == "gpg");
+ signItemAct->setEnabled(info.isFile() &&
+ (info.suffix() != "gpg" && info.suffix() != "sig"));
+ verifyItemAct->setEnabled(
+ info.isFile() && (info.suffix() == "sig" || info.suffix() == "gpg"));
+
+ popUpMenu->exec(dirTreeView->viewport()->mapToGlobal(point));
+ }
}
void FilePage::slotOpenItem() {
- QFileInfo info(mPath);
- if(info.isDir()) {
- qDebug() << "getSelected" << pathEdit->text();
- if(info.isReadable() && info.isExecutable()) {
- qDebug() << "Set Path" << info.filePath();
- dirTreeView->setRootIndex(dirModel->index(info.filePath()));
- } else {
- QMessageBox::critical(this, "Error", "The path is unprivileged or unreachable.");
- }
+ QFileInfo info(mPath);
+ if (info.isDir()) {
+ qDebug() << "getSelected" << pathEdit->text();
+ if (info.isReadable() && info.isExecutable()) {
+ qDebug() << "Set Path" << info.filePath();
+ dirTreeView->setRootIndex(dirModel->index(info.filePath()));
} else {
- auto mainWindow = qobject_cast<MainWindow *>(firstParent);
- qDebug() << "Open Item" << mPath;
- if (mainWindow != nullptr)
- mainWindow->slotOpenFile(mPath);
+ QMessageBox::critical(this, "Error",
+ "The path is unprivileged or unreachable.");
}
+ } else {
+ auto mainWindow = qobject_cast<MainWindow*>(firstParent);
+ qDebug() << "Open Item" << mPath;
+ if (mainWindow != nullptr)
+ mainWindow->slotOpenFile(mPath);
+ }
}
void FilePage::slotDeleteItem() {
- QModelIndex index = dirTreeView->currentIndex();
- QVariant data = dirTreeView->model()->data(index);
+ QModelIndex index = dirTreeView->currentIndex();
+ QVariant data = dirTreeView->model()->data(index);
- auto ret = QMessageBox::warning(this,
- tr("Warning"),
- tr("Are you sure you want to delete it?"),
- QMessageBox::Ok | QMessageBox::Cancel);
+ auto ret = QMessageBox::warning(this, tr("Warning"),
+ tr("Are you sure you want to delete it?"),
+ QMessageBox::Ok | QMessageBox::Cancel);
- if(ret == QMessageBox::Cancel)
- return;
+ if (ret == QMessageBox::Cancel)
+ return;
- qDebug() << "Delete Item" << data.toString();
+ qDebug() << "Delete Item" << data.toString();
- if(!dirModel->remove(index)){
- QMessageBox::critical(this,
- tr("Error"),
- tr("Unable to delete the file or folder."));
- }
+ if (!dirModel->remove(index)) {
+ QMessageBox::critical(this, tr("Error"),
+ tr("Unable to delete the file or folder."));
+ }
}
void FilePage::slotEncryptItem() {
- auto mainWindow = qobject_cast<MainWindow *>(firstParent);
- if(mainWindow != nullptr)
- mainWindow->slotFileEncryptSign();
+ auto mainWindow = qobject_cast<MainWindow*>(firstParent);
+ if (mainWindow != nullptr)
+ mainWindow->slotFileEncryptSign();
}
void FilePage::slotDecryptItem() {
- auto mainWindow = qobject_cast<MainWindow *>(firstParent);
- if(mainWindow != nullptr)
- mainWindow->slotFileDecryptVerify();
+ auto mainWindow = qobject_cast<MainWindow*>(firstParent);
+ if (mainWindow != nullptr)
+ mainWindow->slotFileDecryptVerify();
}
void FilePage::slotSignItem() {
- auto mainWindow = qobject_cast<MainWindow *>(firstParent);
- if(mainWindow != nullptr)
- mainWindow->slotFileSign();
+ auto mainWindow = qobject_cast<MainWindow*>(firstParent);
+ if (mainWindow != nullptr)
+ mainWindow->slotFileSign();
}
void FilePage::slotVerifyItem() {
- auto mainWindow = qobject_cast<MainWindow *>(firstParent);
- if(mainWindow != nullptr)
- mainWindow->slotFileVerify();
+ auto mainWindow = qobject_cast<MainWindow*>(firstParent);
+ if (mainWindow != nullptr)
+ mainWindow->slotFileVerify();
}
-void FilePage::keyPressEvent(QKeyEvent *event) {
- qDebug() << "Key Press" << event->key();
- if(event->key() == Qt::Key_Return || event->key() == Qt::Key_Enter) {
- slotGoPath();
- }
+void FilePage::keyPressEvent(QKeyEvent* event) {
+ qDebug() << "Key Press" << event->key();
+ if (event->key() == Qt::Key_Return || event->key() == Qt::Key_Enter) {
+ slotGoPath();
+ }
}
+
+} // namespace GpgFrontend::UI
diff --git a/src/ui/widgets/FilePage.h b/src/ui/widgets/FilePage.h
new file mode 100644
index 00000000..be7ceea7
--- /dev/null
+++ b/src/ui/widgets/FilePage.h
@@ -0,0 +1,86 @@
+/**
+ * This file is part of GPGFrontend.
+ *
+ * GPGFrontend is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Foobar is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Foobar. If not, see <https://www.gnu.org/licenses/>.
+ *
+ * The initial version of the source code is inherited from gpg4usb-team.
+ * Their source code version also complies with GNU General Public License.
+ *
+ * The source code version of this software was modified and released
+ * by Saturneric<[email protected]> starting on May 12, 2021.
+ *
+ */
+
+#ifndef GPGFRONTEND_FILEPAGE_H
+#define GPGFRONTEND_FILEPAGE_H
+
+#include "ui/GpgFrontendUI.h"
+
+namespace GpgFrontend::UI {
+
+class FilePage : public QWidget {
+ Q_OBJECT
+ public:
+ explicit FilePage(QWidget* parent = nullptr);
+
+ [[nodiscard]] QString getSelected() const;
+
+ void createPopupMenu();
+
+ signals:
+ void pathChanged(const QString& path);
+
+ private slots:
+
+ void fileTreeViewItemClicked(const QModelIndex& index);
+ void fileTreeViewItemDoubleClicked(const QModelIndex& index);
+
+ void slotUpLevel();
+ void slotGoPath();
+
+ void slotOpenItem();
+ void slotDeleteItem();
+ void slotEncryptItem();
+ void slotDecryptItem();
+ void slotSignItem();
+ void slotVerifyItem();
+
+ void onCustomContextMenu(const QPoint& point);
+
+ protected:
+ void keyPressEvent(QKeyEvent* event) override;
+
+ private:
+ QFileSystemModel* dirModel;
+ QTreeView* dirTreeView;
+ QLineEdit* pathEdit;
+ QString mPath;
+ QString selectedPath;
+
+ QPushButton* upLevelButton;
+ QPushButton* goPathButton;
+ QPushButton* refreshButton;
+
+ QMenu* popUpMenu{};
+ QAction* encryptItemAct{};
+ QAction* decryptItemAct{};
+ QAction* signItemAct{};
+ QAction* verifyItemAct{};
+
+ QWidget* firstParent;
+};
+
+} // namespace GpgFrontend::UI
+
+#endif // GPGFRONTEND_FILEPAGE_H
diff --git a/src/ui/widgets/HelpPage.cpp b/src/ui/widgets/HelpPage.cpp
index e018da81..dfc24929 100644
--- a/src/ui/widgets/HelpPage.cpp
+++ b/src/ui/widgets/HelpPage.cpp
@@ -26,25 +26,24 @@
#include <utility>
-HelpPage::HelpPage(const QString &path, QWidget *parent) :
- QWidget(parent) {
+namespace GpgFrontend::UI {
- browser = new QTextBrowser();
- auto *mainLayout = new QVBoxLayout();
- mainLayout->setSpacing(0);
- mainLayout->addWidget(browser);
- mainLayout->setContentsMargins(0, 0, 0, 0);
- setLayout(mainLayout);
-
- connect(browser, SIGNAL(anchorClicked(QUrl)), this, SLOT(slotOpenUrl(QUrl)));
- browser->setOpenLinks(false);
- browser->setSource(localizedHelp(QUrl(path)));
- browser->setFocus();
+HelpPage::HelpPage(const QString& path, QWidget* parent) : QWidget(parent) {
+ browser = new QTextBrowser();
+ auto* mainLayout = new QVBoxLayout();
+ mainLayout->setSpacing(0);
+ mainLayout->addWidget(browser);
+ mainLayout->setContentsMargins(0, 0, 0, 0);
+ setLayout(mainLayout);
+ connect(browser, SIGNAL(anchorClicked(QUrl)), this, SLOT(slotOpenUrl(QUrl)));
+ browser->setOpenLinks(false);
+ browser->setSource(localizedHelp(QUrl(path)));
+ browser->setFocus();
}
-void HelpPage::slotOpenUrl(const QUrl &url) {
- browser->setSource(localizedHelp(url));
+void HelpPage::slotOpenUrl(const QUrl& url) {
+ browser->setSource(localizedHelp(url));
};
/**
@@ -55,29 +54,31 @@ void HelpPage::slotOpenUrl(const QUrl &url) {
* @param url
* @return
*/
-QUrl HelpPage::localizedHelp(const QUrl &url) {
- QString path = url.toLocalFile();
- QString filename = path.mid(path.lastIndexOf("/") + 1);
- QString filepath = path.left(path.lastIndexOf("/") + 1);
- QStringList fileparts = filename.split(".");
-
- //QSettings settings;
- QString lang = QSettings().value("int/lang", QLocale::system().name()).toString();
- if (lang.isEmpty()) {
- lang = QLocale::system().name();
- }
+QUrl HelpPage::localizedHelp(const QUrl& url) {
+ QString path = url.toLocalFile();
+ QString filename = path.mid(path.lastIndexOf("/") + 1);
+ QString filepath = path.left(path.lastIndexOf("/") + 1);
+ QStringList fileparts = filename.split(".");
- fileparts.insert(1, lang);
- QString langfile = filepath + fileparts.join(".");
+ // QSettings settings;
+ QString lang =
+ QSettings().value("int/lang", QLocale::system().name()).toString();
+ if (lang.isEmpty()) {
+ lang = QLocale::system().name();
+ }
- if (QFile(QUrl(langfile).toLocalFile()).exists()) {
- return langfile;
- } else {
- return path;
- }
+ fileparts.insert(1, lang);
+ QString langfile = filepath + fileparts.join(".");
+ if (QFile(QUrl(langfile).toLocalFile()).exists()) {
+ return langfile;
+ } else {
+ return path;
+ }
}
-QTextBrowser *HelpPage::getBrowser() {
- return browser;
+QTextBrowser* HelpPage::getBrowser() {
+ return browser;
}
+
+} // namespace GpgFrontend::UI
diff --git a/include/ui/widgets/HelpPage.h b/src/ui/widgets/HelpPage.h
index 0b5e4ca3..25490557 100644
--- a/include/ui/widgets/HelpPage.h
+++ b/src/ui/widgets/HelpPage.h
@@ -22,25 +22,28 @@
#ifndef HELPPAGE_H
#define HELPPAGE_H
-#include <GpgFrontend.h>
+#include "ui/GpgFrontendUI.h"
-class HelpPage : public QWidget {
-Q_OBJECT
-public:
- explicit HelpPage(const QString& path, QWidget *parent = nullptr);
+namespace GpgFrontend::UI {
- QTextBrowser *getBrowser();
+class HelpPage : public QWidget {
+ Q_OBJECT
+ public:
+ explicit HelpPage(const QString& path, QWidget* parent = nullptr);
-signals:
+ QTextBrowser* getBrowser();
-public slots:
+ signals:
- void slotOpenUrl(const QUrl& url);
+ public slots:
-private:
- QTextBrowser *browser; /** The textbrowser of the tab */
- QUrl localizedHelp(const QUrl& path);
+ void slotOpenUrl(const QUrl& url);
+ private:
+ QTextBrowser* browser; /** The textbrowser of the tab */
+ QUrl localizedHelp(const QUrl& path);
};
-#endif // HELPPAGE_H
+} // namespace GpgFrontend::UI
+
+#endif // HELPPAGE_H
diff --git a/src/ui/widgets/InfoBoardWidget.cpp b/src/ui/widgets/InfoBoardWidget.cpp
index 0c0b6bcd..a77ed73c 100644
--- a/src/ui/widgets/InfoBoardWidget.cpp
+++ b/src/ui/widgets/InfoBoardWidget.cpp
@@ -24,170 +24,178 @@
#include "ui/widgets/InfoBoardWidget.h"
-InfoBoardWidget::InfoBoardWidget(QWidget *parent, GpgFrontend::GpgContext *ctx, KeyList *keyList) :
- QWidget(parent), mCtx(ctx), mKeyList(keyList), appPath(qApp->applicationDirPath()),
- settings(RESOURCE_DIR(appPath) + "/conf/gpgfrontend.ini",
- QSettings::IniFormat) {
-
- infoBoard = new QTextEdit(this);
- infoBoard->setReadOnly(true);
- infoBoard->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Expanding);
- infoBoard->setMinimumWidth(480);
- infoBoard->setContentsMargins(0, 0, 0, 0);
-
- connect(mCtx, SIGNAL(signalKeyInfoChanged()), this, SLOT(slotReset()));
-
- importFromKeyserverAct = new QAction(tr("Import missing key from Keyserver"), this);
- connect(importFromKeyserverAct, SIGNAL(triggered()), this, SLOT(slotImportFromKeyserver()));
-
- detailMenu = new QMenu(this);
- detailMenu->addAction(importFromKeyserverAct);
- importFromKeyserverAct->setVisible(false);
-
- auto *actionButtonMenu = new QWidget();
- actionButtonMenu->setContentsMargins(0, 0, 0, 0);
- actionButtonMenu->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Minimum);
- actionButtonMenu->setFixedHeight(36);
-
- actionButtonLayout = new QHBoxLayout();
- actionButtonLayout->setContentsMargins(5, 5, 5, 5);
- actionButtonLayout->setSpacing(0);
- actionButtonMenu->setLayout(actionButtonLayout);
-
- auto label = new QLabel(tr("Optional Actions"));
- label->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Minimum);
- label->setContentsMargins(0, 0, 0, 0);
-
- actionButtonLayout->addWidget(label);
- actionButtonLayout->addStretch();
-
-
- QFrame *line;
- line = new QFrame(this);
- line->setFrameShape(QFrame::HLine);
- line->setFrameShadow(QFrame::Sunken);
- line->setContentsMargins(0, 0, 0, 0);
-
- auto *notificationWidgetLayout = new QVBoxLayout(this);
- notificationWidgetLayout->setContentsMargins(0, 0, 0, 0);
- notificationWidgetLayout->setSpacing(0);
-
- notificationWidgetLayout->addWidget(infoBoard);
- notificationWidgetLayout->setStretchFactor(infoBoard, 10);
- notificationWidgetLayout->addWidget(actionButtonMenu);
- notificationWidgetLayout->setStretchFactor(actionButtonMenu, 1);
- notificationWidgetLayout->addWidget(line);
- notificationWidgetLayout->setStretchFactor(line, 1);
- notificationWidgetLayout->addStretch(0);
- this->setLayout(notificationWidgetLayout);
+namespace GpgFrontend::UI {
+
+InfoBoardWidget::InfoBoardWidget(QWidget* parent, KeyList* keyList)
+ : QWidget(parent),
+ mKeyList(keyList),
+ appPath(qApp->applicationDirPath()),
+ settings(RESOURCE_DIR(appPath) + "/conf/gpgfrontend.ini",
+ QSettings::IniFormat) {
+ infoBoard = new QTextEdit(this);
+ infoBoard->setReadOnly(true);
+ infoBoard->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Expanding);
+ infoBoard->setMinimumWidth(480);
+ infoBoard->setContentsMargins(0, 0, 0, 0);
+
+ importFromKeyserverAct =
+ new QAction(tr("Import missing key from Keyserver"), this);
+ connect(importFromKeyserverAct, SIGNAL(triggered()), this,
+ SLOT(slotImportFromKeyserver()));
+
+ detailMenu = new QMenu(this);
+ detailMenu->addAction(importFromKeyserverAct);
+ importFromKeyserverAct->setVisible(false);
+
+ auto* actionButtonMenu = new QWidget();
+ actionButtonMenu->setContentsMargins(0, 0, 0, 0);
+ actionButtonMenu->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Minimum);
+ actionButtonMenu->setFixedHeight(36);
+
+ actionButtonLayout = new QHBoxLayout();
+ actionButtonLayout->setContentsMargins(5, 5, 5, 5);
+ actionButtonLayout->setSpacing(0);
+ actionButtonMenu->setLayout(actionButtonLayout);
+
+ auto label = new QLabel(tr("Optional Actions"));
+ label->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Minimum);
+ label->setContentsMargins(0, 0, 0, 0);
+
+ actionButtonLayout->addWidget(label);
+ actionButtonLayout->addStretch();
+
+ QFrame* line;
+ line = new QFrame(this);
+ line->setFrameShape(QFrame::HLine);
+ line->setFrameShadow(QFrame::Sunken);
+ line->setContentsMargins(0, 0, 0, 0);
+
+ auto* notificationWidgetLayout = new QVBoxLayout(this);
+ notificationWidgetLayout->setContentsMargins(0, 0, 0, 0);
+ notificationWidgetLayout->setSpacing(0);
+
+ notificationWidgetLayout->addWidget(infoBoard);
+ notificationWidgetLayout->setStretchFactor(infoBoard, 10);
+ notificationWidgetLayout->addWidget(actionButtonMenu);
+ notificationWidgetLayout->setStretchFactor(actionButtonMenu, 1);
+ notificationWidgetLayout->addWidget(line);
+ notificationWidgetLayout->setStretchFactor(line, 1);
+ notificationWidgetLayout->addStretch(0);
+ this->setLayout(notificationWidgetLayout);
}
void InfoBoardWidget::slotImportFromKeyserver() {
- auto *importDialog = new KeyServerImportDialog(mCtx, mKeyList, false, this);
- importDialog->slotImport(*keysNotInList);
+ auto* importDialog = new KeyServerImportDialog(mKeyList, false, this);
+ importDialog->slotImport(*keysNotInList);
}
-void InfoBoardWidget::setInfoBoard(const QString &text, InfoBoardStatus verifyLabelStatus) {
- QString color;
- infoBoard->clear();
- switch (verifyLabelStatus) {
- case INFO_ERROR_OK:
- color = "#008000";
- break;
- case INFO_ERROR_WARN:
- color = "#FF8C00";
- break;
- case INFO_ERROR_CRITICAL:
- color = "#DC143C";
- break;
- default:
- break;
- }
- infoBoard->append(text);
-
- infoBoard->setAutoFillBackground(true);
- QPalette status = infoBoard->palette();
- status.setColor(QPalette::Text, color);
- infoBoard->setPalette(status);
- auto infoBoardFontSize = settings.value("informationBoard/fontSize", 10).toInt();
- infoBoard->setFont(QFont("Times", infoBoardFontSize));
+void InfoBoardWidget::setInfoBoard(const QString& text,
+ InfoBoardStatus verifyLabelStatus) {
+ QString color;
+ infoBoard->clear();
+ switch (verifyLabelStatus) {
+ case INFO_ERROR_OK:
+ color = "#008000";
+ break;
+ case INFO_ERROR_WARN:
+ color = "#FF8C00";
+ break;
+ case INFO_ERROR_CRITICAL:
+ color = "#DC143C";
+ break;
+ default:
+ break;
+ }
+ infoBoard->append(text);
+
+ infoBoard->setAutoFillBackground(true);
+ QPalette status = infoBoard->palette();
+ status.setColor(QPalette::Text, color);
+ infoBoard->setPalette(status);
+ auto infoBoardFontSize =
+ settings.value("informationBoard/fontSize", 10).toInt();
+ infoBoard->setFont(QFont("Times", infoBoardFontSize));
}
-void InfoBoardWidget::slotRefresh(const QString &text, InfoBoardStatus status) {
- infoBoard->clear();
- setInfoBoard(text, status);
- infoBoard->verticalScrollBar()->setValue(0);
+void InfoBoardWidget::slotRefresh(const QString& text, InfoBoardStatus status) {
+ infoBoard->clear();
+ setInfoBoard(text, status);
+ infoBoard->verticalScrollBar()->setValue(0);
}
-void InfoBoardWidget::associateTextEdit(QTextEdit *edit) {
- if (mTextPage != nullptr)
- disconnect(mTextPage, SIGNAL(textChanged()), this, SLOT(slotReset()));
- this->mTextPage = edit;
- connect(edit, SIGNAL(textChanged()), this, SLOT(slotReset()));
+void InfoBoardWidget::associateTextEdit(QTextEdit* edit) {
+ if (mTextPage != nullptr)
+ disconnect(mTextPage, SIGNAL(textChanged()), this, SLOT(slotReset()));
+ this->mTextPage = edit;
+ connect(edit, SIGNAL(textChanged()), this, SLOT(slotReset()));
}
-void InfoBoardWidget::associateFileTreeView(FilePage *treeView) {
-// if (mFileTreeView != nullptr)
-// disconnect(mFileTreeView, &FilePage::pathChanged, this, &InfoBoardWidget::slotReset);
-// this->mFileTreeView = treeView;
-// connect(treeView, &FilePage::pathChanged, this, &InfoBoardWidget::slotReset);
+void InfoBoardWidget::associateFileTreeView(FilePage* treeView) {
+ // if (mFileTreeView != nullptr)
+ // disconnect(mFileTreeView, &FilePage::pathChanged, this,
+ // &InfoBoardWidget::slotReset);
+ // this->mFileTreeView = treeView;
+ // connect(treeView, &FilePage::pathChanged, this,
+ // &InfoBoardWidget::slotReset);
}
-void InfoBoardWidget::associateTabWidget(QTabWidget *tab) {
- if (mTextPage != nullptr)
- disconnect(mTextPage, SIGNAL(textChanged()), this, SLOT(slotReset()));
-// if (mFileTreeView != nullptr)
-// disconnect(mFileTreeView, &FilePage::pathChanged, this, &InfoBoardWidget::slotReset);
- if (mTabWidget != nullptr) {
- disconnect(mTabWidget, SIGNAL(tabBarClicked(int)), this, SLOT(slotReset()));
- connect(mTabWidget, SIGNAL(tabCloseRequested(int)), this, SLOT(slotReset()));
- }
-
- mTextPage = nullptr;
- mFileTreeView = nullptr;
- mTabWidget = tab;
- connect(tab, SIGNAL(tabBarClicked(int)), this, SLOT(slotReset()));
- connect(tab, SIGNAL(tabCloseRequested(int)), this, SLOT(slotReset()));
+void InfoBoardWidget::associateTabWidget(QTabWidget* tab) {
+ if (mTextPage != nullptr)
+ disconnect(mTextPage, SIGNAL(textChanged()), this, SLOT(slotReset()));
+ // if (mFileTreeView != nullptr)
+ // disconnect(mFileTreeView, &FilePage::pathChanged, this,
+ // &InfoBoardWidget::slotReset);
+ if (mTabWidget != nullptr) {
+ disconnect(mTabWidget, SIGNAL(tabBarClicked(int)), this, SLOT(slotReset()));
+ connect(mTabWidget, SIGNAL(tabCloseRequested(int)), this,
+ SLOT(slotReset()));
+ }
+
+ mTextPage = nullptr;
+ mFileTreeView = nullptr;
+ mTabWidget = tab;
+ connect(tab, SIGNAL(tabBarClicked(int)), this, SLOT(slotReset()));
+ connect(tab, SIGNAL(tabCloseRequested(int)), this, SLOT(slotReset()));
}
-
-void InfoBoardWidget::addOptionalAction(const QString &name, const std::function<void()> &action) {
- auto actionButton = new QPushButton(name);
- auto layout = new QHBoxLayout();
- layout->setContentsMargins(5, 0, 5, 0);
- infoBoard->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Minimum);
- // set margin from surroundings
- layout->addWidget(actionButton);
- actionButtonLayout->addLayout(layout);
- connect(actionButton, &QPushButton::clicked, this, [=]() {
- action();
- });
+void InfoBoardWidget::addOptionalAction(const QString& name,
+ const std::function<void()>& action) {
+ auto actionButton = new QPushButton(name);
+ auto layout = new QHBoxLayout();
+ layout->setContentsMargins(5, 0, 5, 0);
+ infoBoard->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Minimum);
+ // set margin from surroundings
+ layout->addWidget(actionButton);
+ actionButtonLayout->addLayout(layout);
+ connect(actionButton, &QPushButton::clicked, this, [=]() { action(); });
}
/**
* Delete All item in actionButtonLayout
*/
void InfoBoardWidget::resetOptionActionsMenu() {
- deleteWidgetsInLayout(actionButtonLayout, 2);
+ deleteWidgetsInLayout(actionButtonLayout, 2);
}
void InfoBoardWidget::slotReset() {
- this->infoBoard->clear();
- resetOptionActionsMenu();
+ this->infoBoard->clear();
+ resetOptionActionsMenu();
}
/**
* Try Delete all widget from target layout
* @param layout target layout
*/
-void InfoBoardWidget::deleteWidgetsInLayout(QLayout *layout, int start_index) {
- QLayoutItem *item;
- while ((item = layout->layout()->takeAt(start_index)) != nullptr) {
- layout->removeItem(item);
- if (item->layout() != nullptr)
- deleteWidgetsInLayout(item->layout());
- else if (item->widget() != nullptr)
- delete item->widget();
- delete item;
- }
+void InfoBoardWidget::deleteWidgetsInLayout(QLayout* layout, int start_index) {
+ QLayoutItem* item;
+ while ((item = layout->layout()->takeAt(start_index)) != nullptr) {
+ layout->removeItem(item);
+ if (item->layout() != nullptr)
+ deleteWidgetsInLayout(item->layout());
+ else if (item->widget() != nullptr)
+ delete item->widget();
+ delete item;
+ }
}
+
+} // namespace GpgFrontend::UI
diff --git a/src/ui/widgets/InfoBoardWidget.h b/src/ui/widgets/InfoBoardWidget.h
new file mode 100644
index 00000000..5512a78a
--- /dev/null
+++ b/src/ui/widgets/InfoBoardWidget.h
@@ -0,0 +1,118 @@
+/**
+ * This file is part of GPGFrontend.
+ *
+ * GPGFrontend is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Foobar is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Foobar. If not, see <https://www.gnu.org/licenses/>.
+ *
+ * The initial version of the source code is inherited from gpg4usb-team.
+ * Their source code version also complies with GNU General Public License.
+ *
+ * The source code version of this software was modified and released
+ * by Saturneric<[email protected]> starting on May 12, 2021.
+ *
+ */
+
+#ifndef __VERIFYNOTIFICATION_H__
+#define __VERIFYNOTIFICATION_H__
+
+#include "EditorPage.h"
+#include "FilePage.h"
+#include "gpg/result_analyse/VerifyResultAnalyse.h"
+#include "ui/VerifyDetailsDialog.h"
+
+namespace GpgFrontend::UI {
+/**
+ * @details Enumeration for the status of Verifylabel
+ */
+typedef enum {
+ INFO_ERROR_OK = 0,
+ INFO_ERROR_WARN = 1,
+ INFO_ERROR_CRITICAL = 2,
+ INFO_ERROR_NEUTRAL = 3,
+} InfoBoardStatus;
+
+/**
+ * @brief Class for handling the verifylabel shown at buttom of a textedit-page
+ */
+class InfoBoardWidget : public QWidget {
+ Q_OBJECT
+ public:
+ /**
+ * @brief
+ *
+ * @param ctx The GPGme-Context
+ * @param parent The parent widget
+ */
+ explicit InfoBoardWidget(QWidget* parent, KeyList* keyList);
+
+ void associateTextEdit(QTextEdit* edit);
+
+ void associateFileTreeView(FilePage* treeView);
+
+ void associateTabWidget(QTabWidget* tab);
+
+ void addOptionalAction(const QString& name,
+ const std::function<void()>& action);
+
+ void resetOptionActionsMenu();
+
+ /**
+ * @details Set the text and background-color of verify notification.
+ *
+ * @param text The text to be set.
+ * @param verifyLabelStatus The status of label to set the specified color.
+ */
+ void setInfoBoard(const QString& text, InfoBoardStatus verifyLabelStatus);
+
+ QStringList* keysNotInList; /** List with keys, which are in signature but not
+ in keylist */
+
+ public slots:
+
+ /**
+ * @details Import the keys contained in keysNotInList from keyserver
+ *
+ */
+ void slotImportFromKeyserver();
+
+ void slotReset();
+
+ /**
+ * @details Refresh the contents of dialog.
+ */
+ void slotRefresh(const QString& text, InfoBoardStatus status);
+
+ private:
+ QString appPath;
+ QSettings settings;
+
+ QMenu* detailMenu; /** Menu for te Button in verfiyNotification */
+ QAction* importFromKeyserverAct; /** Action for importing keys from keyserver
+ which are notin keylist */
+ QTextEdit* infoBoard;
+ KeyList* mKeyList; /** Table holding the keys */
+
+ QTextEdit* mTextPage{nullptr}; /** TextEdit associated to the notification */
+ FilePage* mFileTreeView{
+ nullptr}; /** TreeView associated to the notification */
+ QTabWidget* mTabWidget{
+ nullptr}; /** TreeView associated to the notification */
+
+ QHBoxLayout* actionButtonLayout;
+
+ void deleteWidgetsInLayout(QLayout* layout, int start_index = 0);
+};
+
+} // namespace GpgFrontend::UI
+
+#endif // __VERIFYNOTIFICATION_H__ \ No newline at end of file
diff --git a/src/ui/widgets/KeyList.cpp b/src/ui/widgets/KeyList.cpp
index 8a334e3e..f340cafc 100644
--- a/src/ui/widgets/KeyList.cpp
+++ b/src/ui/widgets/KeyList.cpp
@@ -23,397 +23,387 @@
*/
#include "ui/widgets/KeyList.h"
+#include "gpg/function/GpgKeyGetter.h"
#include <utility>
-KeyList::KeyList(GpgFrontend::GpgContext *ctx,
- KeyListRow::KeyType selectType,
- KeyListColumn::InfoType infoType,
- QWidget *parent)
- : QWidget(parent), mSelectType(selectType), mInfoType(infoType), appPath(qApp->applicationDirPath()),
- settings(RESOURCE_DIR(appPath) + "/conf/gpgfrontend.ini", QSettings::IniFormat) {
- mCtx = ctx;
-
-
- mKeyList = new QTableWidget(this);
- mKeyList->setColumnCount(7);
- mKeyList->horizontalHeader()->setSectionResizeMode(QHeaderView::ResizeToContents);
- mKeyList->verticalHeader()->hide();
- mKeyList->setShowGrid(false);
- mKeyList->sortByColumn(2, Qt::AscendingOrder);
- mKeyList->setSelectionBehavior(QAbstractItemView::SelectRows);
- mKeyList->setSelectionMode(QAbstractItemView::SingleSelection);
-
- // tableitems not editable
- mKeyList->setEditTriggers(QAbstractItemView::NoEditTriggers);
- // no focus (rectangle around tableitems)
- // may be it should focus on whole row
- mKeyList->setFocusPolicy(Qt::NoFocus);
-
- mKeyList->setAlternatingRowColors(true);
-
- // Hidden Column For Purpose
- if (!(mInfoType & KeyListColumn::TYPE)) {
- mKeyList->setColumnHidden(1, true);
- }
- if (!(mInfoType & KeyListColumn::NAME)) {
- mKeyList->setColumnHidden(2, true);
- }
- if (!(mInfoType & KeyListColumn::EmailAddress)) {
- mKeyList->setColumnHidden(3, true);
- }
- if (!(mInfoType & KeyListColumn::Usage)) {
- mKeyList->setColumnHidden(4, true);
- }
- if (!(mInfoType & KeyListColumn::Validity)) {
- mKeyList->setColumnHidden(5, true);
- }
- if (!(mInfoType & KeyListColumn::FingerPrint)) {
- mKeyList->setColumnHidden(6, true);
- }
+namespace GpgFrontend::UI {
- QStringList labels;
- labels << tr("Select") << tr("Type") << tr("Name") << tr("Email Address")
- << tr("Usage") << tr("Validity") << tr("Finger Print");
+KeyList::KeyList(KeyListRow::KeyType selectType,
+ KeyListColumn::InfoType infoType,
+ QWidget* parent)
+ : QWidget(parent),
+ appPath(qApp->applicationDirPath()),
+ settings(RESOURCE_DIR(appPath) + "/conf/gpgfrontend.ini",
+ QSettings::IniFormat),
+ mSelectType(selectType),
+ mInfoType(infoType) {
+ mKeyList = new QTableWidget(this);
+ mKeyList->setColumnCount(7);
+ mKeyList->horizontalHeader()->setSectionResizeMode(
+ QHeaderView::ResizeToContents);
+ mKeyList->verticalHeader()->hide();
+ mKeyList->setShowGrid(false);
+ mKeyList->sortByColumn(2, Qt::AscendingOrder);
+ mKeyList->setSelectionBehavior(QAbstractItemView::SelectRows);
+ mKeyList->setSelectionMode(QAbstractItemView::SingleSelection);
+
+ // tableitems not editable
+ mKeyList->setEditTriggers(QAbstractItemView::NoEditTriggers);
+ // no focus (rectangle around tableitems)
+ // may be it should focus on whole row
+ mKeyList->setFocusPolicy(Qt::NoFocus);
+
+ mKeyList->setAlternatingRowColors(true);
+
+ // Hidden Column For Purpose
+ if (!(mInfoType & KeyListColumn::TYPE)) {
+ mKeyList->setColumnHidden(1, true);
+ }
+ if (!(mInfoType & KeyListColumn::NAME)) {
+ mKeyList->setColumnHidden(2, true);
+ }
+ if (!(mInfoType & KeyListColumn::EmailAddress)) {
+ mKeyList->setColumnHidden(3, true);
+ }
+ if (!(mInfoType & KeyListColumn::Usage)) {
+ mKeyList->setColumnHidden(4, true);
+ }
+ if (!(mInfoType & KeyListColumn::Validity)) {
+ mKeyList->setColumnHidden(5, true);
+ }
+ if (!(mInfoType & KeyListColumn::FingerPrint)) {
+ mKeyList->setColumnHidden(6, true);
+ }
+
+ QStringList labels;
+ labels << tr("Select") << tr("Type") << tr("Name") << tr("Email Address")
+ << tr("Usage") << tr("Validity") << tr("Finger Print");
+
+ mKeyList->setHorizontalHeaderLabels(labels);
+ mKeyList->horizontalHeader()->setStretchLastSection(false);
+
+ auto* layout = new QVBoxLayout;
+ layout->addWidget(mKeyList);
+ layout->setContentsMargins(0, 0, 0, 0);
+ layout->setSpacing(3);
+ setLayout(layout);
+
+ popupMenu = new QMenu(this);
+
+ connect(mKeyList, SIGNAL(doubleClicked(const QModelIndex&)), this,
+ SLOT(slotDoubleClicked(const QModelIndex&)));
+ setAcceptDrops(true);
+ slotRefresh();
+}
- mKeyList->setHorizontalHeaderLabels(labels);
- mKeyList->horizontalHeader()->setStretchLastSection(false);
+void KeyList::slotRefresh() {
+ auto keyList = getChecked();
+ // while filling the table, sort enabled causes errors
+ mKeyList->setSortingEnabled(false);
+ mKeyList->clearContents();
- auto *layout = new QVBoxLayout;
- layout->addWidget(mKeyList);
- layout->setContentsMargins(0, 0, 0, 0);
- layout->setSpacing(3);
- setLayout(layout);
+ auto keys = GpgKeyGetter::GetInstance().FetchKey();
- popupMenu = new QMenu(this);
+ auto it = keys->begin();
- connect(mKeyList, SIGNAL(doubleClicked(const QModelIndex &)),
- this, SLOT(slotDoubleClicked(const QModelIndex &)));
- connect(mCtx, SIGNAL(signalKeyInfoChanged()), this, SLOT(slotRefresh()));
- setAcceptDrops(true);
- slotRefresh();
-}
+ int row_count = 0;
-void KeyList::slotRefresh() {
- QStringList *keyList;
- keyList = getChecked();
- // while filling the table, sort enabled causes errors
- mKeyList->setSortingEnabled(false);
- mKeyList->clearContents();
-
- GpgKeyList keys = mCtx->getKeys();
-
- auto it = keys.begin();
-
- int row_count = 0;
-
- while (it != keys.end()) {
- if (mFilter != nullptr) {
- if (!mFilter(*it)) {
- it = keys.erase(it);
- continue;
- }
- }
- if (!excluded_key_ids.isEmpty()) {
-
- auto iterator = std::find_if(excluded_key_ids.begin(), excluded_key_ids.end(),
- [it](const auto &key_id) -> bool {
- if (it->id == key_id) return true;
- else return false;
- });
-
- if (iterator != excluded_key_ids.end()) {
- it = keys.erase(it);
- continue;
- }
- }
- if (mSelectType == KeyListRow::ONLY_SECRET_KEY && !it->is_private_key) {
- it = keys.erase(it);
- continue;
- }
- row_count++;
- it++;
+ while (it != keys->end()) {
+ if (mFilter != nullptr) {
+ if (!mFilter(*it)) {
+ it = keys->erase(it);
+ continue;
+ }
+ }
+ if (!excluded_key_ids.empty()) {
+ auto iterator =
+ std::find_if(excluded_key_ids.begin(), excluded_key_ids.end(),
+ [it](const auto& key_id) -> bool {
+ if (it->id() == key_id)
+ return true;
+ else
+ return false;
+ });
+
+ if (iterator != excluded_key_ids.end()) {
+ it = keys->erase(it);
+ continue;
+ }
+ }
+ if (mSelectType == KeyListRow::ONLY_SECRET_KEY && !it->is_private_key()) {
+ it = keys->erase(it);
+ continue;
+ }
+ row_count++;
+ it++;
+ }
+
+ mKeyList->setRowCount(row_count);
+
+ int row_index = 0;
+ it = keys->begin();
+ buffered_keys.clear();
+
+ while (it != keys->end()) {
+ buffered_keys.push_back(
+ std::move(GpgKeyGetter::GetInstance().GetKey(it->id())));
+
+ auto* tmp0 = new QTableWidgetItem(QString::number(row_index));
+ tmp0->setFlags(Qt::ItemIsUserCheckable | Qt::ItemIsEnabled |
+ Qt::ItemIsSelectable);
+ tmp0->setTextAlignment(Qt::AlignCenter);
+ tmp0->setCheckState(Qt::Unchecked);
+ mKeyList->setItem(row_index, 0, tmp0);
+
+ QString type_str;
+ QTextStream type_steam(&type_str);
+ if (it->is_private_key()) {
+ type_steam << "pub/sec";
+ } else {
+ type_steam << "pub";
}
- mKeyList->setRowCount(row_count);
-
- int row_index = 0;
- it = keys.begin();
- buffered_keys.clear();
-
- while (it != keys.end()) {
-
- buffered_keys.push_back(*it);
-
- auto *tmp0 = new QTableWidgetItem(QString::number(row_index));
- tmp0->setFlags(Qt::ItemIsUserCheckable | Qt::ItemIsEnabled | Qt::ItemIsSelectable);
- tmp0->setTextAlignment(Qt::AlignCenter);
- tmp0->setCheckState(Qt::Unchecked);
- mKeyList->setItem(row_index, 0, tmp0);
-
- QString type_str;
- QTextStream type_steam(&type_str);
- if (it->is_private_key) {
- type_steam << "pub/sec";
- } else {
- type_steam << "pub";
- }
-
- if (it->is_private_key && !it->has_master_key) {
- type_steam << "#";
- }
- auto *tmp1 = new QTableWidgetItem(type_str);
- mKeyList->setItem(row_index, 1, tmp1);
-
- auto *tmp2 = new QTableWidgetItem(it->name);
- tmp2->setToolTip(it->name);
- mKeyList->setItem(row_index, 2, tmp2);
- auto *tmp3 = new QTableWidgetItem(it->email);
- tmp3->setToolTip(it->email);
- mKeyList->setItem(row_index, 3, tmp3);
-
- QString usage;
- QTextStream usage_steam(&usage);
-
- if (GpgFrontend::GpgContext::checkIfKeyCanCert(*it))
- usage_steam << "C";
- if (GpgFrontend::GpgContext::checkIfKeyCanEncr(*it))
- usage_steam << "E";
- if (GpgFrontend::GpgContext::checkIfKeyCanSign(*it))
- usage_steam << "S";
- if (GpgFrontend::GpgContext::checkIfKeyCanAuth(*it))
- usage_steam << "A";
-
- auto *temp_usage = new QTableWidgetItem(usage);
- temp_usage->setTextAlignment(Qt::AlignCenter);
- mKeyList->setItem(row_index, 4, temp_usage);
-
- auto *temp_validity = new QTableWidgetItem(it->owner_trust);
- temp_validity->setTextAlignment(Qt::AlignCenter);
- mKeyList->setItem(row_index, 5, temp_validity);
-
- auto *temp_fpr = new QTableWidgetItem(it->fpr);
- temp_fpr->setTextAlignment(Qt::AlignCenter);
- mKeyList->setItem(row_index, 6, temp_fpr);
-
- // strike out expired keys
- if (it->expired || it->revoked) {
- QFont strike = tmp2->font();
- strike.setStrikeOut(true);
- tmp0->setFont(strike);
- temp_usage->setFont(strike);
- temp_fpr->setFont(strike);
- temp_validity->setFont(strike);
- tmp1->setFont(strike);
- tmp2->setFont(strike);
- tmp3->setFont(strike);
- }
-
- it++;
- ++row_index;
+ if (it->is_private_key() && !it->has_master_key()) {
+ type_steam << "#";
+ }
+ auto* tmp1 = new QTableWidgetItem(type_str);
+ mKeyList->setItem(row_index, 1, tmp1);
+
+ auto* tmp2 = new QTableWidgetItem(QString::fromStdString(it->name()));
+ mKeyList->setItem(row_index, 2, tmp2);
+ auto* tmp3 = new QTableWidgetItem(QString::fromStdString(it->email()));
+ mKeyList->setItem(row_index, 3, tmp3);
+
+ QString usage;
+ QTextStream usage_steam(&usage);
+
+ if (it->CanCertActual())
+ usage_steam << "C";
+ if (it->CanEncrActual())
+ usage_steam << "E";
+ if (it->CanSignActual())
+ usage_steam << "S";
+ if (it->CanAuthActual())
+ usage_steam << "A";
+
+ auto* temp_usage = new QTableWidgetItem(usage);
+ temp_usage->setTextAlignment(Qt::AlignCenter);
+ mKeyList->setItem(row_index, 4, temp_usage);
+
+ auto* temp_validity =
+ new QTableWidgetItem(QString::fromStdString(it->owner_trust()));
+ temp_validity->setTextAlignment(Qt::AlignCenter);
+ mKeyList->setItem(row_index, 5, temp_validity);
+
+ auto* temp_fpr = new QTableWidgetItem(QString::fromStdString(it->fpr()));
+ temp_fpr->setTextAlignment(Qt::AlignCenter);
+ mKeyList->setItem(row_index, 6, temp_fpr);
+
+ // strike out expired keys
+ if (it->expired() || it->revoked()) {
+ QFont strike = tmp2->font();
+ strike.setStrikeOut(true);
+ tmp0->setFont(strike);
+ temp_usage->setFont(strike);
+ temp_fpr->setFont(strike);
+ temp_validity->setFont(strike);
+ tmp1->setFont(strike);
+ tmp2->setFont(strike);
+ tmp3->setFont(strike);
}
+ it++;
+ ++row_index;
+ }
- setChecked(keyList);
+ setChecked(std::move(keyList));
}
-QStringList *KeyList::getChecked() {
- auto *ret = new QStringList();
- for (int i = 0; i < mKeyList->rowCount(); i++) {
- if (mKeyList->item(i, 0)->checkState() == Qt::Checked) {
- *ret << buffered_keys[i].id;
- }
+KeyIdArgsListPtr KeyList::getChecked() {
+ auto ret = std::make_unique<KeyIdArgsList>();
+ for (int i = 0; i < mKeyList->rowCount(); i++) {
+ if (mKeyList->item(i, 0)->checkState() == Qt::Checked) {
+ ret->push_back(buffered_keys[i].id());
}
- return ret;
+ }
+ return std::move(ret);
}
-QStringList *KeyList::getAllPrivateKeys() {
- auto *ret = new QStringList();
- for (int i = 0; i < mKeyList->rowCount(); i++) {
- if (mKeyList->item(i, 1) && buffered_keys[i].is_private_key) {
- *ret << buffered_keys[i].id;
- }
+KeyIdArgsListPtr KeyList::getAllPrivateKeys() {
+ auto ret = std::make_unique<KeyIdArgsList>();
+ for (int i = 0; i < mKeyList->rowCount(); i++) {
+ if (mKeyList->item(i, 1) && buffered_keys[i].is_private_key()) {
+ ret->push_back(buffered_keys[i].id());
}
- return ret;
+ }
+ return std::move(ret);
}
-QStringList *KeyList::getPrivateChecked() {
- auto *ret = new QStringList();
- for (int i = 0; i < mKeyList->rowCount(); i++) {
- if ((mKeyList->item(i, 0)->checkState() == Qt::Checked) && (mKeyList->item(i, 1))) {
- *ret << buffered_keys[i].id;
- }
+KeyIdArgsListPtr KeyList::getPrivateChecked() {
+ auto ret = std::make_unique<KeyIdArgsList>();
+ for (int i = 0; i < mKeyList->rowCount(); i++) {
+ if ((mKeyList->item(i, 0)->checkState() == Qt::Checked) &&
+ (mKeyList->item(i, 1))) {
+ ret->push_back(buffered_keys[i].id());
}
- return ret;
+ }
+ return std::move(ret);
}
-void KeyList::setChecked(QStringList *keyIds) {
- if (!keyIds->isEmpty()) {
- for (int i = 0; i < mKeyList->rowCount(); i++) {
- if (keyIds->contains(buffered_keys[i].id)) {
- mKeyList->item(i, 0)->setCheckState(Qt::Checked);
- }
- }
+void KeyList::setChecked(const KeyIdArgsListPtr& keyIds) {
+ if (!keyIds->empty()) {
+ for (int i = 0; i < mKeyList->rowCount(); i++) {
+ if (std::find(keyIds->begin(), keyIds->end(), buffered_keys[i].id()) !=
+ keyIds->end()) {
+ mKeyList->item(i, 0)->setCheckState(Qt::Checked);
+ }
}
+ }
}
-QStringList *KeyList::getSelected() {
- auto *ret = new QStringList();
+KeyIdArgsListPtr KeyList::getSelected() {
+ auto ret = std::make_unique<KeyIdArgsList>();
- for (int i = 0; i < mKeyList->rowCount(); i++) {
- if (mKeyList->item(i, 0)->isSelected() == 1) {
- *ret << buffered_keys[i].id;
- }
+ for (int i = 0; i < mKeyList->rowCount(); i++) {
+ if (mKeyList->item(i, 0)->isSelected() == 1) {
+ ret->push_back(buffered_keys[i].id());
}
- return ret;
+ }
+ return std::move(ret);
}
[[maybe_unused]] bool KeyList::containsPrivateKeys() {
- for (int i = 0; i < mKeyList->rowCount(); i++) {
- if (mKeyList->item(i, 1)) {
- return true;
- }
+ for (int i = 0; i < mKeyList->rowCount(); i++) {
+ if (mKeyList->item(i, 1)) {
+ return true;
}
- return false;
+ }
+ return false;
}
void KeyList::setColumnWidth(int row, int size) {
- mKeyList->setColumnWidth(row, size);
+ mKeyList->setColumnWidth(row, size);
}
-void KeyList::contextMenuEvent(QContextMenuEvent *event) {
- if (mKeyList->selectedItems().length() > 0) {
- popupMenu->exec(event->globalPos());
- }
-
+void KeyList::contextMenuEvent(QContextMenuEvent* event) {
+ if (mKeyList->selectedItems().length() > 0) {
+ popupMenu->exec(event->globalPos());
+ }
}
void KeyList::addSeparator() {
- popupMenu->addSeparator();
+ popupMenu->addSeparator();
}
-void KeyList::addMenuAction(QAction *act) {
- popupMenu->addAction(act);
+void KeyList::addMenuAction(QAction* act) {
+ popupMenu->addAction(act);
}
-void KeyList::dropEvent(QDropEvent *event) {
-
- auto *dialog = new QDialog();
-
- dialog->setWindowTitle(tr("Import Keys"));
- QLabel *label;
- label = new QLabel(
- tr("You've dropped something on the table.\n GpgFrontend will now try to import key(s).") + "\n");
-
- // "always import keys"-CheckBox
- auto *checkBox = new QCheckBox(tr("Always import without bothering."));
- if (settings.value("general/confirmImportKeys").toBool()) checkBox->setCheckState(Qt::Unchecked);
-
- // Buttons for ok and cancel
- auto *buttonBox = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel);
- connect(buttonBox, SIGNAL(accepted()), dialog, SLOT(accept()));
- connect(buttonBox, SIGNAL(rejected()), dialog, SLOT(reject()));
-
- auto *vbox = new QVBoxLayout();
- vbox->addWidget(label);
- vbox->addWidget(checkBox);
- vbox->addWidget(buttonBox);
-
- dialog->setLayout(vbox);
-
- if (settings.value("general/confirmImportKeys", Qt::Checked).toBool()) {
- dialog->exec();
- if (dialog->result() == QDialog::Rejected) {
- return;
- }
- if (checkBox->isChecked()) {
- settings.setValue("general/confirmImportKeys", false);
- } else {
- settings.setValue("general/confirmImportKeys", true);
-
- }
+void KeyList::dropEvent(QDropEvent* event) {
+ auto* dialog = new QDialog();
+
+ dialog->setWindowTitle(tr("Import Keys"));
+ QLabel* label;
+ label = new QLabel(tr("You've dropped something on the table.\n GpgFrontend "
+ "will now try to import key(s).") +
+ "\n");
+
+ // "always import keys"-CheckBox
+ auto* checkBox = new QCheckBox(tr("Always import without bothering."));
+ if (settings.value("general/confirmImportKeys").toBool())
+ checkBox->setCheckState(Qt::Unchecked);
+
+ // Buttons for ok and cancel
+ auto* buttonBox =
+ new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel);
+ connect(buttonBox, SIGNAL(accepted()), dialog, SLOT(accept()));
+ connect(buttonBox, SIGNAL(rejected()), dialog, SLOT(reject()));
+
+ auto* vbox = new QVBoxLayout();
+ vbox->addWidget(label);
+ vbox->addWidget(checkBox);
+ vbox->addWidget(buttonBox);
+
+ dialog->setLayout(vbox);
+
+ if (settings.value("general/confirmImportKeys", Qt::Checked).toBool()) {
+ dialog->exec();
+ if (dialog->result() == QDialog::Rejected) {
+ return;
}
-
- if (event->mimeData()->hasUrls()) {
- for (const QUrl &tmp : event->mimeData()->urls()) {
- QFile file;
- file.setFileName(tmp.toLocalFile());
- if (!file.open(QIODevice::ReadOnly)) {
- qDebug() << tr("Couldn't Open File: ") + tmp.toString();
- }
- QByteArray inBuffer = file.readAll();
- this->importKeys(inBuffer);
- file.close();
- }
+ if (checkBox->isChecked()) {
+ settings.setValue("general/confirmImportKeys", false);
} else {
- QByteArray inBuffer(event->mimeData()->text().toUtf8());
- this->importKeys(inBuffer);
+ settings.setValue("general/confirmImportKeys", true);
+ }
+ }
+
+ if (event->mimeData()->hasUrls()) {
+ for (const QUrl& tmp : event->mimeData()->urls()) {
+ QFile file;
+ file.setFileName(tmp.toLocalFile());
+ if (!file.open(QIODevice::ReadOnly)) {
+ qDebug() << tr("Couldn't Open File: ") + tmp.toString();
+ }
+ QByteArray inBuffer = file.readAll();
+ this->importKeys(inBuffer);
+ file.close();
}
+ } else {
+ QByteArray inBuffer(event->mimeData()->text().toUtf8());
+ this->importKeys(inBuffer);
+ }
}
-void KeyList::dragEnterEvent(QDragEnterEvent *event) {
- event->acceptProposedAction();
+void KeyList::dragEnterEvent(QDragEnterEvent* event) {
+ event->acceptProposedAction();
}
/** set background color for Keys and put them to top
*
*/
-[[maybe_unused]] void KeyList::markKeys(QStringList *keyIds) {
- foreach(QString id, *keyIds) {
- qDebug() << "marked: " << id;
- }
+[[maybe_unused]] void KeyList::markKeys(QStringList* keyIds) {
+ foreach (QString id, *keyIds) { qDebug() << "marked: " << id; }
}
-void KeyList::importKeys(QByteArray inBuffer) {
- GpgImportInformation result = mCtx->importKey(std::move(inBuffer));
- new KeyImportDetailDialog(mCtx, result, false, this);
+void KeyList::importKeys(const QByteArray& inBuffer) {
+ auto std_buffer = std::make_unique<ByteArray>(inBuffer.toStdString());
+ GpgImportInformation result =
+ GpgKeyImportExportor::GetInstance().ImportKey(std::move(std_buffer));
+ new KeyImportDetailDialog(result, false, this);
}
-void KeyList::getCheckedKeys(QVector<GpgKey> &keys) {
- keys.clear();
- for (int i = 0; i < mKeyList->rowCount(); i++) {
- if (mKeyList->item(i, 0)->checkState() == Qt::Checked) {
- keys.push_back(buffered_keys[i]);
- }
- }
+void KeyList::setExcludeKeys(std::initializer_list<std::string> key_ids) {
+ excluded_key_ids.clear();
+ for (auto& key_id : key_ids) {
+ excluded_key_ids.push_back(key_id);
+ }
}
-void KeyList::setExcludeKeys(std::initializer_list<QString> key_ids) {
- excluded_key_ids.clear();
- for (auto &key_id : key_ids) {
- excluded_key_ids.push_back(key_id);
- }
+void KeyList::setFilter(std::function<bool(const GpgKey&)> filter) {
+ this->mFilter = std::move(filter);
}
-void KeyList::setFilter(std::function<bool(const GpgKey &)> filter) {
- this->mFilter = std::move(filter);
+void KeyList::slotDoubleClicked(const QModelIndex& index) {
+ if (mAction != nullptr) {
+ const auto key =
+ GpgKeyGetter::GetInstance().GetKey(buffered_keys[index.row()].id());
+ mAction(key, this);
+ }
}
-void KeyList::slotDoubleClicked(const QModelIndex &index) {
- if (mAction != nullptr) {
- const auto key = mCtx->getKeyRefById(buffered_keys[index.row()].id);
- mAction(key, this);
- }
-
+void KeyList::setDoubleClickedAction(
+ std::function<void(const GpgKey&, QWidget*)> action) {
+ this->mAction = std::move(action);
}
-void KeyList::setDoubleClickedAction(std::function<void(const GpgKey &, QWidget *)> action) {
- this->mAction = std::move(action);
-}
-
-void KeyList::getPrivateCheckedKeys(QVector<GpgKey> &keys) {
- keys.clear();
- for (int i = 0; i < mKeyList->rowCount(); i++) {
- if (mKeyList->item(i, 0)->checkState() == Qt::Checked && buffered_keys[i].is_private_key) {
- keys.push_back(buffered_keys[i]);
- }
+std::string KeyList::getSelectedKey() {
+ for (int i = 0; i < mKeyList->rowCount(); i++) {
+ if (mKeyList->item(i, 0)->isSelected() == 1) {
+ return buffered_keys[i].id();
}
+ }
+ return {};
}
-GpgKey KeyList::getSelectedKey() {
- for (int i = 0; i < mKeyList->rowCount(); i++) {
- if (mKeyList->item(i, 0)->isSelected() == 1) {
- return buffered_keys[i];
- }
- }
- return GpgKey();
-}
+} // namespace GpgFrontend::UI
diff --git a/src/ui/widgets/KeyList.h b/src/ui/widgets/KeyList.h
new file mode 100644
index 00000000..c1c49c5c
--- /dev/null
+++ b/src/ui/widgets/KeyList.h
@@ -0,0 +1,124 @@
+/**
+ * This file is part of GPGFrontend.
+ *
+ * GPGFrontend is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Foobar is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Foobar. If not, see <https://www.gnu.org/licenses/>.
+ *
+ * The initial version of the source code is inherited from gpg4usb-team.
+ * Their source code version also complies with GNU General Public License.
+ *
+ * The source code version of this software was modified and released
+ * by Saturneric<[email protected]> starting on May 12, 2021.
+ *
+ */
+
+#ifndef __KEYLIST_H__
+#define __KEYLIST_H__
+
+#include "gpg/GpgContext.h"
+#include "ui/KeyImportDetailDialog.h"
+namespace GpgFrontend::UI {
+
+struct KeyListRow {
+ using KeyType = unsigned int;
+
+ static const KeyType SECRET_OR_PUBLIC_KEY = 0;
+ static const KeyType ONLY_SECRET_KEY = 1;
+};
+
+struct KeyListColumn {
+ using InfoType = unsigned int;
+
+ static constexpr InfoType ALL = ~0;
+ static constexpr InfoType TYPE = 1 << 0;
+ static constexpr InfoType NAME = 1 << 1;
+ static constexpr InfoType EmailAddress = 1 << 2;
+ static constexpr InfoType Usage = 1 << 3;
+ static constexpr InfoType Validity = 1 << 4;
+ static constexpr InfoType FingerPrint = 1 << 5;
+};
+
+class KeyList : public QWidget {
+ Q_OBJECT
+
+ public:
+ explicit KeyList(
+ KeyListRow::KeyType selectType = KeyListRow::SECRET_OR_PUBLIC_KEY,
+ KeyListColumn::InfoType infoType = KeyListColumn::ALL,
+ QWidget* parent = nullptr);
+
+ void setExcludeKeys(std::initializer_list<std::string> key_ids);
+
+ void setFilter(std::function<bool(const GpgKey&)> filter);
+
+ void setDoubleClickedAction(
+ std::function<void(const GpgKey&, QWidget*)> action);
+
+ void setColumnWidth(int row, int size);
+
+ void addMenuAction(QAction* act);
+
+ void addSeparator();
+
+ KeyIdArgsListPtr getChecked();
+
+ KeyIdArgsListPtr getPrivateChecked();
+
+ KeyIdArgsListPtr getAllPrivateKeys();
+
+ void setChecked(const KeyIdArgsListPtr& keyIds);
+
+ KeyIdArgsListPtr getSelected();
+
+ std::string getSelectedKey();
+
+ [[maybe_unused]] static void markKeys(QStringList* keyIds);
+
+ [[maybe_unused]] bool containsPrivateKeys();
+
+ public slots:
+
+ void slotRefresh();
+
+ private:
+ void importKeys(const QByteArray& inBuffer);
+
+ QString appPath;
+ QSettings settings;
+
+ QTableWidget* mKeyList;
+ QMenu* popupMenu;
+ QNetworkAccessManager* qnam{};
+ std::vector<GpgKey> buffered_keys;
+ KeyListRow::KeyType mSelectType;
+ KeyListColumn::InfoType mInfoType;
+ std::vector<std::string> excluded_key_ids;
+
+ std::function<bool(const GpgKey&)> mFilter = nullptr;
+ std::function<void(const GpgKey&, QWidget*)> mAction = nullptr;
+
+ private slots:
+
+ void slotDoubleClicked(const QModelIndex& index);
+
+ protected:
+ void contextMenuEvent(QContextMenuEvent* event) override;
+
+ void dragEnterEvent(QDragEnterEvent* event) override;
+
+ void dropEvent(QDropEvent* event) override;
+};
+
+} // namespace GpgFrontend::UI
+
+#endif // __KEYLIST_H__
diff --git a/src/ui/widgets/SignersPicker.cpp b/src/ui/widgets/SignersPicker.cpp
index b48752c7..58dc8dbc 100644
--- a/src/ui/widgets/SignersPicker.cpp
+++ b/src/ui/widgets/SignersPicker.cpp
@@ -24,36 +24,42 @@
#include "ui/widgets/SignersPicker.h"
-SignersPicker::SignersPicker(GpgFrontend::GpgContext *ctx, QWidget *parent) : mCtx(ctx), QDialog(parent) {
- auto confirmButton = new QPushButton(tr("Confirm"));
- connect(confirmButton, SIGNAL(clicked(bool)), this, SLOT(accept()));
+namespace GpgFrontend::UI {
- /*Setup KeyList*/
- mKeyList = new KeyList(mCtx, KeyListRow::ONLY_SECRET_KEY,
- KeyListColumn::NAME | KeyListColumn::EmailAddress | KeyListColumn::Usage);
+SignersPicker::SignersPicker(GpgFrontend::GpgContext* ctx, QWidget* parent)
+ : mCtx(ctx), QDialog(parent) {
+ auto confirmButton = new QPushButton(tr("Confirm"));
+ connect(confirmButton, SIGNAL(clicked(bool)), this, SLOT(accept()));
- mKeyList->setFilter([](const GpgKey &key) -> bool {
- if (!GpgFrontend::GpgContext::checkIfKeyCanSign(key)) return false;
- else return true;
- });
+ /*Setup KeyList*/
+ mKeyList = new KeyList(
+ mCtx, KeyListRow::ONLY_SECRET_KEY,
+ KeyListColumn::NAME | KeyListColumn::EmailAddress | KeyListColumn::Usage);
- mKeyList->slotRefresh();
+ mKeyList->setFilter([](const GpgKey& key) -> bool {
+ if (!GpgFrontend::GpgContext::checkIfKeyCanSign(key))
+ return false;
+ else
+ return true;
+ });
- auto *vbox2 = new QVBoxLayout();
- vbox2->addWidget(new QLabel("Select Signer(s): "));
- vbox2->addWidget(mKeyList);
- vbox2->addWidget(confirmButton);
- vbox2->addStretch(0);
- setLayout(vbox2);
-
- this->setModal(true);
- this->setWindowTitle("Signers Picker");
- this->setMinimumWidth(480);
- this->show();
+ mKeyList->slotRefresh();
+ auto* vbox2 = new QVBoxLayout();
+ vbox2->addWidget(new QLabel("Select Signer(s): "));
+ vbox2->addWidget(mKeyList);
+ vbox2->addWidget(confirmButton);
+ vbox2->addStretch(0);
+ setLayout(vbox2);
+ this->setModal(true);
+ this->setWindowTitle("Signers Picker");
+ this->setMinimumWidth(480);
+ this->show();
}
-void SignersPicker::getCheckedSigners(QVector<GpgKey> &keys) {
- mKeyList->getPrivateCheckedKeys(keys);
+void SignersPicker::getCheckedSigners(QVector<GpgKey>& keys) {
+ mKeyList->getPrivateCheckedKeys(keys);
}
+
+} // namespace GpgFrontend::UI
diff --git a/include/ui/widgets/SignersPicker.h b/src/ui/widgets/SignersPicker.h
index 4c9c9f2d..17c57e62 100644
--- a/include/ui/widgets/SignersPicker.h
+++ b/src/ui/widgets/SignersPicker.h
@@ -30,19 +30,22 @@
#include "ui/widgets/KeyList.h"
-class SignersPicker : public QDialog {
-Q_OBJECT
+namespace GpgFrontend::UI {
-public:
+class SignersPicker : public QDialog {
+ Q_OBJECT
- explicit SignersPicker(GpgFrontend::GpgContext *ctx, QWidget *parent = nullptr);
+ public:
+ explicit SignersPicker(GpgFrontend::GpgContext* ctx,
+ QWidget* parent = nullptr);
- void getCheckedSigners(QVector<GpgKey> &keys);
+ void getCheckedSigners(QVector<GpgKey>& keys);
-private:
- GpgFrontend::GpgContext *mCtx;
- KeyList *mKeyList;
+ private:
+ GpgFrontend::GpgContext* mCtx;
+ KeyList* mKeyList;
};
+} // namespace GpgFrontend::UI
-#endif //GPGFRONTEND_ZH_CN_TS_SIGNERSPIRCKER_H
+#endif // GPGFRONTEND_ZH_CN_TS_SIGNERSPIRCKER_H
diff --git a/src/ui/widgets/TextEdit.cpp b/src/ui/widgets/TextEdit.cpp
index eab0f799..db60cca7 100644
--- a/src/ui/widgets/TextEdit.cpp
+++ b/src/ui/widgets/TextEdit.cpp
@@ -24,14 +24,16 @@
#include "ui/widgets/TextEdit.h"
-TextEdit::TextEdit(QWidget *parent) : QWidget(parent) {
+namespace GpgFrontend::UI {
+
+TextEdit::TextEdit(QWidget* parent) : QWidget(parent) {
countPage = 0;
tabWidget = new QTabWidget(this);
tabWidget->setMovable(true);
tabWidget->setTabsClosable(true);
tabWidget->setDocumentMode(true);
- auto *layout = new QVBoxLayout;
+ auto* layout = new QVBoxLayout;
layout->addWidget(tabWidget);
layout->setContentsMargins(0, 0, 0, 0);
layout->setSpacing(0);
@@ -52,7 +54,7 @@ TextEdit::TextEdit(QWidget *parent) : QWidget(parent) {
void TextEdit::slotNewTab() {
QString header = tr("untitled") + QString::number(++countPage) + ".txt";
- auto *page = new EditorPage();
+ auto* page = new EditorPage();
tabWidget->addTab(page, header);
tabWidget->setCurrentIndex(tabWidget->count() - 1);
page->getTextPage()->setFocus();
@@ -60,28 +62,25 @@ void TextEdit::slotNewTab() {
this, SLOT(slotShowModified()));
}
-void TextEdit::slotNewHelpTab(const QString &title, const QString &path) const {
-
- auto *page = new HelpPage(path);
+void TextEdit::slotNewHelpTab(const QString& title, const QString& path) const {
+ auto* page = new HelpPage(path);
tabWidget->addTab(page, title);
tabWidget->setCurrentIndex(tabWidget->count() - 1);
}
void TextEdit::slotNewFileTab() const {
-
- auto *page = new FilePage(qobject_cast<QWidget *>(parent()));
+ auto* page = new FilePage(qobject_cast<QWidget*>(parent()));
tabWidget->addTab(page, "[Browser]");
tabWidget->setCurrentIndex(tabWidget->count() - 1);
- connect(page, SIGNAL(pathChanged(const QString &)), this,
- SLOT(slotFilePagePathChanged(const QString &)));
+ connect(page, SIGNAL(pathChanged(const QString&)), this,
+ SLOT(slotFilePagePathChanged(const QString&)));
}
-void TextEdit::slotOpenFile(QString &path) {
-
+void TextEdit::slotOpenFile(QString& path) {
QFile file(path);
if (file.open(QIODevice::ReadOnly | QIODevice::Text)) {
- auto *page = new EditorPage(path);
+ auto* page = new EditorPage(path);
pagesHashMap.insert(page->uuid, page);
QApplication::setOverrideCursor(Qt::WaitCursor);
@@ -104,7 +103,7 @@ void TextEdit::slotOpenFile(QString &path) {
});
page->setFilePath(path);
- QTextDocument *document = page->getTextPage()->document();
+ QTextDocument* document = page->getTextPage()->document();
document->setModified(false);
tabWidget->addTab(page, strippedName(path));
@@ -122,11 +121,11 @@ void TextEdit::slotOpenFile(QString &path) {
}
}
-void TextEdit::slotInsertTargetTextPage(const QString &pagePtr,
- const QString &text) {
+void TextEdit::slotInsertTargetTextPage(const QString& pagePtr,
+ const QString& text) {
auto it = pagesHashMap.find(pagePtr);
if (it != pagesHashMap.end()) {
- auto *taregtTextPage = qobject_cast<EditorPage *>(it.value());
+ auto* taregtTextPage = qobject_cast<EditorPage*>(it.value());
if (taregtTextPage != nullptr) {
taregtTextPage->getTextPage()->insertPlainText(text);
taregtTextPage->getTextPage()->document()->setModified(false);
@@ -134,10 +133,10 @@ void TextEdit::slotInsertTargetTextPage(const QString &pagePtr,
}
}
-void TextEdit::slotReadTargetTextPageStart(const QString &pagePtr) {
+void TextEdit::slotReadTargetTextPageStart(const QString& pagePtr) {
auto it = pagesHashMap.find(pagePtr);
if (it != pagesHashMap.end()) {
- auto *taregtTextPage = qobject_cast<EditorPage *>(it.value());
+ auto* taregtTextPage = qobject_cast<EditorPage*>(it.value());
if (taregtTextPage != nullptr) {
qDebug() << "Setting TextEdit At Start" << pagePtr;
taregtTextPage->getTextPage()->setReadOnly(true);
@@ -150,10 +149,10 @@ void TextEdit::slotReadTargetTextPageStart(const QString &pagePtr) {
}
}
-void TextEdit::slotReadTargetTextPageDone(const QString &pagePtr) {
+void TextEdit::slotReadTargetTextPageDone(const QString& pagePtr) {
auto it = pagesHashMap.find(pagePtr);
if (it != pagesHashMap.end()) {
- auto *taregtTextPage = qobject_cast<EditorPage *>(it.value());
+ auto* taregtTextPage = qobject_cast<EditorPage*>(it.value());
if (taregtTextPage != nullptr) {
qDebug() << "Setting TextEdit At End" << pagePtr;
taregtTextPage->getTextPage()->setReadOnly(false);
@@ -173,18 +172,18 @@ void TextEdit::slotReadTargetTextPageDone(const QString &pagePtr) {
void TextEdit::slotOpen() {
QStringList fileNames =
QFileDialog::getOpenFileNames(this, tr("Open file"), QDir::currentPath());
- for (const auto &fileName : fileNames) {
+ for (const auto& fileName : fileNames) {
if (!fileName.isEmpty()) {
QFile file(fileName);
if (file.open(QIODevice::ReadOnly | QIODevice::Text)) {
- auto *page = new EditorPage(fileName);
+ auto* page = new EditorPage(fileName);
QTextStream in(&file);
QApplication::setOverrideCursor(Qt::WaitCursor);
page->getTextPage()->setPlainText(in.readAll());
page->setFilePath(fileName);
- QTextDocument *document = page->getTextPage()->document();
+ QTextDocument* document = page->getTextPage()->document();
document->setModified(false);
tabWidget->addTab(page, strippedName(fileName));
@@ -222,7 +221,7 @@ void TextEdit::slotSave() {
}
}
-bool TextEdit::saveFile(const QString &fileName) {
+bool TextEdit::saveFile(const QString& fileName) {
if (fileName.isEmpty()) {
return false;
}
@@ -230,13 +229,13 @@ bool TextEdit::saveFile(const QString &fileName) {
QFile file(fileName);
if (file.open(QIODevice::WriteOnly | QIODevice::Text)) {
- EditorPage *page = slotCurPageTextEdit();
+ EditorPage* page = slotCurPageTextEdit();
QTextStream outputStream(&file);
QApplication::setOverrideCursor(Qt::WaitCursor);
outputStream << page->getTextPage()->toPlainText();
QApplication::restoreOverrideCursor();
- QTextDocument *document = page->getTextPage()->document();
+ QTextDocument* document = page->getTextPage()->document();
document->setModified(false);
@@ -259,7 +258,7 @@ bool TextEdit::slotSaveAs() {
return true;
}
- EditorPage *page = slotCurPageTextEdit();
+ EditorPage* page = slotCurPageTextEdit();
QString path;
if (page->getFilePath() != "") {
path = page->getFilePath();
@@ -312,13 +311,12 @@ void TextEdit::removeTab(int index) {
* If it returns false, the close event should be aborted.
*/
bool TextEdit::maybeSaveCurrentTab(bool askToSave) {
-
- EditorPage *page = slotCurPageTextEdit();
+ EditorPage* page = slotCurPageTextEdit();
// if this page is no textedit, there should be nothing to save
if (page == nullptr) {
return true;
}
- QTextDocument *document = page->getTextPage()->document();
+ QTextDocument* document = page->getTextPage()->document();
if (document->isModified()) {
QMessageBox::StandardButton result = QMessageBox::Cancel;
@@ -327,7 +325,7 @@ bool TextEdit::maybeSaveCurrentTab(bool askToSave) {
QString docname = tabWidget->tabText(tabWidget->currentIndex());
docname.remove(0, 2);
- const QString &filePath = page->getFilePath();
+ const QString& filePath = page->getFilePath();
if (askToSave) {
result = QMessageBox::warning(
this, tr("Unsaved document"),
@@ -381,7 +379,7 @@ bool TextEdit::maybeSaveAnyTab() {
if (unsavedDocs.size() > 1) {
QHashIterator<int, QString> i(unsavedDocs);
- QuitDialog *dialog;
+ QuitDialog* dialog;
dialog = new QuitDialog(this, unsavedDocs);
int result = dialog->exec();
@@ -414,8 +412,8 @@ bool TextEdit::maybeSaveAnyTab() {
return false;
}
-QTextEdit *TextEdit::curTextPage() const {
- auto *curTextPage = qobject_cast<EditorPage *>(tabWidget->currentWidget());
+QTextEdit* TextEdit::curTextPage() const {
+ auto* curTextPage = qobject_cast<EditorPage*>(tabWidget->currentWidget());
if (curTextPage != nullptr) {
return curTextPage->getTextPage();
} else {
@@ -423,8 +421,8 @@ QTextEdit *TextEdit::curTextPage() const {
}
}
-FilePage *TextEdit::curFilePage() const {
- auto *curFilePage = qobject_cast<FilePage *>(tabWidget->currentWidget());
+FilePage* TextEdit::curFilePage() const {
+ auto* curFilePage = qobject_cast<FilePage*>(tabWidget->currentWidget());
if (curFilePage != nullptr) {
return curFilePage;
} else {
@@ -432,15 +430,17 @@ FilePage *TextEdit::curFilePage() const {
}
}
-int TextEdit::tabCount() const { return tabWidget->count(); }
+int TextEdit::tabCount() const {
+ return tabWidget->count();
+}
-EditorPage *TextEdit::slotCurPageTextEdit() const {
- auto *curPage = qobject_cast<EditorPage *>(tabWidget->currentWidget());
+EditorPage* TextEdit::slotCurPageTextEdit() const {
+ auto* curPage = qobject_cast<EditorPage*>(tabWidget->currentWidget());
return curPage;
}
-FilePage *TextEdit::slotCurPageFileTreeView() const {
- auto *curPage = qobject_cast<FilePage *>(tabWidget->currentWidget());
+FilePage* TextEdit::slotCurPageFileTreeView() const {
+ auto* curPage = qobject_cast<FilePage*>(tabWidget->currentWidget());
return curPage;
}
@@ -466,7 +466,7 @@ void TextEdit::slotQuote() const {
cursor.endEditBlock();
}
-void TextEdit::slotFillTextEditWithText(const QString &text) const {
+void TextEdit::slotFillTextEditWithText(const QString& text) const {
QTextCursor cursor(curTextPage()->document());
cursor.beginEditBlock();
this->curTextPage()->selectAll();
@@ -474,7 +474,7 @@ void TextEdit::slotFillTextEditWithText(const QString &text) const {
cursor.endEditBlock();
}
-void TextEdit::loadFile(const QString &fileName) {
+void TextEdit::loadFile(const QString& fileName) {
QFile file(fileName);
if (!file.open(QFile::ReadOnly | QFile::Text)) {
QMessageBox::warning(
@@ -492,7 +492,7 @@ void TextEdit::loadFile(const QString &fileName) {
// statusBar()->showMessage(tr("File loaded"), 2000);
}
-QString TextEdit::strippedName(const QString &fullFileName) {
+QString TextEdit::strippedName(const QString& fullFileName) {
return QFileInfo(fullFileName).fileName();
}
@@ -502,13 +502,13 @@ void TextEdit::slotPrint() {
}
#ifndef QT_NO_PRINTER
- QTextDocument *document;
+ QTextDocument* document;
if (curTextPage() != nullptr) {
document = curTextPage()->document();
}
QPrinter printer;
- auto *dlg = new QPrintDialog(&printer, this);
+ auto* dlg = new QPrintDialog(&printer, this);
if (dlg->exec() != QDialog::Accepted) {
return;
}
@@ -549,11 +549,11 @@ void TextEdit::slotSwitchTabDown() const {
* return a hash of tabindexes and title of unsaved tabs
*/
QHash<int, QString> TextEdit::unsavedDocuments() const {
- QHash<int, QString> unsavedDocs; // this list could be used to implement gedit
- // like "unsaved changed"-dialog
+ QHash<int, QString> unsavedDocs; // this list could be used to implement
+ // gedit like "unsaved changed"-dialog
for (int i = 0; i < tabWidget->count(); i++) {
- auto *ep = qobject_cast<EditorPage *>(tabWidget->widget(i));
+ auto* ep = qobject_cast<EditorPage*>(tabWidget->widget(i));
if (ep != nullptr && ep->getTextPage()->document()->isModified()) {
QString docname = tabWidget->tabText(i);
// remove * before name of modified doc
@@ -633,7 +633,7 @@ void TextEdit::slotSelectAll() const {
curTextPage()->selectAll();
}
-void TextEdit::slotFilePagePathChanged(const QString &path) {
+void TextEdit::slotFilePagePathChanged(const QString& path) {
int index = tabWidget->currentIndex();
QString mPath;
QFileInfo fileInfo(path);
@@ -647,3 +647,5 @@ void TextEdit::slotFilePagePathChanged(const QString &path) {
mPath.append("/");
tabWidget->setTabText(index, mPath);
}
+
+} // namespace GpgFrontend::UI
diff --git a/src/ui/widgets/TextEdit.h b/src/ui/widgets/TextEdit.h
new file mode 100644
index 00000000..6af70345
--- /dev/null
+++ b/src/ui/widgets/TextEdit.h
@@ -0,0 +1,301 @@
+/**
+ * This file is part of GPGFrontend.
+ *
+ * GPGFrontend is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * Foobar is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with Foobar. If not, see <https://www.gnu.org/licenses/>.
+ *
+ * The initial version of the source code is inherited from gpg4usb-team.
+ * Their source code version also complies with GNU General Public License.
+ *
+ * The source code version of this software was modified and released
+ * by Saturneric<[email protected]> starting on May 12, 2021.
+ *
+ */
+
+#ifndef __TEXTEDIT_H__
+#define __TEXTEDIT_H__
+
+#include "ui/QuitDialog.h"
+#include "ui/widgets/EditorPage.h"
+#include "ui/widgets/FilePage.h"
+#include "ui/widgets/HelpPage.h"
+
+namespace GpgFrontend::UI {
+/**
+ * @brief TextEdit class
+ */
+class TextEdit : public QWidget {
+ Q_OBJECT
+ public:
+ /**
+ * @brief
+ */
+ TextEdit(QWidget* parent);
+
+ /**
+ * @details Load the content of file into the current textpage
+ *
+ * @param fileName QString containing the filename to load
+ * @return nothing
+ */
+ void loadFile(const QString& fileName);
+
+ /**
+ * @details Checks if there are unsaved documents in any tab,
+ * which may need to be saved. Call this function before
+ * closing the programme or all tabs.
+ * @return \li false, if the close event should be aborted.
+ * \li true, otherwise
+ */
+ bool maybeSaveAnyTab();
+
+ [[nodiscard]] int tabCount() const;
+
+ /**
+ * @details textpage of the currently activated tab
+ * @return \li reference to QTextEdit if tab has one
+ * \li 0 otherwise (e.g. if helppage)
+ */
+ [[nodiscard]] QTextEdit* curTextPage() const;
+
+ [[nodiscard]] FilePage* curFilePage() const;
+
+ /**
+ * @details List of currently unsaved tabs.
+ * @returns QHash<int, QString> Hash of tabindexes and title of unsaved tabs.
+ */
+ [[nodiscard]] QHash<int, QString> unsavedDocuments() const;
+
+ QTabWidget* tabWidget; /** Widget containing the tabs of the editor */
+
+ public slots:
+
+ /**
+ * @details Return pointer to the currently activated text edit tab page.
+ *
+ */
+ [[nodiscard]] EditorPage* slotCurPageTextEdit() const;
+
+ /**
+ * @details Return pointer to the currently activated file treeview tab page.
+ *
+ */
+ [[nodiscard]] FilePage* slotCurPageFileTreeView() const;
+
+ /**
+ * @details Insert a ">" at the begining of every line of current textedit.
+ */
+ void slotQuote() const;
+
+ /**
+ * @details replace the text of currently active textedit with given text.
+ * @param text to fill on.
+ */
+ void slotFillTextEditWithText(const QString& text) const;
+
+ /**
+ * @details Saves the content of the current tab, if it has a filepath
+ * otherwise it calls saveAs for the current tab
+ */
+ void slotSave();
+
+ /**
+ * @details Opens a savefiledialog and calls saveFile with the choosen
+ * filename.
+ *
+ * @return Return the return value of the savefile method
+ */
+ bool slotSaveAs();
+
+ /**
+ * @details Show an OpenFileDoalog and open the file in a new tab.
+ * Shows an error dialog, if the open fails.
+ * Set the focus to the tab of the opened file.
+ */
+ void slotOpen();
+
+ /**
+ * @details Open a print-dialog for the current tab
+ */
+ void slotPrint();
+
+ /**
+ * @details Adds a new tab with the title "untitled"+countpage+".txt"
+ * Sets the focus to the new tab. Increase Tab-Count by
+ * one
+ */
+ void slotNewTab();
+
+ /**
+ * @details Adds a new tab with opening file by path
+ */
+ void slotOpenFile(QString& path);
+
+ /**
+ * @details Adds a new tab with the given title and opens given html file.
+ * Increase Tab-Count by one
+ * @param title title for the tab
+ * @param path path for html file to show
+ */
+ void slotNewHelpTab(const QString& title, const QString& path) const;
+
+ /**
+ * New File Tab to do file operation
+ */
+ void slotNewFileTab() const;
+
+ /**
+ * @details put a * in front of current tabs title, if current textedit is
+ * modified
+ */
+ void slotShowModified() const;
+
+ /**
+ * @details close the current tab and decrease TabWidget->count by \a 1
+ *
+ */
+ void slotCloseTab();
+
+ /**
+ * @details Switch to the next tab.
+ *
+ */
+ void slotSwitchTabUp() const;
+
+ /**
+ * @details Switch to the previous tab.
+ *
+ */
+ void slotSwitchTabDown() const;
+
+ /**
+ * @details Insert text in target Text Edit
+ */
+ void slotInsertTargetTextPage(const QString& pagePtr, const QString& text);
+
+ void slotReadTargetTextPageStart(const QString& pageStr);
+
+ void slotReadTargetTextPageDone(const QString& pagePtr);
+
+ signals:
+
+ void readTargetTextPageStart(const QString& pagePtr);
+
+ void insertTargetTextPage(const QString& pagePtr, const QString& text);
+
+ void readTargetTextPageDone(const QString& pagePtr);
+
+ private:
+ /**
+ * @details return just a filename stripped of a whole path
+ *
+ * @param a filename path
+ * @return QString containing the filename
+ */
+ static QString strippedName(const QString& fullFileName);
+
+ /**
+ * @brief
+ *
+ * @param askToSave
+ */
+ bool maybeSaveCurrentTab(bool askToSave);
+
+ /****************************************************************************************
+ * Name: countPage
+ * Description: int cotaining the number of added tabs
+ */
+ int countPage; /* TODO */
+
+ QHash<const QString, QWidget*> pagesHashMap;
+
+ private slots:
+
+ void slotFilePagePathChanged(const QString& path);
+
+ /**
+ * @details Remove the tab with given index
+ *
+ * @param index Tab-number to remove
+ */
+ void removeTab(int index);
+
+ /**
+ * @details Cut selected text in current textpage.
+ */
+ void slotCut() const;
+
+ /**
+ * @details Copy selected text of current textpage to clipboard.
+ */
+ void slotCopy() const;
+
+ /**
+ * @details Paste text from clipboard to current textpage.
+ */
+ void slotPaste() const;
+
+ /**
+ * @details Undo last change in current textpage.
+ *
+ */
+ void slotUndo() const;
+ /****************************************************************************************
+ * Name: redo
+ * Description: redo last change in current textpage
+ * Parameters: none
+ * Return Values: none
+ * Change on members: none
+ */
+ /**
+ * @brief
+ *
+ */
+ void slotRedo() const;
+
+ void slotZoomIn() const;
+
+ void slotZoomOut() const;
+ /****************************************************************************************
+ * Name: selectAll
+ * Description: select all in current textpage
+ * Parameters: none
+ * Return Values: none
+ * Change on members: none
+ */
+ /**
+ * @brief
+ *
+ */
+ void slotSelectAll() const;
+
+ protected:
+ /****************************************************************************************
+ * Name: saveFile
+ * Description: Saves the content of currentTab to the file filename
+ * Parameters: QString filename contains the full path of the file to
+ * save Return Values: true, if the file was saved succesfully false, if
+ * parameter filename is empty or the saving failed Change on members: sets
+ * isModified of the current tab to false
+ */
+ /**
+ * @brief
+ *
+ * @param fileName
+ */
+ bool saveFile(const QString& fileName);
+};
+
+} // namespace GpgFrontend::UI
+
+#endif // __TEXTEDIT_H__
diff --git a/src/ui/widgets/VerifyKeyDetailBox.cpp b/src/ui/widgets/VerifyKeyDetailBox.cpp
index 4d88389c..76af201d 100644
--- a/src/ui/widgets/VerifyKeyDetailBox.cpp
+++ b/src/ui/widgets/VerifyKeyDetailBox.cpp
@@ -24,180 +24,193 @@
#include "ui/widgets/VerifyKeyDetailBox.h"
-VerifyKeyDetailBox::VerifyKeyDetailBox(QWidget *parent, GpgFrontend::GpgContext *ctx, KeyList *keyList,
- gpgme_signature_t signature) :
- QGroupBox(parent), mCtx(ctx), mKeyList(keyList), fpr(signature->fpr) {
+#include "gpg/function/GpgKeyGetter.h"
- auto *vbox = new QVBoxLayout();
+namespace GpgFrontend::UI {
- switch (gpg_err_code(signature->status)) {
- case GPG_ERR_NO_PUBKEY: {
- this->setTitle("A Error Signature");
- auto *importButton = new QPushButton(tr("Import from keyserver"));
- connect(importButton, SIGNAL(clicked()), this, SLOT(slotImportFormKeyserver()));
+VerifyKeyDetailBox::VerifyKeyDetailBox(QWidget* parent,
+ KeyList* keyList,
+ gpgme_signature_t signature)
+ : QGroupBox(parent), mKeyList(keyList), fpr(signature->fpr) {
+ auto* vbox = new QVBoxLayout();
- this->setTitle(tr("Key not present with id 0x") + signature->fpr);
+ switch (gpg_err_code(signature->status)) {
+ case GPG_ERR_NO_PUBKEY: {
+ this->setTitle("A Error Signature");
+ auto* importButton = new QPushButton(tr("Import from keyserver"));
+ connect(importButton, SIGNAL(clicked()), this,
+ SLOT(slotImportFormKeyserver()));
- auto grid = new QGridLayout();
+ this->setTitle(tr("Key not present with id 0x") + signature->fpr);
- grid->addWidget(new QLabel(tr("Status:")), 0, 0);
- //grid->addWidget(new QLabel(tr("Fingerprint:")), 1, 0);
- grid->addWidget(new QLabel(tr("Key not present in keylist")), 0, 1);
- //grid->addWidget(new QLabel(signature->fpr), 1, 1);
- grid->addWidget(importButton, 2, 0, 2, 1);
+ auto grid = new QGridLayout();
- vbox->addLayout(grid);
- break;
- }
- case GPG_ERR_NO_ERROR: {
- this->setTitle("A Signature:");
- auto gird = createKeyInfoGrid(signature);
- if(gird != nullptr) {
- vbox->addLayout(gird);
- } else {
- vbox->addWidget(new QLabel(tr("Key Information is NOT Available")));
- if(signature->fpr != nullptr) {
- vbox->addWidget(new QLabel(tr("Fingerprint: ") + QString(signature->fpr)));
- }
- }
- break;
+ grid->addWidget(new QLabel(tr("Status:")), 0, 0);
+ // grid->addWidget(new QLabel(tr("Fingerprint:")), 1, 0);
+ grid->addWidget(new QLabel(tr("Key not present in keylist")), 0, 1);
+ // grid->addWidget(new QLabel(signature->fpr), 1, 1);
+ grid->addWidget(importButton, 2, 0, 2, 1);
+
+ vbox->addLayout(grid);
+ break;
+ }
+ case GPG_ERR_NO_ERROR: {
+ this->setTitle("A Signature:");
+ auto gird = createKeyInfoGrid(signature);
+ if (gird != nullptr) {
+ vbox->addLayout(gird);
+ } else {
+ vbox->addWidget(new QLabel(tr("Key Information is NOT Available")));
+ if (signature->fpr != nullptr) {
+ vbox->addWidget(
+ new QLabel(tr("Fingerprint: ") + QString(signature->fpr)));
}
- case GPG_ERR_CERT_REVOKED: {
- this->setTitle("An Error Signature");
- vbox->addWidget(new QLabel(tr("Status: Cert Revoked")));
- auto gird = createKeyInfoGrid(signature);
- if (gird != nullptr) {
- vbox->addLayout(gird);
- } else {
- vbox->addWidget(new QLabel(tr("Key Information is NOT Available")));
- if(signature->fpr != nullptr) {
- vbox->addWidget(new QLabel(tr("Fingerprint: ") + QString(signature->fpr)));
- }
- }
- break;
+ }
+ break;
+ }
+ case GPG_ERR_CERT_REVOKED: {
+ this->setTitle("An Error Signature");
+ vbox->addWidget(new QLabel(tr("Status: Cert Revoked")));
+ auto gird = createKeyInfoGrid(signature);
+ if (gird != nullptr) {
+ vbox->addLayout(gird);
+ } else {
+ vbox->addWidget(new QLabel(tr("Key Information is NOT Available")));
+ if (signature->fpr != nullptr) {
+ vbox->addWidget(
+ new QLabel(tr("Fingerprint: ") + QString(signature->fpr)));
}
- case GPG_ERR_SIG_EXPIRED: {
- this->setTitle("An Error Signature");
- vbox->addWidget(new QLabel(tr("Status: Signature Expired")));
- auto gird = createKeyInfoGrid(signature);
- if (gird != nullptr) {
- vbox->addLayout(gird);
- } else {
- vbox->addWidget(new QLabel(tr("Key Information is NOT Available")));
- if(signature->fpr != nullptr) {
- vbox->addWidget(new QLabel(tr("Fingerprint: ") + QString(signature->fpr)));
- }
- }
- break;
+ }
+ break;
+ }
+ case GPG_ERR_SIG_EXPIRED: {
+ this->setTitle("An Error Signature");
+ vbox->addWidget(new QLabel(tr("Status: Signature Expired")));
+ auto gird = createKeyInfoGrid(signature);
+ if (gird != nullptr) {
+ vbox->addLayout(gird);
+ } else {
+ vbox->addWidget(new QLabel(tr("Key Information is NOT Available")));
+ if (signature->fpr != nullptr) {
+ vbox->addWidget(
+ new QLabel(tr("Fingerprint: ") + QString(signature->fpr)));
}
- case GPG_ERR_KEY_EXPIRED: {
- this->setTitle("An Error Signature");
- vbox->addWidget(new QLabel(tr("Status: Signature Expired")));
- vbox->addWidget(new QLabel(tr("Status: Key Expired")));
- auto gird = createKeyInfoGrid(signature);
- if (gird != nullptr) {
- vbox->addLayout(gird);
- } else {
- vbox->addWidget(new QLabel(tr("Key Information is NOT Available")));
- if(signature->fpr != nullptr) {
- vbox->addWidget(new QLabel(tr("Fingerprint: ") + QString(signature->fpr)));
- }
- }
- break;
+ }
+ break;
+ }
+ case GPG_ERR_KEY_EXPIRED: {
+ this->setTitle("An Error Signature");
+ vbox->addWidget(new QLabel(tr("Status: Signature Expired")));
+ vbox->addWidget(new QLabel(tr("Status: Key Expired")));
+ auto gird = createKeyInfoGrid(signature);
+ if (gird != nullptr) {
+ vbox->addLayout(gird);
+ } else {
+ vbox->addWidget(new QLabel(tr("Key Information is NOT Available")));
+ if (signature->fpr != nullptr) {
+ vbox->addWidget(
+ new QLabel(tr("Fingerprint: ") + QString(signature->fpr)));
}
- case GPG_ERR_GENERAL: {
- this->setTitle("An Error Signature");
- vbox->addWidget(new QLabel(tr("Status: General Error")));
- auto gird = createKeyInfoGrid(signature);
- if (gird != nullptr) {
- vbox->addLayout(gird);
- } else {
- vbox->addWidget(new QLabel(tr("Key Information is NOT Available")));
- if(signature->fpr != nullptr) {
- vbox->addWidget(new QLabel(tr("Fingerprint: ") + QString(signature->fpr)));
- }
- }
- break;
+ }
+ break;
+ }
+ case GPG_ERR_GENERAL: {
+ this->setTitle("An Error Signature");
+ vbox->addWidget(new QLabel(tr("Status: General Error")));
+ auto gird = createKeyInfoGrid(signature);
+ if (gird != nullptr) {
+ vbox->addLayout(gird);
+ } else {
+ vbox->addWidget(new QLabel(tr("Key Information is NOT Available")));
+ if (signature->fpr != nullptr) {
+ vbox->addWidget(
+ new QLabel(tr("Fingerprint: ") + QString(signature->fpr)));
}
- default: {
- this->setTitle("An Error Signature");
- this->setTitle(tr("Status: Unknown Error"));
- auto gird = createKeyInfoGrid(signature);
- if (gird != nullptr) {
- vbox->addLayout(gird);
- } else {
- vbox->addWidget(new QLabel(tr("Key Information is NOT Available")));
- if(signature->fpr != nullptr) {
- vbox->addWidget(new QLabel(tr("Fingerprint: ") + QString(signature->fpr)));
- }
- }
- break;
+ }
+ break;
+ }
+ default: {
+ this->setTitle("An Error Signature");
+ this->setTitle(tr("Status: Unknown Error"));
+ auto gird = createKeyInfoGrid(signature);
+ if (gird != nullptr) {
+ vbox->addLayout(gird);
+ } else {
+ vbox->addWidget(new QLabel(tr("Key Information is NOT Available")));
+ if (signature->fpr != nullptr) {
+ vbox->addWidget(
+ new QLabel(tr("Fingerprint: ") + QString(signature->fpr)));
}
+ }
+ break;
}
- this->setLayout(vbox);
+ }
+ this->setLayout(vbox);
}
void VerifyKeyDetailBox::slotImportFormKeyserver() {
- auto *importDialog = new KeyServerImportDialog(mCtx, mKeyList, false, this);
- importDialog->slotImport(QStringList(fpr));
+ auto* importDialog = new KeyServerImportDialog(mKeyList, false, this);
+ importDialog->slotImport(QStringList(fpr));
}
QString VerifyKeyDetailBox::beautifyFingerprint(QString fingerprint) {
- uint len = fingerprint.length();
- if ((len > 0) && (len % 4 == 0))
- for (uint n = 0; 4 * (n + 1) < len; ++n)
- fingerprint.insert(static_cast<int>(5u * n + 4u), ' ');
- return fingerprint;
+ uint len = fingerprint.length();
+ if ((len > 0) && (len % 4 == 0))
+ for (uint n = 0; 4 * (n + 1) < len; ++n)
+ fingerprint.insert(static_cast<int>(5u * n + 4u), ' ');
+ return fingerprint;
}
-QGridLayout *VerifyKeyDetailBox::createKeyInfoGrid(gpgme_signature_t &signature) {
-
- auto grid = new QGridLayout();
- GpgKey key = mCtx->getKeyRefByFpr(signature->fpr);
-
- if(!key.good) return nullptr;
- grid->addWidget(new QLabel(tr("Signer Name:")), 0, 0);
- grid->addWidget(new QLabel(tr("Signer Email:")), 1, 0);
- grid->addWidget(new QLabel(tr("Key's Fingerprint:")), 2, 0);
- grid->addWidget(new QLabel(tr("Valid:")), 3, 0);
- grid->addWidget(new QLabel(tr("Flags:")), 4, 0);
-
- grid->addWidget(new QLabel(key.name), 0, 1);
- grid->addWidget(new QLabel(key.email), 1, 1);
- grid->addWidget(new QLabel(beautifyFingerprint(signature->fpr)), 2, 1);
-
-
- if(signature->summary & GPGME_SIGSUM_VALID) {
- grid->addWidget(new QLabel(tr("Fully Valid")), 3, 1);
- } else {
- grid->addWidget(new QLabel(tr("NOT Fully Valid")), 3, 1);
- }
-
- QString flags;
- QTextStream textStream(&flags);
-
- if(signature->summary & GPGME_SIGSUM_GREEN) {
- textStream << tr("Good ");
- }
- if(signature->summary & GPGME_SIGSUM_RED) {
- textStream << tr("Bad ");
- }
- if(signature->summary & GPGME_SIGSUM_SIG_EXPIRED) {
- textStream << tr("Expired ");
- }
- if(signature->summary & GPGME_SIGSUM_KEY_MISSING) {
- textStream << tr("Missing Key ");
- }
- if(signature->summary & GPGME_SIGSUM_KEY_REVOKED) {
- textStream << tr("Revoked Key ");
- }
- if(signature->summary & GPGME_SIGSUM_KEY_EXPIRED) {
- textStream << tr("Expired Key ");
- }
- if(signature->summary & GPGME_SIGSUM_CRL_MISSING) {
- textStream << tr("Missing CRL ");
- }
-
- grid->addWidget(new QLabel(tr(flags.toUtf8().constData())), 4, 1);
- return grid;
+QGridLayout* VerifyKeyDetailBox::createKeyInfoGrid(
+ gpgme_signature_t& signature) {
+ auto grid = new QGridLayout();
+ GpgKey key = GpgKeyGetter::GetInstance().GetKey(signature->fpr);
+
+ if (!key.good())
+ return nullptr;
+ grid->addWidget(new QLabel(tr("Signer Name:")), 0, 0);
+ grid->addWidget(new QLabel(tr("Signer Email:")), 1, 0);
+ grid->addWidget(new QLabel(tr("Key's Fingerprint:")), 2, 0);
+ grid->addWidget(new QLabel(tr("Valid:")), 3, 0);
+ grid->addWidget(new QLabel(tr("Flags:")), 4, 0);
+
+ grid->addWidget(new QLabel(QString::fromStdString(key.name())), 0, 1);
+ grid->addWidget(new QLabel(QString::fromStdString(key.email())), 1, 1);
+ grid->addWidget(new QLabel(beautifyFingerprint(signature->fpr)), 2, 1);
+
+ if (signature->summary & GPGME_SIGSUM_VALID) {
+ grid->addWidget(new QLabel(tr("Fully Valid")), 3, 1);
+ } else {
+ grid->addWidget(new QLabel(tr("NOT Fully Valid")), 3, 1);
+ }
+
+ QString flags;
+ QTextStream textStream(&flags);
+
+ if (signature->summary & GPGME_SIGSUM_GREEN) {
+ textStream << tr("Good ");
+ }
+ if (signature->summary & GPGME_SIGSUM_RED) {
+ textStream << tr("Bad ");
+ }
+ if (signature->summary & GPGME_SIGSUM_SIG_EXPIRED) {
+ textStream << tr("Expired ");
+ }
+ if (signature->summary & GPGME_SIGSUM_KEY_MISSING) {
+ textStream << tr("Missing Key ");
+ }
+ if (signature->summary & GPGME_SIGSUM_KEY_REVOKED) {
+ textStream << tr("Revoked Key ");
+ }
+ if (signature->summary & GPGME_SIGSUM_KEY_EXPIRED) {
+ textStream << tr("Expired Key ");
+ }
+ if (signature->summary & GPGME_SIGSUM_CRL_MISSING) {
+ textStream << tr("Missing CRL ");
+ }
+
+ grid->addWidget(new QLabel(tr(flags.toUtf8().constData())), 4, 1);
+ return grid;
}
+
+} // namespace GpgFrontend::UI \ No newline at end of file
diff --git a/include/ui/widgets/VerifyKeyDetailBox.h b/src/ui/widgets/VerifyKeyDetailBox.h
index 3c9a6cfe..7a6ded4e 100644
--- a/include/ui/widgets/VerifyKeyDetailBox.h
+++ b/src/ui/widgets/VerifyKeyDetailBox.h
@@ -25,29 +25,32 @@
#ifndef __VERIFYKEYDETAILBOX_H__
#define __VERIFYKEYDETAILBOX_H__
-#include "ui/widgets/KeyList.h"
#include "ui/KeyServerImportDialog.h"
+#include "ui/widgets/KeyList.h"
+
+namespace GpgFrontend::UI {
class VerifyKeyDetailBox : public QGroupBox {
-Q_OBJECT
-public:
- explicit VerifyKeyDetailBox(QWidget *parent, GpgFrontend::GpgContext *ctx, KeyList *mKeyList,
- gpgme_signature_t signature);
+ Q_OBJECT
+ public:
+ explicit VerifyKeyDetailBox(QWidget* parent,
+ KeyList* mKeyList,
+ gpgme_signature_t signature);
-private slots:
+ private slots:
- void slotImportFormKeyserver();
+ void slotImportFormKeyserver();
-private:
- GpgFrontend::GpgContext *mCtx;
- KeyList *mKeyList;
+ private:
+ KeyList* mKeyList;
- static QString beautifyFingerprint(QString fingerprint);
+ static QString beautifyFingerprint(QString fingerprint);
- QGridLayout *createKeyInfoGrid(gpgme_signature_t &signature);
+ static QGridLayout* createKeyInfoGrid(gpgme_signature_t& signature);
- QString fpr;
+ QString fpr;
};
-#endif // __VERIFYKEYDETAILBOX_H__
+} // namespace GpgFrontend::UI
+#endif // __VERIFYKEYDETAILBOX_H__
diff --git a/test/GpgCoreTestBasicOpera.cpp b/test/GpgCoreTestBasicOpera.cpp
index 12cc3def..5d692c67 100644
--- a/test/GpgCoreTestBasicOpera.cpp
+++ b/test/GpgCoreTestBasicOpera.cpp
@@ -39,7 +39,7 @@ TEST_F(GpgCoreTest, CoreEncryptDecrTest) {
auto encrpyt_key = GpgKeyGetter::GetInstance(default_channel)
.GetPubkey("467F14220CE8DCF780CF4BAD8465C55B25C9B7D1");
ByteArray encrypt_text = "Hello GpgFrontend!";
- BypeArrayPtr encr_out_data;
+ ByteArrayPtr encr_out_data;
GpgEncrResult e_result;
std::vector<GpgKey> keys;
keys.push_back(std::move(encrpyt_key));
@@ -50,7 +50,7 @@ TEST_F(GpgCoreTest, CoreEncryptDecrTest) {
ASSERT_EQ(check_gpg_error_2_err_code(err), GPG_ERR_NO_ERROR);
GpgDecrResult d_result;
- BypeArrayPtr decr_out_data;
+ ByteArrayPtr decr_out_data;
err = BasicOperator::GetInstance(default_channel)
.Decrypt(*encr_out_data, decr_out_data, d_result);
ASSERT_EQ(check_gpg_error_2_err_code(err), GPG_ERR_NO_ERROR);
@@ -63,7 +63,7 @@ TEST_F(GpgCoreTest, CoreSignVerifyNormalTest) {
auto encrpyt_key = GpgKeyGetter::GetInstance(default_channel)
.GetPubkey("467F14220CE8DCF780CF4BAD8465C55B25C9B7D1");
ByteArray sign_text = "Hello GpgFrontend!";
- BypeArrayPtr sign_out_data;
+ ByteArrayPtr sign_out_data;
GpgSignResult s_result;
std::vector<GpgKey> keys;
keys.push_back(std::move(encrpyt_key));
@@ -74,7 +74,7 @@ TEST_F(GpgCoreTest, CoreSignVerifyNormalTest) {
ASSERT_EQ(s_result->invalid_signers, nullptr);
GpgVerifyResult v_result;
- BypeArrayPtr sign_buff = nullptr;
+ ByteArrayPtr sign_buff = nullptr;
err = BasicOperator::GetInstance(default_channel)
.Verify(*sign_out_data, sign_buff, v_result);
ASSERT_EQ(check_gpg_error_2_err_code(err), GPG_ERR_NO_ERROR);
@@ -88,7 +88,7 @@ TEST_F(GpgCoreTest, CoreSignVerifyDetachTest) {
auto encrpyt_key = GpgKeyGetter::GetInstance(default_channel)
.GetPubkey("467F14220CE8DCF780CF4BAD8465C55B25C9B7D1");
ByteArray sign_text = "Hello GpgFrontend!";
- BypeArrayPtr sign_out_data;
+ ByteArrayPtr sign_out_data;
GpgSignResult s_result;
std::vector<GpgKey> keys;
keys.push_back(std::move(encrpyt_key));
@@ -112,7 +112,7 @@ TEST_F(GpgCoreTest, CoreSignVerifyClearTest) {
auto sign_key = GpgKeyGetter::GetInstance(default_channel)
.GetKey("467F14220CE8DCF780CF4BAD8465C55B25C9B7D1");
ByteArray sign_text = "Hello GpgFrontend!";
- BypeArrayPtr sign_out_data;
+ ByteArrayPtr sign_out_data;
GpgSignResult s_result;
std::vector<GpgKey> keys;
keys.push_back(std::move(sign_key));
@@ -123,7 +123,7 @@ TEST_F(GpgCoreTest, CoreSignVerifyClearTest) {
ASSERT_EQ(s_result->invalid_signers, nullptr);
GpgVerifyResult v_result;
- BypeArrayPtr sign_buff = nullptr;
+ ByteArrayPtr sign_buff = nullptr;
err = BasicOperator::GetInstance(default_channel)
.Verify(*sign_out_data, sign_buff, v_result);
ASSERT_EQ(check_gpg_error_2_err_code(err), GPG_ERR_NO_ERROR);
@@ -143,7 +143,7 @@ TEST_F(GpgCoreTest, CoreEncryptSignDecrVerifyTest) {
ASSERT_TRUE(sign_key.is_private_key());
ASSERT_TRUE(sign_key.CanSignActual());
ByteArray encrypt_text = "Hello GpgFrontend!";
- BypeArrayPtr encr_out_data;
+ ByteArrayPtr encr_out_data;
GpgEncrResult e_result;
GpgSignResult s_result;
@@ -160,7 +160,7 @@ TEST_F(GpgCoreTest, CoreEncryptSignDecrVerifyTest) {
GpgDecrResult d_result;
GpgVerifyResult v_result;
- BypeArrayPtr decr_out_data = nullptr;
+ ByteArrayPtr decr_out_data = nullptr;
err = BasicOperator::GetInstance(default_channel)
.DecryptVerify(*encr_out_data, decr_out_data, d_result, v_result);
ASSERT_EQ(check_gpg_error_2_err_code(err), GPG_ERR_NO_ERROR);
diff --git a/include/rapidjson/allocators.h b/third_party/rapidjson/allocators.h
index 98affe03..98affe03 100644
--- a/include/rapidjson/allocators.h
+++ b/third_party/rapidjson/allocators.h
diff --git a/third_party/rapidjson/document.h b/third_party/rapidjson/document.h
new file mode 100644
index 00000000..f2d57fd1
--- /dev/null
+++ b/third_party/rapidjson/document.h
@@ -0,0 +1,3231 @@
+// Tencent is pleased to support the open source community by making RapidJSON
+// available.
+//
+// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All
+// rights reserved.
+//
+// Licensed under the MIT License (the "License"); you may not use this file
+// except in compliance with the License. You may obtain a copy of the License
+// at
+//
+// http://opensource.org/licenses/MIT
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+// License for the specific language governing permissions and limitations under
+// the License.
+
+#ifndef RAPIDJSON_DOCUMENT_H_
+#define RAPIDJSON_DOCUMENT_H_
+
+/*! \file document.h */
+
+#include <limits>
+#include <new> // placement new
+#include "encodedstream.h"
+#include "memorystream.h"
+#include "rapidjson/internal/meta.h"
+#include "rapidjson/internal/strfunc.h"
+#include "reader.h"
+
+RAPIDJSON_DIAG_PUSH
+#ifdef _MSC_VER
+RAPIDJSON_DIAG_OFF(4127) // conditional expression is constant
+RAPIDJSON_DIAG_OFF(
+ 4244) // conversion from kXxxFlags to 'uint16_t', possible loss of data
+#endif
+
+#ifdef __clang__
+RAPIDJSON_DIAG_OFF(padded)
+RAPIDJSON_DIAG_OFF(switch - enum)
+RAPIDJSON_DIAG_OFF(c++ 98 - compat)
+#endif
+
+#ifdef __GNUC__
+RAPIDJSON_DIAG_OFF(effc++)
+#if __GNUC__ >= 6
+RAPIDJSON_DIAG_OFF(terminate) // ignore throwing RAPIDJSON_ASSERT in
+ // RAPIDJSON_NOEXCEPT functions
+#endif
+#endif // __GNUC__
+
+#ifndef RAPIDJSON_NOMEMBERITERATORCLASS
+#include <iterator> // std::iterator, std::random_access_iterator_tag
+#endif
+
+#if RAPIDJSON_HAS_CXX11_RVALUE_REFS
+#include <utility> // std::move
+#endif
+
+RAPIDJSON_NAMESPACE_BEGIN
+
+// Forward declaration.
+template <typename Encoding, typename Allocator>
+class GenericValue;
+
+template <typename Encoding, typename Allocator, typename StackAllocator>
+class GenericDocument;
+
+//! Name-value pair in a JSON object value.
+/*!
+ This class was internal to GenericValue. It used to be a inner struct.
+ But a compiler (IBM XL C/C++ for AIX) have reported to have problem with
+ that so it moved as a namespace scope struct.
+ https://code.google.com/p/rapidjson/issues/detail?id=64
+*/
+template <typename Encoding, typename Allocator>
+struct GenericMember {
+ GenericValue<Encoding, Allocator>
+ name; //!< name of member (must be a string)
+ GenericValue<Encoding, Allocator> value; //!< value of member.
+};
+
+///////////////////////////////////////////////////////////////////////////////
+// GenericMemberIterator
+
+#ifndef RAPIDJSON_NOMEMBERITERATORCLASS
+
+//! (Constant) member iterator for a JSON object value
+/*!
+ \tparam Const Is this a constant iterator?
+ \tparam Encoding Encoding of the value. (Even non-string values need to
+ have the same encoding in a document) \tparam Allocator Allocator type for
+ allocating memory of object, array and string.
+
+ This class implements a Random Access Iterator for GenericMember elements
+ of a GenericValue, see ISO/IEC 14882:2003(E) C++ standard, 24.1
+ [lib.iterator.requirements].
+
+ \note This iterator implementation is mainly intended to avoid implicit
+ conversions from iterator values to \c NULL,
+ e.g. from GenericValue::FindMember.
+
+ \note Define \c RAPIDJSON_NOMEMBERITERATORCLASS to fall back to a
+ pointer-based implementation, if your platform doesn't provide
+ the C++ <iterator> header.
+
+ \see GenericMember, GenericValue::MemberIterator,
+ GenericValue::ConstMemberIterator
+ */
+template <bool Const, typename Encoding, typename Allocator>
+class GenericMemberIterator
+ : public std::iterator<std::random_access_iterator_tag,
+ typename internal::MaybeAddConst<
+ Const,
+ GenericMember<Encoding, Allocator> >::Type> {
+ friend class GenericValue<Encoding, Allocator>;
+ template <bool, typename, typename>
+ friend class GenericMemberIterator;
+
+ typedef GenericMember<Encoding, Allocator> PlainType;
+ typedef typename internal::MaybeAddConst<Const, PlainType>::Type ValueType;
+ typedef std::iterator<std::random_access_iterator_tag, ValueType> BaseType;
+
+ public:
+ //! Iterator type itself
+ typedef GenericMemberIterator Iterator;
+ //! Constant iterator type
+ typedef GenericMemberIterator<true, Encoding, Allocator> ConstIterator;
+ //! Non-constant iterator type
+ typedef GenericMemberIterator<false, Encoding, Allocator> NonConstIterator;
+
+ //! Pointer to (const) GenericMember
+ typedef typename BaseType::pointer Pointer;
+ //! Reference to (const) GenericMember
+ typedef typename BaseType::reference Reference;
+ //! Signed integer type (e.g. \c ptrdiff_t)
+ typedef typename BaseType::difference_type DifferenceType;
+
+ //! Default constructor (singular value)
+ /*! Creates an iterator pointing to no element.
+ \note All operations, except for comparisons, are undefined on such
+ values.
+ */
+ GenericMemberIterator() : ptr_() {}
+
+ //! Iterator conversions to more const
+ /*!
+ \param it (Non-const) iterator to copy from
+
+ Allows the creation of an iterator from another GenericMemberIterator
+ that is "less const". Especially, creating a non-constant iterator
+ from a constant iterator are disabled:
+ \li const -> non-const (not ok)
+ \li const -> const (ok)
+ \li non-const -> const (ok)
+ \li non-const -> non-const (ok)
+
+ \note If the \c Const template parameter is already \c false, this
+ constructor effectively defines a regular copy-constructor.
+ Otherwise, the copy constructor is implicitly defined.
+ */
+ GenericMemberIterator(const NonConstIterator& it) : ptr_(it.ptr_) {}
+ Iterator& operator=(const NonConstIterator& it) {
+ ptr_ = it.ptr_;
+ return *this;
+ }
+
+ //! @name stepping
+ //@{
+ Iterator& operator++() {
+ ++ptr_;
+ return *this;
+ }
+ Iterator& operator--() {
+ --ptr_;
+ return *this;
+ }
+ Iterator operator++(int) {
+ Iterator old(*this);
+ ++ptr_;
+ return old;
+ }
+ Iterator operator--(int) {
+ Iterator old(*this);
+ --ptr_;
+ return old;
+ }
+ //@}
+
+ //! @name increment/decrement
+ //@{
+ Iterator operator+(DifferenceType n) const { return Iterator(ptr_ + n); }
+ Iterator operator-(DifferenceType n) const { return Iterator(ptr_ - n); }
+
+ Iterator& operator+=(DifferenceType n) {
+ ptr_ += n;
+ return *this;
+ }
+ Iterator& operator-=(DifferenceType n) {
+ ptr_ -= n;
+ return *this;
+ }
+ //@}
+
+ //! @name relations
+ //@{
+ bool operator==(ConstIterator that) const { return ptr_ == that.ptr_; }
+ bool operator!=(ConstIterator that) const { return ptr_ != that.ptr_; }
+ bool operator<=(ConstIterator that) const { return ptr_ <= that.ptr_; }
+ bool operator>=(ConstIterator that) const { return ptr_ >= that.ptr_; }
+ bool operator<(ConstIterator that) const { return ptr_ < that.ptr_; }
+ bool operator>(ConstIterator that) const { return ptr_ > that.ptr_; }
+ //@}
+
+ //! @name dereference
+ //@{
+ Reference operator*() const { return *ptr_; }
+ Pointer operator->() const { return ptr_; }
+ Reference operator[](DifferenceType n) const { return ptr_[n]; }
+ //@}
+
+ //! Distance
+ DifferenceType operator-(ConstIterator that) const {
+ return ptr_ - that.ptr_;
+ }
+
+ private:
+ //! Internal constructor from plain pointer
+ explicit GenericMemberIterator(Pointer p) : ptr_(p) {}
+
+ Pointer ptr_; //!< raw pointer
+};
+
+#else // RAPIDJSON_NOMEMBERITERATORCLASS
+
+// class-based member iterator implementation disabled, use plain pointers
+
+template <bool Const, typename Encoding, typename Allocator>
+struct GenericMemberIterator;
+
+//! non-const GenericMemberIterator
+template <typename Encoding, typename Allocator>
+struct GenericMemberIterator<false, Encoding, Allocator> {
+ //! use plain pointer as iterator type
+ typedef GenericMember<Encoding, Allocator>* Iterator;
+};
+//! const GenericMemberIterator
+template <typename Encoding, typename Allocator>
+struct GenericMemberIterator<true, Encoding, Allocator> {
+ //! use plain const pointer as iterator type
+ typedef const GenericMember<Encoding, Allocator>* Iterator;
+};
+
+#endif // RAPIDJSON_NOMEMBERITERATORCLASS
+
+///////////////////////////////////////////////////////////////////////////////
+// GenericStringRef
+
+//! Reference to a constant string (not taking a copy)
+/*!
+ \tparam CharType character type of the string
+
+ This helper class is used to automatically infer constant string
+ references for string literals, especially from \c const \b (!)
+ character arrays.
+
+ The main use is for creating JSON string values without copying the
+ source string via an \ref Allocator. This requires that the referenced
+ string pointers have a sufficient lifetime, which exceeds the lifetime
+ of the associated GenericValue.
+
+ \b Example
+ \code
+ Value v("foo"); // ok, no need to copy & calculate length
+ const char foo[] = "foo";
+ v.SetString(foo); // ok
+
+ const char* bar = foo;
+ // Value x(bar); // not ok, can't rely on bar's lifetime
+ Value x(StringRef(bar)); // lifetime explicitly guaranteed by user
+ Value y(StringRef(bar, 3)); // ok, explicitly pass length
+ \endcode
+
+ \see StringRef, GenericValue::SetString
+*/
+template <typename CharType>
+struct GenericStringRef {
+ typedef CharType Ch; //!< character type of the string
+
+ //! Create string reference from \c const character array
+#ifndef __clang__ // -Wdocumentation
+ /*!
+ This constructor implicitly creates a constant string reference from
+ a \c const character array. It has better performance than
+ \ref StringRef(const CharType*) by inferring the string \ref length
+ from the array length, and also supports strings containing null
+ characters.
+
+ \tparam N length of the string, automatically inferred
+
+ \param str Constant character array, lifetime assumed to be longer
+ than the use of the string in e.g. a GenericValue
+
+ \post \ref s == str
+
+ \note Constant complexity.
+ \note There is a hidden, private overload to disallow references to
+ non-const character arrays to be created via this constructor.
+ By this, e.g. function-scope arrays used to be filled via
+ \c snprintf are excluded from consideration.
+ In such cases, the referenced string should be \b copied to the
+ GenericValue instead.
+ */
+#endif
+ template <SizeType N>
+ GenericStringRef(const CharType (&str)[N]) RAPIDJSON_NOEXCEPT
+ : s(str),
+ length(N - 1) {}
+
+ //! Explicitly create string reference from \c const character pointer
+#ifndef __clang__ // -Wdocumentation
+ /*!
+ This constructor can be used to \b explicitly create a reference to
+ a constant string pointer.
+
+ \see StringRef(const CharType*)
+
+ \param str Constant character pointer, lifetime assumed to be longer
+ than the use of the string in e.g. a GenericValue
+
+ \post \ref s == str
+
+ \note There is a hidden, private overload to disallow references to
+ non-const character arrays to be created via this constructor.
+ By this, e.g. function-scope arrays used to be filled via
+ \c snprintf are excluded from consideration.
+ In such cases, the referenced string should be \b copied to the
+ GenericValue instead.
+ */
+#endif
+ explicit GenericStringRef(const CharType* str)
+ : s(str), length(internal::StrLen(str)) {
+ RAPIDJSON_ASSERT(s != 0);
+ }
+
+ //! Create constant string reference from pointer and length
+#ifndef __clang__ // -Wdocumentation
+ /*! \param str constant string, lifetime assumed to be longer than the use of
+ the string in e.g. a GenericValue \param len length of the string,
+ excluding the trailing NULL terminator
+
+ \post \ref s == str && \ref length == len
+ \note Constant complexity.
+ */
+#endif
+ GenericStringRef(const CharType* str, SizeType len) : s(str), length(len) {
+ RAPIDJSON_ASSERT(s != 0);
+ }
+
+ GenericStringRef(const GenericStringRef& rhs)
+ : s(rhs.s), length(rhs.length) {}
+
+ GenericStringRef& operator=(const GenericStringRef& rhs) {
+ s = rhs.s;
+ length = rhs.length;
+ }
+
+ //! implicit conversion to plain CharType pointer
+ operator const Ch*() const { return s; }
+
+ const Ch* const s; //!< plain CharType pointer
+ const SizeType length; //!< length of the string (excluding the trailing NULL
+ //!< terminator)
+
+ private:
+ //! Disallow construction from non-const array
+ template <SizeType N>
+ GenericStringRef(CharType (&str)[N]) /* = delete */;
+};
+
+//! Mark a character pointer as constant string
+/*! Mark a plain character pointer as a "string literal". This function
+ can be used to avoid copying a character string to be referenced as a
+ value in a JSON GenericValue object, if the string's lifetime is known
+ to be valid long enough.
+ \tparam CharType Character type of the string
+ \param str Constant string, lifetime assumed to be longer than the use of
+ the string in e.g. a GenericValue \return GenericStringRef string reference
+ object \relatesalso GenericStringRef
+
+ \see GenericValue::GenericValue(StringRefType),
+ GenericValue::operator=(StringRefType),
+ GenericValue::SetString(StringRefType), GenericValue::PushBack(StringRefType,
+ Allocator&), GenericValue::AddMember
+*/
+template <typename CharType>
+inline GenericStringRef<CharType> StringRef(const CharType* str) {
+ return GenericStringRef<CharType>(str, internal::StrLen(str));
+}
+
+//! Mark a character pointer as constant string
+/*! Mark a plain character pointer as a "string literal". This function
+ can be used to avoid copying a character string to be referenced as a
+ value in a JSON GenericValue object, if the string's lifetime is known
+ to be valid long enough.
+
+ This version has better performance with supplied length, and also
+ supports string containing null characters.
+
+ \tparam CharType character type of the string
+ \param str Constant string, lifetime assumed to be longer than the use of
+ the string in e.g. a GenericValue \param length The length of source string.
+ \return GenericStringRef string reference object
+ \relatesalso GenericStringRef
+*/
+template <typename CharType>
+inline GenericStringRef<CharType> StringRef(const CharType* str,
+ size_t length) {
+ return GenericStringRef<CharType>(str, SizeType(length));
+}
+
+#if RAPIDJSON_HAS_STDSTRING
+//! Mark a string object as constant string
+/*! Mark a string object (e.g. \c std::string) as a "string literal".
+ This function can be used to avoid copying a string to be referenced as a
+ value in a JSON GenericValue object, if the string's lifetime is known
+ to be valid long enough.
+
+ \tparam CharType character type of the string
+ \param str Constant string, lifetime assumed to be longer than the use of
+ the string in e.g. a GenericValue \return GenericStringRef string reference
+ object \relatesalso GenericStringRef \note Requires the definition of the
+ preprocessor symbol \ref RAPIDJSON_HAS_STDSTRING.
+*/
+template <typename CharType>
+inline GenericStringRef<CharType> StringRef(
+ const std::basic_string<CharType>& str) {
+ return GenericStringRef<CharType>(str.data(), SizeType(str.size()));
+}
+#endif
+
+///////////////////////////////////////////////////////////////////////////////
+// GenericValue type traits
+namespace internal {
+
+template <typename T, typename Encoding = void, typename Allocator = void>
+struct IsGenericValueImpl : FalseType {};
+
+// select candidates according to nested encoding and allocator types
+template <typename T>
+struct IsGenericValueImpl<T,
+ typename Void<typename T::EncodingType>::Type,
+ typename Void<typename T::AllocatorType>::Type>
+ : IsBaseOf<
+ GenericValue<typename T::EncodingType, typename T::AllocatorType>,
+ T>::Type {};
+
+// helper to match arbitrary GenericValue instantiations, including derived
+// classes
+template <typename T>
+struct IsGenericValue : IsGenericValueImpl<T>::Type {};
+
+} // namespace internal
+
+///////////////////////////////////////////////////////////////////////////////
+// TypeHelper
+
+namespace internal {
+
+template <typename ValueType, typename T>
+struct TypeHelper {};
+
+template <typename ValueType>
+struct TypeHelper<ValueType, bool> {
+ static bool Is(const ValueType& v) { return v.IsBool(); }
+ static bool Get(const ValueType& v) { return v.GetBool(); }
+ static ValueType& Set(ValueType& v, bool data) { return v.SetBool(data); }
+ static ValueType& Set(ValueType& v,
+ bool data,
+ typename ValueType::AllocatorType&) {
+ return v.SetBool(data);
+ }
+};
+
+template <typename ValueType>
+struct TypeHelper<ValueType, int> {
+ static bool Is(const ValueType& v) { return v.IsInt(); }
+ static int Get(const ValueType& v) { return v.GetInt(); }
+ static ValueType& Set(ValueType& v, int data) { return v.SetInt(data); }
+ static ValueType& Set(ValueType& v,
+ int data,
+ typename ValueType::AllocatorType&) {
+ return v.SetInt(data);
+ }
+};
+
+template <typename ValueType>
+struct TypeHelper<ValueType, unsigned> {
+ static bool Is(const ValueType& v) { return v.IsUint(); }
+ static unsigned Get(const ValueType& v) { return v.GetUint(); }
+ static ValueType& Set(ValueType& v, unsigned data) { return v.SetUint(data); }
+ static ValueType& Set(ValueType& v,
+ unsigned data,
+ typename ValueType::AllocatorType&) {
+ return v.SetUint(data);
+ }
+};
+
+template <typename ValueType>
+struct TypeHelper<ValueType, int64_t> {
+ static bool Is(const ValueType& v) { return v.IsInt64(); }
+ static int64_t Get(const ValueType& v) { return v.GetInt64(); }
+ static ValueType& Set(ValueType& v, int64_t data) { return v.SetInt64(data); }
+ static ValueType& Set(ValueType& v,
+ int64_t data,
+ typename ValueType::AllocatorType&) {
+ return v.SetInt64(data);
+ }
+};
+
+template <typename ValueType>
+struct TypeHelper<ValueType, uint64_t> {
+ static bool Is(const ValueType& v) { return v.IsUint64(); }
+ static uint64_t Get(const ValueType& v) { return v.GetUint64(); }
+ static ValueType& Set(ValueType& v, uint64_t data) {
+ return v.SetUint64(data);
+ }
+ static ValueType& Set(ValueType& v,
+ uint64_t data,
+ typename ValueType::AllocatorType&) {
+ return v.SetUint64(data);
+ }
+};
+
+template <typename ValueType>
+struct TypeHelper<ValueType, double> {
+ static bool Is(const ValueType& v) { return v.IsDouble(); }
+ static double Get(const ValueType& v) { return v.GetDouble(); }
+ static ValueType& Set(ValueType& v, double data) { return v.SetDouble(data); }
+ static ValueType& Set(ValueType& v,
+ double data,
+ typename ValueType::AllocatorType&) {
+ return v.SetDouble(data);
+ }
+};
+
+template <typename ValueType>
+struct TypeHelper<ValueType, float> {
+ static bool Is(const ValueType& v) { return v.IsFloat(); }
+ static float Get(const ValueType& v) { return v.GetFloat(); }
+ static ValueType& Set(ValueType& v, float data) { return v.SetFloat(data); }
+ static ValueType& Set(ValueType& v,
+ float data,
+ typename ValueType::AllocatorType&) {
+ return v.SetFloat(data);
+ }
+};
+
+template <typename ValueType>
+struct TypeHelper<ValueType, const typename ValueType::Ch*> {
+ typedef const typename ValueType::Ch* StringType;
+ static bool Is(const ValueType& v) { return v.IsString(); }
+ static StringType Get(const ValueType& v) { return v.GetString(); }
+ static ValueType& Set(ValueType& v, const StringType data) {
+ return v.SetString(typename ValueType::StringRefType(data));
+ }
+ static ValueType& Set(ValueType& v,
+ const StringType data,
+ typename ValueType::AllocatorType& a) {
+ return v.SetString(data, a);
+ }
+};
+
+#if RAPIDJSON_HAS_STDSTRING
+template <typename ValueType>
+struct TypeHelper<ValueType, std::basic_string<typename ValueType::Ch> > {
+ typedef std::basic_string<typename ValueType::Ch> StringType;
+ static bool Is(const ValueType& v) { return v.IsString(); }
+ static StringType Get(const ValueType& v) {
+ return StringType(v.GetString(), v.GetStringLength());
+ }
+ static ValueType& Set(ValueType& v,
+ const StringType& data,
+ typename ValueType::AllocatorType& a) {
+ return v.SetString(data, a);
+ }
+};
+#endif
+
+template <typename ValueType>
+struct TypeHelper<ValueType, typename ValueType::Array> {
+ typedef typename ValueType::Array ArrayType;
+ static bool Is(const ValueType& v) { return v.IsArray(); }
+ static ArrayType Get(ValueType& v) { return v.GetArray(); }
+ static ValueType& Set(ValueType& v, ArrayType data) { return v = data; }
+ static ValueType& Set(ValueType& v,
+ ArrayType data,
+ typename ValueType::AllocatorType&) {
+ return v = data;
+ }
+};
+
+template <typename ValueType>
+struct TypeHelper<ValueType, typename ValueType::ConstArray> {
+ typedef typename ValueType::ConstArray ArrayType;
+ static bool Is(const ValueType& v) { return v.IsArray(); }
+ static ArrayType Get(const ValueType& v) { return v.GetArray(); }
+};
+
+template <typename ValueType>
+struct TypeHelper<ValueType, typename ValueType::Object> {
+ typedef typename ValueType::Object ObjectType;
+ static bool Is(const ValueType& v) { return v.IsObject(); }
+ static ObjectType Get(ValueType& v) { return v.GetObject(); }
+ static ValueType& Set(ValueType& v, ObjectType data) { return v = data; }
+ static ValueType& Set(ValueType& v,
+ ObjectType data,
+ typename ValueType::AllocatorType&) {
+ v = data;
+ }
+};
+
+template <typename ValueType>
+struct TypeHelper<ValueType, typename ValueType::ConstObject> {
+ typedef typename ValueType::ConstObject ObjectType;
+ static bool Is(const ValueType& v) { return v.IsObject(); }
+ static ObjectType Get(const ValueType& v) { return v.GetObject(); }
+};
+
+} // namespace internal
+
+// Forward declarations
+template <bool, typename>
+class GenericArray;
+template <bool, typename>
+class GenericObject;
+
+///////////////////////////////////////////////////////////////////////////////
+// GenericValue
+
+//! Represents a JSON value. Use Value for UTF8 encoding and default allocator.
+/*!
+ A JSON value can be one of 7 types. This class is a variant type supporting
+ these types.
+
+ Use the Value if UTF8 and default allocator
+
+ \tparam Encoding Encoding of the value. (Even non-string values need to
+ have the same encoding in a document) \tparam Allocator Allocator type for
+ allocating memory of object, array and string.
+*/
+template <typename Encoding, typename Allocator = MemoryPoolAllocator<> >
+class GenericValue {
+ public:
+ //! Name-value pair in an object.
+ typedef GenericMember<Encoding, Allocator> Member;
+ typedef Encoding EncodingType; //!< Encoding type from template parameter.
+ typedef Allocator AllocatorType; //!< Allocator type from template parameter.
+ typedef typename Encoding::Ch Ch; //!< Character type derived from Encoding.
+ typedef GenericStringRef<Ch>
+ StringRefType; //!< Reference to a constant string
+ typedef typename GenericMemberIterator<false, Encoding, Allocator>::Iterator
+ MemberIterator; //!< Member iterator for iterating in object.
+ typedef typename GenericMemberIterator<true, Encoding, Allocator>::Iterator
+ ConstMemberIterator; //!< Constant member iterator for iterating in
+ //!< object.
+ typedef GenericValue*
+ ValueIterator; //!< Value iterator for iterating in array.
+ typedef const GenericValue*
+ ConstValueIterator; //!< Constant value iterator for iterating in array.
+ typedef GenericValue<Encoding, Allocator>
+ ValueType; //!< Value type of itself.
+ typedef GenericArray<false, ValueType> Array;
+ typedef GenericArray<true, ValueType> ConstArray;
+ typedef GenericObject<false, ValueType> Object;
+ typedef GenericObject<true, ValueType> ConstObject;
+
+ //!@name Constructors and destructor.
+ //@{
+
+ //! Default constructor creates a null value.
+ GenericValue() RAPIDJSON_NOEXCEPT : data_() { data_.f.flags = kNullFlag; }
+
+#if RAPIDJSON_HAS_CXX11_RVALUE_REFS
+ //! Move constructor in C++11
+ GenericValue(GenericValue&& rhs) RAPIDJSON_NOEXCEPT : data_(rhs.data_) {
+ rhs.data_.f.flags = kNullFlag; // give up contents
+ }
+#endif
+
+ private:
+ //! Copy constructor is not permitted.
+ GenericValue(const GenericValue& rhs);
+
+#if RAPIDJSON_HAS_CXX11_RVALUE_REFS
+ //! Moving from a GenericDocument is not permitted.
+ template <typename StackAllocator>
+ GenericValue(GenericDocument<Encoding, Allocator, StackAllocator>&& rhs);
+
+ //! Move assignment from a GenericDocument is not permitted.
+ template <typename StackAllocator>
+ GenericValue& operator=(
+ GenericDocument<Encoding, Allocator, StackAllocator>&& rhs);
+#endif
+
+ public:
+ //! Constructor with JSON value type.
+ /*! This creates a Value of specified type with default content.
+ \param type Type of the value.
+ \note Default content for number is zero.
+ */
+ explicit GenericValue(Type type) RAPIDJSON_NOEXCEPT : data_() {
+ static const uint16_t defaultFlags[7] = {
+ kNullFlag, kFalseFlag, kTrueFlag, kObjectFlag,
+ kArrayFlag, kShortStringFlag, kNumberAnyFlag};
+ RAPIDJSON_ASSERT(type <= kNumberType);
+ data_.f.flags = defaultFlags[type];
+
+ // Use ShortString to store empty string.
+ if (type == kStringType)
+ data_.ss.SetLength(0);
+ }
+
+ //! Explicit copy constructor (with allocator)
+ /*! Creates a copy of a Value by using the given Allocator
+ \tparam SourceAllocator allocator of \c rhs
+ \param rhs Value to copy from (read-only)
+ \param allocator Allocator for allocating copied elements and buffers.
+ Commonly use GenericDocument::GetAllocator(). \see CopyFrom()
+ */
+ template <typename SourceAllocator>
+ GenericValue(const GenericValue<Encoding, SourceAllocator>& rhs,
+ Allocator& allocator);
+
+ //! Constructor for boolean value.
+ /*! \param b Boolean value
+ \note This constructor is limited to \em real boolean values and rejects
+ implicitly converted types like arbitrary pointers. Use an explicit
+ cast to \c bool, if you want to construct a boolean JSON value in such
+ cases.
+ */
+#ifndef RAPIDJSON_DOXYGEN_RUNNING // hide SFINAE from Doxygen
+ template <typename T>
+ explicit GenericValue(T b, RAPIDJSON_ENABLEIF((internal::IsSame<bool, T>)))
+ RAPIDJSON_NOEXCEPT // See #472
+#else
+ explicit GenericValue(bool b) RAPIDJSON_NOEXCEPT
+#endif
+ : data_() {
+ // safe-guard against failing SFINAE
+ RAPIDJSON_STATIC_ASSERT((internal::IsSame<bool, T>::Value));
+ data_.f.flags = b ? kTrueFlag : kFalseFlag;
+ }
+
+ //! Constructor for int value.
+ explicit GenericValue(int i) RAPIDJSON_NOEXCEPT : data_() {
+ data_.n.i64 = i;
+ data_.f.flags =
+ (i >= 0) ? (kNumberIntFlag | kUintFlag | kUint64Flag) : kNumberIntFlag;
+ }
+
+ //! Constructor for unsigned value.
+ explicit GenericValue(unsigned u) RAPIDJSON_NOEXCEPT : data_() {
+ data_.n.u64 = u;
+ data_.f.flags = (u & 0x80000000)
+ ? kNumberUintFlag
+ : (kNumberUintFlag | kIntFlag | kInt64Flag);
+ }
+
+ //! Constructor for int64_t value.
+ explicit GenericValue(int64_t i64) RAPIDJSON_NOEXCEPT : data_() {
+ data_.n.i64 = i64;
+ data_.f.flags = kNumberInt64Flag;
+ if (i64 >= 0) {
+ data_.f.flags |= kNumberUint64Flag;
+ if (!(static_cast<uint64_t>(i64) &
+ RAPIDJSON_UINT64_C2(0xFFFFFFFF, 0x00000000)))
+ data_.f.flags |= kUintFlag;
+ if (!(static_cast<uint64_t>(i64) &
+ RAPIDJSON_UINT64_C2(0xFFFFFFFF, 0x80000000)))
+ data_.f.flags |= kIntFlag;
+ } else if (i64 >= static_cast<int64_t>(
+ RAPIDJSON_UINT64_C2(0xFFFFFFFF, 0x80000000)))
+ data_.f.flags |= kIntFlag;
+ }
+
+ //! Constructor for uint64_t value.
+ explicit GenericValue(uint64_t u64) RAPIDJSON_NOEXCEPT : data_() {
+ data_.n.u64 = u64;
+ data_.f.flags = kNumberUint64Flag;
+ if (!(u64 & RAPIDJSON_UINT64_C2(0x80000000, 0x00000000)))
+ data_.f.flags |= kInt64Flag;
+ if (!(u64 & RAPIDJSON_UINT64_C2(0xFFFFFFFF, 0x00000000)))
+ data_.f.flags |= kUintFlag;
+ if (!(u64 & RAPIDJSON_UINT64_C2(0xFFFFFFFF, 0x80000000)))
+ data_.f.flags |= kIntFlag;
+ }
+
+ //! Constructor for double value.
+ explicit GenericValue(double d) RAPIDJSON_NOEXCEPT : data_() {
+ data_.n.d = d;
+ data_.f.flags = kNumberDoubleFlag;
+ }
+
+ //! Constructor for constant string (i.e. do not make a copy of string)
+ GenericValue(const Ch* s, SizeType length) RAPIDJSON_NOEXCEPT : data_() {
+ SetStringRaw(StringRef(s, length));
+ }
+
+ //! Constructor for constant string (i.e. do not make a copy of string)
+ explicit GenericValue(StringRefType s) RAPIDJSON_NOEXCEPT : data_() {
+ SetStringRaw(s);
+ }
+
+ //! Constructor for copy-string (i.e. do make a copy of string)
+ GenericValue(const Ch* s, SizeType length, Allocator& allocator) : data_() {
+ SetStringRaw(StringRef(s, length), allocator);
+ }
+
+ //! Constructor for copy-string (i.e. do make a copy of string)
+ GenericValue(const Ch* s, Allocator& allocator) : data_() {
+ SetStringRaw(StringRef(s), allocator);
+ }
+
+#if RAPIDJSON_HAS_STDSTRING
+ //! Constructor for copy-string from a string object (i.e. do make a copy of
+ //! string)
+ /*! \note Requires the definition of the preprocessor symbol \ref
+ * RAPIDJSON_HAS_STDSTRING.
+ */
+ GenericValue(const std::basic_string<Ch>& s, Allocator& allocator) : data_() {
+ SetStringRaw(StringRef(s), allocator);
+ }
+#endif
+
+ //! Constructor for Array.
+ /*!
+ \param a An array obtained by \c GetArray().
+ \note \c Array is always pass-by-value.
+ \note the source array is moved into this value and the sourec array
+ becomes empty.
+ */
+ GenericValue(Array a) RAPIDJSON_NOEXCEPT : data_(a.value_.data_) {
+ a.value_.data_ = Data();
+ a.value_.data_.f.flags = kArrayFlag;
+ }
+
+ //! Constructor for Object.
+ /*!
+ \param o An object obtained by \c GetObject().
+ \note \c Object is always pass-by-value.
+ \note the source object is moved into this value and the sourec object
+ becomes empty.
+ */
+ GenericValue(Object o) RAPIDJSON_NOEXCEPT : data_(o.value_.data_) {
+ o.value_.data_ = Data();
+ o.value_.data_.f.flags = kObjectFlag;
+ }
+
+ //! Destructor.
+ /*! Need to destruct elements of array, members of object, or copy-string.
+ */
+ ~GenericValue() {
+ if (Allocator::kNeedFree) { // Shortcut by Allocator's trait
+ switch (data_.f.flags) {
+ case kArrayFlag: {
+ GenericValue* e = GetElementsPointer();
+ for (GenericValue* v = e; v != e + data_.a.size; ++v)
+ v->~GenericValue();
+ Allocator::Free(e);
+ } break;
+
+ case kObjectFlag:
+ for (MemberIterator m = MemberBegin(); m != MemberEnd(); ++m)
+ m->~Member();
+ Allocator::Free(GetMembersPointer());
+ break;
+
+ case kCopyStringFlag:
+ Allocator::Free(const_cast<Ch*>(GetStringPointer()));
+ break;
+
+ default:
+ break; // Do nothing for other types.
+ }
+ }
+ }
+
+ //@}
+
+ //!@name Assignment operators
+ //@{
+
+ //! Assignment with move semantics.
+ /*! \param rhs Source of the assignment. It will become a null value after
+ * assignment.
+ */
+ GenericValue& operator=(GenericValue& rhs) RAPIDJSON_NOEXCEPT {
+ RAPIDJSON_ASSERT(this != &rhs);
+ this->~GenericValue();
+ RawAssign(rhs);
+ return *this;
+ }
+
+#if RAPIDJSON_HAS_CXX11_RVALUE_REFS
+ //! Move assignment in C++11
+ GenericValue& operator=(GenericValue&& rhs) RAPIDJSON_NOEXCEPT {
+ return *this = rhs.Move();
+ }
+#endif
+
+ //! Assignment of constant string reference (no copy)
+ /*! \param str Constant string reference to be assigned
+ \note This overload is needed to avoid clashes with the generic primitive
+ type assignment overload below. \see GenericStringRef, operator=(T)
+ */
+ GenericValue& operator=(StringRefType str) RAPIDJSON_NOEXCEPT {
+ GenericValue s(str);
+ return *this = s;
+ }
+
+ //! Assignment with primitive types.
+ /*! \tparam T Either \ref Type, \c int, \c unsigned, \c int64_t, \c uint64_t
+ \param value The value to be assigned.
+
+ \note The source type \c T explicitly disallows all pointer types,
+ especially (\c const) \ref Ch*. This helps avoiding implicitly
+ referencing character strings with insufficient lifetime, use
+ \ref SetString(const Ch*, Allocator&) (for copying) or
+ \ref StringRef() (to explicitly mark the pointer as constant) instead.
+ All other pointer types would implicitly convert to \c bool,
+ use \ref SetBool() instead.
+ */
+ template <typename T>
+ RAPIDJSON_DISABLEIF_RETURN((internal::IsPointer<T>), (GenericValue&))
+ operator=(T value) {
+ GenericValue v(value);
+ return *this = v;
+ }
+
+ //! Deep-copy assignment from Value
+ /*! Assigns a \b copy of the Value to the current Value object
+ \tparam SourceAllocator Allocator type of \c rhs
+ \param rhs Value to copy from (read-only)
+ \param allocator Allocator to use for copying
+ */
+ template <typename SourceAllocator>
+ GenericValue& CopyFrom(const GenericValue<Encoding, SourceAllocator>& rhs,
+ Allocator& allocator) {
+ RAPIDJSON_ASSERT(static_cast<void*>(this) !=
+ static_cast<void const*>(&rhs));
+ this->~GenericValue();
+ new (this) GenericValue(rhs, allocator);
+ return *this;
+ }
+
+ //! Exchange the contents of this value with those of other.
+ /*!
+ \param other Another value.
+ \note Constant complexity.
+ */
+ GenericValue& Swap(GenericValue& other) RAPIDJSON_NOEXCEPT {
+ GenericValue temp;
+ temp.RawAssign(*this);
+ RawAssign(other);
+ other.RawAssign(temp);
+ return *this;
+ }
+
+ //! free-standing swap function helper
+ /*!
+ Helper function to enable support for common swap implementation pattern
+ based on \c std::swap: \code void swap(MyClass& a, MyClass& b) { using
+ std::swap; swap(a.value, b.value);
+ // ...
+ }
+ \endcode
+ \see Swap()
+ */
+ friend inline void swap(GenericValue& a, GenericValue& b) RAPIDJSON_NOEXCEPT {
+ a.Swap(b);
+ }
+
+ //! Prepare Value for move semantics
+ /*! \return *this */
+ GenericValue& Move() RAPIDJSON_NOEXCEPT { return *this; }
+ //@}
+
+ //!@name Equal-to and not-equal-to operators
+ //@{
+ //! Equal-to operator
+ /*!
+ \note If an object contains duplicated named member, comparing equality
+ with any object is always \c false. \note Linear time complexity (number of
+ all values in the subtree and total lengths of all strings).
+ */
+ template <typename SourceAllocator>
+ bool operator==(const GenericValue<Encoding, SourceAllocator>& rhs) const {
+ typedef GenericValue<Encoding, SourceAllocator> RhsType;
+ if (GetType() != rhs.GetType())
+ return false;
+
+ switch (GetType()) {
+ case kObjectType: // Warning: O(n^2) inner-loop
+ if (data_.o.size != rhs.data_.o.size)
+ return false;
+ for (ConstMemberIterator lhsMemberItr = MemberBegin();
+ lhsMemberItr != MemberEnd(); ++lhsMemberItr) {
+ typename RhsType::ConstMemberIterator rhsMemberItr =
+ rhs.FindMember(lhsMemberItr->name);
+ if (rhsMemberItr == rhs.MemberEnd() ||
+ lhsMemberItr->value != rhsMemberItr->value)
+ return false;
+ }
+ return true;
+
+ case kArrayType:
+ if (data_.a.size != rhs.data_.a.size)
+ return false;
+ for (SizeType i = 0; i < data_.a.size; i++)
+ if ((*this)[i] != rhs[i])
+ return false;
+ return true;
+
+ case kStringType:
+ return StringEqual(rhs);
+
+ case kNumberType:
+ if (IsDouble() || rhs.IsDouble()) {
+ double a = GetDouble(); // May convert from integer to double.
+ double b = rhs.GetDouble(); // Ditto
+ return a >= b && a <= b; // Prevent -Wfloat-equal
+ } else
+ return data_.n.u64 == rhs.data_.n.u64;
+
+ default:
+ return true;
+ }
+ }
+
+ //! Equal-to operator with const C-string pointer
+ bool operator==(const Ch* rhs) const {
+ return *this == GenericValue(StringRef(rhs));
+ }
+
+#if RAPIDJSON_HAS_STDSTRING
+ //! Equal-to operator with string object
+ /*! \note Requires the definition of the preprocessor symbol \ref
+ * RAPIDJSON_HAS_STDSTRING.
+ */
+ bool operator==(const std::basic_string<Ch>& rhs) const {
+ return *this == GenericValue(StringRef(rhs));
+ }
+#endif
+
+ //! Equal-to operator with primitive types
+ /*! \tparam T Either \ref Type, \c int, \c unsigned, \c int64_t, \c uint64_t,
+ * \c double, \c true, \c false
+ */
+ template <typename T>
+ RAPIDJSON_DISABLEIF_RETURN(
+ (internal::OrExpr<internal::IsPointer<T>, internal::IsGenericValue<T> >),
+ (bool))
+ operator==(const T& rhs) const {
+ return *this == GenericValue(rhs);
+ }
+
+ //! Not-equal-to operator
+ /*! \return !(*this == rhs)
+ */
+ template <typename SourceAllocator>
+ bool operator!=(const GenericValue<Encoding, SourceAllocator>& rhs) const {
+ return !(*this == rhs);
+ }
+
+ //! Not-equal-to operator with const C-string pointer
+ bool operator!=(const Ch* rhs) const { return !(*this == rhs); }
+
+ //! Not-equal-to operator with arbitrary types
+ /*! \return !(*this == rhs)
+ */
+ template <typename T>
+ RAPIDJSON_DISABLEIF_RETURN((internal::IsGenericValue<T>), (bool))
+ operator!=(const T& rhs) const {
+ return !(*this == rhs);
+ }
+
+ //! Equal-to operator with arbitrary types (symmetric version)
+ /*! \return (rhs == lhs)
+ */
+ template <typename T>
+ friend RAPIDJSON_DISABLEIF_RETURN((internal::IsGenericValue<T>), (bool))
+ operator==(const T& lhs, const GenericValue& rhs) {
+ return rhs == lhs;
+ }
+
+ //! Not-Equal-to operator with arbitrary types (symmetric version)
+ /*! \return !(rhs == lhs)
+ */
+ template <typename T>
+ friend RAPIDJSON_DISABLEIF_RETURN((internal::IsGenericValue<T>), (bool))
+ operator!=(const T& lhs, const GenericValue& rhs) {
+ return !(rhs == lhs);
+ }
+ //@}
+
+ //!@name Type
+ //@{
+
+ Type GetType() const { return static_cast<Type>(data_.f.flags & kTypeMask); }
+ bool IsNull() const { return data_.f.flags == kNullFlag; }
+ bool IsFalse() const { return data_.f.flags == kFalseFlag; }
+ bool IsTrue() const { return data_.f.flags == kTrueFlag; }
+ bool IsBool() const { return (data_.f.flags & kBoolFlag) != 0; }
+ bool IsObject() const { return data_.f.flags == kObjectFlag; }
+ bool IsArray() const { return data_.f.flags == kArrayFlag; }
+ bool IsNumber() const { return (data_.f.flags & kNumberFlag) != 0; }
+ bool IsInt() const { return (data_.f.flags & kIntFlag) != 0; }
+ bool IsUint() const { return (data_.f.flags & kUintFlag) != 0; }
+ bool IsInt64() const { return (data_.f.flags & kInt64Flag) != 0; }
+ bool IsUint64() const { return (data_.f.flags & kUint64Flag) != 0; }
+ bool IsDouble() const { return (data_.f.flags & kDoubleFlag) != 0; }
+ bool IsString() const { return (data_.f.flags & kStringFlag) != 0; }
+
+ // Checks whether a number can be losslessly converted to a double.
+ bool IsLosslessDouble() const {
+ if (!IsNumber())
+ return false;
+ if (IsUint64()) {
+ uint64_t u = GetUint64();
+ volatile double d = static_cast<double>(u);
+ return (d >= 0.0) &&
+ (d < static_cast<double>(std::numeric_limits<uint64_t>::max())) &&
+ (u == static_cast<uint64_t>(d));
+ }
+ if (IsInt64()) {
+ int64_t i = GetInt64();
+ volatile double d = static_cast<double>(i);
+ return (d >= static_cast<double>(std::numeric_limits<int64_t>::min())) &&
+ (d < static_cast<double>(std::numeric_limits<int64_t>::max())) &&
+ (i == static_cast<int64_t>(d));
+ }
+ return true; // double, int, uint are always lossless
+ }
+
+ // Checks whether a number is a float (possible lossy).
+ bool IsFloat() const {
+ if ((data_.f.flags & kDoubleFlag) == 0)
+ return false;
+ double d = GetDouble();
+ return d >= -3.4028234e38 && d <= 3.4028234e38;
+ }
+ // Checks whether a number can be losslessly converted to a float.
+ bool IsLosslessFloat() const {
+ if (!IsNumber())
+ return false;
+ double a = GetDouble();
+ if (a < static_cast<double>(-std::numeric_limits<float>::max()) ||
+ a > static_cast<double>(std::numeric_limits<float>::max()))
+ return false;
+ double b = static_cast<double>(static_cast<float>(a));
+ return a >= b && a <= b; // Prevent -Wfloat-equal
+ }
+
+ //@}
+
+ //!@name Null
+ //@{
+
+ GenericValue& SetNull() {
+ this->~GenericValue();
+ new (this) GenericValue();
+ return *this;
+ }
+
+ //@}
+
+ //!@name Bool
+ //@{
+
+ bool GetBool() const {
+ RAPIDJSON_ASSERT(IsBool());
+ return data_.f.flags == kTrueFlag;
+ }
+ //!< Set boolean value
+ /*! \post IsBool() == true */
+ GenericValue& SetBool(bool b) {
+ this->~GenericValue();
+ new (this) GenericValue(b);
+ return *this;
+ }
+
+ //@}
+
+ //!@name Object
+ //@{
+
+ //! Set this value as an empty object.
+ /*! \post IsObject() == true */
+ GenericValue& SetObject() {
+ this->~GenericValue();
+ new (this) GenericValue(kObjectType);
+ return *this;
+ }
+
+ //! Get the number of members in the object.
+ SizeType MemberCount() const {
+ RAPIDJSON_ASSERT(IsObject());
+ return data_.o.size;
+ }
+
+ //! Check whether the object is empty.
+ bool ObjectEmpty() const {
+ RAPIDJSON_ASSERT(IsObject());
+ return data_.o.size == 0;
+ }
+
+ //! Get a value from an object associated with the name.
+ /*! \pre IsObject() == true
+ \tparam T Either \c Ch or \c const \c Ch (template used for disambiguation
+ with \ref operator[](SizeType)) \note In version 0.1x, if the member is not
+ found, this function returns a null value. This makes issue 7. Since 0.2,
+ if the name is not correct, it will assert. If user is unsure whether a
+ member exists, user should use HasMember() first. A better approach is to
+ use FindMember(). \note Linear time complexity.
+ */
+ template <typename T>
+ RAPIDJSON_DISABLEIF_RETURN(
+ (internal::NotExpr<
+ internal::IsSame<typename internal::RemoveConst<T>::Type, Ch> >),
+ (GenericValue&))
+ operator[](T* name) {
+ GenericValue n(StringRef(name));
+ return (*this)[n];
+ }
+ template <typename T>
+ RAPIDJSON_DISABLEIF_RETURN(
+ (internal::NotExpr<
+ internal::IsSame<typename internal::RemoveConst<T>::Type, Ch> >),
+ (const GenericValue&))
+ operator[](T* name) const {
+ return const_cast<GenericValue&>(*this)[name];
+ }
+
+ //! Get a value from an object associated with the name.
+ /*! \pre IsObject() == true
+ \tparam SourceAllocator Allocator of the \c name value
+
+ \note Compared to \ref operator[](T*), this version is faster because it
+ does not need a StrLen(). And it can also handle strings with embedded null
+ characters.
+
+ \note Linear time complexity.
+ */
+ template <typename SourceAllocator>
+ GenericValue& operator[](
+ const GenericValue<Encoding, SourceAllocator>& name) {
+ MemberIterator member = FindMember(name);
+ if (member != MemberEnd())
+ return member->value;
+ else {
+ RAPIDJSON_ASSERT(false); // see above note
+
+ // This will generate -Wexit-time-destructors in clang
+ // static GenericValue NullValue;
+ // return NullValue;
+
+ // Use static buffer and placement-new to prevent destruction
+ static char buffer[sizeof(GenericValue)];
+ return *new (buffer) GenericValue();
+ }
+ }
+ template <typename SourceAllocator>
+ const GenericValue& operator[](
+ const GenericValue<Encoding, SourceAllocator>& name) const {
+ return const_cast<GenericValue&>(*this)[name];
+ }
+
+#if RAPIDJSON_HAS_STDSTRING
+ //! Get a value from an object associated with name (string object).
+ GenericValue& operator[](const std::basic_string<Ch>& name) {
+ return (*this)[GenericValue(StringRef(name))];
+ }
+ const GenericValue& operator[](const std::basic_string<Ch>& name) const {
+ return (*this)[GenericValue(StringRef(name))];
+ }
+#endif
+
+ //! Const member iterator
+ /*! \pre IsObject() == true */
+ ConstMemberIterator MemberBegin() const {
+ RAPIDJSON_ASSERT(IsObject());
+ return ConstMemberIterator(GetMembersPointer());
+ }
+ //! Const \em past-the-end member iterator
+ /*! \pre IsObject() == true */
+ ConstMemberIterator MemberEnd() const {
+ RAPIDJSON_ASSERT(IsObject());
+ return ConstMemberIterator(GetMembersPointer() + data_.o.size);
+ }
+ //! Member iterator
+ /*! \pre IsObject() == true */
+ MemberIterator MemberBegin() {
+ RAPIDJSON_ASSERT(IsObject());
+ return MemberIterator(GetMembersPointer());
+ }
+ //! \em Past-the-end member iterator
+ /*! \pre IsObject() == true */
+ MemberIterator MemberEnd() {
+ RAPIDJSON_ASSERT(IsObject());
+ return MemberIterator(GetMembersPointer() + data_.o.size);
+ }
+
+ //! Check whether a member exists in the object.
+ /*!
+ \param name Member name to be searched.
+ \pre IsObject() == true
+ \return Whether a member with that name exists.
+ \note It is better to use FindMember() directly if you need the obtain the
+ value as well. \note Linear time complexity.
+ */
+ bool HasMember(const Ch* name) const {
+ return FindMember(name) != MemberEnd();
+ }
+
+#if RAPIDJSON_HAS_STDSTRING
+ //! Check whether a member exists in the object with string object.
+ /*!
+ \param name Member name to be searched.
+ \pre IsObject() == true
+ \return Whether a member with that name exists.
+ \note It is better to use FindMember() directly if you need the obtain the
+ value as well. \note Linear time complexity.
+ */
+ bool HasMember(const std::basic_string<Ch>& name) const {
+ return FindMember(name) != MemberEnd();
+ }
+#endif
+
+ //! Check whether a member exists in the object with GenericValue name.
+ /*!
+ This version is faster because it does not need a StrLen(). It can also
+ handle string with null character. \param name Member name to be searched.
+ \pre IsObject() == true
+ \return Whether a member with that name exists.
+ \note It is better to use FindMember() directly if you need the obtain the
+ value as well. \note Linear time complexity.
+ */
+ template <typename SourceAllocator>
+ bool HasMember(const GenericValue<Encoding, SourceAllocator>& name) const {
+ return FindMember(name) != MemberEnd();
+ }
+
+ //! Find member by name.
+ /*!
+ \param name Member name to be searched.
+ \pre IsObject() == true
+ \return Iterator to member, if it exists.
+ Otherwise returns \ref MemberEnd().
+
+ \note Earlier versions of Rapidjson returned a \c NULL pointer, in case
+ the requested member doesn't exist. For consistency with e.g.
+ \c std::map, this has been changed to MemberEnd() now.
+ \note Linear time complexity.
+ */
+ MemberIterator FindMember(const Ch* name) {
+ GenericValue n(StringRef(name));
+ return FindMember(n);
+ }
+
+ ConstMemberIterator FindMember(const Ch* name) const {
+ return const_cast<GenericValue&>(*this).FindMember(name);
+ }
+
+ //! Find member by name.
+ /*!
+ This version is faster because it does not need a StrLen(). It can also
+ handle string with null character. \param name Member name to be searched.
+ \pre IsObject() == true
+ \return Iterator to member, if it exists.
+ Otherwise returns \ref MemberEnd().
+
+ \note Earlier versions of Rapidjson returned a \c NULL pointer, in case
+ the requested member doesn't exist. For consistency with e.g.
+ \c std::map, this has been changed to MemberEnd() now.
+ \note Linear time complexity.
+ */
+ template <typename SourceAllocator>
+ MemberIterator FindMember(
+ const GenericValue<Encoding, SourceAllocator>& name) {
+ RAPIDJSON_ASSERT(IsObject());
+ RAPIDJSON_ASSERT(name.IsString());
+ MemberIterator member = MemberBegin();
+ for (; member != MemberEnd(); ++member)
+ if (name.StringEqual(member->name))
+ break;
+ return member;
+ }
+ template <typename SourceAllocator>
+ ConstMemberIterator FindMember(
+ const GenericValue<Encoding, SourceAllocator>& name) const {
+ return const_cast<GenericValue&>(*this).FindMember(name);
+ }
+
+#if RAPIDJSON_HAS_STDSTRING
+ //! Find member by string object name.
+ /*!
+ \param name Member name to be searched.
+ \pre IsObject() == true
+ \return Iterator to member, if it exists.
+ Otherwise returns \ref MemberEnd().
+ */
+ MemberIterator FindMember(const std::basic_string<Ch>& name) {
+ return FindMember(GenericValue(StringRef(name)));
+ }
+ ConstMemberIterator FindMember(const std::basic_string<Ch>& name) const {
+ return FindMember(GenericValue(StringRef(name)));
+ }
+#endif
+
+ //! Add a member (name-value pair) to the object.
+ /*! \param name A string value as name of member.
+ \param value Value of any type.
+ \param allocator Allocator for reallocating memory. It must be the same
+ one as used before. Commonly use GenericDocument::GetAllocator(). \return
+ The value itself for fluent API. \note The ownership of \c name and \c
+ value will be transferred to this object on success. \pre IsObject() &&
+ name.IsString() \post name.IsNull() && value.IsNull() \note Amortized
+ Constant time complexity.
+ */
+ GenericValue& AddMember(GenericValue& name,
+ GenericValue& value,
+ Allocator& allocator) {
+ RAPIDJSON_ASSERT(IsObject());
+ RAPIDJSON_ASSERT(name.IsString());
+
+ ObjectData& o = data_.o;
+ if (o.size >= o.capacity) {
+ if (o.capacity == 0) {
+ o.capacity = kDefaultObjectCapacity;
+ SetMembersPointer(reinterpret_cast<Member*>(
+ allocator.Malloc(o.capacity * sizeof(Member))));
+ } else {
+ SizeType oldCapacity = o.capacity;
+ o.capacity += (oldCapacity + 1) / 2; // grow by factor 1.5
+ SetMembersPointer(reinterpret_cast<Member*>(
+ allocator.Realloc(GetMembersPointer(), oldCapacity * sizeof(Member),
+ o.capacity * sizeof(Member))));
+ }
+ }
+ Member* members = GetMembersPointer();
+ members[o.size].name.RawAssign(name);
+ members[o.size].value.RawAssign(value);
+ o.size++;
+ return *this;
+ }
+
+ //! Add a constant string value as member (name-value pair) to the object.
+ /*! \param name A string value as name of member.
+ \param value constant string reference as value of member.
+ \param allocator Allocator for reallocating memory. It must be the same
+ one as used before. Commonly use GenericDocument::GetAllocator(). \return
+ The value itself for fluent API. \pre IsObject() \note This overload is
+ needed to avoid clashes with the generic primitive type
+ AddMember(GenericValue&,T,Allocator&) overload below. \note Amortized
+ Constant time complexity.
+ */
+ GenericValue& AddMember(GenericValue& name,
+ StringRefType value,
+ Allocator& allocator) {
+ GenericValue v(value);
+ return AddMember(name, v, allocator);
+ }
+
+#if RAPIDJSON_HAS_STDSTRING
+ //! Add a string object as member (name-value pair) to the object.
+ /*! \param name A string value as name of member.
+ \param value constant string reference as value of member.
+ \param allocator Allocator for reallocating memory. It must be the same
+ one as used before. Commonly use GenericDocument::GetAllocator(). \return
+ The value itself for fluent API. \pre IsObject() \note This overload is
+ needed to avoid clashes with the generic primitive type
+ AddMember(GenericValue&,T,Allocator&) overload below. \note Amortized
+ Constant time complexity.
+ */
+ GenericValue& AddMember(GenericValue& name,
+ std::basic_string<Ch>& value,
+ Allocator& allocator) {
+ GenericValue v(value, allocator);
+ return AddMember(name, v, allocator);
+ }
+#endif
+
+ //! Add any primitive value as member (name-value pair) to the object.
+ /*! \tparam T Either \ref Type, \c int, \c unsigned, \c int64_t, \c uint64_t
+ \param name A string value as name of member.
+ \param value Value of primitive type \c T as value of member
+ \param allocator Allocator for reallocating memory. Commonly use
+ GenericDocument::GetAllocator(). \return The value itself for fluent API.
+ \pre IsObject()
+
+ \note The source type \c T explicitly disallows all pointer types,
+ especially (\c const) \ref Ch*. This helps avoiding implicitly
+ referencing character strings with insufficient lifetime, use
+ \ref AddMember(StringRefType, GenericValue&, Allocator&) or \ref
+ AddMember(StringRefType, StringRefType, Allocator&).
+ All other pointer types would implicitly convert to \c bool,
+ use an explicit cast instead, if needed.
+ \note Amortized Constant time complexity.
+ */
+ template <typename T>
+ RAPIDJSON_DISABLEIF_RETURN(
+ (internal::OrExpr<internal::IsPointer<T>, internal::IsGenericValue<T> >),
+ (GenericValue&))
+ AddMember(GenericValue& name, T value, Allocator& allocator) {
+ GenericValue v(value);
+ return AddMember(name, v, allocator);
+ }
+
+#if RAPIDJSON_HAS_CXX11_RVALUE_REFS
+ GenericValue& AddMember(GenericValue&& name,
+ GenericValue&& value,
+ Allocator& allocator) {
+ return AddMember(name, value, allocator);
+ }
+ GenericValue& AddMember(GenericValue&& name,
+ GenericValue& value,
+ Allocator& allocator) {
+ return AddMember(name, value, allocator);
+ }
+ GenericValue& AddMember(GenericValue& name,
+ GenericValue&& value,
+ Allocator& allocator) {
+ return AddMember(name, value, allocator);
+ }
+ GenericValue& AddMember(StringRefType name,
+ GenericValue&& value,
+ Allocator& allocator) {
+ GenericValue n(name);
+ return AddMember(n, value, allocator);
+ }
+#endif // RAPIDJSON_HAS_CXX11_RVALUE_REFS
+
+ //! Add a member (name-value pair) to the object.
+ /*! \param name A constant string reference as name of member.
+ \param value Value of any type.
+ \param allocator Allocator for reallocating memory. It must be the same
+ one as used before. Commonly use GenericDocument::GetAllocator(). \return
+ The value itself for fluent API. \note The ownership of \c value will be
+ transferred to this object on success. \pre IsObject() \post
+ value.IsNull() \note Amortized Constant time complexity.
+ */
+ GenericValue& AddMember(StringRefType name,
+ GenericValue& value,
+ Allocator& allocator) {
+ GenericValue n(name);
+ return AddMember(n, value, allocator);
+ }
+
+ //! Add a constant string value as member (name-value pair) to the object.
+ /*! \param name A constant string reference as name of member.
+ \param value constant string reference as value of member.
+ \param allocator Allocator for reallocating memory. It must be the same
+ one as used before. Commonly use GenericDocument::GetAllocator(). \return
+ The value itself for fluent API. \pre IsObject() \note This overload is
+ needed to avoid clashes with the generic primitive type
+ AddMember(StringRefType,T,Allocator&) overload below. \note Amortized
+ Constant time complexity.
+ */
+ GenericValue& AddMember(StringRefType name,
+ StringRefType value,
+ Allocator& allocator) {
+ GenericValue v(value);
+ return AddMember(name, v, allocator);
+ }
+
+ //! Add any primitive value as member (name-value pair) to the object.
+ /*! \tparam T Either \ref Type, \c int, \c unsigned, \c int64_t, \c uint64_t
+ \param name A constant string reference as name of member.
+ \param value Value of primitive type \c T as value of member
+ \param allocator Allocator for reallocating memory. Commonly use
+ GenericDocument::GetAllocator(). \return The value itself for fluent API.
+ \pre IsObject()
+
+ \note The source type \c T explicitly disallows all pointer types,
+ especially (\c const) \ref Ch*. This helps avoiding implicitly
+ referencing character strings with insufficient lifetime, use
+ \ref AddMember(StringRefType, GenericValue&, Allocator&) or \ref
+ AddMember(StringRefType, StringRefType, Allocator&).
+ All other pointer types would implicitly convert to \c bool,
+ use an explicit cast instead, if needed.
+ \note Amortized Constant time complexity.
+ */
+ template <typename T>
+ RAPIDJSON_DISABLEIF_RETURN(
+ (internal::OrExpr<internal::IsPointer<T>, internal::IsGenericValue<T> >),
+ (GenericValue&))
+ AddMember(StringRefType name, T value, Allocator& allocator) {
+ GenericValue n(name);
+ return AddMember(n, value, allocator);
+ }
+
+ //! Remove all members in the object.
+ /*! This function do not deallocate memory in the object, i.e. the capacity is
+ unchanged. \note Linear time complexity.
+ */
+ void RemoveAllMembers() {
+ RAPIDJSON_ASSERT(IsObject());
+ for (MemberIterator m = MemberBegin(); m != MemberEnd(); ++m)
+ m->~Member();
+ data_.o.size = 0;
+ }
+
+ //! Remove a member in object by its name.
+ /*! \param name Name of member to be removed.
+ \return Whether the member existed.
+ \note This function may reorder the object members. Use \ref
+ EraseMember(ConstMemberIterator) if you need to preserve the
+ relative order of the remaining members.
+ \note Linear time complexity.
+ */
+ bool RemoveMember(const Ch* name) {
+ GenericValue n(StringRef(name));
+ return RemoveMember(n);
+ }
+
+#if RAPIDJSON_HAS_STDSTRING
+ bool RemoveMember(const std::basic_string<Ch>& name) {
+ return RemoveMember(GenericValue(StringRef(name)));
+ }
+#endif
+
+ template <typename SourceAllocator>
+ bool RemoveMember(const GenericValue<Encoding, SourceAllocator>& name) {
+ MemberIterator m = FindMember(name);
+ if (m != MemberEnd()) {
+ RemoveMember(m);
+ return true;
+ } else
+ return false;
+ }
+
+ //! Remove a member in object by iterator.
+ /*! \param m member iterator (obtained by FindMember() or MemberBegin()).
+ \return the new iterator after removal.
+ \note This function may reorder the object members. Use \ref
+ EraseMember(ConstMemberIterator) if you need to preserve the
+ relative order of the remaining members.
+ \note Constant time complexity.
+ */
+ MemberIterator RemoveMember(MemberIterator m) {
+ RAPIDJSON_ASSERT(IsObject());
+ RAPIDJSON_ASSERT(data_.o.size > 0);
+ RAPIDJSON_ASSERT(GetMembersPointer() != 0);
+ RAPIDJSON_ASSERT(m >= MemberBegin() && m < MemberEnd());
+
+ MemberIterator last(GetMembersPointer() + (data_.o.size - 1));
+ if (data_.o.size > 1 && m != last)
+ *m = *last; // Move the last one to this place
+ else
+ m->~Member(); // Only one left, just destroy
+ --data_.o.size;
+ return m;
+ }
+
+ //! Remove a member from an object by iterator.
+ /*! \param pos iterator to the member to remove
+ \pre IsObject() == true && \ref MemberBegin() <= \c pos < \ref MemberEnd()
+ \return Iterator following the removed element.
+ If the iterator \c pos refers to the last element, the \ref
+ MemberEnd() iterator is returned. \note This function preserves the
+ relative order of the remaining object members. If you do not need this,
+ use the more efficient \ref RemoveMember(MemberIterator). \note Linear time
+ complexity.
+ */
+ MemberIterator EraseMember(ConstMemberIterator pos) {
+ return EraseMember(pos, pos + 1);
+ }
+
+ //! Remove members in the range [first, last) from an object.
+ /*! \param first iterator to the first member to remove
+ \param last iterator following the last member to remove
+ \pre IsObject() == true && \ref MemberBegin() <= \c first <= \c last <=
+ \ref MemberEnd() \return Iterator following the last removed element. \note
+ This function preserves the relative order of the remaining object members.
+ \note Linear time complexity.
+ */
+ MemberIterator EraseMember(ConstMemberIterator first,
+ ConstMemberIterator last) {
+ RAPIDJSON_ASSERT(IsObject());
+ RAPIDJSON_ASSERT(data_.o.size > 0);
+ RAPIDJSON_ASSERT(GetMembersPointer() != 0);
+ RAPIDJSON_ASSERT(first >= MemberBegin());
+ RAPIDJSON_ASSERT(first <= last);
+ RAPIDJSON_ASSERT(last <= MemberEnd());
+
+ MemberIterator pos = MemberBegin() + (first - MemberBegin());
+ for (MemberIterator itr = pos; itr != last; ++itr)
+ itr->~Member();
+ std::memmove(&*pos, &*last,
+ static_cast<size_t>(MemberEnd() - last) * sizeof(Member));
+ data_.o.size -= static_cast<SizeType>(last - first);
+ return pos;
+ }
+
+ //! Erase a member in object by its name.
+ /*! \param name Name of member to be removed.
+ \return Whether the member existed.
+ \note Linear time complexity.
+ */
+ bool EraseMember(const Ch* name) {
+ GenericValue n(StringRef(name));
+ return EraseMember(n);
+ }
+
+#if RAPIDJSON_HAS_STDSTRING
+ bool EraseMember(const std::basic_string<Ch>& name) {
+ return EraseMember(GenericValue(StringRef(name)));
+ }
+#endif
+
+ template <typename SourceAllocator>
+ bool EraseMember(const GenericValue<Encoding, SourceAllocator>& name) {
+ MemberIterator m = FindMember(name);
+ if (m != MemberEnd()) {
+ EraseMember(m);
+ return true;
+ } else
+ return false;
+ }
+
+ Object GetObject() {
+ RAPIDJSON_ASSERT(IsObject());
+ return Object(*this);
+ }
+ ConstObject GetObject() const {
+ RAPIDJSON_ASSERT(IsObject());
+ return ConstObject(*this);
+ }
+
+ //@}
+
+ //!@name Array
+ //@{
+
+ //! Set this value as an empty array.
+ /*! \post IsArray == true */
+ GenericValue& SetArray() {
+ this->~GenericValue();
+ new (this) GenericValue(kArrayType);
+ return *this;
+ }
+
+ //! Get the number of elements in array.
+ SizeType Size() const {
+ RAPIDJSON_ASSERT(IsArray());
+ return data_.a.size;
+ }
+
+ //! Get the capacity of array.
+ SizeType Capacity() const {
+ RAPIDJSON_ASSERT(IsArray());
+ return data_.a.capacity;
+ }
+
+ //! Check whether the array is empty.
+ bool Empty() const {
+ RAPIDJSON_ASSERT(IsArray());
+ return data_.a.size == 0;
+ }
+
+ //! Remove all elements in the array.
+ /*! This function do not deallocate memory in the array, i.e. the capacity is
+ unchanged. \note Linear time complexity.
+ */
+ void Clear() {
+ RAPIDJSON_ASSERT(IsArray());
+ GenericValue* e = GetElementsPointer();
+ for (GenericValue* v = e; v != e + data_.a.size; ++v)
+ v->~GenericValue();
+ data_.a.size = 0;
+ }
+
+ //! Get an element from array by index.
+ /*! \pre IsArray() == true
+ \param index Zero-based index of element.
+ \see operator[](T*)
+ */
+ GenericValue& operator[](SizeType index) {
+ RAPIDJSON_ASSERT(IsArray());
+ RAPIDJSON_ASSERT(index < data_.a.size);
+ return GetElementsPointer()[index];
+ }
+ const GenericValue& operator[](SizeType index) const {
+ return const_cast<GenericValue&>(*this)[index];
+ }
+
+ //! Element iterator
+ /*! \pre IsArray() == true */
+ ValueIterator Begin() {
+ RAPIDJSON_ASSERT(IsArray());
+ return GetElementsPointer();
+ }
+ //! \em Past-the-end element iterator
+ /*! \pre IsArray() == true */
+ ValueIterator End() {
+ RAPIDJSON_ASSERT(IsArray());
+ return GetElementsPointer() + data_.a.size;
+ }
+ //! Constant element iterator
+ /*! \pre IsArray() == true */
+ ConstValueIterator Begin() const {
+ return const_cast<GenericValue&>(*this).Begin();
+ }
+ //! Constant \em past-the-end element iterator
+ /*! \pre IsArray() == true */
+ ConstValueIterator End() const {
+ return const_cast<GenericValue&>(*this).End();
+ }
+
+ //! Request the array to have enough capacity to store elements.
+ /*! \param newCapacity The capacity that the array at least need to have.
+ \param allocator Allocator for reallocating memory. It must be the same
+ one as used before. Commonly use GenericDocument::GetAllocator(). \return
+ The value itself for fluent API. \note Linear time complexity.
+ */
+ GenericValue& Reserve(SizeType newCapacity, Allocator& allocator) {
+ RAPIDJSON_ASSERT(IsArray());
+ if (newCapacity > data_.a.capacity) {
+ SetElementsPointer(reinterpret_cast<GenericValue*>(allocator.Realloc(
+ GetElementsPointer(), data_.a.capacity * sizeof(GenericValue),
+ newCapacity * sizeof(GenericValue))));
+ data_.a.capacity = newCapacity;
+ }
+ return *this;
+ }
+
+ //! Append a GenericValue at the end of the array.
+ /*! \param value Value to be appended.
+ \param allocator Allocator for reallocating memory. It must be the same
+ one as used before. Commonly use GenericDocument::GetAllocator(). \pre
+ IsArray() == true \post value.IsNull() == true \return The value itself for
+ fluent API. \note The ownership of \c value will be transferred to this
+ array on success. \note If the number of elements to be appended is known,
+ calls Reserve() once first may be more efficient. \note Amortized constant
+ time complexity.
+ */
+ GenericValue& PushBack(GenericValue& value, Allocator& allocator) {
+ RAPIDJSON_ASSERT(IsArray());
+ if (data_.a.size >= data_.a.capacity)
+ Reserve(data_.a.capacity == 0
+ ? kDefaultArrayCapacity
+ : (data_.a.capacity + (data_.a.capacity + 1) / 2),
+ allocator);
+ GetElementsPointer()[data_.a.size++].RawAssign(value);
+ return *this;
+ }
+
+#if RAPIDJSON_HAS_CXX11_RVALUE_REFS
+ GenericValue& PushBack(GenericValue&& value, Allocator& allocator) {
+ return PushBack(value, allocator);
+ }
+#endif // RAPIDJSON_HAS_CXX11_RVALUE_REFS
+
+ //! Append a constant string reference at the end of the array.
+ /*! \param value Constant string reference to be appended.
+ \param allocator Allocator for reallocating memory. It must be the same
+ one used previously. Commonly use GenericDocument::GetAllocator(). \pre
+ IsArray() == true \return The value itself for fluent API. \note If the
+ number of elements to be appended is known, calls Reserve() once first may
+ be more efficient. \note Amortized constant time complexity. \see
+ GenericStringRef
+ */
+ GenericValue& PushBack(StringRefType value, Allocator& allocator) {
+ return (*this).template PushBack<StringRefType>(value, allocator);
+ }
+
+ //! Append a primitive value at the end of the array.
+ /*! \tparam T Either \ref Type, \c int, \c unsigned, \c int64_t, \c uint64_t
+ \param value Value of primitive type T to be appended.
+ \param allocator Allocator for reallocating memory. It must be the same
+ one as used before. Commonly use GenericDocument::GetAllocator(). \pre
+ IsArray() == true \return The value itself for fluent API. \note If the
+ number of elements to be appended is known, calls Reserve() once first may
+ be more efficient.
+
+ \note The source type \c T explicitly disallows all pointer types,
+ especially (\c const) \ref Ch*. This helps avoiding implicitly
+ referencing character strings with insufficient lifetime, use
+ \ref PushBack(GenericValue&, Allocator&) or \ref
+ PushBack(StringRefType, Allocator&).
+ All other pointer types would implicitly convert to \c bool,
+ use an explicit cast instead, if needed.
+ \note Amortized constant time complexity.
+ */
+ template <typename T>
+ RAPIDJSON_DISABLEIF_RETURN(
+ (internal::OrExpr<internal::IsPointer<T>, internal::IsGenericValue<T> >),
+ (GenericValue&))
+ PushBack(T value, Allocator& allocator) {
+ GenericValue v(value);
+ return PushBack(v, allocator);
+ }
+
+ //! Remove the last element in the array.
+ /*!
+ \note Constant time complexity.
+ */
+ GenericValue& PopBack() {
+ RAPIDJSON_ASSERT(IsArray());
+ RAPIDJSON_ASSERT(!Empty());
+ GetElementsPointer()[--data_.a.size].~GenericValue();
+ return *this;
+ }
+
+ //! Remove an element of array by iterator.
+ /*!
+ \param pos iterator to the element to remove
+ \pre IsArray() == true && \ref Begin() <= \c pos < \ref End()
+ \return Iterator following the removed element. If the iterator pos refers
+ to the last element, the End() iterator is returned. \note Linear time
+ complexity.
+ */
+ ValueIterator Erase(ConstValueIterator pos) { return Erase(pos, pos + 1); }
+
+ //! Remove elements in the range [first, last) of the array.
+ /*!
+ \param first iterator to the first element to remove
+ \param last iterator following the last element to remove
+ \pre IsArray() == true && \ref Begin() <= \c first <= \c last <= \ref
+ End() \return Iterator following the last removed element. \note Linear
+ time complexity.
+ */
+ ValueIterator Erase(ConstValueIterator first, ConstValueIterator last) {
+ RAPIDJSON_ASSERT(IsArray());
+ RAPIDJSON_ASSERT(data_.a.size > 0);
+ RAPIDJSON_ASSERT(GetElementsPointer() != 0);
+ RAPIDJSON_ASSERT(first >= Begin());
+ RAPIDJSON_ASSERT(first <= last);
+ RAPIDJSON_ASSERT(last <= End());
+ ValueIterator pos = Begin() + (first - Begin());
+ for (ValueIterator itr = pos; itr != last; ++itr)
+ itr->~GenericValue();
+ std::memmove(pos, last,
+ static_cast<size_t>(End() - last) * sizeof(GenericValue));
+ data_.a.size -= static_cast<SizeType>(last - first);
+ return pos;
+ }
+
+ Array GetArray() {
+ RAPIDJSON_ASSERT(IsArray());
+ return Array(*this);
+ }
+ ConstArray GetArray() const {
+ RAPIDJSON_ASSERT(IsArray());
+ return ConstArray(*this);
+ }
+
+ //@}
+
+ //!@name Number
+ //@{
+
+ int GetInt() const {
+ RAPIDJSON_ASSERT(data_.f.flags & kIntFlag);
+ return data_.n.i.i;
+ }
+ unsigned GetUint() const {
+ RAPIDJSON_ASSERT(data_.f.flags & kUintFlag);
+ return data_.n.u.u;
+ }
+ int64_t GetInt64() const {
+ RAPIDJSON_ASSERT(data_.f.flags & kInt64Flag);
+ return data_.n.i64;
+ }
+ uint64_t GetUint64() const {
+ RAPIDJSON_ASSERT(data_.f.flags & kUint64Flag);
+ return data_.n.u64;
+ }
+
+ //! Get the value as double type.
+ /*! \note If the value is 64-bit integer type, it may lose precision. Use \c
+ * IsLosslessDouble() to check whether the converison is lossless.
+ */
+ double GetDouble() const {
+ RAPIDJSON_ASSERT(IsNumber());
+ if ((data_.f.flags & kDoubleFlag) != 0)
+ return data_.n.d; // exact type, no conversion.
+ if ((data_.f.flags & kIntFlag) != 0)
+ return data_.n.i.i; // int -> double
+ if ((data_.f.flags & kUintFlag) != 0)
+ return data_.n.u.u; // unsigned -> double
+ if ((data_.f.flags & kInt64Flag) != 0)
+ return static_cast<double>(
+ data_.n.i64); // int64_t -> double (may lose precision)
+ RAPIDJSON_ASSERT((data_.f.flags & kUint64Flag) != 0);
+ return static_cast<double>(
+ data_.n.u64); // uint64_t -> double (may lose precision)
+ }
+
+ //! Get the value as float type.
+ /*! \note If the value is 64-bit integer type, it may lose precision. Use \c
+ * IsLosslessFloat() to check whether the converison is lossless.
+ */
+ float GetFloat() const { return static_cast<float>(GetDouble()); }
+
+ GenericValue& SetInt(int i) {
+ this->~GenericValue();
+ new (this) GenericValue(i);
+ return *this;
+ }
+ GenericValue& SetUint(unsigned u) {
+ this->~GenericValue();
+ new (this) GenericValue(u);
+ return *this;
+ }
+ GenericValue& SetInt64(int64_t i64) {
+ this->~GenericValue();
+ new (this) GenericValue(i64);
+ return *this;
+ }
+ GenericValue& SetUint64(uint64_t u64) {
+ this->~GenericValue();
+ new (this) GenericValue(u64);
+ return *this;
+ }
+ GenericValue& SetDouble(double d) {
+ this->~GenericValue();
+ new (this) GenericValue(d);
+ return *this;
+ }
+ GenericValue& SetFloat(float f) {
+ this->~GenericValue();
+ new (this) GenericValue(f);
+ return *this;
+ }
+
+ //@}
+
+ //!@name String
+ //@{
+
+ const Ch* GetString() const {
+ RAPIDJSON_ASSERT(IsString());
+ return (data_.f.flags & kInlineStrFlag) ? data_.ss.str : GetStringPointer();
+ }
+
+ //! Get the length of string.
+ /*! Since rapidjson permits "\\u0000" in the json string,
+ * strlen(v.GetString()) may not equal to v.GetStringLength().
+ */
+ SizeType GetStringLength() const {
+ RAPIDJSON_ASSERT(IsString());
+ return ((data_.f.flags & kInlineStrFlag) ? (data_.ss.GetLength())
+ : data_.s.length);
+ }
+
+ //! Set this value as a string without copying source string.
+ /*! This version has better performance with supplied length, and also support
+ string containing null character. \param s source string pointer. \param
+ length The length of source string, excluding the trailing null terminator.
+ \return The value itself for fluent API.
+ \post IsString() == true && GetString() == s && GetStringLength() ==
+ length \see SetString(StringRefType)
+ */
+ GenericValue& SetString(const Ch* s, SizeType length) {
+ return SetString(StringRef(s, length));
+ }
+
+ //! Set this value as a string without copying source string.
+ /*! \param s source string reference
+ \return The value itself for fluent API.
+ \post IsString() == true && GetString() == s && GetStringLength() ==
+ s.length
+ */
+ GenericValue& SetString(StringRefType s) {
+ this->~GenericValue();
+ SetStringRaw(s);
+ return *this;
+ }
+
+ //! Set this value as a string by copying from source string.
+ /*! This version has better performance with supplied length, and also support
+ string containing null character. \param s source string. \param length The
+ length of source string, excluding the trailing null terminator. \param
+ allocator Allocator for allocating copied buffer. Commonly use
+ GenericDocument::GetAllocator(). \return The value itself for fluent API.
+ \post IsString() == true && GetString() != s && strcmp(GetString(),s) == 0
+ && GetStringLength() == length
+ */
+ GenericValue& SetString(const Ch* s, SizeType length, Allocator& allocator) {
+ this->~GenericValue();
+ SetStringRaw(StringRef(s, length), allocator);
+ return *this;
+ }
+
+ //! Set this value as a string by copying from source string.
+ /*! \param s source string.
+ \param allocator Allocator for allocating copied buffer. Commonly use
+ GenericDocument::GetAllocator(). \return The value itself for fluent API.
+ \post IsString() == true && GetString() != s && strcmp(GetString(),s) == 0
+ && GetStringLength() == length
+ */
+ GenericValue& SetString(const Ch* s, Allocator& allocator) {
+ return SetString(s, internal::StrLen(s), allocator);
+ }
+
+#if RAPIDJSON_HAS_STDSTRING
+ //! Set this value as a string by copying from source string.
+ /*! \param s source string.
+ \param allocator Allocator for allocating copied buffer. Commonly use
+ GenericDocument::GetAllocator(). \return The value itself for fluent API.
+ \post IsString() == true && GetString() != s.data() &&
+ strcmp(GetString(),s.data() == 0 && GetStringLength() == s.size() \note
+ Requires the definition of the preprocessor symbol \ref
+ RAPIDJSON_HAS_STDSTRING.
+ */
+ GenericValue& SetString(const std::basic_string<Ch>& s,
+ Allocator& allocator) {
+ return SetString(s.data(), SizeType(s.size()), allocator);
+ }
+#endif
+
+ //@}
+
+ //!@name Array
+ //@{
+
+ //! Templated version for checking whether this value is type T.
+ /*!
+ \tparam T Either \c bool, \c int, \c unsigned, \c int64_t, \c uint64_t, \c
+ double, \c float, \c const \c char*, \c std::basic_string<Ch>
+ */
+ template <typename T>
+ bool Is() const {
+ return internal::TypeHelper<ValueType, T>::Is(*this);
+ }
+
+ template <typename T>
+ T Get() const {
+ return internal::TypeHelper<ValueType, T>::Get(*this);
+ }
+
+ template <typename T>
+ T Get() {
+ return internal::TypeHelper<ValueType, T>::Get(*this);
+ }
+
+ template <typename T>
+ ValueType& Set(const T& data) {
+ return internal::TypeHelper<ValueType, T>::Set(*this, data);
+ }
+
+ template <typename T>
+ ValueType& Set(const T& data, AllocatorType& allocator) {
+ return internal::TypeHelper<ValueType, T>::Set(*this, data, allocator);
+ }
+
+ //@}
+
+ //! Generate events of this value to a Handler.
+ /*! This function adopts the GoF visitor pattern.
+ Typical usage is to output this JSON value as JSON text via Writer, which
+ is a Handler. It can also be used to deep clone this value via
+ GenericDocument, which is also a Handler. \tparam Handler type of handler.
+ \param handler An object implementing concept Handler.
+ */
+ template <typename Handler>
+ bool Accept(Handler& handler) const {
+ switch (GetType()) {
+ case kNullType:
+ return handler.Null();
+ case kFalseType:
+ return handler.Bool(false);
+ case kTrueType:
+ return handler.Bool(true);
+
+ case kObjectType:
+ if (RAPIDJSON_UNLIKELY(!handler.StartObject()))
+ return false;
+ for (ConstMemberIterator m = MemberBegin(); m != MemberEnd(); ++m) {
+ RAPIDJSON_ASSERT(m->name.IsString()); // User may change the type of
+ // name by MemberIterator.
+ if (RAPIDJSON_UNLIKELY(
+ !handler.Key(m->name.GetString(), m->name.GetStringLength(),
+ (m->name.data_.f.flags & kCopyFlag) != 0)))
+ return false;
+ if (RAPIDJSON_UNLIKELY(!m->value.Accept(handler)))
+ return false;
+ }
+ return handler.EndObject(data_.o.size);
+
+ case kArrayType:
+ if (RAPIDJSON_UNLIKELY(!handler.StartArray()))
+ return false;
+ for (const GenericValue* v = Begin(); v != End(); ++v)
+ if (RAPIDJSON_UNLIKELY(!v->Accept(handler)))
+ return false;
+ return handler.EndArray(data_.a.size);
+
+ case kStringType:
+ return handler.String(GetString(), GetStringLength(),
+ (data_.f.flags & kCopyFlag) != 0);
+
+ default:
+ RAPIDJSON_ASSERT(GetType() == kNumberType);
+ if (IsDouble())
+ return handler.Double(data_.n.d);
+ else if (IsInt())
+ return handler.Int(data_.n.i.i);
+ else if (IsUint())
+ return handler.Uint(data_.n.u.u);
+ else if (IsInt64())
+ return handler.Int64(data_.n.i64);
+ else
+ return handler.Uint64(data_.n.u64);
+ }
+ }
+
+ private:
+ template <typename, typename>
+ friend class GenericValue;
+ template <typename, typename, typename>
+ friend class GenericDocument;
+
+ enum {
+ kBoolFlag = 0x0008,
+ kNumberFlag = 0x0010,
+ kIntFlag = 0x0020,
+ kUintFlag = 0x0040,
+ kInt64Flag = 0x0080,
+ kUint64Flag = 0x0100,
+ kDoubleFlag = 0x0200,
+ kStringFlag = 0x0400,
+ kCopyFlag = 0x0800,
+ kInlineStrFlag = 0x1000,
+
+ // Initial flags of different types.
+ kNullFlag = kNullType,
+ kTrueFlag = kTrueType | kBoolFlag,
+ kFalseFlag = kFalseType | kBoolFlag,
+ kNumberIntFlag = kNumberType | kNumberFlag | kIntFlag | kInt64Flag,
+ kNumberUintFlag =
+ kNumberType | kNumberFlag | kUintFlag | kUint64Flag | kInt64Flag,
+ kNumberInt64Flag = kNumberType | kNumberFlag | kInt64Flag,
+ kNumberUint64Flag = kNumberType | kNumberFlag | kUint64Flag,
+ kNumberDoubleFlag = kNumberType | kNumberFlag | kDoubleFlag,
+ kNumberAnyFlag = kNumberType | kNumberFlag | kIntFlag | kInt64Flag |
+ kUintFlag | kUint64Flag | kDoubleFlag,
+ kConstStringFlag = kStringType | kStringFlag,
+ kCopyStringFlag = kStringType | kStringFlag | kCopyFlag,
+ kShortStringFlag = kStringType | kStringFlag | kCopyFlag | kInlineStrFlag,
+ kObjectFlag = kObjectType,
+ kArrayFlag = kArrayType,
+
+ kTypeMask = 0x07
+ };
+
+ static const SizeType kDefaultArrayCapacity = 16;
+ static const SizeType kDefaultObjectCapacity = 16;
+
+ struct Flag {
+#if RAPIDJSON_48BITPOINTER_OPTIMIZATION
+ char payload[sizeof(SizeType) * 2 +
+ 6]; // 2 x SizeType + lower 48-bit pointer
+#elif RAPIDJSON_64BIT
+ char payload[sizeof(SizeType) * 2 + sizeof(void*) + 6]; // 6 padding bytes
+#else
+ char payload[sizeof(SizeType) * 2 + sizeof(void*) +
+ 2]; // 2 padding bytes
+#endif
+ uint16_t flags;
+ };
+
+ struct String {
+ SizeType length;
+ SizeType hashcode; //!< reserved
+ const Ch* str;
+ }; // 12 bytes in 32-bit mode, 16 bytes in 64-bit mode
+
+ // implementation detail: ShortString can represent zero-terminated strings up
+ // to MaxSize chars (excluding the terminating zero) and store a value to
+ // determine the length of the contained string in the last character
+ // str[LenPos] by storing "MaxSize - length" there. If the string to store has
+ // the maximal length of MaxSize then str[LenPos] will be 0 and therefore act
+ // as the string terminator as well. For getting the string length back from
+ // that value just use "MaxSize - str[LenPos]". This allows to store 13-chars
+ // strings in 32-bit mode, 21-chars strings in 64-bit mode, 13-chars strings
+ // for RAPIDJSON_48BITPOINTER_OPTIMIZATION=1 inline (for `UTF8`-encoded
+ // strings).
+ struct ShortString {
+ enum {
+ MaxChars = sizeof(static_cast<Flag*>(0)->payload) / sizeof(Ch),
+ MaxSize = MaxChars - 1,
+ LenPos = MaxSize
+ };
+ Ch str[MaxChars];
+
+ inline static bool Usable(SizeType len) { return (MaxSize >= len); }
+ inline void SetLength(SizeType len) {
+ str[LenPos] = static_cast<Ch>(MaxSize - len);
+ }
+ inline SizeType GetLength() const {
+ return static_cast<SizeType>(MaxSize - str[LenPos]);
+ }
+ }; // at most as many bytes as "String" above => 12 bytes in 32-bit mode, 16
+ // bytes in 64-bit mode
+
+ // By using proper binary layout, retrieval of different integer types do not
+ // need conversions.
+ union Number {
+#if RAPIDJSON_ENDIAN == RAPIDJSON_LITTLEENDIAN
+ struct I {
+ int i;
+ char padding[4];
+ } i;
+ struct U {
+ unsigned u;
+ char padding2[4];
+ } u;
+#else
+ struct I {
+ char padding[4];
+ int i;
+ } i;
+ struct U {
+ char padding2[4];
+ unsigned u;
+ } u;
+#endif
+ int64_t i64;
+ uint64_t u64;
+ double d;
+ }; // 8 bytes
+
+ struct ObjectData {
+ SizeType size;
+ SizeType capacity;
+ Member* members;
+ }; // 12 bytes in 32-bit mode, 16 bytes in 64-bit mode
+
+ struct ArrayData {
+ SizeType size;
+ SizeType capacity;
+ GenericValue* elements;
+ }; // 12 bytes in 32-bit mode, 16 bytes in 64-bit mode
+
+ union Data {
+ String s;
+ ShortString ss;
+ Number n;
+ ObjectData o;
+ ArrayData a;
+ Flag f;
+ }; // 16 bytes in 32-bit mode, 24 bytes in 64-bit mode, 16 bytes in 64-bit
+ // with RAPIDJSON_48BITPOINTER_OPTIMIZATION
+
+ RAPIDJSON_FORCEINLINE const Ch* GetStringPointer() const {
+ return RAPIDJSON_GETPOINTER(Ch, data_.s.str);
+ }
+ RAPIDJSON_FORCEINLINE const Ch* SetStringPointer(const Ch* str) {
+ return RAPIDJSON_SETPOINTER(Ch, data_.s.str, str);
+ }
+ RAPIDJSON_FORCEINLINE GenericValue* GetElementsPointer() const {
+ return RAPIDJSON_GETPOINTER(GenericValue, data_.a.elements);
+ }
+ RAPIDJSON_FORCEINLINE GenericValue* SetElementsPointer(
+ GenericValue* elements) {
+ return RAPIDJSON_SETPOINTER(GenericValue, data_.a.elements, elements);
+ }
+ RAPIDJSON_FORCEINLINE Member* GetMembersPointer() const {
+ return RAPIDJSON_GETPOINTER(Member, data_.o.members);
+ }
+ RAPIDJSON_FORCEINLINE Member* SetMembersPointer(Member* members) {
+ return RAPIDJSON_SETPOINTER(Member, data_.o.members, members);
+ }
+
+ // Initialize this value as array with initial data, without calling
+ // destructor.
+ void SetArrayRaw(GenericValue* values, SizeType count, Allocator& allocator) {
+ data_.f.flags = kArrayFlag;
+ if (count) {
+ GenericValue* e = static_cast<GenericValue*>(
+ allocator.Malloc(count * sizeof(GenericValue)));
+ SetElementsPointer(e);
+ std::memcpy(e, values, count * sizeof(GenericValue));
+ } else
+ SetElementsPointer(0);
+ data_.a.size = data_.a.capacity = count;
+ }
+
+ //! Initialize this value as object with initial data, without calling
+ //! destructor.
+ void SetObjectRaw(Member* members, SizeType count, Allocator& allocator) {
+ data_.f.flags = kObjectFlag;
+ if (count) {
+ Member* m =
+ static_cast<Member*>(allocator.Malloc(count * sizeof(Member)));
+ SetMembersPointer(m);
+ std::memcpy(m, members, count * sizeof(Member));
+ } else
+ SetMembersPointer(0);
+ data_.o.size = data_.o.capacity = count;
+ }
+
+ //! Initialize this value as constant string, without calling destructor.
+ void SetStringRaw(StringRefType s) RAPIDJSON_NOEXCEPT {
+ data_.f.flags = kConstStringFlag;
+ SetStringPointer(s);
+ data_.s.length = s.length;
+ }
+
+ //! Initialize this value as copy string with initial data, without calling
+ //! destructor.
+ void SetStringRaw(StringRefType s, Allocator& allocator) {
+ Ch* str = 0;
+ if (ShortString::Usable(s.length)) {
+ data_.f.flags = kShortStringFlag;
+ data_.ss.SetLength(s.length);
+ str = data_.ss.str;
+ } else {
+ data_.f.flags = kCopyStringFlag;
+ data_.s.length = s.length;
+ str = static_cast<Ch*>(allocator.Malloc((s.length + 1) * sizeof(Ch)));
+ SetStringPointer(str);
+ }
+ std::memcpy(str, s, s.length * sizeof(Ch));
+ str[s.length] = '\0';
+ }
+
+ //! Assignment without calling destructor
+ void RawAssign(GenericValue& rhs) RAPIDJSON_NOEXCEPT {
+ data_ = rhs.data_;
+ // data_.f.flags = rhs.data_.f.flags;
+ rhs.data_.f.flags = kNullFlag;
+ }
+
+ template <typename SourceAllocator>
+ bool StringEqual(const GenericValue<Encoding, SourceAllocator>& rhs) const {
+ RAPIDJSON_ASSERT(IsString());
+ RAPIDJSON_ASSERT(rhs.IsString());
+
+ const SizeType len1 = GetStringLength();
+ const SizeType len2 = rhs.GetStringLength();
+ if (len1 != len2) {
+ return false;
+ }
+
+ const Ch* const str1 = GetString();
+ const Ch* const str2 = rhs.GetString();
+ if (str1 == str2) {
+ return true;
+ } // fast path for constant string
+
+ return (std::memcmp(str1, str2, sizeof(Ch) * len1) == 0);
+ }
+
+ Data data_;
+};
+
+//! GenericValue with UTF8 encoding
+typedef GenericValue<UTF8<> > Value;
+
+///////////////////////////////////////////////////////////////////////////////
+// GenericDocument
+
+//! A document for parsing JSON text as DOM.
+/*!
+ \note implements Handler concept
+ \tparam Encoding Encoding for both parsing and string storage.
+ \tparam Allocator Allocator for allocating memory for the DOM
+ \tparam StackAllocator Allocator for allocating memory for stack during
+ parsing. \warning Although GenericDocument inherits from GenericValue, the
+ API does \b not provide any virtual functions, especially no virtual
+ destructor. To avoid memory leaks, do not \c delete a GenericDocument object
+ via a pointer to a GenericValue.
+*/
+template <typename Encoding,
+ typename Allocator = MemoryPoolAllocator<>,
+ typename StackAllocator = CrtAllocator>
+class GenericDocument : public GenericValue<Encoding, Allocator> {
+ public:
+ typedef typename Encoding::Ch Ch; //!< Character type derived from Encoding.
+ typedef GenericValue<Encoding, Allocator>
+ ValueType; //!< Value type of the document.
+ typedef Allocator AllocatorType; //!< Allocator type from template parameter.
+
+ //! Constructor
+ /*! Creates an empty document of specified type.
+ \param type Mandatory type of object to create.
+ \param allocator Optional allocator for allocating memory.
+ \param stackCapacity Optional initial capacity of stack in bytes.
+ \param stackAllocator Optional allocator for allocating memory for
+ stack.
+ */
+ explicit GenericDocument(Type type,
+ Allocator* allocator = 0,
+ size_t stackCapacity = kDefaultStackCapacity,
+ StackAllocator* stackAllocator = 0)
+ : GenericValue<Encoding, Allocator>(type),
+ allocator_(allocator),
+ ownAllocator_(0),
+ stack_(stackAllocator, stackCapacity),
+ parseResult_() {
+ if (!allocator_)
+ ownAllocator_ = allocator_ = RAPIDJSON_NEW(Allocator());
+ }
+
+ //! Constructor
+ /*! Creates an empty document which type is Null.
+ \param allocator Optional allocator for allocating memory.
+ \param stackCapacity Optional initial capacity of stack in bytes.
+ \param stackAllocator Optional allocator for allocating memory for
+ stack.
+ */
+ GenericDocument(Allocator* allocator = 0,
+ size_t stackCapacity = kDefaultStackCapacity,
+ StackAllocator* stackAllocator = 0)
+ : allocator_(allocator),
+ ownAllocator_(0),
+ stack_(stackAllocator, stackCapacity),
+ parseResult_() {
+ if (!allocator_)
+ ownAllocator_ = allocator_ = RAPIDJSON_NEW(Allocator());
+ }
+
+#if RAPIDJSON_HAS_CXX11_RVALUE_REFS
+ //! Move constructor in C++11
+ GenericDocument(GenericDocument&& rhs) RAPIDJSON_NOEXCEPT
+ : ValueType(std::forward<ValueType>(
+ rhs)), // explicit cast to avoid prohibited move from Document
+ allocator_(rhs.allocator_),
+ ownAllocator_(rhs.ownAllocator_),
+ stack_(std::move(rhs.stack_)),
+ parseResult_(rhs.parseResult_) {
+ rhs.allocator_ = 0;
+ rhs.ownAllocator_ = 0;
+ rhs.parseResult_ = ParseResult();
+ }
+#endif
+
+ ~GenericDocument() { Destroy(); }
+
+#if RAPIDJSON_HAS_CXX11_RVALUE_REFS
+ //! Move assignment in C++11
+ GenericDocument& operator=(GenericDocument&& rhs) RAPIDJSON_NOEXCEPT {
+ // The cast to ValueType is necessary here, because otherwise it would
+ // attempt to call GenericValue's templated assignment operator.
+ ValueType::operator=(std::forward<ValueType>(rhs));
+
+ // Calling the destructor here would prematurely call stack_'s destructor
+ Destroy();
+
+ allocator_ = rhs.allocator_;
+ ownAllocator_ = rhs.ownAllocator_;
+ stack_ = std::move(rhs.stack_);
+ parseResult_ = rhs.parseResult_;
+
+ rhs.allocator_ = 0;
+ rhs.ownAllocator_ = 0;
+ rhs.parseResult_ = ParseResult();
+
+ return *this;
+ }
+#endif
+
+ //! Exchange the contents of this document with those of another.
+ /*!
+ \param rhs Another document.
+ \note Constant complexity.
+ \see GenericValue::Swap
+ */
+ GenericDocument& Swap(GenericDocument& rhs) RAPIDJSON_NOEXCEPT {
+ ValueType::Swap(rhs);
+ stack_.Swap(rhs.stack_);
+ internal::Swap(allocator_, rhs.allocator_);
+ internal::Swap(ownAllocator_, rhs.ownAllocator_);
+ internal::Swap(parseResult_, rhs.parseResult_);
+ return *this;
+ }
+
+ //! free-standing swap function helper
+ /*!
+ Helper function to enable support for common swap implementation pattern
+ based on \c std::swap: \code void swap(MyClass& a, MyClass& b) { using
+ std::swap; swap(a.doc, b.doc);
+ // ...
+ }
+ \endcode
+ \see Swap()
+ */
+ friend inline void swap(GenericDocument& a,
+ GenericDocument& b) RAPIDJSON_NOEXCEPT {
+ a.Swap(b);
+ }
+
+ //! Populate this document by a generator which produces SAX events.
+ /*! \tparam Generator A functor with <tt>bool f(Handler)</tt> prototype.
+ \param g Generator functor which sends SAX events to the parameter.
+ \return The document itself for fluent API.
+ */
+ template <typename Generator>
+ GenericDocument& Populate(Generator& g) {
+ ClearStackOnExit scope(*this);
+ if (g(*this)) {
+ RAPIDJSON_ASSERT(stack_.GetSize() ==
+ sizeof(ValueType)); // Got one and only one root object
+ ValueType::operator=(*stack_.template Pop<ValueType>(
+ 1)); // Move value from stack to document
+ }
+ return *this;
+ }
+
+ //!@name Parse from stream
+ //!@{
+
+ //! Parse JSON text from an input stream (with Encoding conversion)
+ /*! \tparam parseFlags Combination of \ref ParseFlag.
+ \tparam SourceEncoding Encoding of input stream
+ \tparam InputStream Type of input stream, implementing Stream concept
+ \param is Input stream to be parsed.
+ \return The document itself for fluent API.
+ */
+ template <unsigned parseFlags, typename SourceEncoding, typename InputStream>
+ GenericDocument& ParseStream(InputStream& is) {
+ GenericReader<SourceEncoding, Encoding, StackAllocator> reader(
+ stack_.HasAllocator() ? &stack_.GetAllocator() : 0);
+ ClearStackOnExit scope(*this);
+ parseResult_ = reader.template Parse<parseFlags>(is, *this);
+ if (parseResult_) {
+ RAPIDJSON_ASSERT(stack_.GetSize() ==
+ sizeof(ValueType)); // Got one and only one root object
+ ValueType::operator=(*stack_.template Pop<ValueType>(
+ 1)); // Move value from stack to document
+ }
+ return *this;
+ }
+
+ //! Parse JSON text from an input stream
+ /*! \tparam parseFlags Combination of \ref ParseFlag.
+ \tparam InputStream Type of input stream, implementing Stream concept
+ \param is Input stream to be parsed.
+ \return The document itself for fluent API.
+ */
+ template <unsigned parseFlags, typename InputStream>
+ GenericDocument& ParseStream(InputStream& is) {
+ return ParseStream<parseFlags, Encoding, InputStream>(is);
+ }
+
+ //! Parse JSON text from an input stream (with \ref kParseDefaultFlags)
+ /*! \tparam InputStream Type of input stream, implementing Stream concept
+ \param is Input stream to be parsed.
+ \return The document itself for fluent API.
+ */
+ template <typename InputStream>
+ GenericDocument& ParseStream(InputStream& is) {
+ return ParseStream<kParseDefaultFlags, Encoding, InputStream>(is);
+ }
+ //!@}
+
+ //!@name Parse in-place from mutable string
+ //!@{
+
+ //! Parse JSON text from a mutable string
+ /*! \tparam parseFlags Combination of \ref ParseFlag.
+ \param str Mutable zero-terminated string to be parsed.
+ \return The document itself for fluent API.
+ */
+ template <unsigned parseFlags>
+ GenericDocument& ParseInsitu(Ch* str) {
+ GenericInsituStringStream<Encoding> s(str);
+ return ParseStream<parseFlags | kParseInsituFlag>(s);
+ }
+
+ //! Parse JSON text from a mutable string (with \ref kParseDefaultFlags)
+ /*! \param str Mutable zero-terminated string to be parsed.
+ \return The document itself for fluent API.
+ */
+ GenericDocument& ParseInsitu(Ch* str) {
+ return ParseInsitu<kParseDefaultFlags>(str);
+ }
+ //!@}
+
+ //!@name Parse from read-only string
+ //!@{
+
+ //! Parse JSON text from a read-only string (with Encoding conversion)
+ /*! \tparam parseFlags Combination of \ref ParseFlag (must not contain \ref
+ kParseInsituFlag). \tparam SourceEncoding Transcoding from input Encoding
+ \param str Read-only zero-terminated string to be parsed.
+ */
+ template <unsigned parseFlags, typename SourceEncoding>
+ GenericDocument& Parse(const typename SourceEncoding::Ch* str) {
+ RAPIDJSON_ASSERT(!(parseFlags & kParseInsituFlag));
+ GenericStringStream<SourceEncoding> s(str);
+ return ParseStream<parseFlags, SourceEncoding>(s);
+ }
+
+ //! Parse JSON text from a read-only string
+ /*! \tparam parseFlags Combination of \ref ParseFlag (must not contain \ref
+ kParseInsituFlag). \param str Read-only zero-terminated string to be
+ parsed.
+ */
+ template <unsigned parseFlags>
+ GenericDocument& Parse(const Ch* str) {
+ return Parse<parseFlags, Encoding>(str);
+ }
+
+ //! Parse JSON text from a read-only string (with \ref kParseDefaultFlags)
+ /*! \param str Read-only zero-terminated string to be parsed.
+ */
+ GenericDocument& Parse(const Ch* str) {
+ return Parse<kParseDefaultFlags>(str);
+ }
+
+ template <unsigned parseFlags, typename SourceEncoding>
+ GenericDocument& Parse(const typename SourceEncoding::Ch* str,
+ size_t length) {
+ RAPIDJSON_ASSERT(!(parseFlags & kParseInsituFlag));
+ MemoryStream ms(static_cast<const char*>(str),
+ length * sizeof(typename SourceEncoding::Ch));
+ EncodedInputStream<SourceEncoding, MemoryStream> is(ms);
+ ParseStream<parseFlags, SourceEncoding>(is);
+ return *this;
+ }
+
+ template <unsigned parseFlags>
+ GenericDocument& Parse(const Ch* str, size_t length) {
+ return Parse<parseFlags, Encoding>(str, length);
+ }
+
+ GenericDocument& Parse(const Ch* str, size_t length) {
+ return Parse<kParseDefaultFlags>(str, length);
+ }
+
+#if RAPIDJSON_HAS_STDSTRING
+ template <unsigned parseFlags, typename SourceEncoding>
+ GenericDocument& Parse(
+ const std::basic_string<typename SourceEncoding::Ch>& str) {
+ // c_str() is constant complexity according to standard. Should be faster
+ // than Parse(const char*, size_t)
+ return Parse<parseFlags, SourceEncoding>(str.c_str());
+ }
+
+ template <unsigned parseFlags>
+ GenericDocument& Parse(const std::basic_string<Ch>& str) {
+ return Parse<parseFlags, Encoding>(str.c_str());
+ }
+
+ GenericDocument& Parse(const std::basic_string<Ch>& str) {
+ return Parse<kParseDefaultFlags>(str);
+ }
+#endif // RAPIDJSON_HAS_STDSTRING
+
+ //!@}
+
+ //!@name Handling parse errors
+ //!@{
+
+ //! Whether a parse error has occured in the last parsing.
+ bool HasParseError() const { return parseResult_.IsError(); }
+
+ //! Get the \ref ParseErrorCode of last parsing.
+ ParseErrorCode GetParseError() const { return parseResult_.Code(); }
+
+ //! Get the position of last parsing error in input, 0 otherwise.
+ size_t GetErrorOffset() const { return parseResult_.Offset(); }
+
+ //! Implicit conversion to get the last parse result
+#ifndef __clang // -Wdocumentation
+ /*! \return \ref ParseResult of the last parse operation
+
+ \code
+ Document doc;
+ ParseResult ok = doc.Parse(json);
+ if (!ok)
+ printf( "JSON parse error: %s (%u)\n", GetParseError_En(ok.Code()),
+ ok.Offset()); \endcode
+ */
+#endif
+ operator ParseResult() const { return parseResult_; }
+ //!@}
+
+ //! Get the allocator of this document.
+ Allocator& GetAllocator() {
+ RAPIDJSON_ASSERT(allocator_);
+ return *allocator_;
+ }
+
+ //! Get the capacity of stack in bytes.
+ size_t GetStackCapacity() const { return stack_.GetCapacity(); }
+
+ private:
+ // clear stack on any exit from ParseStream, e.g. due to exception
+ struct ClearStackOnExit {
+ explicit ClearStackOnExit(GenericDocument& d) : d_(d) {}
+ ~ClearStackOnExit() { d_.ClearStack(); }
+
+ private:
+ ClearStackOnExit(const ClearStackOnExit&);
+ ClearStackOnExit& operator=(const ClearStackOnExit&);
+ GenericDocument& d_;
+ };
+
+ // callers of the following private Handler functions
+ // template <typename,typename,typename> friend class GenericReader; // for
+ // parsing
+ template <typename, typename>
+ friend class GenericValue; // for deep copying
+
+ public:
+ // Implementation of Handler
+ bool Null() {
+ new (stack_.template Push<ValueType>()) ValueType();
+ return true;
+ }
+ bool Bool(bool b) {
+ new (stack_.template Push<ValueType>()) ValueType(b);
+ return true;
+ }
+ bool Int(int i) {
+ new (stack_.template Push<ValueType>()) ValueType(i);
+ return true;
+ }
+ bool Uint(unsigned i) {
+ new (stack_.template Push<ValueType>()) ValueType(i);
+ return true;
+ }
+ bool Int64(int64_t i) {
+ new (stack_.template Push<ValueType>()) ValueType(i);
+ return true;
+ }
+ bool Uint64(uint64_t i) {
+ new (stack_.template Push<ValueType>()) ValueType(i);
+ return true;
+ }
+ bool Double(double d) {
+ new (stack_.template Push<ValueType>()) ValueType(d);
+ return true;
+ }
+
+ bool RawNumber(const Ch* str, SizeType length, bool copy) {
+ if (copy)
+ new (stack_.template Push<ValueType>())
+ ValueType(str, length, GetAllocator());
+ else
+ new (stack_.template Push<ValueType>()) ValueType(str, length);
+ return true;
+ }
+
+ bool String(const Ch* str, SizeType length, bool copy) {
+ if (copy)
+ new (stack_.template Push<ValueType>())
+ ValueType(str, length, GetAllocator());
+ else
+ new (stack_.template Push<ValueType>()) ValueType(str, length);
+ return true;
+ }
+
+ bool StartObject() {
+ new (stack_.template Push<ValueType>()) ValueType(kObjectType);
+ return true;
+ }
+
+ bool Key(const Ch* str, SizeType length, bool copy) {
+ return String(str, length, copy);
+ }
+
+ bool EndObject(SizeType memberCount) {
+ typename ValueType::Member* members =
+ stack_.template Pop<typename ValueType::Member>(memberCount);
+ stack_.template Top<ValueType>()->SetObjectRaw(members, memberCount,
+ GetAllocator());
+ return true;
+ }
+
+ bool StartArray() {
+ new (stack_.template Push<ValueType>()) ValueType(kArrayType);
+ return true;
+ }
+
+ bool EndArray(SizeType elementCount) {
+ ValueType* elements = stack_.template Pop<ValueType>(elementCount);
+ stack_.template Top<ValueType>()->SetArrayRaw(elements, elementCount,
+ GetAllocator());
+ return true;
+ }
+
+ private:
+ //! Prohibit copying
+ GenericDocument(const GenericDocument&);
+ //! Prohibit assignment
+ GenericDocument& operator=(const GenericDocument&);
+
+ void ClearStack() {
+ if (Allocator::kNeedFree)
+ while (stack_.GetSize() >
+ 0) // Here assumes all elements in stack array are GenericValue
+ // (Member is actually 2 GenericValue objects)
+ (stack_.template Pop<ValueType>(1))->~ValueType();
+ else
+ stack_.Clear();
+ stack_.ShrinkToFit();
+ }
+
+ void Destroy() { RAPIDJSON_DELETE(ownAllocator_); }
+
+ static const size_t kDefaultStackCapacity = 1024;
+ Allocator* allocator_;
+ Allocator* ownAllocator_;
+ internal::Stack<StackAllocator> stack_;
+ ParseResult parseResult_;
+};
+
+//! GenericDocument with UTF8 encoding
+typedef GenericDocument<UTF8<> > Document;
+
+// defined here due to the dependency on GenericDocument
+template <typename Encoding, typename Allocator>
+template <typename SourceAllocator>
+inline GenericValue<Encoding, Allocator>::GenericValue(
+ const GenericValue<Encoding, SourceAllocator>& rhs,
+ Allocator& allocator) {
+ switch (rhs.GetType()) {
+ case kObjectType:
+ case kArrayType: { // perform deep copy via SAX Handler
+ GenericDocument<Encoding, Allocator> d(&allocator);
+ rhs.Accept(d);
+ RawAssign(*d.stack_.template Pop<GenericValue>(1));
+ } break;
+ case kStringType:
+ if (rhs.data_.f.flags == kConstStringFlag) {
+ data_.f.flags = rhs.data_.f.flags;
+ data_ = *reinterpret_cast<const Data*>(&rhs.data_);
+ } else {
+ SetStringRaw(StringRef(rhs.GetString(), rhs.GetStringLength()),
+ allocator);
+ }
+ break;
+ default:
+ data_.f.flags = rhs.data_.f.flags;
+ data_ = *reinterpret_cast<const Data*>(&rhs.data_);
+ break;
+ }
+}
+
+//! Helper class for accessing Value of array type.
+/*!
+ Instance of this helper class is obtained by \c GenericValue::GetArray().
+ In addition to all APIs for array type, it provides range-based for loop if
+ \c RAPIDJSON_HAS_CXX11_RANGE_FOR=1.
+*/
+template <bool Const, typename ValueT>
+class GenericArray {
+ public:
+ typedef GenericArray<true, ValueT> ConstArray;
+ typedef GenericArray<false, ValueT> Array;
+ typedef ValueT PlainType;
+ typedef typename internal::MaybeAddConst<Const, PlainType>::Type ValueType;
+ typedef ValueType* ValueIterator; // This may be const or non-const iterator
+ typedef const ValueT* ConstValueIterator;
+ typedef typename ValueType::AllocatorType AllocatorType;
+ typedef typename ValueType::StringRefType StringRefType;
+
+ template <typename, typename>
+ friend class GenericValue;
+
+ GenericArray(const GenericArray& rhs) : value_(rhs.value_) {}
+ GenericArray& operator=(const GenericArray& rhs) {
+ value_ = rhs.value_;
+ return *this;
+ }
+ ~GenericArray() {}
+
+ SizeType Size() const { return value_.Size(); }
+ SizeType Capacity() const { return value_.Capacity(); }
+ bool Empty() const { return value_.Empty(); }
+ void Clear() const { value_.Clear(); }
+ ValueType& operator[](SizeType index) const { return value_[index]; }
+ ValueIterator Begin() const { return value_.Begin(); }
+ ValueIterator End() const { return value_.End(); }
+ GenericArray Reserve(SizeType newCapacity, AllocatorType& allocator) const {
+ value_.Reserve(newCapacity, allocator);
+ return *this;
+ }
+ GenericArray PushBack(ValueType& value, AllocatorType& allocator) const {
+ value_.PushBack(value, allocator);
+ return *this;
+ }
+#if RAPIDJSON_HAS_CXX11_RVALUE_REFS
+ GenericArray PushBack(ValueType&& value, AllocatorType& allocator) const {
+ value_.PushBack(value, allocator);
+ return *this;
+ }
+#endif // RAPIDJSON_HAS_CXX11_RVALUE_REFS
+ GenericArray PushBack(StringRefType value, AllocatorType& allocator) const {
+ value_.PushBack(value, allocator);
+ return *this;
+ }
+ template <typename T>
+ RAPIDJSON_DISABLEIF_RETURN(
+ (internal::OrExpr<internal::IsPointer<T>, internal::IsGenericValue<T> >),
+ (const GenericArray&))
+ PushBack(T value, AllocatorType& allocator) const {
+ value_.PushBack(value, allocator);
+ return *this;
+ }
+ GenericArray PopBack() const {
+ value_.PopBack();
+ return *this;
+ }
+ ValueIterator Erase(ConstValueIterator pos) const {
+ return value_.Erase(pos);
+ }
+ ValueIterator Erase(ConstValueIterator first, ConstValueIterator last) const {
+ return value_.Erase(first, last);
+ }
+
+#if RAPIDJSON_HAS_CXX11_RANGE_FOR
+ ValueIterator begin() const { return value_.Begin(); }
+ ValueIterator end() const { return value_.End(); }
+#endif
+
+ private:
+ GenericArray();
+ GenericArray(ValueType& value) : value_(value) {}
+ ValueType& value_;
+};
+
+//! Helper class for accessing Value of object type.
+/*!
+ Instance of this helper class is obtained by \c GenericValue::GetObject().
+ In addition to all APIs for array type, it provides range-based for loop if
+ \c RAPIDJSON_HAS_CXX11_RANGE_FOR=1.
+*/
+template <bool Const, typename ValueT>
+class GenericObject {
+ public:
+ typedef GenericObject<true, ValueT> ConstObject;
+ typedef GenericObject<false, ValueT> Object;
+ typedef ValueT PlainType;
+ typedef typename internal::MaybeAddConst<Const, PlainType>::Type ValueType;
+ typedef GenericMemberIterator<Const,
+ typename ValueT::EncodingType,
+ typename ValueT::AllocatorType>
+ MemberIterator; // This may be const or non-const iterator
+ typedef GenericMemberIterator<true,
+ typename ValueT::EncodingType,
+ typename ValueT::AllocatorType>
+ ConstMemberIterator;
+ typedef typename ValueType::AllocatorType AllocatorType;
+ typedef typename ValueType::StringRefType StringRefType;
+ typedef typename ValueType::EncodingType EncodingType;
+ typedef typename ValueType::Ch Ch;
+
+ template <typename, typename>
+ friend class GenericValue;
+
+ GenericObject(const GenericObject& rhs) : value_(rhs.value_) {}
+ GenericObject& operator=(const GenericObject& rhs) {
+ value_ = rhs.value_;
+ return *this;
+ }
+ ~GenericObject() {}
+
+ SizeType MemberCount() const { return value_.MemberCount(); }
+ bool ObjectEmpty() const { return value_.ObjectEmpty(); }
+ template <typename T>
+ ValueType& operator[](T* name) const {
+ return value_[name];
+ }
+ template <typename SourceAllocator>
+ ValueType& operator[](
+ const GenericValue<EncodingType, SourceAllocator>& name) const {
+ return value_[name];
+ }
+#if RAPIDJSON_HAS_STDSTRING
+ ValueType& operator[](const std::basic_string<Ch>& name) const {
+ return value_[name];
+ }
+#endif
+ MemberIterator MemberBegin() const { return value_.MemberBegin(); }
+ MemberIterator MemberEnd() const { return value_.MemberEnd(); }
+ bool HasMember(const Ch* name) const { return value_.HasMember(name); }
+#if RAPIDJSON_HAS_STDSTRING
+ bool HasMember(const std::basic_string<Ch>& name) const {
+ return value_.HasMember(name);
+ }
+#endif
+ template <typename SourceAllocator>
+ bool HasMember(
+ const GenericValue<EncodingType, SourceAllocator>& name) const {
+ return value_.HasMember(name);
+ }
+ MemberIterator FindMember(const Ch* name) const {
+ return value_.FindMember(name);
+ }
+ template <typename SourceAllocator>
+ MemberIterator FindMember(
+ const GenericValue<EncodingType, SourceAllocator>& name) const {
+ return value_.FindMember(name);
+ }
+#if RAPIDJSON_HAS_STDSTRING
+ MemberIterator FindMember(const std::basic_string<Ch>& name) const {
+ return value_.FindMember(name);
+ }
+#endif
+ GenericObject AddMember(ValueType& name,
+ ValueType& value,
+ AllocatorType& allocator) const {
+ value_.AddMember(name, value, allocator);
+ return *this;
+ }
+ GenericObject AddMember(ValueType& name,
+ StringRefType value,
+ AllocatorType& allocator) const {
+ value_.AddMember(name, value, allocator);
+ return *this;
+ }
+#if RAPIDJSON_HAS_STDSTRING
+ GenericObject AddMember(ValueType& name,
+ std::basic_string<Ch>& value,
+ AllocatorType& allocator) const {
+ value_.AddMember(name, value, allocator);
+ return *this;
+ }
+#endif
+ template <typename T>
+ RAPIDJSON_DISABLEIF_RETURN(
+ (internal::OrExpr<internal::IsPointer<T>, internal::IsGenericValue<T> >),
+ (ValueType&))
+ AddMember(ValueType& name, T value, AllocatorType& allocator) const {
+ value_.AddMember(name, value, allocator);
+ return *this;
+ }
+#if RAPIDJSON_HAS_CXX11_RVALUE_REFS
+ GenericObject AddMember(ValueType&& name,
+ ValueType&& value,
+ AllocatorType& allocator) const {
+ value_.AddMember(name, value, allocator);
+ return *this;
+ }
+ GenericObject AddMember(ValueType&& name,
+ ValueType& value,
+ AllocatorType& allocator) const {
+ value_.AddMember(name, value, allocator);
+ return *this;
+ }
+ GenericObject AddMember(ValueType& name,
+ ValueType&& value,
+ AllocatorType& allocator) const {
+ value_.AddMember(name, value, allocator);
+ return *this;
+ }
+ GenericObject AddMember(StringRefType name,
+ ValueType&& value,
+ AllocatorType& allocator) const {
+ value_.AddMember(name, value, allocator);
+ return *this;
+ }
+#endif // RAPIDJSON_HAS_CXX11_RVALUE_REFS
+ GenericObject AddMember(StringRefType name,
+ ValueType& value,
+ AllocatorType& allocator) const {
+ value_.AddMember(name, value, allocator);
+ return *this;
+ }
+ GenericObject AddMember(StringRefType name,
+ StringRefType value,
+ AllocatorType& allocator) const {
+ value_.AddMember(name, value, allocator);
+ return *this;
+ }
+ template <typename T>
+ RAPIDJSON_DISABLEIF_RETURN(
+ (internal::OrExpr<internal::IsPointer<T>, internal::IsGenericValue<T> >),
+ (GenericObject))
+ AddMember(StringRefType name, T value, AllocatorType& allocator) const {
+ value_.AddMember(name, value, allocator);
+ return *this;
+ }
+ void RemoveAllMembers() { return value_.RemoveAllMembers(); }
+ bool RemoveMember(const Ch* name) const { return value_.RemoveMember(name); }
+#if RAPIDJSON_HAS_STDSTRING
+ bool RemoveMember(const std::basic_string<Ch>& name) const {
+ return value_.RemoveMember(name);
+ }
+#endif
+ template <typename SourceAllocator>
+ bool RemoveMember(
+ const GenericValue<EncodingType, SourceAllocator>& name) const {
+ return value_.RemoveMember(name);
+ }
+ MemberIterator RemoveMember(MemberIterator m) const {
+ return value_.RemoveMember(m);
+ }
+ MemberIterator EraseMember(ConstMemberIterator pos) const {
+ return value_.EraseMember(pos);
+ }
+ MemberIterator EraseMember(ConstMemberIterator first,
+ ConstMemberIterator last) const {
+ return value_.EraseMember(first, last);
+ }
+ bool EraseMember(const Ch* name) const { return value_.EraseMember(name); }
+#if RAPIDJSON_HAS_STDSTRING
+ bool EraseMember(const std::basic_string<Ch>& name) const {
+ return EraseMember(ValueType(StringRef(name)));
+ }
+#endif
+ template <typename SourceAllocator>
+ bool EraseMember(
+ const GenericValue<EncodingType, SourceAllocator>& name) const {
+ return value_.EraseMember(name);
+ }
+
+#if RAPIDJSON_HAS_CXX11_RANGE_FOR
+ MemberIterator begin() const { return value_.MemberBegin(); }
+ MemberIterator end() const { return value_.MemberEnd(); }
+#endif
+
+ private:
+ GenericObject();
+ GenericObject(ValueType& value) : value_(value) {}
+ ValueType& value_;
+};
+
+RAPIDJSON_NAMESPACE_END
+RAPIDJSON_DIAG_POP
+
+#endif // RAPIDJSON_DOCUMENT_H_
diff --git a/include/rapidjson/encodedstream.h b/third_party/rapidjson/encodedstream.h
index 14506838..14506838 100644
--- a/include/rapidjson/encodedstream.h
+++ b/third_party/rapidjson/encodedstream.h
diff --git a/include/rapidjson/encodings.h b/third_party/rapidjson/encodings.h
index baa7c2b1..baa7c2b1 100644
--- a/include/rapidjson/encodings.h
+++ b/third_party/rapidjson/encodings.h
diff --git a/include/rapidjson/error/en.h b/third_party/rapidjson/error/en.h
index 2db838bf..2db838bf 100644
--- a/include/rapidjson/error/en.h
+++ b/third_party/rapidjson/error/en.h
diff --git a/third_party/rapidjson/error/error.h b/third_party/rapidjson/error/error.h
new file mode 100644
index 00000000..f8058477
--- /dev/null
+++ b/third_party/rapidjson/error/error.h
@@ -0,0 +1,172 @@
+// Tencent is pleased to support the open source community by making RapidJSON
+// available.
+//
+// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All
+// rights reserved.
+//
+// Licensed under the MIT License (the "License"); you may not use this file
+// except in compliance with the License. You may obtain a copy of the License
+// at
+//
+// http://opensource.org/licenses/MIT
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+// License for the specific language governing permissions and limitations under
+// the License.
+
+#ifndef RAPIDJSON_ERROR_ERROR_H_
+#define RAPIDJSON_ERROR_ERROR_H_
+
+#include "rapidjson/rapidjson.h"
+
+#ifdef __clang__
+RAPIDJSON_DIAG_PUSH
+RAPIDJSON_DIAG_OFF(padded)
+#endif
+
+/*! \file error.h */
+
+/*! \defgroup RAPIDJSON_ERRORS RapidJSON error handling */
+
+///////////////////////////////////////////////////////////////////////////////
+// RAPIDJSON_ERROR_CHARTYPE
+
+//! Character type of error messages.
+/*! \ingroup RAPIDJSON_ERRORS
+ The default character type is \c char.
+ On Windows, user can define this macro as \c TCHAR for supporting both
+ unicode/non-unicode settings.
+*/
+#ifndef RAPIDJSON_ERROR_CHARTYPE
+#define RAPIDJSON_ERROR_CHARTYPE char
+#endif
+
+///////////////////////////////////////////////////////////////////////////////
+// RAPIDJSON_ERROR_STRING
+
+//! Macro for converting string literial to \ref RAPIDJSON_ERROR_CHARTYPE[].
+/*! \ingroup RAPIDJSON_ERRORS
+ By default this conversion macro does nothing.
+ On Windows, user can define this macro as \c _T(x) for supporting both
+ unicode/non-unicode settings.
+*/
+#ifndef RAPIDJSON_ERROR_STRING
+#define RAPIDJSON_ERROR_STRING(x) x
+#endif
+
+RAPIDJSON_NAMESPACE_BEGIN
+
+///////////////////////////////////////////////////////////////////////////////
+// ParseErrorCode
+
+//! Error code of parsing.
+/*! \ingroup RAPIDJSON_ERRORS
+ \see GenericReader::Parse, GenericReader::GetParseErrorCode
+*/
+enum ParseErrorCode {
+ kParseErrorNone = 0, //!< No error.
+
+ kParseErrorDocumentEmpty, //!< The document is empty.
+ kParseErrorDocumentRootNotSingular, //!< The document root must not follow by
+ //!< other values.
+
+ kParseErrorValueInvalid, //!< Invalid value.
+
+ kParseErrorObjectMissName, //!< Missing a name for object member.
+ kParseErrorObjectMissColon, //!< Missing a colon after a name of object
+ //!< member.
+ kParseErrorObjectMissCommaOrCurlyBracket, //!< Missing a comma or '}' after
+ //!< an object member.
+
+ kParseErrorArrayMissCommaOrSquareBracket, //!< Missing a comma or ']' after
+ //!< an array element.
+
+ kParseErrorStringUnicodeEscapeInvalidHex, //!< Incorrect hex digit after \\u
+ //!< escape in string.
+ kParseErrorStringUnicodeSurrogateInvalid, //!< The surrogate pair in string
+ //!< is invalid.
+ kParseErrorStringEscapeInvalid, //!< Invalid escape character in string.
+ kParseErrorStringMissQuotationMark, //!< Missing a closing quotation mark in
+ //!< string.
+ kParseErrorStringInvalidEncoding, //!< Invalid encoding in string.
+
+ kParseErrorNumberTooBig, //!< Number too big to be stored in double.
+ kParseErrorNumberMissFraction, //!< Miss fraction part in number.
+ kParseErrorNumberMissExponent, //!< Miss exponent in number.
+
+ kParseErrorTermination, //!< Parsing was terminated.
+ kParseErrorUnspecificSyntaxError //!< Unspecific syntax error.
+};
+
+//! Result of parsing (wraps ParseErrorCode)
+/*!
+ \ingroup RAPIDJSON_ERRORS
+ \code
+ Document doc;
+ ParseResult ok = doc.Parse("[42]");
+ if (!ok) {
+ fprintf(stderr, "JSON parse error: %s (%u)",
+ GetParseError_En(ok.Code()), ok.Offset());
+ exit(EXIT_FAILURE);
+ }
+ \endcode
+ \see GenericReader::Parse, GenericDocument::Parse
+*/
+struct ParseResult {
+ public:
+ //! Default constructor, no error.
+ ParseResult() : code_(kParseErrorNone), offset_(0) {}
+ //! Constructor to set an error.
+ ParseResult(ParseErrorCode code, size_t offset)
+ : code_(code), offset_(offset) {}
+
+ //! Get the error code.
+ ParseErrorCode Code() const { return code_; }
+ //! Get the error offset, if \ref IsError(), 0 otherwise.
+ size_t Offset() const { return offset_; }
+
+ //! Conversion to \c bool, returns \c true, iff !\ref IsError().
+ operator bool() const { return !IsError(); }
+ //! Whether the result is an error.
+ bool IsError() const { return code_ != kParseErrorNone; }
+
+ bool operator==(const ParseResult& that) const { return code_ == that.code_; }
+ bool operator==(ParseErrorCode code) const { return code_ == code; }
+ friend bool operator==(ParseErrorCode code, const ParseResult& err) {
+ return code == err.code_;
+ }
+
+ //! Reset error code.
+ void Clear() { Set(kParseErrorNone); }
+ //! Update error code and offset.
+ void Set(ParseErrorCode code, size_t offset = 0) {
+ code_ = code;
+ offset_ = offset;
+ }
+
+ private:
+ ParseErrorCode code_;
+ size_t offset_;
+};
+
+//! Function pointer type of GetParseError().
+/*! \ingroup RAPIDJSON_ERRORS
+
+ This is the prototype for \c GetParseError_X(), where \c X is a locale.
+ User can dynamically change locale in runtime, e.g.:
+\code
+ GetParseErrorFunc GetParseError = GetParseError_En; // or whatever
+ const RAPIDJSON_ERROR_CHARTYPE* s =
+GetParseError(document.GetParseErrorCode()); \endcode
+*/
+typedef const RAPIDJSON_ERROR_CHARTYPE* (*GetParseErrorFunc)(ParseErrorCode);
+
+RAPIDJSON_NAMESPACE_END
+
+#ifdef __clang__
+RAPIDJSON_DIAG_POP
+#endif
+
+#endif // RAPIDJSON_ERROR_ERROR_H_
diff --git a/include/rapidjson/filereadstream.h b/third_party/rapidjson/filereadstream.h
index b56ea13b..b56ea13b 100644
--- a/include/rapidjson/filereadstream.h
+++ b/third_party/rapidjson/filereadstream.h
diff --git a/include/rapidjson/filewritestream.h b/third_party/rapidjson/filewritestream.h
index 6378dd60..6378dd60 100644
--- a/include/rapidjson/filewritestream.h
+++ b/third_party/rapidjson/filewritestream.h
diff --git a/include/rapidjson/fwd.h b/third_party/rapidjson/fwd.h
index e8104e84..e8104e84 100644
--- a/include/rapidjson/fwd.h
+++ b/third_party/rapidjson/fwd.h
diff --git a/third_party/rapidjson/internal/biginteger.h b/third_party/rapidjson/internal/biginteger.h
new file mode 100644
index 00000000..bd6c0539
--- /dev/null
+++ b/third_party/rapidjson/internal/biginteger.h
@@ -0,0 +1,319 @@
+// Tencent is pleased to support the open source community by making RapidJSON
+// available.
+//
+// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All
+// rights reserved.
+//
+// Licensed under the MIT License (the "License"); you may not use this file
+// except in compliance with the License. You may obtain a copy of the License
+// at
+//
+// http://opensource.org/licenses/MIT
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+// License for the specific language governing permissions and limitations under
+// the License.
+
+#ifndef RAPIDJSON_BIGINTEGER_H_
+#define RAPIDJSON_BIGINTEGER_H_
+
+#include "rapidjson/rapidjson.h"
+
+#if defined(_MSC_VER) && defined(_M_AMD64)
+#include <intrin.h> // for _umul128
+#pragma intrinsic(_umul128)
+#endif
+
+RAPIDJSON_NAMESPACE_BEGIN
+namespace internal {
+
+class BigInteger {
+ public:
+ typedef uint64_t Type;
+
+ BigInteger(const BigInteger& rhs) : count_(rhs.count_) {
+ std::memcpy(digits_, rhs.digits_, count_ * sizeof(Type));
+ }
+
+ explicit BigInteger(uint64_t u) : count_(1) { digits_[0] = u; }
+
+ BigInteger(const char* decimals, size_t length) : count_(1) {
+ RAPIDJSON_ASSERT(length > 0);
+ digits_[0] = 0;
+ size_t i = 0;
+ const size_t kMaxDigitPerIteration =
+ 19; // 2^64 = 18446744073709551616 > 10^19
+ while (length >= kMaxDigitPerIteration) {
+ AppendDecimal64(decimals + i, decimals + i + kMaxDigitPerIteration);
+ length -= kMaxDigitPerIteration;
+ i += kMaxDigitPerIteration;
+ }
+
+ if (length > 0)
+ AppendDecimal64(decimals + i, decimals + i + length);
+ }
+
+ BigInteger& operator=(const BigInteger& rhs) {
+ if (this != &rhs) {
+ count_ = rhs.count_;
+ std::memcpy(digits_, rhs.digits_, count_ * sizeof(Type));
+ }
+ return *this;
+ }
+
+ BigInteger& operator=(uint64_t u) {
+ digits_[0] = u;
+ count_ = 1;
+ return *this;
+ }
+
+ BigInteger& operator+=(uint64_t u) {
+ Type backup = digits_[0];
+ digits_[0] += u;
+ for (size_t i = 0; i < count_ - 1; i++) {
+ if (digits_[i] >= backup)
+ return *this; // no carry
+ backup = digits_[i + 1];
+ digits_[i + 1] += 1;
+ }
+
+ // Last carry
+ if (digits_[count_ - 1] < backup)
+ PushBack(1);
+
+ return *this;
+ }
+
+ BigInteger& operator*=(uint64_t u) {
+ if (u == 0)
+ return *this = 0;
+ if (u == 1)
+ return *this;
+ if (*this == 1)
+ return *this = u;
+
+ uint64_t k = 0;
+ for (size_t i = 0; i < count_; i++) {
+ uint64_t hi;
+ digits_[i] = MulAdd64(digits_[i], u, k, &hi);
+ k = hi;
+ }
+
+ if (k > 0)
+ PushBack(k);
+
+ return *this;
+ }
+
+ BigInteger& operator*=(uint32_t u) {
+ if (u == 0)
+ return *this = 0;
+ if (u == 1)
+ return *this;
+ if (*this == 1)
+ return *this = u;
+
+ uint64_t k = 0;
+ for (size_t i = 0; i < count_; i++) {
+ const uint64_t c = digits_[i] >> 32;
+ const uint64_t d = digits_[i] & 0xFFFFFFFF;
+ const uint64_t uc = u * c;
+ const uint64_t ud = u * d;
+ const uint64_t p0 = ud + k;
+ const uint64_t p1 = uc + (p0 >> 32);
+ digits_[i] = (p0 & 0xFFFFFFFF) | (p1 << 32);
+ k = p1 >> 32;
+ }
+
+ if (k > 0)
+ PushBack(k);
+
+ return *this;
+ }
+
+ BigInteger& operator<<=(size_t shift) {
+ if (IsZero() || shift == 0)
+ return *this;
+
+ size_t offset = shift / kTypeBit;
+ size_t interShift = shift % kTypeBit;
+ RAPIDJSON_ASSERT(count_ + offset <= kCapacity);
+
+ if (interShift == 0) {
+ std::memmove(&digits_[count_ - 1 + offset], &digits_[count_ - 1],
+ count_ * sizeof(Type));
+ count_ += offset;
+ } else {
+ digits_[count_] = 0;
+ for (size_t i = count_; i > 0; i--)
+ digits_[i + offset] = (digits_[i] << interShift) |
+ (digits_[i - 1] >> (kTypeBit - interShift));
+ digits_[offset] = digits_[0] << interShift;
+ count_ += offset;
+ if (digits_[count_])
+ count_++;
+ }
+
+ std::memset(digits_, 0, offset * sizeof(Type));
+
+ return *this;
+ }
+
+ bool operator==(const BigInteger& rhs) const {
+ return count_ == rhs.count_ &&
+ std::memcmp(digits_, rhs.digits_, count_ * sizeof(Type)) == 0;
+ }
+
+ bool operator==(const Type rhs) const {
+ return count_ == 1 && digits_[0] == rhs;
+ }
+
+ BigInteger& MultiplyPow5(unsigned exp) {
+ static const uint32_t kPow5[12] = {
+ 5,
+ 5 * 5,
+ 5 * 5 * 5,
+ 5 * 5 * 5 * 5,
+ 5 * 5 * 5 * 5 * 5,
+ 5 * 5 * 5 * 5 * 5 * 5,
+ 5 * 5 * 5 * 5 * 5 * 5 * 5,
+ 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5,
+ 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5,
+ 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5,
+ 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5,
+ 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5 * 5};
+ if (exp == 0)
+ return *this;
+ for (; exp >= 27; exp -= 27)
+ *this *= RAPIDJSON_UINT64_C2(0X6765C793, 0XFA10079D); // 5^27
+ for (; exp >= 13; exp -= 13)
+ *this *= static_cast<uint32_t>(1220703125u); // 5^13
+ if (exp > 0)
+ *this *= kPow5[exp - 1];
+ return *this;
+ }
+
+ // Compute absolute difference of this and rhs.
+ // Assume this != rhs
+ bool Difference(const BigInteger& rhs, BigInteger* out) const {
+ int cmp = Compare(rhs);
+ RAPIDJSON_ASSERT(cmp != 0);
+ const BigInteger *a, *b; // Makes a > b
+ bool ret;
+ if (cmp < 0) {
+ a = &rhs;
+ b = this;
+ ret = true;
+ } else {
+ a = this;
+ b = &rhs;
+ ret = false;
+ }
+
+ Type borrow = 0;
+ for (size_t i = 0; i < a->count_; i++) {
+ Type d = a->digits_[i] - borrow;
+ if (i < b->count_)
+ d -= b->digits_[i];
+ borrow = (d > a->digits_[i]) ? 1 : 0;
+ out->digits_[i] = d;
+ if (d != 0)
+ out->count_ = i + 1;
+ }
+
+ return ret;
+ }
+
+ int Compare(const BigInteger& rhs) const {
+ if (count_ != rhs.count_)
+ return count_ < rhs.count_ ? -1 : 1;
+
+ for (size_t i = count_; i-- > 0;)
+ if (digits_[i] != rhs.digits_[i])
+ return digits_[i] < rhs.digits_[i] ? -1 : 1;
+
+ return 0;
+ }
+
+ size_t GetCount() const { return count_; }
+ Type GetDigit(size_t index) const {
+ RAPIDJSON_ASSERT(index < count_);
+ return digits_[index];
+ }
+ bool IsZero() const { return count_ == 1 && digits_[0] == 0; }
+
+ private:
+ void AppendDecimal64(const char* begin, const char* end) {
+ uint64_t u = ParseUint64(begin, end);
+ if (IsZero())
+ *this = u;
+ else {
+ unsigned exp = static_cast<unsigned>(end - begin);
+ (MultiplyPow5(exp) <<= exp) += u; // *this = *this * 10^exp + u
+ }
+ }
+
+ void PushBack(Type digit) {
+ RAPIDJSON_ASSERT(count_ < kCapacity);
+ digits_[count_++] = digit;
+ }
+
+ static uint64_t ParseUint64(const char* begin, const char* end) {
+ uint64_t r = 0;
+ for (const char* p = begin; p != end; ++p) {
+ RAPIDJSON_ASSERT(*p >= '0' && *p <= '9');
+ r = r * 10u + static_cast<unsigned>(*p - '0');
+ }
+ return r;
+ }
+
+ // Assume a * b + k < 2^128
+ static uint64_t MulAdd64(uint64_t a,
+ uint64_t b,
+ uint64_t k,
+ uint64_t* outHigh) {
+#if defined(_MSC_VER) && defined(_M_AMD64)
+ uint64_t low = _umul128(a, b, outHigh) + k;
+ if (low < k)
+ (*outHigh)++;
+ return low;
+#elif (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6)) && \
+ defined(__x86_64__)
+ __extension__ typedef unsigned __int128 uint128;
+ uint128 p = static_cast<uint128>(a) * static_cast<uint128>(b);
+ p += k;
+ *outHigh = static_cast<uint64_t>(p >> 64);
+ return static_cast<uint64_t>(p);
+#else
+ const uint64_t a0 = a & 0xFFFFFFFF, a1 = a >> 32, b0 = b & 0xFFFFFFFF,
+ b1 = b >> 32;
+ uint64_t x0 = a0 * b0, x1 = a0 * b1, x2 = a1 * b0, x3 = a1 * b1;
+ x1 += (x0 >> 32); // can't give carry
+ x1 += x2;
+ if (x1 < x2)
+ x3 += (static_cast<uint64_t>(1) << 32);
+ uint64_t lo = (x1 << 32) + (x0 & 0xFFFFFFFF);
+ uint64_t hi = x3 + (x1 >> 32);
+
+ lo += k;
+ if (lo < k)
+ hi++;
+ *outHigh = hi;
+ return lo;
+#endif
+ }
+
+ static const size_t kBitCount = 3328; // 64bit * 54 > 10^1000
+ static const size_t kCapacity = kBitCount / sizeof(Type);
+ static const size_t kTypeBit = sizeof(Type) * 8;
+
+ Type digits_[kCapacity];
+ size_t count_;
+};
+
+} // namespace internal
+RAPIDJSON_NAMESPACE_END
+
+#endif // RAPIDJSON_BIGINTEGER_H_
diff --git a/third_party/rapidjson/internal/diyfp.h b/third_party/rapidjson/internal/diyfp.h
new file mode 100644
index 00000000..1f3d0e16
--- /dev/null
+++ b/third_party/rapidjson/internal/diyfp.h
@@ -0,0 +1,307 @@
+// Tencent is pleased to support the open source community by making RapidJSON
+// available.
+//
+// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All
+// rights reserved.
+//
+// Licensed under the MIT License (the "License"); you may not use this file
+// except in compliance with the License. You may obtain a copy of the License
+// at
+//
+// http://opensource.org/licenses/MIT
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+// License for the specific language governing permissions and limitations under
+// the License.
+
+// This is a C++ header-only implementation of Grisu2 algorithm from the
+// publication: Loitsch, Florian. "Printing floating-point numbers quickly and
+// accurately with integers." ACM Sigplan Notices 45.6 (2010): 233-243.
+
+#ifndef RAPIDJSON_DIYFP_H_
+#define RAPIDJSON_DIYFP_H_
+
+#include "rapidjson/rapidjson.h"
+
+#if defined(_MSC_VER) && defined(_M_AMD64)
+#include <intrin.h>
+#pragma intrinsic(_BitScanReverse64)
+#pragma intrinsic(_umul128)
+#endif
+
+RAPIDJSON_NAMESPACE_BEGIN
+namespace internal {
+
+#ifdef __GNUC__
+RAPIDJSON_DIAG_PUSH
+RAPIDJSON_DIAG_OFF(effc++)
+#endif
+
+#ifdef __clang__
+RAPIDJSON_DIAG_PUSH
+RAPIDJSON_DIAG_OFF(padded)
+#endif
+
+struct DiyFp {
+ DiyFp() : f(), e() {}
+
+ DiyFp(uint64_t fp, int exp) : f(fp), e(exp) {}
+
+ explicit DiyFp(double d) {
+ union {
+ double d;
+ uint64_t u64;
+ } u = {d};
+
+ int biased_e =
+ static_cast<int>((u.u64 & kDpExponentMask) >> kDpSignificandSize);
+ uint64_t significand = (u.u64 & kDpSignificandMask);
+ if (biased_e != 0) {
+ f = significand + kDpHiddenBit;
+ e = biased_e - kDpExponentBias;
+ } else {
+ f = significand;
+ e = kDpMinExponent + 1;
+ }
+ }
+
+ DiyFp operator-(const DiyFp& rhs) const { return DiyFp(f - rhs.f, e); }
+
+ DiyFp operator*(const DiyFp& rhs) const {
+#if defined(_MSC_VER) && defined(_M_AMD64)
+ uint64_t h;
+ uint64_t l = _umul128(f, rhs.f, &h);
+ if (l & (uint64_t(1) << 63)) // rounding
+ h++;
+ return DiyFp(h, e + rhs.e + 64);
+#elif (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6)) && \
+ defined(__x86_64__)
+ __extension__ typedef unsigned __int128 uint128;
+ uint128 p = static_cast<uint128>(f) * static_cast<uint128>(rhs.f);
+ uint64_t h = static_cast<uint64_t>(p >> 64);
+ uint64_t l = static_cast<uint64_t>(p);
+ if (l & (uint64_t(1) << 63)) // rounding
+ h++;
+ return DiyFp(h, e + rhs.e + 64);
+#else
+ const uint64_t M32 = 0xFFFFFFFF;
+ const uint64_t a = f >> 32;
+ const uint64_t b = f & M32;
+ const uint64_t c = rhs.f >> 32;
+ const uint64_t d = rhs.f & M32;
+ const uint64_t ac = a * c;
+ const uint64_t bc = b * c;
+ const uint64_t ad = a * d;
+ const uint64_t bd = b * d;
+ uint64_t tmp = (bd >> 32) + (ad & M32) + (bc & M32);
+ tmp += 1U << 31; /// mult_round
+ return DiyFp(ac + (ad >> 32) + (bc >> 32) + (tmp >> 32), e + rhs.e + 64);
+#endif
+ }
+
+ DiyFp Normalize() const {
+#if defined(_MSC_VER) && defined(_M_AMD64)
+ unsigned long index;
+ _BitScanReverse64(&index, f);
+ return DiyFp(f << (63 - index), e - (63 - index));
+#elif defined(__GNUC__) && __GNUC__ >= 4
+ int s = __builtin_clzll(f);
+ return DiyFp(f << s, e - s);
+#else
+ DiyFp res = *this;
+ while (!(res.f & (static_cast<uint64_t>(1) << 63))) {
+ res.f <<= 1;
+ res.e--;
+ }
+ return res;
+#endif
+ }
+
+ DiyFp NormalizeBoundary() const {
+ DiyFp res = *this;
+ while (!(res.f & (kDpHiddenBit << 1))) {
+ res.f <<= 1;
+ res.e--;
+ }
+ res.f <<= (kDiySignificandSize - kDpSignificandSize - 2);
+ res.e = res.e - (kDiySignificandSize - kDpSignificandSize - 2);
+ return res;
+ }
+
+ void NormalizedBoundaries(DiyFp* minus, DiyFp* plus) const {
+ DiyFp pl = DiyFp((f << 1) + 1, e - 1).NormalizeBoundary();
+ DiyFp mi = (f == kDpHiddenBit) ? DiyFp((f << 2) - 1, e - 2)
+ : DiyFp((f << 1) - 1, e - 1);
+ mi.f <<= mi.e - pl.e;
+ mi.e = pl.e;
+ *plus = pl;
+ *minus = mi;
+ }
+
+ double ToDouble() const {
+ union {
+ double d;
+ uint64_t u64;
+ } u;
+ const uint64_t be = (e == kDpDenormalExponent && (f & kDpHiddenBit) == 0)
+ ? 0
+ : static_cast<uint64_t>(e + kDpExponentBias);
+ u.u64 = (f & kDpSignificandMask) | (be << kDpSignificandSize);
+ return u.d;
+ }
+
+ static const int kDiySignificandSize = 64;
+ static const int kDpSignificandSize = 52;
+ static const int kDpExponentBias = 0x3FF + kDpSignificandSize;
+ static const int kDpMaxExponent = 0x7FF - kDpExponentBias;
+ static const int kDpMinExponent = -kDpExponentBias;
+ static const int kDpDenormalExponent = -kDpExponentBias + 1;
+ static const uint64_t kDpExponentMask =
+ RAPIDJSON_UINT64_C2(0x7FF00000, 0x00000000);
+ static const uint64_t kDpSignificandMask =
+ RAPIDJSON_UINT64_C2(0x000FFFFF, 0xFFFFFFFF);
+ static const uint64_t kDpHiddenBit =
+ RAPIDJSON_UINT64_C2(0x00100000, 0x00000000);
+
+ uint64_t f;
+ int e;
+};
+
+inline DiyFp GetCachedPowerByIndex(size_t index) {
+ // 10^-348, 10^-340, ..., 10^340
+ static const uint64_t kCachedPowers_F[] = {
+ RAPIDJSON_UINT64_C2(0xfa8fd5a0, 0x081c0288),
+ RAPIDJSON_UINT64_C2(0xbaaee17f, 0xa23ebf76),
+ RAPIDJSON_UINT64_C2(0x8b16fb20, 0x3055ac76),
+ RAPIDJSON_UINT64_C2(0xcf42894a, 0x5dce35ea),
+ RAPIDJSON_UINT64_C2(0x9a6bb0aa, 0x55653b2d),
+ RAPIDJSON_UINT64_C2(0xe61acf03, 0x3d1a45df),
+ RAPIDJSON_UINT64_C2(0xab70fe17, 0xc79ac6ca),
+ RAPIDJSON_UINT64_C2(0xff77b1fc, 0xbebcdc4f),
+ RAPIDJSON_UINT64_C2(0xbe5691ef, 0x416bd60c),
+ RAPIDJSON_UINT64_C2(0x8dd01fad, 0x907ffc3c),
+ RAPIDJSON_UINT64_C2(0xd3515c28, 0x31559a83),
+ RAPIDJSON_UINT64_C2(0x9d71ac8f, 0xada6c9b5),
+ RAPIDJSON_UINT64_C2(0xea9c2277, 0x23ee8bcb),
+ RAPIDJSON_UINT64_C2(0xaecc4991, 0x4078536d),
+ RAPIDJSON_UINT64_C2(0x823c1279, 0x5db6ce57),
+ RAPIDJSON_UINT64_C2(0xc2109436, 0x4dfb5637),
+ RAPIDJSON_UINT64_C2(0x9096ea6f, 0x3848984f),
+ RAPIDJSON_UINT64_C2(0xd77485cb, 0x25823ac7),
+ RAPIDJSON_UINT64_C2(0xa086cfcd, 0x97bf97f4),
+ RAPIDJSON_UINT64_C2(0xef340a98, 0x172aace5),
+ RAPIDJSON_UINT64_C2(0xb23867fb, 0x2a35b28e),
+ RAPIDJSON_UINT64_C2(0x84c8d4df, 0xd2c63f3b),
+ RAPIDJSON_UINT64_C2(0xc5dd4427, 0x1ad3cdba),
+ RAPIDJSON_UINT64_C2(0x936b9fce, 0xbb25c996),
+ RAPIDJSON_UINT64_C2(0xdbac6c24, 0x7d62a584),
+ RAPIDJSON_UINT64_C2(0xa3ab6658, 0x0d5fdaf6),
+ RAPIDJSON_UINT64_C2(0xf3e2f893, 0xdec3f126),
+ RAPIDJSON_UINT64_C2(0xb5b5ada8, 0xaaff80b8),
+ RAPIDJSON_UINT64_C2(0x87625f05, 0x6c7c4a8b),
+ RAPIDJSON_UINT64_C2(0xc9bcff60, 0x34c13053),
+ RAPIDJSON_UINT64_C2(0x964e858c, 0x91ba2655),
+ RAPIDJSON_UINT64_C2(0xdff97724, 0x70297ebd),
+ RAPIDJSON_UINT64_C2(0xa6dfbd9f, 0xb8e5b88f),
+ RAPIDJSON_UINT64_C2(0xf8a95fcf, 0x88747d94),
+ RAPIDJSON_UINT64_C2(0xb9447093, 0x8fa89bcf),
+ RAPIDJSON_UINT64_C2(0x8a08f0f8, 0xbf0f156b),
+ RAPIDJSON_UINT64_C2(0xcdb02555, 0x653131b6),
+ RAPIDJSON_UINT64_C2(0x993fe2c6, 0xd07b7fac),
+ RAPIDJSON_UINT64_C2(0xe45c10c4, 0x2a2b3b06),
+ RAPIDJSON_UINT64_C2(0xaa242499, 0x697392d3),
+ RAPIDJSON_UINT64_C2(0xfd87b5f2, 0x8300ca0e),
+ RAPIDJSON_UINT64_C2(0xbce50864, 0x92111aeb),
+ RAPIDJSON_UINT64_C2(0x8cbccc09, 0x6f5088cc),
+ RAPIDJSON_UINT64_C2(0xd1b71758, 0xe219652c),
+ RAPIDJSON_UINT64_C2(0x9c400000, 0x00000000),
+ RAPIDJSON_UINT64_C2(0xe8d4a510, 0x00000000),
+ RAPIDJSON_UINT64_C2(0xad78ebc5, 0xac620000),
+ RAPIDJSON_UINT64_C2(0x813f3978, 0xf8940984),
+ RAPIDJSON_UINT64_C2(0xc097ce7b, 0xc90715b3),
+ RAPIDJSON_UINT64_C2(0x8f7e32ce, 0x7bea5c70),
+ RAPIDJSON_UINT64_C2(0xd5d238a4, 0xabe98068),
+ RAPIDJSON_UINT64_C2(0x9f4f2726, 0x179a2245),
+ RAPIDJSON_UINT64_C2(0xed63a231, 0xd4c4fb27),
+ RAPIDJSON_UINT64_C2(0xb0de6538, 0x8cc8ada8),
+ RAPIDJSON_UINT64_C2(0x83c7088e, 0x1aab65db),
+ RAPIDJSON_UINT64_C2(0xc45d1df9, 0x42711d9a),
+ RAPIDJSON_UINT64_C2(0x924d692c, 0xa61be758),
+ RAPIDJSON_UINT64_C2(0xda01ee64, 0x1a708dea),
+ RAPIDJSON_UINT64_C2(0xa26da399, 0x9aef774a),
+ RAPIDJSON_UINT64_C2(0xf209787b, 0xb47d6b85),
+ RAPIDJSON_UINT64_C2(0xb454e4a1, 0x79dd1877),
+ RAPIDJSON_UINT64_C2(0x865b8692, 0x5b9bc5c2),
+ RAPIDJSON_UINT64_C2(0xc83553c5, 0xc8965d3d),
+ RAPIDJSON_UINT64_C2(0x952ab45c, 0xfa97a0b3),
+ RAPIDJSON_UINT64_C2(0xde469fbd, 0x99a05fe3),
+ RAPIDJSON_UINT64_C2(0xa59bc234, 0xdb398c25),
+ RAPIDJSON_UINT64_C2(0xf6c69a72, 0xa3989f5c),
+ RAPIDJSON_UINT64_C2(0xb7dcbf53, 0x54e9bece),
+ RAPIDJSON_UINT64_C2(0x88fcf317, 0xf22241e2),
+ RAPIDJSON_UINT64_C2(0xcc20ce9b, 0xd35c78a5),
+ RAPIDJSON_UINT64_C2(0x98165af3, 0x7b2153df),
+ RAPIDJSON_UINT64_C2(0xe2a0b5dc, 0x971f303a),
+ RAPIDJSON_UINT64_C2(0xa8d9d153, 0x5ce3b396),
+ RAPIDJSON_UINT64_C2(0xfb9b7cd9, 0xa4a7443c),
+ RAPIDJSON_UINT64_C2(0xbb764c4c, 0xa7a44410),
+ RAPIDJSON_UINT64_C2(0x8bab8eef, 0xb6409c1a),
+ RAPIDJSON_UINT64_C2(0xd01fef10, 0xa657842c),
+ RAPIDJSON_UINT64_C2(0x9b10a4e5, 0xe9913129),
+ RAPIDJSON_UINT64_C2(0xe7109bfb, 0xa19c0c9d),
+ RAPIDJSON_UINT64_C2(0xac2820d9, 0x623bf429),
+ RAPIDJSON_UINT64_C2(0x80444b5e, 0x7aa7cf85),
+ RAPIDJSON_UINT64_C2(0xbf21e440, 0x03acdd2d),
+ RAPIDJSON_UINT64_C2(0x8e679c2f, 0x5e44ff8f),
+ RAPIDJSON_UINT64_C2(0xd433179d, 0x9c8cb841),
+ RAPIDJSON_UINT64_C2(0x9e19db92, 0xb4e31ba9),
+ RAPIDJSON_UINT64_C2(0xeb96bf6e, 0xbadf77d9),
+ RAPIDJSON_UINT64_C2(0xaf87023b, 0x9bf0ee6b)};
+ static const int16_t kCachedPowers_E[] = {
+ -1220, -1193, -1166, -1140, -1113, -1087, -1060, -1034, -1007, -980, -954,
+ -927, -901, -874, -847, -821, -794, -768, -741, -715, -688, -661,
+ -635, -608, -582, -555, -529, -502, -475, -449, -422, -396, -369,
+ -343, -316, -289, -263, -236, -210, -183, -157, -130, -103, -77,
+ -50, -24, 3, 30, 56, 83, 109, 136, 162, 189, 216,
+ 242, 269, 295, 322, 348, 375, 402, 428, 455, 481, 508,
+ 534, 561, 588, 614, 641, 667, 694, 720, 747, 774, 800,
+ 827, 853, 880, 907, 933, 960, 986, 1013, 1039, 1066};
+ return DiyFp(kCachedPowers_F[index], kCachedPowers_E[index]);
+}
+
+inline DiyFp GetCachedPower(int e, int* K) {
+ // int k = static_cast<int>(ceil((-61 - e) * 0.30102999566398114)) + 374;
+ double dk = (-61 - e) * 0.30102999566398114 +
+ 347; // dk must be positive, so can do ceiling in positive
+ int k = static_cast<int>(dk);
+ if (dk - k > 0.0)
+ k++;
+
+ unsigned index = static_cast<unsigned>((k >> 3) + 1);
+ *K = -(-348 + static_cast<int>(
+ index << 3)); // decimal exponent no need lookup table
+
+ return GetCachedPowerByIndex(index);
+}
+
+inline DiyFp GetCachedPower10(int exp, int* outExp) {
+ unsigned index = (static_cast<unsigned>(exp) + 348u) / 8u;
+ *outExp = -348 + static_cast<int>(index) * 8;
+ return GetCachedPowerByIndex(index);
+}
+
+#ifdef __GNUC__
+RAPIDJSON_DIAG_POP
+#endif
+
+#ifdef __clang__
+RAPIDJSON_DIAG_POP
+RAPIDJSON_DIAG_OFF(padded)
+#endif
+
+} // namespace internal
+RAPIDJSON_NAMESPACE_END
+
+#endif // RAPIDJSON_DIYFP_H_
diff --git a/include/rapidjson/internal/dtoa.h b/third_party/rapidjson/internal/dtoa.h
index 8d6350e6..8d6350e6 100644
--- a/include/rapidjson/internal/dtoa.h
+++ b/third_party/rapidjson/internal/dtoa.h
diff --git a/third_party/rapidjson/internal/ieee754.h b/third_party/rapidjson/internal/ieee754.h
new file mode 100644
index 00000000..9a84d645
--- /dev/null
+++ b/third_party/rapidjson/internal/ieee754.h
@@ -0,0 +1,100 @@
+// Tencent is pleased to support the open source community by making RapidJSON
+// available.
+//
+// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All
+// rights reserved.
+//
+// Licensed under the MIT License (the "License"); you may not use this file
+// except in compliance with the License. You may obtain a copy of the License
+// at
+//
+// http://opensource.org/licenses/MIT
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+// License for the specific language governing permissions and limitations under
+// the License.
+
+#ifndef RAPIDJSON_IEEE754_
+#define RAPIDJSON_IEEE754_
+
+#include "rapidjson/rapidjson.h"
+
+RAPIDJSON_NAMESPACE_BEGIN
+namespace internal {
+
+class Double {
+ public:
+ Double() {}
+ Double(double d) : d_(d) {}
+ Double(uint64_t u) : u_(u) {}
+
+ double Value() const { return d_; }
+ uint64_t Uint64Value() const { return u_; }
+
+ double NextPositiveDouble() const {
+ RAPIDJSON_ASSERT(!Sign());
+ return Double(u_ + 1).Value();
+ }
+
+ bool Sign() const { return (u_ & kSignMask) != 0; }
+ uint64_t Significand() const { return u_ & kSignificandMask; }
+ int Exponent() const {
+ return static_cast<int>(((u_ & kExponentMask) >> kSignificandSize) -
+ kExponentBias);
+ }
+
+ bool IsNan() const {
+ return (u_ & kExponentMask) == kExponentMask && Significand() != 0;
+ }
+ bool IsInf() const {
+ return (u_ & kExponentMask) == kExponentMask && Significand() == 0;
+ }
+ bool IsNanOrInf() const { return (u_ & kExponentMask) == kExponentMask; }
+ bool IsNormal() const {
+ return (u_ & kExponentMask) != 0 || Significand() == 0;
+ }
+ bool IsZero() const { return (u_ & (kExponentMask | kSignificandMask)) == 0; }
+
+ uint64_t IntegerSignificand() const {
+ return IsNormal() ? Significand() | kHiddenBit : Significand();
+ }
+ int IntegerExponent() const {
+ return (IsNormal() ? Exponent() : kDenormalExponent) - kSignificandSize;
+ }
+ uint64_t ToBias() const {
+ return (u_ & kSignMask) ? ~u_ + 1 : u_ | kSignMask;
+ }
+
+ static unsigned EffectiveSignificandSize(int order) {
+ if (order >= -1021)
+ return 53;
+ else if (order <= -1074)
+ return 0;
+ else
+ return static_cast<unsigned>(order) + 1074;
+ }
+
+ private:
+ static const int kSignificandSize = 52;
+ static const int kExponentBias = 0x3FF;
+ static const int kDenormalExponent = 1 - kExponentBias;
+ static const uint64_t kSignMask = RAPIDJSON_UINT64_C2(0x80000000, 0x00000000);
+ static const uint64_t kExponentMask =
+ RAPIDJSON_UINT64_C2(0x7FF00000, 0x00000000);
+ static const uint64_t kSignificandMask =
+ RAPIDJSON_UINT64_C2(0x000FFFFF, 0xFFFFFFFF);
+ static const uint64_t kHiddenBit =
+ RAPIDJSON_UINT64_C2(0x00100000, 0x00000000);
+
+ union {
+ double d_;
+ uint64_t u_;
+ };
+};
+
+} // namespace internal
+RAPIDJSON_NAMESPACE_END
+
+#endif // RAPIDJSON_IEEE754_
diff --git a/third_party/rapidjson/internal/itoa.h b/third_party/rapidjson/internal/itoa.h
new file mode 100644
index 00000000..630be875
--- /dev/null
+++ b/third_party/rapidjson/internal/itoa.h
@@ -0,0 +1,303 @@
+// Tencent is pleased to support the open source community by making RapidJSON
+// available.
+//
+// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All
+// rights reserved.
+//
+// Licensed under the MIT License (the "License"); you may not use this file
+// except in compliance with the License. You may obtain a copy of the License
+// at
+//
+// http://opensource.org/licenses/MIT
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+// License for the specific language governing permissions and limitations under
+// the License.
+
+#ifndef RAPIDJSON_ITOA_
+#define RAPIDJSON_ITOA_
+
+#include "rapidjson/rapidjson.h"
+
+RAPIDJSON_NAMESPACE_BEGIN
+namespace internal {
+
+inline const char* GetDigitsLut() {
+ static const char cDigitsLut[200] = {
+ '0', '0', '0', '1', '0', '2', '0', '3', '0', '4', '0', '5', '0', '6', '0',
+ '7', '0', '8', '0', '9', '1', '0', '1', '1', '1', '2', '1', '3', '1', '4',
+ '1', '5', '1', '6', '1', '7', '1', '8', '1', '9', '2', '0', '2', '1', '2',
+ '2', '2', '3', '2', '4', '2', '5', '2', '6', '2', '7', '2', '8', '2', '9',
+ '3', '0', '3', '1', '3', '2', '3', '3', '3', '4', '3', '5', '3', '6', '3',
+ '7', '3', '8', '3', '9', '4', '0', '4', '1', '4', '2', '4', '3', '4', '4',
+ '4', '5', '4', '6', '4', '7', '4', '8', '4', '9', '5', '0', '5', '1', '5',
+ '2', '5', '3', '5', '4', '5', '5', '5', '6', '5', '7', '5', '8', '5', '9',
+ '6', '0', '6', '1', '6', '2', '6', '3', '6', '4', '6', '5', '6', '6', '6',
+ '7', '6', '8', '6', '9', '7', '0', '7', '1', '7', '2', '7', '3', '7', '4',
+ '7', '5', '7', '6', '7', '7', '7', '8', '7', '9', '8', '0', '8', '1', '8',
+ '2', '8', '3', '8', '4', '8', '5', '8', '6', '8', '7', '8', '8', '8', '9',
+ '9', '0', '9', '1', '9', '2', '9', '3', '9', '4', '9', '5', '9', '6', '9',
+ '7', '9', '8', '9', '9'};
+ return cDigitsLut;
+}
+
+inline char* u32toa(uint32_t value, char* buffer) {
+ const char* cDigitsLut = GetDigitsLut();
+
+ if (value < 10000) {
+ const uint32_t d1 = (value / 100) << 1;
+ const uint32_t d2 = (value % 100) << 1;
+
+ if (value >= 1000)
+ *buffer++ = cDigitsLut[d1];
+ if (value >= 100)
+ *buffer++ = cDigitsLut[d1 + 1];
+ if (value >= 10)
+ *buffer++ = cDigitsLut[d2];
+ *buffer++ = cDigitsLut[d2 + 1];
+ } else if (value < 100000000) {
+ // value = bbbbcccc
+ const uint32_t b = value / 10000;
+ const uint32_t c = value % 10000;
+
+ const uint32_t d1 = (b / 100) << 1;
+ const uint32_t d2 = (b % 100) << 1;
+
+ const uint32_t d3 = (c / 100) << 1;
+ const uint32_t d4 = (c % 100) << 1;
+
+ if (value >= 10000000)
+ *buffer++ = cDigitsLut[d1];
+ if (value >= 1000000)
+ *buffer++ = cDigitsLut[d1 + 1];
+ if (value >= 100000)
+ *buffer++ = cDigitsLut[d2];
+ *buffer++ = cDigitsLut[d2 + 1];
+
+ *buffer++ = cDigitsLut[d3];
+ *buffer++ = cDigitsLut[d3 + 1];
+ *buffer++ = cDigitsLut[d4];
+ *buffer++ = cDigitsLut[d4 + 1];
+ } else {
+ // value = aabbbbcccc in decimal
+
+ const uint32_t a = value / 100000000; // 1 to 42
+ value %= 100000000;
+
+ if (a >= 10) {
+ const unsigned i = a << 1;
+ *buffer++ = cDigitsLut[i];
+ *buffer++ = cDigitsLut[i + 1];
+ } else
+ *buffer++ = static_cast<char>('0' + static_cast<char>(a));
+
+ const uint32_t b = value / 10000; // 0 to 9999
+ const uint32_t c = value % 10000; // 0 to 9999
+
+ const uint32_t d1 = (b / 100) << 1;
+ const uint32_t d2 = (b % 100) << 1;
+
+ const uint32_t d3 = (c / 100) << 1;
+ const uint32_t d4 = (c % 100) << 1;
+
+ *buffer++ = cDigitsLut[d1];
+ *buffer++ = cDigitsLut[d1 + 1];
+ *buffer++ = cDigitsLut[d2];
+ *buffer++ = cDigitsLut[d2 + 1];
+ *buffer++ = cDigitsLut[d3];
+ *buffer++ = cDigitsLut[d3 + 1];
+ *buffer++ = cDigitsLut[d4];
+ *buffer++ = cDigitsLut[d4 + 1];
+ }
+ return buffer;
+}
+
+inline char* i32toa(int32_t value, char* buffer) {
+ uint32_t u = static_cast<uint32_t>(value);
+ if (value < 0) {
+ *buffer++ = '-';
+ u = ~u + 1;
+ }
+
+ return u32toa(u, buffer);
+}
+
+inline char* u64toa(uint64_t value, char* buffer) {
+ const char* cDigitsLut = GetDigitsLut();
+ const uint64_t kTen8 = 100000000;
+ const uint64_t kTen9 = kTen8 * 10;
+ const uint64_t kTen10 = kTen8 * 100;
+ const uint64_t kTen11 = kTen8 * 1000;
+ const uint64_t kTen12 = kTen8 * 10000;
+ const uint64_t kTen13 = kTen8 * 100000;
+ const uint64_t kTen14 = kTen8 * 1000000;
+ const uint64_t kTen15 = kTen8 * 10000000;
+ const uint64_t kTen16 = kTen8 * kTen8;
+
+ if (value < kTen8) {
+ uint32_t v = static_cast<uint32_t>(value);
+ if (v < 10000) {
+ const uint32_t d1 = (v / 100) << 1;
+ const uint32_t d2 = (v % 100) << 1;
+
+ if (v >= 1000)
+ *buffer++ = cDigitsLut[d1];
+ if (v >= 100)
+ *buffer++ = cDigitsLut[d1 + 1];
+ if (v >= 10)
+ *buffer++ = cDigitsLut[d2];
+ *buffer++ = cDigitsLut[d2 + 1];
+ } else {
+ // value = bbbbcccc
+ const uint32_t b = v / 10000;
+ const uint32_t c = v % 10000;
+
+ const uint32_t d1 = (b / 100) << 1;
+ const uint32_t d2 = (b % 100) << 1;
+
+ const uint32_t d3 = (c / 100) << 1;
+ const uint32_t d4 = (c % 100) << 1;
+
+ if (value >= 10000000)
+ *buffer++ = cDigitsLut[d1];
+ if (value >= 1000000)
+ *buffer++ = cDigitsLut[d1 + 1];
+ if (value >= 100000)
+ *buffer++ = cDigitsLut[d2];
+ *buffer++ = cDigitsLut[d2 + 1];
+
+ *buffer++ = cDigitsLut[d3];
+ *buffer++ = cDigitsLut[d3 + 1];
+ *buffer++ = cDigitsLut[d4];
+ *buffer++ = cDigitsLut[d4 + 1];
+ }
+ } else if (value < kTen16) {
+ const uint32_t v0 = static_cast<uint32_t>(value / kTen8);
+ const uint32_t v1 = static_cast<uint32_t>(value % kTen8);
+
+ const uint32_t b0 = v0 / 10000;
+ const uint32_t c0 = v0 % 10000;
+
+ const uint32_t d1 = (b0 / 100) << 1;
+ const uint32_t d2 = (b0 % 100) << 1;
+
+ const uint32_t d3 = (c0 / 100) << 1;
+ const uint32_t d4 = (c0 % 100) << 1;
+
+ const uint32_t b1 = v1 / 10000;
+ const uint32_t c1 = v1 % 10000;
+
+ const uint32_t d5 = (b1 / 100) << 1;
+ const uint32_t d6 = (b1 % 100) << 1;
+
+ const uint32_t d7 = (c1 / 100) << 1;
+ const uint32_t d8 = (c1 % 100) << 1;
+
+ if (value >= kTen15)
+ *buffer++ = cDigitsLut[d1];
+ if (value >= kTen14)
+ *buffer++ = cDigitsLut[d1 + 1];
+ if (value >= kTen13)
+ *buffer++ = cDigitsLut[d2];
+ if (value >= kTen12)
+ *buffer++ = cDigitsLut[d2 + 1];
+ if (value >= kTen11)
+ *buffer++ = cDigitsLut[d3];
+ if (value >= kTen10)
+ *buffer++ = cDigitsLut[d3 + 1];
+ if (value >= kTen9)
+ *buffer++ = cDigitsLut[d4];
+ if (value >= kTen8)
+ *buffer++ = cDigitsLut[d4 + 1];
+
+ *buffer++ = cDigitsLut[d5];
+ *buffer++ = cDigitsLut[d5 + 1];
+ *buffer++ = cDigitsLut[d6];
+ *buffer++ = cDigitsLut[d6 + 1];
+ *buffer++ = cDigitsLut[d7];
+ *buffer++ = cDigitsLut[d7 + 1];
+ *buffer++ = cDigitsLut[d8];
+ *buffer++ = cDigitsLut[d8 + 1];
+ } else {
+ const uint32_t a = static_cast<uint32_t>(value / kTen16); // 1 to 1844
+ value %= kTen16;
+
+ if (a < 10)
+ *buffer++ = static_cast<char>('0' + static_cast<char>(a));
+ else if (a < 100) {
+ const uint32_t i = a << 1;
+ *buffer++ = cDigitsLut[i];
+ *buffer++ = cDigitsLut[i + 1];
+ } else if (a < 1000) {
+ *buffer++ = static_cast<char>('0' + static_cast<char>(a / 100));
+
+ const uint32_t i = (a % 100) << 1;
+ *buffer++ = cDigitsLut[i];
+ *buffer++ = cDigitsLut[i + 1];
+ } else {
+ const uint32_t i = (a / 100) << 1;
+ const uint32_t j = (a % 100) << 1;
+ *buffer++ = cDigitsLut[i];
+ *buffer++ = cDigitsLut[i + 1];
+ *buffer++ = cDigitsLut[j];
+ *buffer++ = cDigitsLut[j + 1];
+ }
+
+ const uint32_t v0 = static_cast<uint32_t>(value / kTen8);
+ const uint32_t v1 = static_cast<uint32_t>(value % kTen8);
+
+ const uint32_t b0 = v0 / 10000;
+ const uint32_t c0 = v0 % 10000;
+
+ const uint32_t d1 = (b0 / 100) << 1;
+ const uint32_t d2 = (b0 % 100) << 1;
+
+ const uint32_t d3 = (c0 / 100) << 1;
+ const uint32_t d4 = (c0 % 100) << 1;
+
+ const uint32_t b1 = v1 / 10000;
+ const uint32_t c1 = v1 % 10000;
+
+ const uint32_t d5 = (b1 / 100) << 1;
+ const uint32_t d6 = (b1 % 100) << 1;
+
+ const uint32_t d7 = (c1 / 100) << 1;
+ const uint32_t d8 = (c1 % 100) << 1;
+
+ *buffer++ = cDigitsLut[d1];
+ *buffer++ = cDigitsLut[d1 + 1];
+ *buffer++ = cDigitsLut[d2];
+ *buffer++ = cDigitsLut[d2 + 1];
+ *buffer++ = cDigitsLut[d3];
+ *buffer++ = cDigitsLut[d3 + 1];
+ *buffer++ = cDigitsLut[d4];
+ *buffer++ = cDigitsLut[d4 + 1];
+ *buffer++ = cDigitsLut[d5];
+ *buffer++ = cDigitsLut[d5 + 1];
+ *buffer++ = cDigitsLut[d6];
+ *buffer++ = cDigitsLut[d6 + 1];
+ *buffer++ = cDigitsLut[d7];
+ *buffer++ = cDigitsLut[d7 + 1];
+ *buffer++ = cDigitsLut[d8];
+ *buffer++ = cDigitsLut[d8 + 1];
+ }
+
+ return buffer;
+}
+
+inline char* i64toa(int64_t value, char* buffer) {
+ uint64_t u = static_cast<uint64_t>(value);
+ if (value < 0) {
+ *buffer++ = '-';
+ u = ~u + 1;
+ }
+
+ return u64toa(u, buffer);
+}
+
+} // namespace internal
+RAPIDJSON_NAMESPACE_END
+
+#endif // RAPIDJSON_ITOA_
diff --git a/third_party/rapidjson/internal/meta.h b/third_party/rapidjson/internal/meta.h
new file mode 100644
index 00000000..0dabfacf
--- /dev/null
+++ b/third_party/rapidjson/internal/meta.h
@@ -0,0 +1,238 @@
+// Tencent is pleased to support the open source community by making RapidJSON
+// available.
+//
+// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All
+// rights reserved.
+//
+// Licensed under the MIT License (the "License"); you may not use this file
+// except in compliance with the License. You may obtain a copy of the License
+// at
+//
+// http://opensource.org/licenses/MIT
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+// License for the specific language governing permissions and limitations under
+// the License.
+
+#ifndef RAPIDJSON_INTERNAL_META_H_
+#define RAPIDJSON_INTERNAL_META_H_
+
+#include "rapidjson/rapidjson.h"
+
+#ifdef __GNUC__
+RAPIDJSON_DIAG_PUSH
+RAPIDJSON_DIAG_OFF(effc++)
+#endif
+#if defined(_MSC_VER)
+RAPIDJSON_DIAG_PUSH
+RAPIDJSON_DIAG_OFF(6334)
+#endif
+
+#if RAPIDJSON_HAS_CXX11_TYPETRAITS
+#include <type_traits>
+#endif
+
+//@cond RAPIDJSON_INTERNAL
+RAPIDJSON_NAMESPACE_BEGIN
+namespace internal {
+
+// Helper to wrap/convert arbitrary types to void, useful for arbitrary type
+// matching
+template <typename T>
+struct Void {
+ typedef void Type;
+};
+
+///////////////////////////////////////////////////////////////////////////////
+// BoolType, TrueType, FalseType
+//
+template <bool Cond>
+struct BoolType {
+ static const bool Value = Cond;
+ typedef BoolType Type;
+};
+typedef BoolType<true> TrueType;
+typedef BoolType<false> FalseType;
+
+///////////////////////////////////////////////////////////////////////////////
+// SelectIf, BoolExpr, NotExpr, AndExpr, OrExpr
+//
+
+template <bool C>
+struct SelectIfImpl {
+ template <typename T1, typename T2>
+ struct Apply {
+ typedef T1 Type;
+ };
+};
+template <>
+struct SelectIfImpl<false> {
+ template <typename T1, typename T2>
+ struct Apply {
+ typedef T2 Type;
+ };
+};
+template <bool C, typename T1, typename T2>
+struct SelectIfCond : SelectIfImpl<C>::template Apply<T1, T2> {};
+template <typename C, typename T1, typename T2>
+struct SelectIf : SelectIfCond<C::Value, T1, T2> {};
+
+template <bool Cond1, bool Cond2>
+struct AndExprCond : FalseType {};
+template <>
+struct AndExprCond<true, true> : TrueType {};
+template <bool Cond1, bool Cond2>
+struct OrExprCond : TrueType {};
+template <>
+struct OrExprCond<false, false> : FalseType {};
+
+template <typename C>
+struct BoolExpr : SelectIf<C, TrueType, FalseType>::Type {};
+template <typename C>
+struct NotExpr : SelectIf<C, FalseType, TrueType>::Type {};
+template <typename C1, typename C2>
+struct AndExpr : AndExprCond<C1::Value, C2::Value>::Type {};
+template <typename C1, typename C2>
+struct OrExpr : OrExprCond<C1::Value, C2::Value>::Type {};
+
+///////////////////////////////////////////////////////////////////////////////
+// AddConst, MaybeAddConst, RemoveConst
+template <typename T>
+struct AddConst {
+ typedef const T Type;
+};
+template <bool Constify, typename T>
+struct MaybeAddConst : SelectIfCond<Constify, const T, T> {};
+template <typename T>
+struct RemoveConst {
+ typedef T Type;
+};
+template <typename T>
+struct RemoveConst<const T> {
+ typedef T Type;
+};
+
+///////////////////////////////////////////////////////////////////////////////
+// IsSame, IsConst, IsMoreConst, IsPointer
+//
+template <typename T, typename U>
+struct IsSame : FalseType {};
+template <typename T>
+struct IsSame<T, T> : TrueType {};
+
+template <typename T>
+struct IsConst : FalseType {};
+template <typename T>
+struct IsConst<const T> : TrueType {};
+
+template <typename CT, typename T>
+struct IsMoreConst
+ : AndExpr<
+ IsSame<typename RemoveConst<CT>::Type, typename RemoveConst<T>::Type>,
+ BoolType<IsConst<CT>::Value >= IsConst<T>::Value> >::Type {};
+
+template <typename T>
+struct IsPointer : FalseType {};
+template <typename T>
+struct IsPointer<T*> : TrueType {};
+
+///////////////////////////////////////////////////////////////////////////////
+// IsBaseOf
+//
+#if RAPIDJSON_HAS_CXX11_TYPETRAITS
+
+template <typename B, typename D>
+struct IsBaseOf : BoolType< ::std::is_base_of<B, D>::value> {};
+
+#else // simplified version adopted from Boost
+
+template <typename B, typename D>
+struct IsBaseOfImpl {
+ RAPIDJSON_STATIC_ASSERT(sizeof(B) != 0);
+ RAPIDJSON_STATIC_ASSERT(sizeof(D) != 0);
+
+ typedef char (&Yes)[1];
+ typedef char (&No)[2];
+
+ template <typename T>
+ static Yes Check(const D*, T);
+ static No Check(const B*, int);
+
+ struct Host {
+ operator const B*() const;
+ operator const D*();
+ };
+
+ enum { Value = (sizeof(Check(Host(), 0)) == sizeof(Yes)) };
+};
+
+template <typename B, typename D>
+struct IsBaseOf : OrExpr<IsSame<B, D>, BoolExpr<IsBaseOfImpl<B, D> > >::Type {};
+
+#endif // RAPIDJSON_HAS_CXX11_TYPETRAITS
+
+//////////////////////////////////////////////////////////////////////////
+// EnableIf / DisableIf
+//
+template <bool Condition, typename T = void>
+struct EnableIfCond {
+ typedef T Type;
+};
+template <typename T>
+struct EnableIfCond<false, T> { /* empty */
+};
+
+template <bool Condition, typename T = void>
+struct DisableIfCond {
+ typedef T Type;
+};
+template <typename T>
+struct DisableIfCond<true, T> { /* empty */
+};
+
+template <typename Condition, typename T = void>
+struct EnableIf : EnableIfCond<Condition::Value, T> {};
+
+template <typename Condition, typename T = void>
+struct DisableIf : DisableIfCond<Condition::Value, T> {};
+
+// SFINAE helpers
+struct SfinaeTag {};
+template <typename T>
+struct RemoveSfinaeTag;
+template <typename T>
+struct RemoveSfinaeTag<SfinaeTag& (*)(T)> {
+ typedef T Type;
+};
+
+#define RAPIDJSON_REMOVEFPTR_(type) \
+ typename ::RAPIDJSON_NAMESPACE::internal::RemoveSfinaeTag< \
+ ::RAPIDJSON_NAMESPACE::internal::SfinaeTag&(*)type>::Type
+
+#define RAPIDJSON_ENABLEIF(cond) \
+ typename ::RAPIDJSON_NAMESPACE::internal::EnableIf<RAPIDJSON_REMOVEFPTR_( \
+ cond)>::Type* = NULL
+
+#define RAPIDJSON_DISABLEIF(cond) \
+ typename ::RAPIDJSON_NAMESPACE::internal::DisableIf<RAPIDJSON_REMOVEFPTR_( \
+ cond)>::Type* = NULL
+
+#define RAPIDJSON_ENABLEIF_RETURN(cond, returntype) \
+ typename ::RAPIDJSON_NAMESPACE::internal::EnableIf< \
+ RAPIDJSON_REMOVEFPTR_(cond), RAPIDJSON_REMOVEFPTR_(returntype)>::Type
+
+#define RAPIDJSON_DISABLEIF_RETURN(cond, returntype) \
+ typename ::RAPIDJSON_NAMESPACE::internal::DisableIf< \
+ RAPIDJSON_REMOVEFPTR_(cond), RAPIDJSON_REMOVEFPTR_(returntype)>::Type
+
+} // namespace internal
+RAPIDJSON_NAMESPACE_END
+//@endcond
+
+#if defined(__GNUC__) || defined(_MSC_VER)
+RAPIDJSON_DIAG_POP
+#endif
+
+#endif // RAPIDJSON_INTERNAL_META_H_
diff --git a/third_party/rapidjson/internal/pow10.h b/third_party/rapidjson/internal/pow10.h
new file mode 100644
index 00000000..be06ab7a
--- /dev/null
+++ b/third_party/rapidjson/internal/pow10.h
@@ -0,0 +1,77 @@
+// Tencent is pleased to support the open source community by making RapidJSON
+// available.
+//
+// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All
+// rights reserved.
+//
+// Licensed under the MIT License (the "License"); you may not use this file
+// except in compliance with the License. You may obtain a copy of the License
+// at
+//
+// http://opensource.org/licenses/MIT
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+// License for the specific language governing permissions and limitations under
+// the License.
+
+#ifndef RAPIDJSON_POW10_
+#define RAPIDJSON_POW10_
+
+#include "rapidjson/rapidjson.h"
+
+RAPIDJSON_NAMESPACE_BEGIN
+namespace internal {
+
+//! Computes integer powers of 10 in double (10.0^n).
+/*! This function uses lookup table for fast and accurate results.
+ \param n non-negative exponent. Must <= 308.
+ \return 10.0^n
+*/
+inline double Pow10(int n) {
+ static const double e[] = {
+ // 1e-0...1e308: 309 * 8 bytes = 2472 bytes
+ 1e+0, 1e+1, 1e+2, 1e+3, 1e+4, 1e+5, 1e+6, 1e+7, 1e+8,
+ 1e+9, 1e+10, 1e+11, 1e+12, 1e+13, 1e+14, 1e+15, 1e+16, 1e+17,
+ 1e+18, 1e+19, 1e+20, 1e+21, 1e+22, 1e+23, 1e+24, 1e+25, 1e+26,
+ 1e+27, 1e+28, 1e+29, 1e+30, 1e+31, 1e+32, 1e+33, 1e+34, 1e+35,
+ 1e+36, 1e+37, 1e+38, 1e+39, 1e+40, 1e+41, 1e+42, 1e+43, 1e+44,
+ 1e+45, 1e+46, 1e+47, 1e+48, 1e+49, 1e+50, 1e+51, 1e+52, 1e+53,
+ 1e+54, 1e+55, 1e+56, 1e+57, 1e+58, 1e+59, 1e+60, 1e+61, 1e+62,
+ 1e+63, 1e+64, 1e+65, 1e+66, 1e+67, 1e+68, 1e+69, 1e+70, 1e+71,
+ 1e+72, 1e+73, 1e+74, 1e+75, 1e+76, 1e+77, 1e+78, 1e+79, 1e+80,
+ 1e+81, 1e+82, 1e+83, 1e+84, 1e+85, 1e+86, 1e+87, 1e+88, 1e+89,
+ 1e+90, 1e+91, 1e+92, 1e+93, 1e+94, 1e+95, 1e+96, 1e+97, 1e+98,
+ 1e+99, 1e+100, 1e+101, 1e+102, 1e+103, 1e+104, 1e+105, 1e+106, 1e+107,
+ 1e+108, 1e+109, 1e+110, 1e+111, 1e+112, 1e+113, 1e+114, 1e+115, 1e+116,
+ 1e+117, 1e+118, 1e+119, 1e+120, 1e+121, 1e+122, 1e+123, 1e+124, 1e+125,
+ 1e+126, 1e+127, 1e+128, 1e+129, 1e+130, 1e+131, 1e+132, 1e+133, 1e+134,
+ 1e+135, 1e+136, 1e+137, 1e+138, 1e+139, 1e+140, 1e+141, 1e+142, 1e+143,
+ 1e+144, 1e+145, 1e+146, 1e+147, 1e+148, 1e+149, 1e+150, 1e+151, 1e+152,
+ 1e+153, 1e+154, 1e+155, 1e+156, 1e+157, 1e+158, 1e+159, 1e+160, 1e+161,
+ 1e+162, 1e+163, 1e+164, 1e+165, 1e+166, 1e+167, 1e+168, 1e+169, 1e+170,
+ 1e+171, 1e+172, 1e+173, 1e+174, 1e+175, 1e+176, 1e+177, 1e+178, 1e+179,
+ 1e+180, 1e+181, 1e+182, 1e+183, 1e+184, 1e+185, 1e+186, 1e+187, 1e+188,
+ 1e+189, 1e+190, 1e+191, 1e+192, 1e+193, 1e+194, 1e+195, 1e+196, 1e+197,
+ 1e+198, 1e+199, 1e+200, 1e+201, 1e+202, 1e+203, 1e+204, 1e+205, 1e+206,
+ 1e+207, 1e+208, 1e+209, 1e+210, 1e+211, 1e+212, 1e+213, 1e+214, 1e+215,
+ 1e+216, 1e+217, 1e+218, 1e+219, 1e+220, 1e+221, 1e+222, 1e+223, 1e+224,
+ 1e+225, 1e+226, 1e+227, 1e+228, 1e+229, 1e+230, 1e+231, 1e+232, 1e+233,
+ 1e+234, 1e+235, 1e+236, 1e+237, 1e+238, 1e+239, 1e+240, 1e+241, 1e+242,
+ 1e+243, 1e+244, 1e+245, 1e+246, 1e+247, 1e+248, 1e+249, 1e+250, 1e+251,
+ 1e+252, 1e+253, 1e+254, 1e+255, 1e+256, 1e+257, 1e+258, 1e+259, 1e+260,
+ 1e+261, 1e+262, 1e+263, 1e+264, 1e+265, 1e+266, 1e+267, 1e+268, 1e+269,
+ 1e+270, 1e+271, 1e+272, 1e+273, 1e+274, 1e+275, 1e+276, 1e+277, 1e+278,
+ 1e+279, 1e+280, 1e+281, 1e+282, 1e+283, 1e+284, 1e+285, 1e+286, 1e+287,
+ 1e+288, 1e+289, 1e+290, 1e+291, 1e+292, 1e+293, 1e+294, 1e+295, 1e+296,
+ 1e+297, 1e+298, 1e+299, 1e+300, 1e+301, 1e+302, 1e+303, 1e+304, 1e+305,
+ 1e+306, 1e+307, 1e+308};
+ RAPIDJSON_ASSERT(n >= 0 && n <= 308);
+ return e[n];
+}
+
+} // namespace internal
+RAPIDJSON_NAMESPACE_END
+
+#endif // RAPIDJSON_POW10_
diff --git a/third_party/rapidjson/internal/regex.h b/third_party/rapidjson/internal/regex.h
new file mode 100644
index 00000000..1543d172
--- /dev/null
+++ b/third_party/rapidjson/internal/regex.h
@@ -0,0 +1,733 @@
+// Tencent is pleased to support the open source community by making RapidJSON
+// available.
+//
+// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All
+// rights reserved.
+//
+// Licensed under the MIT License (the "License"); you may not use this file
+// except in compliance with the License. You may obtain a copy of the License
+// at
+//
+// http://opensource.org/licenses/MIT
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+// License for the specific language governing permissions and limitations under
+// the License.
+
+#ifndef RAPIDJSON_INTERNAL_REGEX_H_
+#define RAPIDJSON_INTERNAL_REGEX_H_
+
+#include "rapidjson/allocators.h"
+#include "rapidjson/stream.h"
+#include "stack.h"
+
+#ifdef __clang__
+RAPIDJSON_DIAG_PUSH
+RAPIDJSON_DIAG_OFF(padded)
+RAPIDJSON_DIAG_OFF(switch - enum)
+RAPIDJSON_DIAG_OFF(implicit - fallthrough)
+#endif
+
+#ifdef __GNUC__
+RAPIDJSON_DIAG_PUSH
+RAPIDJSON_DIAG_OFF(effc++)
+#endif
+
+#ifdef _MSC_VER
+RAPIDJSON_DIAG_PUSH
+RAPIDJSON_DIAG_OFF(4512) // assignment operator could not be generated
+#endif
+
+#ifndef RAPIDJSON_REGEX_VERBOSE
+#define RAPIDJSON_REGEX_VERBOSE 0
+#endif
+
+RAPIDJSON_NAMESPACE_BEGIN
+namespace internal {
+
+///////////////////////////////////////////////////////////////////////////////
+// GenericRegex
+
+static const SizeType kRegexInvalidState = ~SizeType(
+ 0); //!< Represents an invalid index in GenericRegex::State::out, out1
+static const SizeType kRegexInvalidRange = ~SizeType(0);
+
+//! Regular expression engine with subset of ECMAscript grammar.
+/*!
+ Supported regular expression syntax:
+ - \c ab Concatenation
+ - \c a|b Alternation
+ - \c a? Zero or one
+ - \c a* Zero or more
+ - \c a+ One or more
+ - \c a{3} Exactly 3 times
+ - \c a{3,} At least 3 times
+ - \c a{3,5} 3 to 5 times
+ - \c (ab) Grouping
+ - \c ^a At the beginning
+ - \c a$ At the end
+ - \c . Any character
+ - \c [abc] Character classes
+ - \c [a-c] Character class range
+ - \c [a-z0-9_] Character class combination
+ - \c [^abc] Negated character classes
+ - \c [^a-c] Negated character class range
+ - \c [\b] Backspace (U+0008)
+ - \c \\| \\\\ ... Escape characters
+ - \c \\f Form feed (U+000C)
+ - \c \\n Line feed (U+000A)
+ - \c \\r Carriage return (U+000D)
+ - \c \\t Tab (U+0009)
+ - \c \\v Vertical tab (U+000B)
+
+ \note This is a Thompson NFA engine, implemented with reference to
+ Cox, Russ. "Regular Expression Matching Can Be Simple And Fast (but is
+ slow in Java, Perl, PHP, Python, Ruby,...).",
+ https://swtch.com/~rsc/regexp/regexp1.html
+*/
+template <typename Encoding, typename Allocator = CrtAllocator>
+class GenericRegex {
+ public:
+ typedef typename Encoding::Ch Ch;
+
+ GenericRegex(const Ch* source, Allocator* allocator = 0)
+ : states_(allocator, 256),
+ ranges_(allocator, 256),
+ root_(kRegexInvalidState),
+ stateCount_(),
+ rangeCount_(),
+ stateSet_(),
+ state0_(allocator, 0),
+ state1_(allocator, 0),
+ anchorBegin_(),
+ anchorEnd_() {
+ GenericStringStream<Encoding> ss(source);
+ DecodedStream<GenericStringStream<Encoding> > ds(ss);
+ Parse(ds);
+ }
+
+ ~GenericRegex() { Allocator::Free(stateSet_); }
+
+ bool IsValid() const { return root_ != kRegexInvalidState; }
+
+ template <typename InputStream>
+ bool Match(InputStream& is) const {
+ return SearchWithAnchoring(is, true, true);
+ }
+
+ bool Match(const Ch* s) const {
+ GenericStringStream<Encoding> is(s);
+ return Match(is);
+ }
+
+ template <typename InputStream>
+ bool Search(InputStream& is) const {
+ return SearchWithAnchoring(is, anchorBegin_, anchorEnd_);
+ }
+
+ bool Search(const Ch* s) const {
+ GenericStringStream<Encoding> is(s);
+ return Search(is);
+ }
+
+ private:
+ enum Operator {
+ kZeroOrOne,
+ kZeroOrMore,
+ kOneOrMore,
+ kConcatenation,
+ kAlternation,
+ kLeftParenthesis
+ };
+
+ static const unsigned kAnyCharacterClass = 0xFFFFFFFF; //!< For '.'
+ static const unsigned kRangeCharacterClass = 0xFFFFFFFE;
+ static const unsigned kRangeNegationFlag = 0x80000000;
+
+ struct Range {
+ unsigned start; //
+ unsigned end;
+ SizeType next;
+ };
+
+ struct State {
+ SizeType out; //!< Equals to kInvalid for matching state
+ SizeType out1; //!< Equals to non-kInvalid for split
+ SizeType rangeStart;
+ unsigned codepoint;
+ };
+
+ struct Frag {
+ Frag(SizeType s, SizeType o, SizeType m) : start(s), out(o), minIndex(m) {}
+ SizeType start;
+ SizeType out; //!< link-list of all output states
+ SizeType minIndex;
+ };
+
+ template <typename SourceStream>
+ class DecodedStream {
+ public:
+ DecodedStream(SourceStream& ss) : ss_(ss), codepoint_() { Decode(); }
+ unsigned Peek() { return codepoint_; }
+ unsigned Take() {
+ unsigned c = codepoint_;
+ if (c) // No further decoding when '\0'
+ Decode();
+ return c;
+ }
+
+ private:
+ void Decode() {
+ if (!Encoding::Decode(ss_, &codepoint_))
+ codepoint_ = 0;
+ }
+
+ SourceStream& ss_;
+ unsigned codepoint_;
+ };
+
+ State& GetState(SizeType index) {
+ RAPIDJSON_ASSERT(index < stateCount_);
+ return states_.template Bottom<State>()[index];
+ }
+
+ const State& GetState(SizeType index) const {
+ RAPIDJSON_ASSERT(index < stateCount_);
+ return states_.template Bottom<State>()[index];
+ }
+
+ Range& GetRange(SizeType index) {
+ RAPIDJSON_ASSERT(index < rangeCount_);
+ return ranges_.template Bottom<Range>()[index];
+ }
+
+ const Range& GetRange(SizeType index) const {
+ RAPIDJSON_ASSERT(index < rangeCount_);
+ return ranges_.template Bottom<Range>()[index];
+ }
+
+ template <typename InputStream>
+ void Parse(DecodedStream<InputStream>& ds) {
+ Allocator allocator;
+ Stack<Allocator> operandStack(&allocator, 256); // Frag
+ Stack<Allocator> operatorStack(&allocator, 256); // Operator
+ Stack<Allocator> atomCountStack(&allocator,
+ 256); // unsigned (Atom per parenthesis)
+
+ *atomCountStack.template Push<unsigned>() = 0;
+
+ unsigned codepoint;
+ while (ds.Peek() != 0) {
+ switch (codepoint = ds.Take()) {
+ case '^':
+ anchorBegin_ = true;
+ break;
+
+ case '$':
+ anchorEnd_ = true;
+ break;
+
+ case '|':
+ while (!operatorStack.Empty() &&
+ *operatorStack.template Top<Operator>() < kAlternation)
+ if (!Eval(operandStack, *operatorStack.template Pop<Operator>(1)))
+ return;
+ *operatorStack.template Push<Operator>() = kAlternation;
+ *atomCountStack.template Top<unsigned>() = 0;
+ break;
+
+ case '(':
+ *operatorStack.template Push<Operator>() = kLeftParenthesis;
+ *atomCountStack.template Push<unsigned>() = 0;
+ break;
+
+ case ')':
+ while (!operatorStack.Empty() &&
+ *operatorStack.template Top<Operator>() != kLeftParenthesis)
+ if (!Eval(operandStack, *operatorStack.template Pop<Operator>(1)))
+ return;
+ if (operatorStack.Empty())
+ return;
+ operatorStack.template Pop<Operator>(1);
+ atomCountStack.template Pop<unsigned>(1);
+ ImplicitConcatenation(atomCountStack, operatorStack);
+ break;
+
+ case '?':
+ if (!Eval(operandStack, kZeroOrOne))
+ return;
+ break;
+
+ case '*':
+ if (!Eval(operandStack, kZeroOrMore))
+ return;
+ break;
+
+ case '+':
+ if (!Eval(operandStack, kOneOrMore))
+ return;
+ break;
+
+ case '{': {
+ unsigned n, m;
+ if (!ParseUnsigned(ds, &n))
+ return;
+
+ if (ds.Peek() == ',') {
+ ds.Take();
+ if (ds.Peek() == '}')
+ m = kInfinityQuantifier;
+ else if (!ParseUnsigned(ds, &m) || m < n)
+ return;
+ } else
+ m = n;
+
+ if (!EvalQuantifier(operandStack, n, m) || ds.Peek() != '}')
+ return;
+ ds.Take();
+ } break;
+
+ case '.':
+ PushOperand(operandStack, kAnyCharacterClass);
+ ImplicitConcatenation(atomCountStack, operatorStack);
+ break;
+
+ case '[': {
+ SizeType range;
+ if (!ParseRange(ds, &range))
+ return;
+ SizeType s = NewState(kRegexInvalidState, kRegexInvalidState,
+ kRangeCharacterClass);
+ GetState(s).rangeStart = range;
+ *operandStack.template Push<Frag>() = Frag(s, s, s);
+ }
+ ImplicitConcatenation(atomCountStack, operatorStack);
+ break;
+
+ case '\\': // Escape character
+ if (!CharacterEscape(ds, &codepoint))
+ return; // Unsupported escape character
+ // fall through to default
+
+ default: // Pattern character
+ PushOperand(operandStack, codepoint);
+ ImplicitConcatenation(atomCountStack, operatorStack);
+ }
+ }
+
+ while (!operatorStack.Empty())
+ if (!Eval(operandStack, *operatorStack.template Pop<Operator>(1)))
+ return;
+
+ // Link the operand to matching state.
+ if (operandStack.GetSize() == sizeof(Frag)) {
+ Frag* e = operandStack.template Pop<Frag>(1);
+ Patch(e->out, NewState(kRegexInvalidState, kRegexInvalidState, 0));
+ root_ = e->start;
+
+#if RAPIDJSON_REGEX_VERBOSE
+ printf("root: %d\n", root_);
+ for (SizeType i = 0; i < stateCount_; i++) {
+ State& s = GetState(i);
+ printf("[%2d] out: %2d out1: %2d c: '%c'\n", i, s.out, s.out1,
+ (char)s.codepoint);
+ }
+ printf("\n");
+#endif
+ }
+
+ // Preallocate buffer for SearchWithAnchoring()
+ RAPIDJSON_ASSERT(stateSet_ == 0);
+ if (stateCount_ > 0) {
+ stateSet_ = static_cast<unsigned*>(
+ states_.GetAllocator().Malloc(GetStateSetSize()));
+ state0_.template Reserve<SizeType>(stateCount_);
+ state1_.template Reserve<SizeType>(stateCount_);
+ }
+ }
+
+ SizeType NewState(SizeType out, SizeType out1, unsigned codepoint) {
+ State* s = states_.template Push<State>();
+ s->out = out;
+ s->out1 = out1;
+ s->codepoint = codepoint;
+ s->rangeStart = kRegexInvalidRange;
+ return stateCount_++;
+ }
+
+ void PushOperand(Stack<Allocator>& operandStack, unsigned codepoint) {
+ SizeType s = NewState(kRegexInvalidState, kRegexInvalidState, codepoint);
+ *operandStack.template Push<Frag>() = Frag(s, s, s);
+ }
+
+ void ImplicitConcatenation(Stack<Allocator>& atomCountStack,
+ Stack<Allocator>& operatorStack) {
+ if (*atomCountStack.template Top<unsigned>())
+ *operatorStack.template Push<Operator>() = kConcatenation;
+ (*atomCountStack.template Top<unsigned>())++;
+ }
+
+ SizeType Append(SizeType l1, SizeType l2) {
+ SizeType old = l1;
+ while (GetState(l1).out != kRegexInvalidState)
+ l1 = GetState(l1).out;
+ GetState(l1).out = l2;
+ return old;
+ }
+
+ void Patch(SizeType l, SizeType s) {
+ for (SizeType next; l != kRegexInvalidState; l = next) {
+ next = GetState(l).out;
+ GetState(l).out = s;
+ }
+ }
+
+ bool Eval(Stack<Allocator>& operandStack, Operator op) {
+ switch (op) {
+ case kConcatenation:
+ RAPIDJSON_ASSERT(operandStack.GetSize() >= sizeof(Frag) * 2);
+ {
+ Frag e2 = *operandStack.template Pop<Frag>(1);
+ Frag e1 = *operandStack.template Pop<Frag>(1);
+ Patch(e1.out, e2.start);
+ *operandStack.template Push<Frag>() =
+ Frag(e1.start, e2.out, Min(e1.minIndex, e2.minIndex));
+ }
+ return true;
+
+ case kAlternation:
+ if (operandStack.GetSize() >= sizeof(Frag) * 2) {
+ Frag e2 = *operandStack.template Pop<Frag>(1);
+ Frag e1 = *operandStack.template Pop<Frag>(1);
+ SizeType s = NewState(e1.start, e2.start, 0);
+ *operandStack.template Push<Frag>() =
+ Frag(s, Append(e1.out, e2.out), Min(e1.minIndex, e2.minIndex));
+ return true;
+ }
+ return false;
+
+ case kZeroOrOne:
+ if (operandStack.GetSize() >= sizeof(Frag)) {
+ Frag e = *operandStack.template Pop<Frag>(1);
+ SizeType s = NewState(kRegexInvalidState, e.start, 0);
+ *operandStack.template Push<Frag>() =
+ Frag(s, Append(e.out, s), e.minIndex);
+ return true;
+ }
+ return false;
+
+ case kZeroOrMore:
+ if (operandStack.GetSize() >= sizeof(Frag)) {
+ Frag e = *operandStack.template Pop<Frag>(1);
+ SizeType s = NewState(kRegexInvalidState, e.start, 0);
+ Patch(e.out, s);
+ *operandStack.template Push<Frag>() = Frag(s, s, e.minIndex);
+ return true;
+ }
+ return false;
+
+ default:
+ RAPIDJSON_ASSERT(op == kOneOrMore);
+ if (operandStack.GetSize() >= sizeof(Frag)) {
+ Frag e = *operandStack.template Pop<Frag>(1);
+ SizeType s = NewState(kRegexInvalidState, e.start, 0);
+ Patch(e.out, s);
+ *operandStack.template Push<Frag>() = Frag(e.start, s, e.minIndex);
+ return true;
+ }
+ return false;
+ }
+ }
+
+ bool EvalQuantifier(Stack<Allocator>& operandStack, unsigned n, unsigned m) {
+ RAPIDJSON_ASSERT(n <= m);
+ RAPIDJSON_ASSERT(operandStack.GetSize() >= sizeof(Frag));
+
+ if (n == 0) {
+ if (m == 0) // a{0} not support
+ return false;
+ else if (m == kInfinityQuantifier)
+ Eval(operandStack, kZeroOrMore); // a{0,} -> a*
+ else {
+ Eval(operandStack, kZeroOrOne); // a{0,5} -> a?
+ for (unsigned i = 0; i < m - 1; i++)
+ CloneTopOperand(operandStack); // a{0,5} -> a? a? a? a? a?
+ for (unsigned i = 0; i < m - 1; i++)
+ Eval(operandStack, kConcatenation); // a{0,5} -> a?a?a?a?a?
+ }
+ return true;
+ }
+
+ for (unsigned i = 0; i < n - 1; i++) // a{3} -> a a a
+ CloneTopOperand(operandStack);
+
+ if (m == kInfinityQuantifier)
+ Eval(operandStack, kOneOrMore); // a{3,} -> a a a+
+ else if (m > n) {
+ CloneTopOperand(operandStack); // a{3,5} -> a a a a
+ Eval(operandStack, kZeroOrOne); // a{3,5} -> a a a a?
+ for (unsigned i = n; i < m - 1; i++)
+ CloneTopOperand(operandStack); // a{3,5} -> a a a a? a?
+ for (unsigned i = n; i < m; i++)
+ Eval(operandStack, kConcatenation); // a{3,5} -> a a aa?a?
+ }
+
+ for (unsigned i = 0; i < n - 1; i++)
+ Eval(operandStack,
+ kConcatenation); // a{3} -> aaa, a{3,} -> aaa+, a{3.5} -> aaaa?a?
+
+ return true;
+ }
+
+ static SizeType Min(SizeType a, SizeType b) { return a < b ? a : b; }
+
+ void CloneTopOperand(Stack<Allocator>& operandStack) {
+ const Frag src =
+ *operandStack
+ .template Top<Frag>(); // Copy constructor to prevent invalidation
+ SizeType count =
+ stateCount_ - src.minIndex; // Assumes top operand contains states in
+ // [src->minIndex, stateCount_)
+ State* s = states_.template Push<State>(count);
+ memcpy(s, &GetState(src.minIndex), count * sizeof(State));
+ for (SizeType j = 0; j < count; j++) {
+ if (s[j].out != kRegexInvalidState)
+ s[j].out += count;
+ if (s[j].out1 != kRegexInvalidState)
+ s[j].out1 += count;
+ }
+ *operandStack.template Push<Frag>() =
+ Frag(src.start + count, src.out + count, src.minIndex + count);
+ stateCount_ += count;
+ }
+
+ template <typename InputStream>
+ bool ParseUnsigned(DecodedStream<InputStream>& ds, unsigned* u) {
+ unsigned r = 0;
+ if (ds.Peek() < '0' || ds.Peek() > '9')
+ return false;
+ while (ds.Peek() >= '0' && ds.Peek() <= '9') {
+ if (r >= 429496729 && ds.Peek() > '5') // 2^32 - 1 = 4294967295
+ return false; // overflow
+ r = r * 10 + (ds.Take() - '0');
+ }
+ *u = r;
+ return true;
+ }
+
+ template <typename InputStream>
+ bool ParseRange(DecodedStream<InputStream>& ds, SizeType* range) {
+ bool isBegin = true;
+ bool negate = false;
+ int step = 0;
+ SizeType start = kRegexInvalidRange;
+ SizeType current = kRegexInvalidRange;
+ unsigned codepoint;
+ while ((codepoint = ds.Take()) != 0) {
+ if (isBegin) {
+ isBegin = false;
+ if (codepoint == '^') {
+ negate = true;
+ continue;
+ }
+ }
+
+ switch (codepoint) {
+ case ']':
+ if (start == kRegexInvalidRange)
+ return false; // Error: nothing inside []
+ if (step == 2) { // Add trailing '-'
+ SizeType r = NewRange('-');
+ RAPIDJSON_ASSERT(current != kRegexInvalidRange);
+ GetRange(current).next = r;
+ }
+ if (negate)
+ GetRange(start).start |= kRangeNegationFlag;
+ *range = start;
+ return true;
+
+ case '\\':
+ if (ds.Peek() == 'b') {
+ ds.Take();
+ codepoint = 0x0008; // Escape backspace character
+ } else if (!CharacterEscape(ds, &codepoint))
+ return false;
+ // fall through to default
+
+ default:
+ switch (step) {
+ case 1:
+ if (codepoint == '-') {
+ step++;
+ break;
+ }
+ // fall through to step 0 for other characters
+
+ case 0: {
+ SizeType r = NewRange(codepoint);
+ if (current != kRegexInvalidRange)
+ GetRange(current).next = r;
+ if (start == kRegexInvalidRange)
+ start = r;
+ current = r;
+ }
+ step = 1;
+ break;
+
+ default:
+ RAPIDJSON_ASSERT(step == 2);
+ GetRange(current).end = codepoint;
+ step = 0;
+ }
+ }
+ }
+ return false;
+ }
+
+ SizeType NewRange(unsigned codepoint) {
+ Range* r = ranges_.template Push<Range>();
+ r->start = r->end = codepoint;
+ r->next = kRegexInvalidRange;
+ return rangeCount_++;
+ }
+
+ template <typename InputStream>
+ bool CharacterEscape(DecodedStream<InputStream>& ds,
+ unsigned* escapedCodepoint) {
+ unsigned codepoint;
+ switch (codepoint = ds.Take()) {
+ case '^':
+ case '$':
+ case '|':
+ case '(':
+ case ')':
+ case '?':
+ case '*':
+ case '+':
+ case '.':
+ case '[':
+ case ']':
+ case '{':
+ case '}':
+ case '\\':
+ *escapedCodepoint = codepoint;
+ return true;
+ case 'f':
+ *escapedCodepoint = 0x000C;
+ return true;
+ case 'n':
+ *escapedCodepoint = 0x000A;
+ return true;
+ case 'r':
+ *escapedCodepoint = 0x000D;
+ return true;
+ case 't':
+ *escapedCodepoint = 0x0009;
+ return true;
+ case 'v':
+ *escapedCodepoint = 0x000B;
+ return true;
+ default:
+ return false; // Unsupported escape character
+ }
+ }
+
+ template <typename InputStream>
+ bool SearchWithAnchoring(InputStream& is,
+ bool anchorBegin,
+ bool anchorEnd) const {
+ RAPIDJSON_ASSERT(IsValid());
+ DecodedStream<InputStream> ds(is);
+
+ state0_.Clear();
+ Stack<Allocator>*current = &state0_, *next = &state1_;
+ const size_t stateSetSize = GetStateSetSize();
+ std::memset(stateSet_, 0, stateSetSize);
+
+ bool matched = AddState(*current, root_);
+ unsigned codepoint;
+ while (!current->Empty() && (codepoint = ds.Take()) != 0) {
+ std::memset(stateSet_, 0, stateSetSize);
+ next->Clear();
+ matched = false;
+ for (const SizeType* s = current->template Bottom<SizeType>();
+ s != current->template End<SizeType>(); ++s) {
+ const State& sr = GetState(*s);
+ if (sr.codepoint == codepoint || sr.codepoint == kAnyCharacterClass ||
+ (sr.codepoint == kRangeCharacterClass &&
+ MatchRange(sr.rangeStart, codepoint))) {
+ matched = AddState(*next, sr.out) || matched;
+ if (!anchorEnd && matched)
+ return true;
+ }
+ if (!anchorBegin)
+ AddState(*next, root_);
+ }
+ internal::Swap(current, next);
+ }
+
+ return matched;
+ }
+
+ size_t GetStateSetSize() const { return (stateCount_ + 31) / 32 * 4; }
+
+ // Return whether the added states is a match state
+ bool AddState(Stack<Allocator>& l, SizeType index) const {
+ RAPIDJSON_ASSERT(index != kRegexInvalidState);
+
+ const State& s = GetState(index);
+ if (s.out1 != kRegexInvalidState) { // Split
+ bool matched = AddState(l, s.out);
+ return AddState(l, s.out1) || matched;
+ } else if (!(stateSet_[index >> 5] & (1 << (index & 31)))) {
+ stateSet_[index >> 5] |= (1 << (index & 31));
+ *l.template PushUnsafe<SizeType>() = index;
+ }
+ return s.out ==
+ kRegexInvalidState; // by using PushUnsafe() above, we can ensure s
+ // is not validated due to reallocation.
+ }
+
+ bool MatchRange(SizeType rangeIndex, unsigned codepoint) const {
+ bool yes = (GetRange(rangeIndex).start & kRangeNegationFlag) == 0;
+ while (rangeIndex != kRegexInvalidRange) {
+ const Range& r = GetRange(rangeIndex);
+ if (codepoint >= (r.start & ~kRangeNegationFlag) && codepoint <= r.end)
+ return yes;
+ rangeIndex = r.next;
+ }
+ return !yes;
+ }
+
+ Stack<Allocator> states_;
+ Stack<Allocator> ranges_;
+ SizeType root_;
+ SizeType stateCount_;
+ SizeType rangeCount_;
+
+ static const unsigned kInfinityQuantifier = ~0u;
+
+ // For SearchWithAnchoring()
+ uint32_t* stateSet_; // allocated by states_.GetAllocator()
+ mutable Stack<Allocator> state0_;
+ mutable Stack<Allocator> state1_;
+ bool anchorBegin_;
+ bool anchorEnd_;
+};
+
+typedef GenericRegex<UTF8<> > Regex;
+
+} // namespace internal
+RAPIDJSON_NAMESPACE_END
+
+#ifdef __clang__
+RAPIDJSON_DIAG_POP
+#endif
+
+#ifdef _MSC_VER
+RAPIDJSON_DIAG_POP
+#endif
+
+#endif // RAPIDJSON_INTERNAL_REGEX_H_
diff --git a/third_party/rapidjson/internal/stack.h b/third_party/rapidjson/internal/stack.h
new file mode 100644
index 00000000..ec5d9239
--- /dev/null
+++ b/third_party/rapidjson/internal/stack.h
@@ -0,0 +1,243 @@
+// Tencent is pleased to support the open source community by making RapidJSON
+// available.
+//
+// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All
+// rights reserved.
+//
+// Licensed under the MIT License (the "License"); you may not use this file
+// except in compliance with the License. You may obtain a copy of the License
+// at
+//
+// http://opensource.org/licenses/MIT
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+// License for the specific language governing permissions and limitations under
+// the License.
+
+#ifndef RAPIDJSON_INTERNAL_STACK_H_
+#define RAPIDJSON_INTERNAL_STACK_H_
+
+#include "rapidjson/allocators.h"
+#include "swap.h"
+
+#if defined(__clang__)
+RAPIDJSON_DIAG_PUSH
+RAPIDJSON_DIAG_OFF(c++ 98 - compat)
+#endif
+
+RAPIDJSON_NAMESPACE_BEGIN
+namespace internal {
+
+///////////////////////////////////////////////////////////////////////////////
+// Stack
+
+//! A type-unsafe stack for storing different types of data.
+/*! \tparam Allocator Allocator for allocating stack memory.
+ */
+template <typename Allocator>
+class Stack {
+ public:
+ // Optimization note: Do not allocate memory for stack_ in constructor.
+ // Do it lazily when first Push() -> Expand() -> Resize().
+ Stack(Allocator* allocator, size_t stackCapacity)
+ : allocator_(allocator),
+ ownAllocator_(0),
+ stack_(0),
+ stackTop_(0),
+ stackEnd_(0),
+ initialCapacity_(stackCapacity) {}
+
+#if RAPIDJSON_HAS_CXX11_RVALUE_REFS
+ Stack(Stack&& rhs)
+ : allocator_(rhs.allocator_),
+ ownAllocator_(rhs.ownAllocator_),
+ stack_(rhs.stack_),
+ stackTop_(rhs.stackTop_),
+ stackEnd_(rhs.stackEnd_),
+ initialCapacity_(rhs.initialCapacity_) {
+ rhs.allocator_ = 0;
+ rhs.ownAllocator_ = 0;
+ rhs.stack_ = 0;
+ rhs.stackTop_ = 0;
+ rhs.stackEnd_ = 0;
+ rhs.initialCapacity_ = 0;
+ }
+#endif
+
+ ~Stack() { Destroy(); }
+
+#if RAPIDJSON_HAS_CXX11_RVALUE_REFS
+ Stack& operator=(Stack&& rhs) {
+ if (&rhs != this) {
+ Destroy();
+
+ allocator_ = rhs.allocator_;
+ ownAllocator_ = rhs.ownAllocator_;
+ stack_ = rhs.stack_;
+ stackTop_ = rhs.stackTop_;
+ stackEnd_ = rhs.stackEnd_;
+ initialCapacity_ = rhs.initialCapacity_;
+
+ rhs.allocator_ = 0;
+ rhs.ownAllocator_ = 0;
+ rhs.stack_ = 0;
+ rhs.stackTop_ = 0;
+ rhs.stackEnd_ = 0;
+ rhs.initialCapacity_ = 0;
+ }
+ return *this;
+ }
+#endif
+
+ void Swap(Stack& rhs) RAPIDJSON_NOEXCEPT {
+ internal::Swap(allocator_, rhs.allocator_);
+ internal::Swap(ownAllocator_, rhs.ownAllocator_);
+ internal::Swap(stack_, rhs.stack_);
+ internal::Swap(stackTop_, rhs.stackTop_);
+ internal::Swap(stackEnd_, rhs.stackEnd_);
+ internal::Swap(initialCapacity_, rhs.initialCapacity_);
+ }
+
+ void Clear() { stackTop_ = stack_; }
+
+ void ShrinkToFit() {
+ if (Empty()) {
+ // If the stack is empty, completely deallocate the memory.
+ Allocator::Free(stack_);
+ stack_ = 0;
+ stackTop_ = 0;
+ stackEnd_ = 0;
+ } else
+ Resize(GetSize());
+ }
+
+ // Optimization note: try to minimize the size of this function for force
+ // inline. Expansion is run very infrequently, so it is moved to another
+ // (probably non-inline) function.
+ template <typename T>
+ RAPIDJSON_FORCEINLINE void Reserve(size_t count = 1) {
+ // Expand the stack if needed
+ if (RAPIDJSON_UNLIKELY(stackTop_ + sizeof(T) * count > stackEnd_))
+ Expand<T>(count);
+ }
+
+ template <typename T>
+ RAPIDJSON_FORCEINLINE T* Push(size_t count = 1) {
+ Reserve<T>(count);
+ return PushUnsafe<T>(count);
+ }
+
+ template <typename T>
+ RAPIDJSON_FORCEINLINE T* PushUnsafe(size_t count = 1) {
+ RAPIDJSON_ASSERT(stackTop_ + sizeof(T) * count <= stackEnd_);
+ T* ret = reinterpret_cast<T*>(stackTop_);
+ stackTop_ += sizeof(T) * count;
+ return ret;
+ }
+
+ template <typename T>
+ T* Pop(size_t count) {
+ RAPIDJSON_ASSERT(GetSize() >= count * sizeof(T));
+ stackTop_ -= count * sizeof(T);
+ return reinterpret_cast<T*>(stackTop_);
+ }
+
+ template <typename T>
+ T* Top() {
+ RAPIDJSON_ASSERT(GetSize() >= sizeof(T));
+ return reinterpret_cast<T*>(stackTop_ - sizeof(T));
+ }
+
+ template <typename T>
+ const T* Top() const {
+ RAPIDJSON_ASSERT(GetSize() >= sizeof(T));
+ return reinterpret_cast<T*>(stackTop_ - sizeof(T));
+ }
+
+ template <typename T>
+ T* End() {
+ return reinterpret_cast<T*>(stackTop_);
+ }
+
+ template <typename T>
+ const T* End() const {
+ return reinterpret_cast<T*>(stackTop_);
+ }
+
+ template <typename T>
+ T* Bottom() {
+ return reinterpret_cast<T*>(stack_);
+ }
+
+ template <typename T>
+ const T* Bottom() const {
+ return reinterpret_cast<T*>(stack_);
+ }
+
+ bool HasAllocator() const { return allocator_ != 0; }
+
+ Allocator& GetAllocator() {
+ RAPIDJSON_ASSERT(allocator_);
+ return *allocator_;
+ }
+
+ bool Empty() const { return stackTop_ == stack_; }
+ size_t GetSize() const { return static_cast<size_t>(stackTop_ - stack_); }
+ size_t GetCapacity() const { return static_cast<size_t>(stackEnd_ - stack_); }
+
+ private:
+ template <typename T>
+ void Expand(size_t count) {
+ // Only expand the capacity if the current stack exists. Otherwise just
+ // create a stack with initial capacity.
+ size_t newCapacity;
+ if (stack_ == 0) {
+ if (!allocator_)
+ ownAllocator_ = allocator_ = RAPIDJSON_NEW(Allocator());
+ newCapacity = initialCapacity_;
+ } else {
+ newCapacity = GetCapacity();
+ newCapacity += (newCapacity + 1) / 2;
+ }
+ size_t newSize = GetSize() + sizeof(T) * count;
+ if (newCapacity < newSize)
+ newCapacity = newSize;
+
+ Resize(newCapacity);
+ }
+
+ void Resize(size_t newCapacity) {
+ const size_t size = GetSize(); // Backup the current size
+ stack_ = static_cast<char*>(
+ allocator_->Realloc(stack_, GetCapacity(), newCapacity));
+ stackTop_ = stack_ + size;
+ stackEnd_ = stack_ + newCapacity;
+ }
+
+ void Destroy() {
+ Allocator::Free(stack_);
+ RAPIDJSON_DELETE(ownAllocator_); // Only delete if it is owned by the stack
+ }
+
+ // Prohibit copy constructor & assignment operator.
+ Stack(const Stack&);
+ Stack& operator=(const Stack&);
+
+ Allocator* allocator_;
+ Allocator* ownAllocator_;
+ char* stack_;
+ char* stackTop_;
+ char* stackEnd_;
+ size_t initialCapacity_;
+};
+
+} // namespace internal
+RAPIDJSON_NAMESPACE_END
+
+#if defined(__clang__)
+RAPIDJSON_DIAG_POP
+#endif
+
+#endif // RAPIDJSON_STACK_H_
diff --git a/third_party/rapidjson/internal/strfunc.h b/third_party/rapidjson/internal/strfunc.h
new file mode 100644
index 00000000..59b63188
--- /dev/null
+++ b/third_party/rapidjson/internal/strfunc.h
@@ -0,0 +1,63 @@
+// Tencent is pleased to support the open source community by making RapidJSON
+// available.
+//
+// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All
+// rights reserved.
+//
+// Licensed under the MIT License (the "License"); you may not use this file
+// except in compliance with the License. You may obtain a copy of the License
+// at
+//
+// http://opensource.org/licenses/MIT
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+// License for the specific language governing permissions and limitations under
+// the License.
+
+#ifndef RAPIDJSON_INTERNAL_STRFUNC_H_
+#define RAPIDJSON_INTERNAL_STRFUNC_H_
+
+#include "rapidjson/stream.h"
+
+RAPIDJSON_NAMESPACE_BEGIN
+namespace internal {
+
+//! Custom strlen() which works on different character types.
+/*! \tparam Ch Character type (e.g. char, wchar_t, short)
+ \param s Null-terminated input string.
+ \return Number of characters in the string.
+ \note This has the same semantics as strlen(), the return value is not
+ number of Unicode codepoints.
+*/
+template <typename Ch>
+inline SizeType StrLen(const Ch* s) {
+ const Ch* p = s;
+ while (*p)
+ ++p;
+ return SizeType(p - s);
+}
+
+//! Returns number of code points in a encoded string.
+template <typename Encoding>
+bool CountStringCodePoint(const typename Encoding::Ch* s,
+ SizeType length,
+ SizeType* outCount) {
+ GenericStringStream<Encoding> is(s);
+ const typename Encoding::Ch* end = s + length;
+ SizeType count = 0;
+ while (is.src_ < end) {
+ unsigned codepoint;
+ if (!Encoding::Decode(is, &codepoint))
+ return false;
+ count++;
+ }
+ *outCount = count;
+ return true;
+}
+
+} // namespace internal
+RAPIDJSON_NAMESPACE_END
+
+#endif // RAPIDJSON_INTERNAL_STRFUNC_H_
diff --git a/include/rapidjson/internal/strtod.h b/third_party/rapidjson/internal/strtod.h
index 289c413b..289c413b 100644
--- a/include/rapidjson/internal/strtod.h
+++ b/third_party/rapidjson/internal/strtod.h
diff --git a/include/rapidjson/internal/swap.h b/third_party/rapidjson/internal/swap.h
index 666e49f9..33e24dcb 100644
--- a/include/rapidjson/internal/swap.h
+++ b/third_party/rapidjson/internal/swap.h
@@ -1,46 +1,50 @@
-// Tencent is pleased to support the open source community by making RapidJSON available.
+// Tencent is pleased to support the open source community by making RapidJSON
+// available.
//
-// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved.
+// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All
+// rights reserved.
//
-// Licensed under the MIT License (the "License"); you may not use this file except
-// in compliance with the License. You may obtain a copy of the License at
+// Licensed under the MIT License (the "License"); you may not use this file
+// except in compliance with the License. You may obtain a copy of the License
+// at
//
// http://opensource.org/licenses/MIT
//
-// Unless required by applicable law or agreed to in writing, software distributed
-// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
-// CONDITIONS OF ANY KIND, either express or implied. See the License for the
-// specific language governing permissions and limitations under the License.
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+// License for the specific language governing permissions and limitations under
+// the License.
#ifndef RAPIDJSON_INTERNAL_SWAP_H_
#define RAPIDJSON_INTERNAL_SWAP_H_
-#include "../rapidjson.h"
+#include "rapidjson/rapidjson.h"
#if defined(__clang__)
RAPIDJSON_DIAG_PUSH
-RAPIDJSON_DIAG_OFF(c++98-compat)
+RAPIDJSON_DIAG_OFF(c++ 98 - compat)
#endif
RAPIDJSON_NAMESPACE_BEGIN
namespace internal {
//! Custom swap() to avoid dependency on C++ <algorithm> header
-/*! \tparam T Type of the arguments to swap, should be instantiated with primitive C++ types only.
- \note This has the same semantics as std::swap().
+/*! \tparam T Type of the arguments to swap, should be instantiated with
+ primitive C++ types only. \note This has the same semantics as std::swap().
*/
template <typename T>
inline void Swap(T& a, T& b) RAPIDJSON_NOEXCEPT {
- T tmp = a;
- a = b;
- b = tmp;
+ T tmp = a;
+ a = b;
+ b = tmp;
}
-} // namespace internal
+} // namespace internal
RAPIDJSON_NAMESPACE_END
#if defined(__clang__)
RAPIDJSON_DIAG_POP
#endif
-#endif // RAPIDJSON_INTERNAL_SWAP_H_
+#endif // RAPIDJSON_INTERNAL_SWAP_H_
diff --git a/include/rapidjson/istreamwrapper.h b/third_party/rapidjson/istreamwrapper.h
index f5fe2897..f5fe2897 100644
--- a/include/rapidjson/istreamwrapper.h
+++ b/third_party/rapidjson/istreamwrapper.h
diff --git a/third_party/rapidjson/memorybuffer.h b/third_party/rapidjson/memorybuffer.h
new file mode 100644
index 00000000..200dd1ae
--- /dev/null
+++ b/third_party/rapidjson/memorybuffer.h
@@ -0,0 +1,78 @@
+// Tencent is pleased to support the open source community by making RapidJSON
+// available.
+//
+// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All
+// rights reserved.
+//
+// Licensed under the MIT License (the "License"); you may not use this file
+// except in compliance with the License. You may obtain a copy of the License
+// at
+//
+// http://opensource.org/licenses/MIT
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+// License for the specific language governing permissions and limitations under
+// the License.
+
+#ifndef RAPIDJSON_MEMORYBUFFER_H_
+#define RAPIDJSON_MEMORYBUFFER_H_
+
+#include "rapidjson/internal/stack.h"
+#include "stream.h"
+
+RAPIDJSON_NAMESPACE_BEGIN
+
+//! Represents an in-memory output byte stream.
+/*!
+ This class is mainly for being wrapped by EncodedOutputStream or
+ AutoUTFOutputStream.
+
+ It is similar to FileWriteBuffer but the destination is an in-memory buffer
+ instead of a file.
+
+ Differences between MemoryBuffer and StringBuffer:
+ 1. StringBuffer has Encoding but MemoryBuffer is only a byte buffer.
+ 2. StringBuffer::GetString() returns a null-terminated string.
+ MemoryBuffer::GetBuffer() returns a buffer without terminator.
+
+ \tparam Allocator type for allocating memory buffer.
+ \note implements Stream concept
+*/
+template <typename Allocator = CrtAllocator>
+struct GenericMemoryBuffer {
+ typedef char Ch; // byte
+
+ GenericMemoryBuffer(Allocator* allocator = 0,
+ size_t capacity = kDefaultCapacity)
+ : stack_(allocator, capacity) {}
+
+ void Put(Ch c) { *stack_.template Push<Ch>() = c; }
+ void Flush() {}
+
+ void Clear() { stack_.Clear(); }
+ void ShrinkToFit() { stack_.ShrinkToFit(); }
+ Ch* Push(size_t count) { return stack_.template Push<Ch>(count); }
+ void Pop(size_t count) { stack_.template Pop<Ch>(count); }
+
+ const Ch* GetBuffer() const { return stack_.template Bottom<Ch>(); }
+
+ size_t GetSize() const { return stack_.GetSize(); }
+
+ static const size_t kDefaultCapacity = 256;
+ mutable internal::Stack<Allocator> stack_;
+};
+
+typedef GenericMemoryBuffer<> MemoryBuffer;
+
+//! Implement specialized version of PutN() with memset() for better
+//! performance.
+template <>
+inline void PutN(MemoryBuffer& memoryBuffer, char c, size_t n) {
+ std::memset(memoryBuffer.stack_.Push<char>(n), c, n * sizeof(c));
+}
+
+RAPIDJSON_NAMESPACE_END
+
+#endif // RAPIDJSON_MEMORYBUFFER_H_
diff --git a/include/rapidjson/memorystream.h b/third_party/rapidjson/memorystream.h
index 1d71d8a4..1d71d8a4 100644
--- a/include/rapidjson/memorystream.h
+++ b/third_party/rapidjson/memorystream.h
diff --git a/include/rapidjson/msinttypes/inttypes.h b/third_party/rapidjson/msinttypes/inttypes.h
index 18111286..18111286 100644
--- a/include/rapidjson/msinttypes/inttypes.h
+++ b/third_party/rapidjson/msinttypes/inttypes.h
diff --git a/include/rapidjson/msinttypes/stdint.h b/third_party/rapidjson/msinttypes/stdint.h
index 3d4477b9..3d4477b9 100644
--- a/include/rapidjson/msinttypes/stdint.h
+++ b/third_party/rapidjson/msinttypes/stdint.h
diff --git a/include/rapidjson/ostreamwrapper.h b/third_party/rapidjson/ostreamwrapper.h
index 6f4667c0..6f4667c0 100644
--- a/include/rapidjson/ostreamwrapper.h
+++ b/third_party/rapidjson/ostreamwrapper.h
diff --git a/third_party/rapidjson/pointer.h b/third_party/rapidjson/pointer.h
new file mode 100644
index 00000000..ad401606
--- /dev/null
+++ b/third_party/rapidjson/pointer.h
@@ -0,0 +1,1716 @@
+// Tencent is pleased to support the open source community by making RapidJSON
+// available.
+//
+// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All
+// rights reserved.
+//
+// Licensed under the MIT License (the "License"); you may not use this file
+// except in compliance with the License. You may obtain a copy of the License
+// at
+//
+// http://opensource.org/licenses/MIT
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+// License for the specific language governing permissions and limitations under
+// the License.
+
+#ifndef RAPIDJSON_POINTER_H_
+#define RAPIDJSON_POINTER_H_
+
+#include "document.h"
+#include "rapidjson/internal/itoa.h"
+
+#ifdef __clang__
+RAPIDJSON_DIAG_PUSH
+RAPIDJSON_DIAG_OFF(switch - enum)
+#endif
+
+#ifdef _MSC_VER
+RAPIDJSON_DIAG_PUSH
+RAPIDJSON_DIAG_OFF(4512) // assignment operator could not be generated
+#endif
+
+RAPIDJSON_NAMESPACE_BEGIN
+
+static const SizeType kPointerInvalidIndex =
+ ~SizeType(0); //!< Represents an invalid index in GenericPointer::Token
+
+//! Error code of parsing.
+/*! \ingroup RAPIDJSON_ERRORS
+ \see GenericPointer::GenericPointer, GenericPointer::GetParseErrorCode
+*/
+enum PointerParseErrorCode {
+ kPointerParseErrorNone = 0, //!< The parse is successful
+
+ kPointerParseErrorTokenMustBeginWithSolidus, //!< A token must begin with a
+ //!< '/'
+ kPointerParseErrorInvalidEscape, //!< Invalid escape
+ kPointerParseErrorInvalidPercentEncoding, //!< Invalid percent encoding in
+ //!< URI fragment
+ kPointerParseErrorCharacterMustPercentEncode //!< A character must percent
+ //!< encoded in URI fragment
+};
+
+///////////////////////////////////////////////////////////////////////////////
+// GenericPointer
+
+//! Represents a JSON Pointer. Use Pointer for UTF8 encoding and default
+//! allocator.
+/*!
+ This class implements RFC 6901 "JavaScript Object Notation (JSON) Pointer"
+ (https://tools.ietf.org/html/rfc6901).
+
+ A JSON pointer is for identifying a specific value in a JSON document
+ (GenericDocument). It can simplify coding of DOM tree manipulation, because
+ it can access multiple-level depth of DOM tree with single API call.
+
+ After it parses a string representation (e.g. "/foo/0" or URI fragment
+ representation (e.g. "#/foo/0") into its internal representation (tokens),
+ it can be used to resolve a specific value in multiple documents, or
+ sub-tree of documents.
+
+ Contrary to GenericValue, Pointer can be copy constructed and copy assigned.
+ Apart from assignment, a Pointer cannot be modified after construction.
+
+ Although Pointer is very convenient, please aware that constructing Pointer
+ involves parsing and dynamic memory allocation. A special constructor with
+ user- supplied tokens eliminates these.
+
+ GenericPointer depends on GenericDocument and GenericValue.
+
+ \tparam ValueType The value type of the DOM tree. E.g. GenericValue<UTF8<> >
+ \tparam Allocator The allocator type for allocating memory for internal
+ representation.
+
+ \note GenericPointer uses same encoding of ValueType.
+ However, Allocator of GenericPointer is independent of Allocator of Value.
+*/
+template <typename ValueType, typename Allocator = CrtAllocator>
+class GenericPointer {
+ public:
+ typedef typename ValueType::EncodingType
+ EncodingType; //!< Encoding type from Value
+ typedef typename ValueType::Ch Ch; //!< Character type from Value
+
+ //! A token is the basic units of internal representation.
+ /*!
+ A JSON pointer string representation "/foo/123" is parsed to two tokens:
+ "foo" and 123. 123 will be represented in both numeric form and string
+ form. They are resolved according to the actual value type (object or
+ array).
+
+ For token that are not numbers, or the numeric value is out of bound
+ (greater than limits of SizeType), they are only treated as string form
+ (i.e. the token's index will be equal to kPointerInvalidIndex).
+
+ This struct is public so that user can create a Pointer without parsing
+ and allocation, using a special constructor.
+ */
+ struct Token {
+ const Ch* name; //!< Name of the token. It has null character at the end
+ //!< but it can contain null character.
+ SizeType length; //!< Length of the name.
+ SizeType index; //!< A valid array index, if it is not equal to
+ //!< kPointerInvalidIndex.
+ };
+
+ //!@name Constructors and destructor.
+ //@{
+
+ //! Default constructor.
+ GenericPointer(Allocator* allocator = 0)
+ : allocator_(allocator),
+ ownAllocator_(),
+ nameBuffer_(),
+ tokens_(),
+ tokenCount_(),
+ parseErrorOffset_(),
+ parseErrorCode_(kPointerParseErrorNone) {}
+
+ //! Constructor that parses a string or URI fragment representation.
+ /*!
+ \param source A null-terminated, string or URI fragment representation of
+ JSON pointer. \param allocator User supplied allocator for this pointer. If
+ no allocator is provided, it creates a self-owned one.
+ */
+ explicit GenericPointer(const Ch* source, Allocator* allocator = 0)
+ : allocator_(allocator),
+ ownAllocator_(),
+ nameBuffer_(),
+ tokens_(),
+ tokenCount_(),
+ parseErrorOffset_(),
+ parseErrorCode_(kPointerParseErrorNone) {
+ Parse(source, internal::StrLen(source));
+ }
+
+#if RAPIDJSON_HAS_STDSTRING
+ //! Constructor that parses a string or URI fragment representation.
+ /*!
+ \param source A string or URI fragment representation of JSON pointer.
+ \param allocator User supplied allocator for this pointer. If no allocator
+ is provided, it creates a self-owned one. \note Requires the definition of
+ the preprocessor symbol \ref RAPIDJSON_HAS_STDSTRING.
+ */
+ explicit GenericPointer(const std::basic_string<Ch>& source,
+ Allocator* allocator = 0)
+ : allocator_(allocator),
+ ownAllocator_(),
+ nameBuffer_(),
+ tokens_(),
+ tokenCount_(),
+ parseErrorOffset_(),
+ parseErrorCode_(kPointerParseErrorNone) {
+ Parse(source.c_str(), source.size());
+ }
+#endif
+
+ //! Constructor that parses a string or URI fragment representation, with
+ //! length of the source string.
+ /*!
+ \param source A string or URI fragment representation of JSON pointer.
+ \param length Length of source.
+ \param allocator User supplied allocator for this pointer. If no allocator
+ is provided, it creates a self-owned one. \note Slightly faster than the
+ overload without length.
+ */
+ GenericPointer(const Ch* source, size_t length, Allocator* allocator = 0)
+ : allocator_(allocator),
+ ownAllocator_(),
+ nameBuffer_(),
+ tokens_(),
+ tokenCount_(),
+ parseErrorOffset_(),
+ parseErrorCode_(kPointerParseErrorNone) {
+ Parse(source, length);
+ }
+
+ //! Constructor with user-supplied tokens.
+ /*!
+ This constructor let user supplies const array of tokens.
+ This prevents the parsing process and eliminates allocation.
+ This is preferred for memory constrained environments.
+
+ \param tokens An constant array of tokens representing the JSON pointer.
+ \param tokenCount Number of tokens.
+
+ \b Example
+ \code
+ #define NAME(s) { s, sizeof(s) / sizeof(s[0]) - 1, kPointerInvalidIndex }
+ #define INDEX(i) { #i, sizeof(#i) - 1, i }
+
+ static const Pointer::Token kTokens[] = { NAME("foo"), INDEX(123) };
+ static const Pointer p(kTokens, sizeof(kTokens) / sizeof(kTokens[0]));
+ // Equivalent to static const Pointer p("/foo/123");
+
+ #undef NAME
+ #undef INDEX
+ \endcode
+ */
+ GenericPointer(const Token* tokens, size_t tokenCount)
+ : allocator_(),
+ ownAllocator_(),
+ nameBuffer_(),
+ tokens_(const_cast<Token*>(tokens)),
+ tokenCount_(tokenCount),
+ parseErrorOffset_(),
+ parseErrorCode_(kPointerParseErrorNone) {}
+
+ //! Copy constructor.
+ GenericPointer(const GenericPointer& rhs, Allocator* allocator = 0)
+ : allocator_(allocator),
+ ownAllocator_(),
+ nameBuffer_(),
+ tokens_(),
+ tokenCount_(),
+ parseErrorOffset_(),
+ parseErrorCode_(kPointerParseErrorNone) {
+ *this = rhs;
+ }
+
+ //! Destructor.
+ ~GenericPointer() {
+ if (nameBuffer_) // If user-supplied tokens constructor is used,
+ // nameBuffer_ is nullptr and tokens_ are not deallocated.
+ Allocator::Free(tokens_);
+ RAPIDJSON_DELETE(ownAllocator_);
+ }
+
+ //! Assignment operator.
+ GenericPointer& operator=(const GenericPointer& rhs) {
+ if (this != &rhs) {
+ // Do not delete ownAllcator
+ if (nameBuffer_)
+ Allocator::Free(tokens_);
+
+ tokenCount_ = rhs.tokenCount_;
+ parseErrorOffset_ = rhs.parseErrorOffset_;
+ parseErrorCode_ = rhs.parseErrorCode_;
+
+ if (rhs.nameBuffer_)
+ CopyFromRaw(rhs); // Normally parsed tokens.
+ else {
+ tokens_ = rhs.tokens_; // User supplied const tokens.
+ nameBuffer_ = 0;
+ }
+ }
+ return *this;
+ }
+
+ //@}
+
+ //!@name Append token
+ //@{
+
+ //! Append a token and return a new Pointer
+ /*!
+ \param token Token to be appended.
+ \param allocator Allocator for the newly return Pointer.
+ \return A new Pointer with appended token.
+ */
+ GenericPointer Append(const Token& token, Allocator* allocator = 0) const {
+ GenericPointer r;
+ r.allocator_ = allocator;
+ Ch* p = r.CopyFromRaw(*this, 1, token.length + 1);
+ std::memcpy(p, token.name, (token.length + 1) * sizeof(Ch));
+ r.tokens_[tokenCount_].name = p;
+ r.tokens_[tokenCount_].length = token.length;
+ r.tokens_[tokenCount_].index = token.index;
+ return r;
+ }
+
+ //! Append a name token with length, and return a new Pointer
+ /*!
+ \param name Name to be appended.
+ \param length Length of name.
+ \param allocator Allocator for the newly return Pointer.
+ \return A new Pointer with appended token.
+ */
+ GenericPointer Append(const Ch* name,
+ SizeType length,
+ Allocator* allocator = 0) const {
+ Token token = {name, length, kPointerInvalidIndex};
+ return Append(token, allocator);
+ }
+
+ //! Append a name token without length, and return a new Pointer
+ /*!
+ \param name Name (const Ch*) to be appended.
+ \param allocator Allocator for the newly return Pointer.
+ \return A new Pointer with appended token.
+ */
+ template <typename T>
+ RAPIDJSON_DISABLEIF_RETURN(
+ (internal::NotExpr<
+ internal::IsSame<typename internal::RemoveConst<T>::Type, Ch> >),
+ (GenericPointer))
+ Append(T* name, Allocator* allocator = 0) const {
+ return Append(name, StrLen(name), allocator);
+ }
+
+#if RAPIDJSON_HAS_STDSTRING
+ //! Append a name token, and return a new Pointer
+ /*!
+ \param name Name to be appended.
+ \param allocator Allocator for the newly return Pointer.
+ \return A new Pointer with appended token.
+ */
+ GenericPointer Append(const std::basic_string<Ch>& name,
+ Allocator* allocator = 0) const {
+ return Append(name.c_str(), static_cast<SizeType>(name.size()), allocator);
+ }
+#endif
+
+ //! Append a index token, and return a new Pointer
+ /*!
+ \param index Index to be appended.
+ \param allocator Allocator for the newly return Pointer.
+ \return A new Pointer with appended token.
+ */
+ GenericPointer Append(SizeType index, Allocator* allocator = 0) const {
+ char buffer[21];
+ char* end = sizeof(SizeType) == 4 ? internal::u32toa(index, buffer)
+ : internal::u64toa(index, buffer);
+ SizeType length = static_cast<SizeType>(end - buffer);
+ buffer[length] = '\0';
+
+ if (sizeof(Ch) == 1) {
+ Token token = {reinterpret_cast<Ch*>(buffer), length, index};
+ return Append(token, allocator);
+ } else {
+ Ch name[21];
+ for (size_t i = 0; i <= length; i++)
+ name[i] = buffer[i];
+ Token token = {name, length, index};
+ return Append(token, allocator);
+ }
+ }
+
+ //! Append a token by value, and return a new Pointer
+ /*!
+ \param token token to be appended.
+ \param allocator Allocator for the newly return Pointer.
+ \return A new Pointer with appended token.
+ */
+ GenericPointer Append(const ValueType& token,
+ Allocator* allocator = 0) const {
+ if (token.IsString())
+ return Append(token.GetString(), token.GetStringLength(), allocator);
+ else {
+ RAPIDJSON_ASSERT(token.IsUint64());
+ RAPIDJSON_ASSERT(token.GetUint64() <= SizeType(~0));
+ return Append(static_cast<SizeType>(token.GetUint64()), allocator);
+ }
+ }
+
+ //!@name Handling Parse Error
+ //@{
+
+ //! Check whether this is a valid pointer.
+ bool IsValid() const { return parseErrorCode_ == kPointerParseErrorNone; }
+
+ //! Get the parsing error offset in code unit.
+ size_t GetParseErrorOffset() const { return parseErrorOffset_; }
+
+ //! Get the parsing error code.
+ PointerParseErrorCode GetParseErrorCode() const { return parseErrorCode_; }
+
+ //@}
+
+ //! Get the allocator of this pointer.
+ Allocator& GetAllocator() { return *allocator_; }
+
+ //!@name Tokens
+ //@{
+
+ //! Get the token array (const version only).
+ const Token* GetTokens() const { return tokens_; }
+
+ //! Get the number of tokens.
+ size_t GetTokenCount() const { return tokenCount_; }
+
+ //@}
+
+ //!@name Equality/inequality operators
+ //@{
+
+ //! Equality operator.
+ /*!
+ \note When any pointers are invalid, always returns false.
+ */
+ bool operator==(const GenericPointer& rhs) const {
+ if (!IsValid() || !rhs.IsValid() || tokenCount_ != rhs.tokenCount_)
+ return false;
+
+ for (size_t i = 0; i < tokenCount_; i++) {
+ if (tokens_[i].index != rhs.tokens_[i].index ||
+ tokens_[i].length != rhs.tokens_[i].length ||
+ (tokens_[i].length != 0 &&
+ std::memcmp(tokens_[i].name, rhs.tokens_[i].name,
+ sizeof(Ch) * tokens_[i].length) != 0)) {
+ return false;
+ }
+ }
+
+ return true;
+ }
+
+ //! Inequality operator.
+ /*!
+ \note When any pointers are invalid, always returns true.
+ */
+ bool operator!=(const GenericPointer& rhs) const { return !(*this == rhs); }
+
+ //@}
+
+ //!@name Stringify
+ //@{
+
+ //! Stringify the pointer into string representation.
+ /*!
+ \tparam OutputStream Type of output stream.
+ \param os The output stream.
+ */
+ template <typename OutputStream>
+ bool Stringify(OutputStream& os) const {
+ return Stringify<false, OutputStream>(os);
+ }
+
+ //! Stringify the pointer into URI fragment representation.
+ /*!
+ \tparam OutputStream Type of output stream.
+ \param os The output stream.
+ */
+ template <typename OutputStream>
+ bool StringifyUriFragment(OutputStream& os) const {
+ return Stringify<true, OutputStream>(os);
+ }
+
+ //@}
+
+ //!@name Create value
+ //@{
+
+ //! Create a value in a subtree.
+ /*!
+ If the value is not exist, it creates all parent values and a JSON Null
+ value. So it always succeed and return the newly created or existing value.
+
+ Remind that it may change types of parents according to tokens, so it
+ potentially removes previously stored values. For example, if a document
+ was an array, and "/foo" is used to create a value, then the document
+ will be changed to an object, and all existing array elements are lost.
+
+ \param root Root value of a DOM subtree to be resolved. It can be any
+ value other than document root. \param allocator Allocator for creating the
+ values if the specified value or its parents are not exist. \param
+ alreadyExist If non-null, it stores whether the resolved value is already
+ exist. \return The resolved newly created (a JSON Null value), or already
+ exists value.
+ */
+ ValueType& Create(ValueType& root,
+ typename ValueType::AllocatorType& allocator,
+ bool* alreadyExist = 0) const {
+ RAPIDJSON_ASSERT(IsValid());
+ ValueType* v = &root;
+ bool exist = true;
+ for (const Token* t = tokens_; t != tokens_ + tokenCount_; ++t) {
+ if (v->IsArray() && t->name[0] == '-' && t->length == 1) {
+ v->PushBack(ValueType().Move(), allocator);
+ v = &((*v)[v->Size() - 1]);
+ exist = false;
+ } else {
+ if (t->index == kPointerInvalidIndex) { // must be object name
+ if (!v->IsObject())
+ v->SetObject(); // Change to Object
+ } else { // object name or array index
+ if (!v->IsArray() && !v->IsObject())
+ v->SetArray(); // Change to Array
+ }
+
+ if (v->IsArray()) {
+ if (t->index >= v->Size()) {
+ v->Reserve(t->index + 1, allocator);
+ while (t->index >= v->Size())
+ v->PushBack(ValueType().Move(), allocator);
+ exist = false;
+ }
+ v = &((*v)[t->index]);
+ } else {
+ typename ValueType::MemberIterator m =
+ v->FindMember(GenericStringRef<Ch>(t->name, t->length));
+ if (m == v->MemberEnd()) {
+ v->AddMember(ValueType(t->name, t->length, allocator).Move(),
+ ValueType().Move(), allocator);
+ v = &(--v->MemberEnd())
+ ->value; // Assumes AddMember() appends at the end
+ exist = false;
+ } else
+ v = &m->value;
+ }
+ }
+ }
+
+ if (alreadyExist)
+ *alreadyExist = exist;
+
+ return *v;
+ }
+
+ //! Creates a value in a document.
+ /*!
+ \param document A document to be resolved.
+ \param alreadyExist If non-null, it stores whether the resolved value is
+ already exist. \return The resolved newly created, or already exists value.
+ */
+ template <typename stackAllocator>
+ ValueType& Create(GenericDocument<EncodingType,
+ typename ValueType::AllocatorType,
+ stackAllocator>& document,
+ bool* alreadyExist = 0) const {
+ return Create(document, document.GetAllocator(), alreadyExist);
+ }
+
+ //@}
+
+ //!@name Query value
+ //@{
+
+ //! Query a value in a subtree.
+ /*!
+ \param root Root value of a DOM sub-tree to be resolved. It can be any
+ value other than document root. \param unresolvedTokenIndex If the pointer
+ cannot resolve a token in the pointer, this parameter can obtain the index
+ of unresolved token. \return Pointer to the value if it can be resolved.
+ Otherwise null.
+
+ \note
+ There are only 3 situations when a value cannot be resolved:
+ 1. A value in the path is not an array nor object.
+ 2. An object value does not contain the token.
+ 3. A token is out of range of an array value.
+
+ Use unresolvedTokenIndex to retrieve the token index.
+ */
+ ValueType* Get(ValueType& root, size_t* unresolvedTokenIndex = 0) const {
+ RAPIDJSON_ASSERT(IsValid());
+ ValueType* v = &root;
+ for (const Token* t = tokens_; t != tokens_ + tokenCount_; ++t) {
+ switch (v->GetType()) {
+ case kObjectType: {
+ typename ValueType::MemberIterator m =
+ v->FindMember(GenericStringRef<Ch>(t->name, t->length));
+ if (m == v->MemberEnd())
+ break;
+ v = &m->value;
+ }
+ continue;
+ case kArrayType:
+ if (t->index == kPointerInvalidIndex || t->index >= v->Size())
+ break;
+ v = &((*v)[t->index]);
+ continue;
+ default:
+ break;
+ }
+
+ // Error: unresolved token
+ if (unresolvedTokenIndex)
+ *unresolvedTokenIndex = static_cast<size_t>(t - tokens_);
+ return 0;
+ }
+ return v;
+ }
+
+ //! Query a const value in a const subtree.
+ /*!
+ \param root Root value of a DOM sub-tree to be resolved. It can be any
+ value other than document root. \return Pointer to the value if it can be
+ resolved. Otherwise null.
+ */
+ const ValueType* Get(const ValueType& root,
+ size_t* unresolvedTokenIndex = 0) const {
+ return Get(const_cast<ValueType&>(root), unresolvedTokenIndex);
+ }
+
+ //@}
+
+ //!@name Query a value with default
+ //@{
+
+ //! Query a value in a subtree with default value.
+ /*!
+ Similar to Get(), but if the specified value do not exists, it creates all
+ parents and clone the default value. So that this function always succeed.
+
+ \param root Root value of a DOM sub-tree to be resolved. It can be any
+ value other than document root. \param defaultValue Default value to be
+ cloned if the value was not exists. \param allocator Allocator for creating
+ the values if the specified value or its parents are not exist. \see
+ Create()
+ */
+ ValueType& GetWithDefault(
+ ValueType& root,
+ const ValueType& defaultValue,
+ typename ValueType::AllocatorType& allocator) const {
+ bool alreadyExist;
+ Value& v = Create(root, allocator, &alreadyExist);
+ return alreadyExist ? v : v.CopyFrom(defaultValue, allocator);
+ }
+
+ //! Query a value in a subtree with default null-terminated string.
+ ValueType& GetWithDefault(
+ ValueType& root,
+ const Ch* defaultValue,
+ typename ValueType::AllocatorType& allocator) const {
+ bool alreadyExist;
+ Value& v = Create(root, allocator, &alreadyExist);
+ return alreadyExist ? v : v.SetString(defaultValue, allocator);
+ }
+
+#if RAPIDJSON_HAS_STDSTRING
+ //! Query a value in a subtree with default std::basic_string.
+ ValueType& GetWithDefault(
+ ValueType& root,
+ const std::basic_string<Ch>& defaultValue,
+ typename ValueType::AllocatorType& allocator) const {
+ bool alreadyExist;
+ Value& v = Create(root, allocator, &alreadyExist);
+ return alreadyExist ? v : v.SetString(defaultValue, allocator);
+ }
+#endif
+
+ //! Query a value in a subtree with default primitive value.
+ /*!
+ \tparam T Either \ref Type, \c int, \c unsigned, \c int64_t, \c uint64_t,
+ \c bool
+ */
+ template <typename T>
+ RAPIDJSON_DISABLEIF_RETURN(
+ (internal::OrExpr<internal::IsPointer<T>, internal::IsGenericValue<T> >),
+ (ValueType&))
+ GetWithDefault(ValueType& root,
+ T defaultValue,
+ typename ValueType::AllocatorType& allocator) const {
+ return GetWithDefault(root, ValueType(defaultValue).Move(), allocator);
+ }
+
+ //! Query a value in a document with default value.
+ template <typename stackAllocator>
+ ValueType& GetWithDefault(GenericDocument<EncodingType,
+ typename ValueType::AllocatorType,
+ stackAllocator>& document,
+ const ValueType& defaultValue) const {
+ return GetWithDefault(document, defaultValue, document.GetAllocator());
+ }
+
+ //! Query a value in a document with default null-terminated string.
+ template <typename stackAllocator>
+ ValueType& GetWithDefault(GenericDocument<EncodingType,
+ typename ValueType::AllocatorType,
+ stackAllocator>& document,
+ const Ch* defaultValue) const {
+ return GetWithDefault(document, defaultValue, document.GetAllocator());
+ }
+
+#if RAPIDJSON_HAS_STDSTRING
+ //! Query a value in a document with default std::basic_string.
+ template <typename stackAllocator>
+ ValueType& GetWithDefault(GenericDocument<EncodingType,
+ typename ValueType::AllocatorType,
+ stackAllocator>& document,
+ const std::basic_string<Ch>& defaultValue) const {
+ return GetWithDefault(document, defaultValue, document.GetAllocator());
+ }
+#endif
+
+ //! Query a value in a document with default primitive value.
+ /*!
+ \tparam T Either \ref Type, \c int, \c unsigned, \c int64_t, \c uint64_t,
+ \c bool
+ */
+ template <typename T, typename stackAllocator>
+ RAPIDJSON_DISABLEIF_RETURN(
+ (internal::OrExpr<internal::IsPointer<T>, internal::IsGenericValue<T> >),
+ (ValueType&))
+ GetWithDefault(GenericDocument<EncodingType,
+ typename ValueType::AllocatorType,
+ stackAllocator>& document,
+ T defaultValue) const {
+ return GetWithDefault(document, defaultValue, document.GetAllocator());
+ }
+
+ //@}
+
+ //!@name Set a value
+ //@{
+
+ //! Set a value in a subtree, with move semantics.
+ /*!
+ It creates all parents if they are not exist or types are different to the
+ tokens. So this function always succeeds but potentially remove existing
+ values.
+
+ \param root Root value of a DOM sub-tree to be resolved. It can be any
+ value other than document root. \param value Value to be set. \param
+ allocator Allocator for creating the values if the specified value or its
+ parents are not exist. \see Create()
+ */
+ ValueType& Set(ValueType& root,
+ ValueType& value,
+ typename ValueType::AllocatorType& allocator) const {
+ return Create(root, allocator) = value;
+ }
+
+ //! Set a value in a subtree, with copy semantics.
+ ValueType& Set(ValueType& root,
+ const ValueType& value,
+ typename ValueType::AllocatorType& allocator) const {
+ return Create(root, allocator).CopyFrom(value, allocator);
+ }
+
+ //! Set a null-terminated string in a subtree.
+ ValueType& Set(ValueType& root,
+ const Ch* value,
+ typename ValueType::AllocatorType& allocator) const {
+ return Create(root, allocator) = ValueType(value, allocator).Move();
+ }
+
+#if RAPIDJSON_HAS_STDSTRING
+ //! Set a std::basic_string in a subtree.
+ ValueType& Set(ValueType& root,
+ const std::basic_string<Ch>& value,
+ typename ValueType::AllocatorType& allocator) const {
+ return Create(root, allocator) = ValueType(value, allocator).Move();
+ }
+#endif
+
+ //! Set a primitive value in a subtree.
+ /*!
+ \tparam T Either \ref Type, \c int, \c unsigned, \c int64_t, \c uint64_t,
+ \c bool
+ */
+ template <typename T>
+ RAPIDJSON_DISABLEIF_RETURN(
+ (internal::OrExpr<internal::IsPointer<T>, internal::IsGenericValue<T> >),
+ (ValueType&))
+ Set(ValueType& root,
+ T value,
+ typename ValueType::AllocatorType& allocator) const {
+ return Create(root, allocator) = ValueType(value).Move();
+ }
+
+ //! Set a value in a document, with move semantics.
+ template <typename stackAllocator>
+ ValueType& Set(GenericDocument<EncodingType,
+ typename ValueType::AllocatorType,
+ stackAllocator>& document,
+ ValueType& value) const {
+ return Create(document) = value;
+ }
+
+ //! Set a value in a document, with copy semantics.
+ template <typename stackAllocator>
+ ValueType& Set(GenericDocument<EncodingType,
+ typename ValueType::AllocatorType,
+ stackAllocator>& document,
+ const ValueType& value) const {
+ return Create(document).CopyFrom(value, document.GetAllocator());
+ }
+
+ //! Set a null-terminated string in a document.
+ template <typename stackAllocator>
+ ValueType& Set(GenericDocument<EncodingType,
+ typename ValueType::AllocatorType,
+ stackAllocator>& document,
+ const Ch* value) const {
+ return Create(document) = ValueType(value, document.GetAllocator()).Move();
+ }
+
+#if RAPIDJSON_HAS_STDSTRING
+ //! Sets a std::basic_string in a document.
+ template <typename stackAllocator>
+ ValueType& Set(GenericDocument<EncodingType,
+ typename ValueType::AllocatorType,
+ stackAllocator>& document,
+ const std::basic_string<Ch>& value) const {
+ return Create(document) = ValueType(value, document.GetAllocator()).Move();
+ }
+#endif
+
+ //! Set a primitive value in a document.
+ /*!
+ \tparam T Either \ref Type, \c int, \c unsigned, \c int64_t, \c uint64_t, \c
+ bool
+ */
+ template <typename T, typename stackAllocator>
+ RAPIDJSON_DISABLEIF_RETURN(
+ (internal::OrExpr<internal::IsPointer<T>, internal::IsGenericValue<T> >),
+ (ValueType&))
+ Set(GenericDocument<EncodingType,
+ typename ValueType::AllocatorType,
+ stackAllocator>& document,
+ T value) const {
+ return Create(document) = value;
+ }
+
+ //@}
+
+ //!@name Swap a value
+ //@{
+
+ //! Swap a value with a value in a subtree.
+ /*!
+ It creates all parents if they are not exist or types are different to the
+ tokens. So this function always succeeds but potentially remove existing
+ values.
+
+ \param root Root value of a DOM sub-tree to be resolved. It can be any
+ value other than document root. \param value Value to be swapped. \param
+ allocator Allocator for creating the values if the specified value or its
+ parents are not exist. \see Create()
+ */
+ ValueType& Swap(ValueType& root,
+ ValueType& value,
+ typename ValueType::AllocatorType& allocator) const {
+ return Create(root, allocator).Swap(value);
+ }
+
+ //! Swap a value with a value in a document.
+ template <typename stackAllocator>
+ ValueType& Swap(GenericDocument<EncodingType,
+ typename ValueType::AllocatorType,
+ stackAllocator>& document,
+ ValueType& value) const {
+ return Create(document).Swap(value);
+ }
+
+ //@}
+
+ //! Erase a value in a subtree.
+ /*!
+ \param root Root value of a DOM sub-tree to be resolved. It can be any
+ value other than document root. \return Whether the resolved value is found
+ and erased.
+
+ \note Erasing with an empty pointer \c Pointer(""), i.e. the root, always
+ fail and return false.
+ */
+ bool Erase(ValueType& root) const {
+ RAPIDJSON_ASSERT(IsValid());
+ if (tokenCount_ == 0) // Cannot erase the root
+ return false;
+
+ ValueType* v = &root;
+ const Token* last = tokens_ + (tokenCount_ - 1);
+ for (const Token* t = tokens_; t != last; ++t) {
+ switch (v->GetType()) {
+ case kObjectType: {
+ typename ValueType::MemberIterator m =
+ v->FindMember(GenericStringRef<Ch>(t->name, t->length));
+ if (m == v->MemberEnd())
+ return false;
+ v = &m->value;
+ } break;
+ case kArrayType:
+ if (t->index == kPointerInvalidIndex || t->index >= v->Size())
+ return false;
+ v = &((*v)[t->index]);
+ break;
+ default:
+ return false;
+ }
+ }
+
+ switch (v->GetType()) {
+ case kObjectType:
+ return v->EraseMember(GenericStringRef<Ch>(last->name, last->length));
+ case kArrayType:
+ if (last->index == kPointerInvalidIndex || last->index >= v->Size())
+ return false;
+ v->Erase(v->Begin() + last->index);
+ return true;
+ default:
+ return false;
+ }
+ }
+
+ private:
+ //! Clone the content from rhs to this.
+ /*!
+ \param rhs Source pointer.
+ \param extraToken Extra tokens to be allocated.
+ \param extraNameBufferSize Extra name buffer size (in number of Ch) to be
+ allocated. \return Start of non-occupied name buffer, for storing extra
+ names.
+ */
+ Ch* CopyFromRaw(const GenericPointer& rhs,
+ size_t extraToken = 0,
+ size_t extraNameBufferSize = 0) {
+ if (!allocator_) // allocator is independently owned.
+ ownAllocator_ = allocator_ = RAPIDJSON_NEW(Allocator());
+
+ size_t nameBufferSize = rhs.tokenCount_; // null terminators for tokens
+ for (Token* t = rhs.tokens_; t != rhs.tokens_ + rhs.tokenCount_; ++t)
+ nameBufferSize += t->length;
+
+ tokenCount_ = rhs.tokenCount_ + extraToken;
+ tokens_ = static_cast<Token*>(allocator_->Malloc(
+ tokenCount_ * sizeof(Token) +
+ (nameBufferSize + extraNameBufferSize) * sizeof(Ch)));
+ nameBuffer_ = reinterpret_cast<Ch*>(tokens_ + tokenCount_);
+ if (rhs.tokenCount_ > 0) {
+ std::memcpy(tokens_, rhs.tokens_, rhs.tokenCount_ * sizeof(Token));
+ }
+ if (nameBufferSize > 0) {
+ std::memcpy(nameBuffer_, rhs.nameBuffer_, nameBufferSize * sizeof(Ch));
+ }
+
+ // Adjust pointers to name buffer
+ std::ptrdiff_t diff = nameBuffer_ - rhs.nameBuffer_;
+ for (Token* t = tokens_; t != tokens_ + rhs.tokenCount_; ++t)
+ t->name += diff;
+
+ return nameBuffer_ + nameBufferSize;
+ }
+
+ //! Check whether a character should be percent-encoded.
+ /*!
+ According to RFC 3986 2.3 Unreserved Characters.
+ \param c The character (code unit) to be tested.
+ */
+ bool NeedPercentEncode(Ch c) const {
+ return !((c >= '0' && c <= '9') || (c >= 'A' && c <= 'Z') ||
+ (c >= 'a' && c <= 'z') || c == '-' || c == '.' || c == '_' ||
+ c == '~');
+ }
+
+ //! Parse a JSON String or its URI fragment representation into tokens.
+#ifndef __clang__ // -Wdocumentation
+ /*!
+ \param source Either a JSON Pointer string, or its URI fragment
+ representation. Not need to be null terminated. \param length Length of the
+ source string. \note Source cannot be JSON String Representation of JSON
+ Pointer, e.g. In "/\u0000", \u0000 will not be unescaped.
+ */
+#endif
+ void Parse(const Ch* source, size_t length) {
+ RAPIDJSON_ASSERT(source != NULL);
+ RAPIDJSON_ASSERT(nameBuffer_ == 0);
+ RAPIDJSON_ASSERT(tokens_ == 0);
+
+ // Create own allocator if user did not supply.
+ if (!allocator_)
+ ownAllocator_ = allocator_ = RAPIDJSON_NEW(Allocator());
+
+ // Count number of '/' as tokenCount
+ tokenCount_ = 0;
+ for (const Ch* s = source; s != source + length; s++)
+ if (*s == '/')
+ tokenCount_++;
+
+ Token* token = tokens_ = static_cast<Token*>(
+ allocator_->Malloc(tokenCount_ * sizeof(Token) + length * sizeof(Ch)));
+ Ch* name = nameBuffer_ = reinterpret_cast<Ch*>(tokens_ + tokenCount_);
+ size_t i = 0;
+
+ // Detect if it is a URI fragment
+ bool uriFragment = false;
+ if (source[i] == '#') {
+ uriFragment = true;
+ i++;
+ }
+
+ if (i != length && source[i] != '/') {
+ parseErrorCode_ = kPointerParseErrorTokenMustBeginWithSolidus;
+ goto error;
+ }
+
+ while (i < length) {
+ RAPIDJSON_ASSERT(source[i] == '/');
+ i++; // consumes '/'
+
+ token->name = name;
+ bool isNumber = true;
+
+ while (i < length && source[i] != '/') {
+ Ch c = source[i];
+ if (uriFragment) {
+ // Decoding percent-encoding for URI fragment
+ if (c == '%') {
+ PercentDecodeStream is(&source[i], source + length);
+ GenericInsituStringStream<EncodingType> os(name);
+ Ch* begin = os.PutBegin();
+ if (!Transcoder<UTF8<>, EncodingType>().Validate(is, os) ||
+ !is.IsValid()) {
+ parseErrorCode_ = kPointerParseErrorInvalidPercentEncoding;
+ goto error;
+ }
+ size_t len = os.PutEnd(begin);
+ i += is.Tell() - 1;
+ if (len == 1)
+ c = *name;
+ else {
+ name += len;
+ isNumber = false;
+ i++;
+ continue;
+ }
+ } else if (NeedPercentEncode(c)) {
+ parseErrorCode_ = kPointerParseErrorCharacterMustPercentEncode;
+ goto error;
+ }
+ }
+
+ i++;
+
+ // Escaping "~0" -> '~', "~1" -> '/'
+ if (c == '~') {
+ if (i < length) {
+ c = source[i];
+ if (c == '0')
+ c = '~';
+ else if (c == '1')
+ c = '/';
+ else {
+ parseErrorCode_ = kPointerParseErrorInvalidEscape;
+ goto error;
+ }
+ i++;
+ } else {
+ parseErrorCode_ = kPointerParseErrorInvalidEscape;
+ goto error;
+ }
+ }
+
+ // First check for index: all of characters are digit
+ if (c < '0' || c > '9')
+ isNumber = false;
+
+ *name++ = c;
+ }
+ token->length = static_cast<SizeType>(name - token->name);
+ if (token->length == 0)
+ isNumber = false;
+ *name++ = '\0'; // Null terminator
+
+ // Second check for index: more than one digit cannot have leading zero
+ if (isNumber && token->length > 1 && token->name[0] == '0')
+ isNumber = false;
+
+ // String to SizeType conversion
+ SizeType n = 0;
+ if (isNumber) {
+ for (size_t j = 0; j < token->length; j++) {
+ SizeType m = n * 10 + static_cast<SizeType>(token->name[j] - '0');
+ if (m < n) { // overflow detection
+ isNumber = false;
+ break;
+ }
+ n = m;
+ }
+ }
+
+ token->index = isNumber ? n : kPointerInvalidIndex;
+ token++;
+ }
+
+ RAPIDJSON_ASSERT(name <=
+ nameBuffer_ + length); // Should not overflow buffer
+ parseErrorCode_ = kPointerParseErrorNone;
+ return;
+
+ error:
+ Allocator::Free(tokens_);
+ nameBuffer_ = 0;
+ tokens_ = 0;
+ tokenCount_ = 0;
+ parseErrorOffset_ = i;
+ return;
+ }
+
+ //! Stringify to string or URI fragment representation.
+ /*!
+ \tparam uriFragment True for stringifying to URI fragment representation.
+ False for string representation. \tparam OutputStream type of output
+ stream. \param os The output stream.
+ */
+ template <bool uriFragment, typename OutputStream>
+ bool Stringify(OutputStream& os) const {
+ RAPIDJSON_ASSERT(IsValid());
+
+ if (uriFragment)
+ os.Put('#');
+
+ for (Token* t = tokens_; t != tokens_ + tokenCount_; ++t) {
+ os.Put('/');
+ for (size_t j = 0; j < t->length; j++) {
+ Ch c = t->name[j];
+ if (c == '~') {
+ os.Put('~');
+ os.Put('0');
+ } else if (c == '/') {
+ os.Put('~');
+ os.Put('1');
+ } else if (uriFragment && NeedPercentEncode(c)) {
+ // Transcode to UTF8 sequence
+ GenericStringStream<typename ValueType::EncodingType> source(
+ &t->name[j]);
+ PercentEncodeStream<OutputStream> target(os);
+ if (!Transcoder<EncodingType, UTF8<> >().Validate(source, target))
+ return false;
+ j += source.Tell() - 1;
+ } else
+ os.Put(c);
+ }
+ }
+ return true;
+ }
+
+ //! A helper stream for decoding a percent-encoded sequence into code unit.
+ /*!
+ This stream decodes %XY triplet into code unit (0-255).
+ If it encounters invalid characters, it sets output code unit as 0 and
+ mark invalid, and to be checked by IsValid().
+ */
+ class PercentDecodeStream {
+ public:
+ typedef typename ValueType::Ch Ch;
+
+ //! Constructor
+ /*!
+ \param source Start of the stream
+ \param end Past-the-end of the stream.
+ */
+ PercentDecodeStream(const Ch* source, const Ch* end)
+ : src_(source), head_(source), end_(end), valid_(true) {}
+
+ Ch Take() {
+ if (*src_ != '%' || src_ + 3 > end_) { // %XY triplet
+ valid_ = false;
+ return 0;
+ }
+ src_++;
+ Ch c = 0;
+ for (int j = 0; j < 2; j++) {
+ c = static_cast<Ch>(c << 4);
+ Ch h = *src_;
+ if (h >= '0' && h <= '9')
+ c = static_cast<Ch>(c + h - '0');
+ else if (h >= 'A' && h <= 'F')
+ c = static_cast<Ch>(c + h - 'A' + 10);
+ else if (h >= 'a' && h <= 'f')
+ c = static_cast<Ch>(c + h - 'a' + 10);
+ else {
+ valid_ = false;
+ return 0;
+ }
+ src_++;
+ }
+ return c;
+ }
+
+ size_t Tell() const { return static_cast<size_t>(src_ - head_); }
+ bool IsValid() const { return valid_; }
+
+ private:
+ const Ch* src_; //!< Current read position.
+ const Ch* head_; //!< Original head of the string.
+ const Ch* end_; //!< Past-the-end position.
+ bool valid_; //!< Whether the parsing is valid.
+ };
+
+ //! A helper stream to encode character (UTF-8 code unit) into percent-encoded
+ //! sequence.
+ template <typename OutputStream>
+ class PercentEncodeStream {
+ public:
+ PercentEncodeStream(OutputStream& os) : os_(os) {}
+ void Put(char c) { // UTF-8 must be byte
+ unsigned char u = static_cast<unsigned char>(c);
+ static const char hexDigits[16] = {'0', '1', '2', '3', '4', '5',
+ '6', '7', '8', '9', 'A', 'B',
+ 'C', 'D', 'E', 'F'};
+ os_.Put('%');
+ os_.Put(hexDigits[u >> 4]);
+ os_.Put(hexDigits[u & 15]);
+ }
+
+ private:
+ OutputStream& os_;
+ };
+
+ Allocator* allocator_; //!< The current allocator. It is either user-supplied
+ //!< or equal to ownAllocator_.
+ Allocator* ownAllocator_; //!< Allocator owned by this Pointer.
+ Ch* nameBuffer_; //!< A buffer containing all names in tokens.
+ Token* tokens_; //!< A list of tokens.
+ size_t tokenCount_; //!< Number of tokens in tokens_.
+ size_t parseErrorOffset_; //!< Offset in code unit when parsing fail.
+ PointerParseErrorCode parseErrorCode_; //!< Parsing error code.
+};
+
+//! GenericPointer for Value (UTF-8, default allocator).
+typedef GenericPointer<Value> Pointer;
+
+//!@name Helper functions for GenericPointer
+//@{
+
+//////////////////////////////////////////////////////////////////////////////
+
+template <typename T>
+typename T::ValueType& CreateValueByPointer(
+ T& root,
+ const GenericPointer<typename T::ValueType>& pointer,
+ typename T::AllocatorType& a) {
+ return pointer.Create(root, a);
+}
+
+template <typename T, typename CharType, size_t N>
+typename T::ValueType& CreateValueByPointer(T& root,
+ const CharType (&source)[N],
+ typename T::AllocatorType& a) {
+ return GenericPointer<typename T::ValueType>(source, N - 1).Create(root, a);
+}
+
+// No allocator parameter
+
+template <typename DocumentType>
+typename DocumentType::ValueType& CreateValueByPointer(
+ DocumentType& document,
+ const GenericPointer<typename DocumentType::ValueType>& pointer) {
+ return pointer.Create(document);
+}
+
+template <typename DocumentType, typename CharType, size_t N>
+typename DocumentType::ValueType& CreateValueByPointer(
+ DocumentType& document,
+ const CharType (&source)[N]) {
+ return GenericPointer<typename DocumentType::ValueType>(source, N - 1)
+ .Create(document);
+}
+
+//////////////////////////////////////////////////////////////////////////////
+
+template <typename T>
+typename T::ValueType* GetValueByPointer(
+ T& root,
+ const GenericPointer<typename T::ValueType>& pointer,
+ size_t* unresolvedTokenIndex = 0) {
+ return pointer.Get(root, unresolvedTokenIndex);
+}
+
+template <typename T>
+const typename T::ValueType* GetValueByPointer(
+ const T& root,
+ const GenericPointer<typename T::ValueType>& pointer,
+ size_t* unresolvedTokenIndex = 0) {
+ return pointer.Get(root, unresolvedTokenIndex);
+}
+
+template <typename T, typename CharType, size_t N>
+typename T::ValueType* GetValueByPointer(T& root,
+ const CharType (&source)[N],
+ size_t* unresolvedTokenIndex = 0) {
+ return GenericPointer<typename T::ValueType>(source, N - 1)
+ .Get(root, unresolvedTokenIndex);
+}
+
+template <typename T, typename CharType, size_t N>
+const typename T::ValueType* GetValueByPointer(
+ const T& root,
+ const CharType (&source)[N],
+ size_t* unresolvedTokenIndex = 0) {
+ return GenericPointer<typename T::ValueType>(source, N - 1)
+ .Get(root, unresolvedTokenIndex);
+}
+
+//////////////////////////////////////////////////////////////////////////////
+
+template <typename T>
+typename T::ValueType& GetValueByPointerWithDefault(
+ T& root,
+ const GenericPointer<typename T::ValueType>& pointer,
+ const typename T::ValueType& defaultValue,
+ typename T::AllocatorType& a) {
+ return pointer.GetWithDefault(root, defaultValue, a);
+}
+
+template <typename T>
+typename T::ValueType& GetValueByPointerWithDefault(
+ T& root,
+ const GenericPointer<typename T::ValueType>& pointer,
+ const typename T::Ch* defaultValue,
+ typename T::AllocatorType& a) {
+ return pointer.GetWithDefault(root, defaultValue, a);
+}
+
+#if RAPIDJSON_HAS_STDSTRING
+template <typename T>
+typename T::ValueType& GetValueByPointerWithDefault(
+ T& root,
+ const GenericPointer<typename T::ValueType>& pointer,
+ const std::basic_string<typename T::Ch>& defaultValue,
+ typename T::AllocatorType& a) {
+ return pointer.GetWithDefault(root, defaultValue, a);
+}
+#endif
+
+template <typename T, typename T2>
+RAPIDJSON_DISABLEIF_RETURN(
+ (internal::OrExpr<internal::IsPointer<T2>, internal::IsGenericValue<T2> >),
+ (typename T::ValueType&))
+GetValueByPointerWithDefault(
+ T& root,
+ const GenericPointer<typename T::ValueType>& pointer,
+ T2 defaultValue,
+ typename T::AllocatorType& a) {
+ return pointer.GetWithDefault(root, defaultValue, a);
+}
+
+template <typename T, typename CharType, size_t N>
+typename T::ValueType& GetValueByPointerWithDefault(
+ T& root,
+ const CharType (&source)[N],
+ const typename T::ValueType& defaultValue,
+ typename T::AllocatorType& a) {
+ return GenericPointer<typename T::ValueType>(source, N - 1)
+ .GetWithDefault(root, defaultValue, a);
+}
+
+template <typename T, typename CharType, size_t N>
+typename T::ValueType& GetValueByPointerWithDefault(
+ T& root,
+ const CharType (&source)[N],
+ const typename T::Ch* defaultValue,
+ typename T::AllocatorType& a) {
+ return GenericPointer<typename T::ValueType>(source, N - 1)
+ .GetWithDefault(root, defaultValue, a);
+}
+
+#if RAPIDJSON_HAS_STDSTRING
+template <typename T, typename CharType, size_t N>
+typename T::ValueType& GetValueByPointerWithDefault(
+ T& root,
+ const CharType (&source)[N],
+ const std::basic_string<typename T::Ch>& defaultValue,
+ typename T::AllocatorType& a) {
+ return GenericPointer<typename T::ValueType>(source, N - 1)
+ .GetWithDefault(root, defaultValue, a);
+}
+#endif
+
+template <typename T, typename CharType, size_t N, typename T2>
+RAPIDJSON_DISABLEIF_RETURN(
+ (internal::OrExpr<internal::IsPointer<T2>, internal::IsGenericValue<T2> >),
+ (typename T::ValueType&))
+GetValueByPointerWithDefault(T& root,
+ const CharType (&source)[N],
+ T2 defaultValue,
+ typename T::AllocatorType& a) {
+ return GenericPointer<typename T::ValueType>(source, N - 1)
+ .GetWithDefault(root, defaultValue, a);
+}
+
+// No allocator parameter
+
+template <typename DocumentType>
+typename DocumentType::ValueType& GetValueByPointerWithDefault(
+ DocumentType& document,
+ const GenericPointer<typename DocumentType::ValueType>& pointer,
+ const typename DocumentType::ValueType& defaultValue) {
+ return pointer.GetWithDefault(document, defaultValue);
+}
+
+template <typename DocumentType>
+typename DocumentType::ValueType& GetValueByPointerWithDefault(
+ DocumentType& document,
+ const GenericPointer<typename DocumentType::ValueType>& pointer,
+ const typename DocumentType::Ch* defaultValue) {
+ return pointer.GetWithDefault(document, defaultValue);
+}
+
+#if RAPIDJSON_HAS_STDSTRING
+template <typename DocumentType>
+typename DocumentType::ValueType& GetValueByPointerWithDefault(
+ DocumentType& document,
+ const GenericPointer<typename DocumentType::ValueType>& pointer,
+ const std::basic_string<typename DocumentType::Ch>& defaultValue) {
+ return pointer.GetWithDefault(document, defaultValue);
+}
+#endif
+
+template <typename DocumentType, typename T2>
+RAPIDJSON_DISABLEIF_RETURN(
+ (internal::OrExpr<internal::IsPointer<T2>, internal::IsGenericValue<T2> >),
+ (typename DocumentType::ValueType&))
+GetValueByPointerWithDefault(
+ DocumentType& document,
+ const GenericPointer<typename DocumentType::ValueType>& pointer,
+ T2 defaultValue) {
+ return pointer.GetWithDefault(document, defaultValue);
+}
+
+template <typename DocumentType, typename CharType, size_t N>
+typename DocumentType::ValueType& GetValueByPointerWithDefault(
+ DocumentType& document,
+ const CharType (&source)[N],
+ const typename DocumentType::ValueType& defaultValue) {
+ return GenericPointer<typename DocumentType::ValueType>(source, N - 1)
+ .GetWithDefault(document, defaultValue);
+}
+
+template <typename DocumentType, typename CharType, size_t N>
+typename DocumentType::ValueType& GetValueByPointerWithDefault(
+ DocumentType& document,
+ const CharType (&source)[N],
+ const typename DocumentType::Ch* defaultValue) {
+ return GenericPointer<typename DocumentType::ValueType>(source, N - 1)
+ .GetWithDefault(document, defaultValue);
+}
+
+#if RAPIDJSON_HAS_STDSTRING
+template <typename DocumentType, typename CharType, size_t N>
+typename DocumentType::ValueType& GetValueByPointerWithDefault(
+ DocumentType& document,
+ const CharType (&source)[N],
+ const std::basic_string<typename DocumentType::Ch>& defaultValue) {
+ return GenericPointer<typename DocumentType::ValueType>(source, N - 1)
+ .GetWithDefault(document, defaultValue);
+}
+#endif
+
+template <typename DocumentType, typename CharType, size_t N, typename T2>
+RAPIDJSON_DISABLEIF_RETURN(
+ (internal::OrExpr<internal::IsPointer<T2>, internal::IsGenericValue<T2> >),
+ (typename DocumentType::ValueType&))
+GetValueByPointerWithDefault(DocumentType& document,
+ const CharType (&source)[N],
+ T2 defaultValue) {
+ return GenericPointer<typename DocumentType::ValueType>(source, N - 1)
+ .GetWithDefault(document, defaultValue);
+}
+
+//////////////////////////////////////////////////////////////////////////////
+
+template <typename T>
+typename T::ValueType& SetValueByPointer(
+ T& root,
+ const GenericPointer<typename T::ValueType>& pointer,
+ typename T::ValueType& value,
+ typename T::AllocatorType& a) {
+ return pointer.Set(root, value, a);
+}
+
+template <typename T>
+typename T::ValueType& SetValueByPointer(
+ T& root,
+ const GenericPointer<typename T::ValueType>& pointer,
+ const typename T::ValueType& value,
+ typename T::AllocatorType& a) {
+ return pointer.Set(root, value, a);
+}
+
+template <typename T>
+typename T::ValueType& SetValueByPointer(
+ T& root,
+ const GenericPointer<typename T::ValueType>& pointer,
+ const typename T::Ch* value,
+ typename T::AllocatorType& a) {
+ return pointer.Set(root, value, a);
+}
+
+#if RAPIDJSON_HAS_STDSTRING
+template <typename T>
+typename T::ValueType& SetValueByPointer(
+ T& root,
+ const GenericPointer<typename T::ValueType>& pointer,
+ const std::basic_string<typename T::Ch>& value,
+ typename T::AllocatorType& a) {
+ return pointer.Set(root, value, a);
+}
+#endif
+
+template <typename T, typename T2>
+RAPIDJSON_DISABLEIF_RETURN(
+ (internal::OrExpr<internal::IsPointer<T2>, internal::IsGenericValue<T2> >),
+ (typename T::ValueType&))
+SetValueByPointer(T& root,
+ const GenericPointer<typename T::ValueType>& pointer,
+ T2 value,
+ typename T::AllocatorType& a) {
+ return pointer.Set(root, value, a);
+}
+
+template <typename T, typename CharType, size_t N>
+typename T::ValueType& SetValueByPointer(T& root,
+ const CharType (&source)[N],
+ typename T::ValueType& value,
+ typename T::AllocatorType& a) {
+ return GenericPointer<typename T::ValueType>(source, N - 1)
+ .Set(root, value, a);
+}
+
+template <typename T, typename CharType, size_t N>
+typename T::ValueType& SetValueByPointer(T& root,
+ const CharType (&source)[N],
+ const typename T::ValueType& value,
+ typename T::AllocatorType& a) {
+ return GenericPointer<typename T::ValueType>(source, N - 1)
+ .Set(root, value, a);
+}
+
+template <typename T, typename CharType, size_t N>
+typename T::ValueType& SetValueByPointer(T& root,
+ const CharType (&source)[N],
+ const typename T::Ch* value,
+ typename T::AllocatorType& a) {
+ return GenericPointer<typename T::ValueType>(source, N - 1)
+ .Set(root, value, a);
+}
+
+#if RAPIDJSON_HAS_STDSTRING
+template <typename T, typename CharType, size_t N>
+typename T::ValueType& SetValueByPointer(
+ T& root,
+ const CharType (&source)[N],
+ const std::basic_string<typename T::Ch>& value,
+ typename T::AllocatorType& a) {
+ return GenericPointer<typename T::ValueType>(source, N - 1)
+ .Set(root, value, a);
+}
+#endif
+
+template <typename T, typename CharType, size_t N, typename T2>
+RAPIDJSON_DISABLEIF_RETURN(
+ (internal::OrExpr<internal::IsPointer<T2>, internal::IsGenericValue<T2> >),
+ (typename T::ValueType&))
+SetValueByPointer(T& root,
+ const CharType (&source)[N],
+ T2 value,
+ typename T::AllocatorType& a) {
+ return GenericPointer<typename T::ValueType>(source, N - 1)
+ .Set(root, value, a);
+}
+
+// No allocator parameter
+
+template <typename DocumentType>
+typename DocumentType::ValueType& SetValueByPointer(
+ DocumentType& document,
+ const GenericPointer<typename DocumentType::ValueType>& pointer,
+ typename DocumentType::ValueType& value) {
+ return pointer.Set(document, value);
+}
+
+template <typename DocumentType>
+typename DocumentType::ValueType& SetValueByPointer(
+ DocumentType& document,
+ const GenericPointer<typename DocumentType::ValueType>& pointer,
+ const typename DocumentType::ValueType& value) {
+ return pointer.Set(document, value);
+}
+
+template <typename DocumentType>
+typename DocumentType::ValueType& SetValueByPointer(
+ DocumentType& document,
+ const GenericPointer<typename DocumentType::ValueType>& pointer,
+ const typename DocumentType::Ch* value) {
+ return pointer.Set(document, value);
+}
+
+#if RAPIDJSON_HAS_STDSTRING
+template <typename DocumentType>
+typename DocumentType::ValueType& SetValueByPointer(
+ DocumentType& document,
+ const GenericPointer<typename DocumentType::ValueType>& pointer,
+ const std::basic_string<typename DocumentType::Ch>& value) {
+ return pointer.Set(document, value);
+}
+#endif
+
+template <typename DocumentType, typename T2>
+RAPIDJSON_DISABLEIF_RETURN(
+ (internal::OrExpr<internal::IsPointer<T2>, internal::IsGenericValue<T2> >),
+ (typename DocumentType::ValueType&))
+SetValueByPointer(
+ DocumentType& document,
+ const GenericPointer<typename DocumentType::ValueType>& pointer,
+ T2 value) {
+ return pointer.Set(document, value);
+}
+
+template <typename DocumentType, typename CharType, size_t N>
+typename DocumentType::ValueType& SetValueByPointer(
+ DocumentType& document,
+ const CharType (&source)[N],
+ typename DocumentType::ValueType& value) {
+ return GenericPointer<typename DocumentType::ValueType>(source, N - 1)
+ .Set(document, value);
+}
+
+template <typename DocumentType, typename CharType, size_t N>
+typename DocumentType::ValueType& SetValueByPointer(
+ DocumentType& document,
+ const CharType (&source)[N],
+ const typename DocumentType::ValueType& value) {
+ return GenericPointer<typename DocumentType::ValueType>(source, N - 1)
+ .Set(document, value);
+}
+
+template <typename DocumentType, typename CharType, size_t N>
+typename DocumentType::ValueType& SetValueByPointer(
+ DocumentType& document,
+ const CharType (&source)[N],
+ const typename DocumentType::Ch* value) {
+ return GenericPointer<typename DocumentType::ValueType>(source, N - 1)
+ .Set(document, value);
+}
+
+#if RAPIDJSON_HAS_STDSTRING
+template <typename DocumentType, typename CharType, size_t N>
+typename DocumentType::ValueType& SetValueByPointer(
+ DocumentType& document,
+ const CharType (&source)[N],
+ const std::basic_string<typename DocumentType::Ch>& value) {
+ return GenericPointer<typename DocumentType::ValueType>(source, N - 1)
+ .Set(document, value);
+}
+#endif
+
+template <typename DocumentType, typename CharType, size_t N, typename T2>
+RAPIDJSON_DISABLEIF_RETURN(
+ (internal::OrExpr<internal::IsPointer<T2>, internal::IsGenericValue<T2> >),
+ (typename DocumentType::ValueType&))
+SetValueByPointer(DocumentType& document,
+ const CharType (&source)[N],
+ T2 value) {
+ return GenericPointer<typename DocumentType::ValueType>(source, N - 1)
+ .Set(document, value);
+}
+
+//////////////////////////////////////////////////////////////////////////////
+
+template <typename T>
+typename T::ValueType& SwapValueByPointer(
+ T& root,
+ const GenericPointer<typename T::ValueType>& pointer,
+ typename T::ValueType& value,
+ typename T::AllocatorType& a) {
+ return pointer.Swap(root, value, a);
+}
+
+template <typename T, typename CharType, size_t N>
+typename T::ValueType& SwapValueByPointer(T& root,
+ const CharType (&source)[N],
+ typename T::ValueType& value,
+ typename T::AllocatorType& a) {
+ return GenericPointer<typename T::ValueType>(source, N - 1)
+ .Swap(root, value, a);
+}
+
+template <typename DocumentType>
+typename DocumentType::ValueType& SwapValueByPointer(
+ DocumentType& document,
+ const GenericPointer<typename DocumentType::ValueType>& pointer,
+ typename DocumentType::ValueType& value) {
+ return pointer.Swap(document, value);
+}
+
+template <typename DocumentType, typename CharType, size_t N>
+typename DocumentType::ValueType& SwapValueByPointer(
+ DocumentType& document,
+ const CharType (&source)[N],
+ typename DocumentType::ValueType& value) {
+ return GenericPointer<typename DocumentType::ValueType>(source, N - 1)
+ .Swap(document, value);
+}
+
+//////////////////////////////////////////////////////////////////////////////
+
+template <typename T>
+bool EraseValueByPointer(T& root,
+ const GenericPointer<typename T::ValueType>& pointer) {
+ return pointer.Erase(root);
+}
+
+template <typename T, typename CharType, size_t N>
+bool EraseValueByPointer(T& root, const CharType (&source)[N]) {
+ return GenericPointer<typename T::ValueType>(source, N - 1).Erase(root);
+}
+
+//@}
+
+RAPIDJSON_NAMESPACE_END
+
+#ifdef __clang__
+RAPIDJSON_DIAG_POP
+#endif
+
+#ifdef _MSC_VER
+RAPIDJSON_DIAG_POP
+#endif
+
+#endif // RAPIDJSON_POINTER_H_
diff --git a/include/rapidjson/prettywriter.h b/third_party/rapidjson/prettywriter.h
index 0dcb0fee..0dcb0fee 100644
--- a/include/rapidjson/prettywriter.h
+++ b/third_party/rapidjson/prettywriter.h
diff --git a/include/rapidjson/rapidjson.h b/third_party/rapidjson/rapidjson.h
index 053b2ce4..053b2ce4 100644
--- a/include/rapidjson/rapidjson.h
+++ b/third_party/rapidjson/rapidjson.h
diff --git a/third_party/rapidjson/reader.h b/third_party/rapidjson/reader.h
new file mode 100644
index 00000000..ec6bc4ce
--- /dev/null
+++ b/third_party/rapidjson/reader.h
@@ -0,0 +1,2113 @@
+// Tencent is pleased to support the open source community by making RapidJSON
+// available.
+//
+// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All
+// rights reserved.
+//
+// Licensed under the MIT License (the "License"); you may not use this file
+// except in compliance with the License. You may obtain a copy of the License
+// at
+//
+// http://opensource.org/licenses/MIT
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+// License for the specific language governing permissions and limitations under
+// the License.
+
+#ifndef RAPIDJSON_READER_H_
+#define RAPIDJSON_READER_H_
+
+/*! \file reader.h */
+
+#include <limits>
+#include "allocators.h"
+#include "encodedstream.h"
+#include "rapidjson/internal/meta.h"
+#include "rapidjson/internal/stack.h"
+#include "rapidjson/internal/strtod.h"
+#include "stream.h"
+
+#if defined(RAPIDJSON_SIMD) && defined(_MSC_VER)
+#include <intrin.h>
+#pragma intrinsic(_BitScanForward)
+#endif
+#ifdef RAPIDJSON_SSE42
+#include <nmmintrin.h>
+#elif defined(RAPIDJSON_SSE2)
+#include <emmintrin.h>
+#endif
+
+#ifdef _MSC_VER
+RAPIDJSON_DIAG_PUSH
+RAPIDJSON_DIAG_OFF(4127) // conditional expression is constant
+RAPIDJSON_DIAG_OFF(4702) // unreachable code
+#endif
+
+#ifdef __clang__
+RAPIDJSON_DIAG_PUSH
+RAPIDJSON_DIAG_OFF(old - style - cast)
+RAPIDJSON_DIAG_OFF(padded)
+RAPIDJSON_DIAG_OFF(switch - enum)
+#endif
+
+#ifdef __GNUC__
+RAPIDJSON_DIAG_PUSH
+RAPIDJSON_DIAG_OFF(effc++)
+#endif
+
+//!@cond RAPIDJSON_HIDDEN_FROM_DOXYGEN
+#define RAPIDJSON_NOTHING /* deliberately empty */
+#ifndef RAPIDJSON_PARSE_ERROR_EARLY_RETURN
+#define RAPIDJSON_PARSE_ERROR_EARLY_RETURN(value) \
+ RAPIDJSON_MULTILINEMACRO_BEGIN \
+ if (RAPIDJSON_UNLIKELY(HasParseError())) { \
+ return value; \
+ } \
+ RAPIDJSON_MULTILINEMACRO_END
+#endif
+#define RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID \
+ RAPIDJSON_PARSE_ERROR_EARLY_RETURN(RAPIDJSON_NOTHING)
+//!@endcond
+
+/*! \def RAPIDJSON_PARSE_ERROR_NORETURN
+ \ingroup RAPIDJSON_ERRORS
+ \brief Macro to indicate a parse error.
+ \param parseErrorCode \ref rapidjson::ParseErrorCode of the error
+ \param offset position of the error in JSON input (\c size_t)
+
+ This macros can be used as a customization point for the internal
+ error handling mechanism of RapidJSON.
+
+ A common usage model is to throw an exception instead of requiring the
+ caller to explicitly check the \ref rapidjson::GenericReader::Parse's
+ return value:
+
+ \code
+ #define RAPIDJSON_PARSE_ERROR_NORETURN(parseErrorCode,offset) \
+ throw ParseException(parseErrorCode, #parseErrorCode, offset)
+
+ #include <stdexcept> // std::runtime_error
+ #include "rapidjson/error/error.h" // rapidjson::ParseResult
+
+ struct ParseException : std::runtime_error, rapidjson::ParseResult {
+ ParseException(rapidjson::ParseErrorCode code, const char* msg, size_t
+ offset) : std::runtime_error(msg), ParseResult(code, offset) {}
+ };
+
+ #include "rapidjson/reader.h"
+ \endcode
+
+ \see RAPIDJSON_PARSE_ERROR, rapidjson::GenericReader::Parse
+ */
+#ifndef RAPIDJSON_PARSE_ERROR_NORETURN
+#define RAPIDJSON_PARSE_ERROR_NORETURN(parseErrorCode, offset) \
+ RAPIDJSON_MULTILINEMACRO_BEGIN \
+ RAPIDJSON_ASSERT(!HasParseError()); /* Error can only be assigned once */ \
+ SetParseError(parseErrorCode, offset); \
+ RAPIDJSON_MULTILINEMACRO_END
+#endif
+
+/*! \def RAPIDJSON_PARSE_ERROR
+ \ingroup RAPIDJSON_ERRORS
+ \brief (Internal) macro to indicate and handle a parse error.
+ \param parseErrorCode \ref rapidjson::ParseErrorCode of the error
+ \param offset position of the error in JSON input (\c size_t)
+
+ Invokes RAPIDJSON_PARSE_ERROR_NORETURN and stops the parsing.
+
+ \see RAPIDJSON_PARSE_ERROR_NORETURN
+ \hideinitializer
+ */
+#ifndef RAPIDJSON_PARSE_ERROR
+#define RAPIDJSON_PARSE_ERROR(parseErrorCode, offset) \
+ RAPIDJSON_MULTILINEMACRO_BEGIN \
+ RAPIDJSON_PARSE_ERROR_NORETURN(parseErrorCode, offset); \
+ RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID; \
+ RAPIDJSON_MULTILINEMACRO_END
+#endif
+
+#include "rapidjson/error/error.h" // ParseErrorCode, ParseResult
+
+RAPIDJSON_NAMESPACE_BEGIN
+
+///////////////////////////////////////////////////////////////////////////////
+// ParseFlag
+
+/*! \def RAPIDJSON_PARSE_DEFAULT_FLAGS
+ \ingroup RAPIDJSON_CONFIG
+ \brief User-defined kParseDefaultFlags definition.
+
+ User can define this as any \c ParseFlag combinations.
+*/
+#ifndef RAPIDJSON_PARSE_DEFAULT_FLAGS
+#define RAPIDJSON_PARSE_DEFAULT_FLAGS kParseNoFlags
+#endif
+
+//! Combination of parseFlags
+/*! \see Reader::Parse, Document::Parse, Document::ParseInsitu,
+ * Document::ParseStream
+ */
+enum ParseFlag {
+ kParseNoFlags = 0, //!< No flags are set.
+ kParseInsituFlag = 1, //!< In-situ(destructive) parsing.
+ kParseValidateEncodingFlag = 2, //!< Validate encoding of JSON strings.
+ kParseIterativeFlag = 4, //!< Iterative(constant complexity in terms of
+ //!< function call stack size) parsing.
+ kParseStopWhenDoneFlag =
+ 8, //!< After parsing a complete JSON root from stream, stop further
+ //!< processing the rest of stream. When this flag is used, parser
+ //!< will not generate kParseErrorDocumentRootNotSingular error.
+ kParseFullPrecisionFlag =
+ 16, //!< Parse number in full precision (but slower).
+ kParseCommentsFlag =
+ 32, //!< Allow one-line (//) and multi-line (/**/) comments.
+ kParseNumbersAsStringsFlag =
+ 64, //!< Parse all numbers (ints/doubles) as strings.
+ kParseTrailingCommasFlag =
+ 128, //!< Allow trailing commas at the end of objects and arrays.
+ kParseNanAndInfFlag = 256, //!< Allow parsing NaN, Inf, Infinity, -Inf and
+ //!< -Infinity as doubles.
+ kParseDefaultFlags =
+ RAPIDJSON_PARSE_DEFAULT_FLAGS //!< Default parse flags. Can be customized
+ //!< by defining
+ //!< RAPIDJSON_PARSE_DEFAULT_FLAGS
+};
+
+///////////////////////////////////////////////////////////////////////////////
+// Handler
+
+/*! \class rapidjson::Handler
+ \brief Concept for receiving events from GenericReader upon parsing.
+ The functions return true if no error occurs. If they return false,
+ the event publisher should terminate the process.
+\code
+concept Handler {
+ typename Ch;
+
+ bool Null();
+ bool Bool(bool b);
+ bool Int(int i);
+ bool Uint(unsigned i);
+ bool Int64(int64_t i);
+ bool Uint64(uint64_t i);
+ bool Double(double d);
+ /// enabled via kParseNumbersAsStringsFlag, string is not null-terminated
+(use length) bool RawNumber(const Ch* str, SizeType length, bool copy); bool
+String(const Ch* str, SizeType length, bool copy); bool StartObject(); bool
+Key(const Ch* str, SizeType length, bool copy); bool EndObject(SizeType
+memberCount); bool StartArray(); bool EndArray(SizeType elementCount);
+};
+\endcode
+*/
+///////////////////////////////////////////////////////////////////////////////
+// BaseReaderHandler
+
+//! Default implementation of Handler.
+/*! This can be used as base class of any reader handler.
+ \note implements Handler concept
+*/
+template <typename Encoding = UTF8<>, typename Derived = void>
+struct BaseReaderHandler {
+ typedef typename Encoding::Ch Ch;
+
+ typedef typename internal::SelectIf<internal::IsSame<Derived, void>,
+ BaseReaderHandler,
+ Derived>::Type Override;
+
+ bool Default() { return true; }
+ bool Null() { return static_cast<Override&>(*this).Default(); }
+ bool Bool(bool) { return static_cast<Override&>(*this).Default(); }
+ bool Int(int) { return static_cast<Override&>(*this).Default(); }
+ bool Uint(unsigned) { return static_cast<Override&>(*this).Default(); }
+ bool Int64(int64_t) { return static_cast<Override&>(*this).Default(); }
+ bool Uint64(uint64_t) { return static_cast<Override&>(*this).Default(); }
+ bool Double(double) { return static_cast<Override&>(*this).Default(); }
+ /// enabled via kParseNumbersAsStringsFlag, string is not null-terminated (use
+ /// length)
+ bool RawNumber(const Ch* str, SizeType len, bool copy) {
+ return static_cast<Override&>(*this).String(str, len, copy);
+ }
+ bool String(const Ch*, SizeType, bool) {
+ return static_cast<Override&>(*this).Default();
+ }
+ bool StartObject() { return static_cast<Override&>(*this).Default(); }
+ bool Key(const Ch* str, SizeType len, bool copy) {
+ return static_cast<Override&>(*this).String(str, len, copy);
+ }
+ bool EndObject(SizeType) { return static_cast<Override&>(*this).Default(); }
+ bool StartArray() { return static_cast<Override&>(*this).Default(); }
+ bool EndArray(SizeType) { return static_cast<Override&>(*this).Default(); }
+};
+
+///////////////////////////////////////////////////////////////////////////////
+// StreamLocalCopy
+
+namespace internal {
+
+template <typename Stream, int = StreamTraits<Stream>::copyOptimization>
+class StreamLocalCopy;
+
+//! Do copy optimization.
+template <typename Stream>
+class StreamLocalCopy<Stream, 1> {
+ public:
+ StreamLocalCopy(Stream& original) : s(original), original_(original) {}
+ ~StreamLocalCopy() { original_ = s; }
+
+ Stream s;
+
+ private:
+ StreamLocalCopy& operator=(const StreamLocalCopy&) /* = delete */;
+
+ Stream& original_;
+};
+
+//! Keep reference.
+template <typename Stream>
+class StreamLocalCopy<Stream, 0> {
+ public:
+ StreamLocalCopy(Stream& original) : s(original) {}
+
+ Stream& s;
+
+ private:
+ StreamLocalCopy& operator=(const StreamLocalCopy&) /* = delete */;
+};
+
+} // namespace internal
+
+///////////////////////////////////////////////////////////////////////////////
+// SkipWhitespace
+
+//! Skip the JSON white spaces in a stream.
+/*! \param is A input stream for skipping white spaces.
+ \note This function has SSE2/SSE4.2 specialization.
+*/
+template <typename InputStream>
+void SkipWhitespace(InputStream& is) {
+ internal::StreamLocalCopy<InputStream> copy(is);
+ InputStream& s(copy.s);
+
+ typename InputStream::Ch c;
+ while ((c = s.Peek()) == ' ' || c == '\n' || c == '\r' || c == '\t')
+ s.Take();
+}
+
+inline const char* SkipWhitespace(const char* p, const char* end) {
+ while (p != end && (*p == ' ' || *p == '\n' || *p == '\r' || *p == '\t'))
+ ++p;
+ return p;
+}
+
+#ifdef RAPIDJSON_SSE42
+//! Skip whitespace with SSE 4.2 pcmpistrm instruction, testing 16 8-byte
+//! characters at once.
+inline const char* SkipWhitespace_SIMD(const char* p) {
+ // Fast return for single non-whitespace
+ if (*p == ' ' || *p == '\n' || *p == '\r' || *p == '\t')
+ ++p;
+ else
+ return p;
+
+ // 16-byte align to the next boundary
+ const char* nextAligned = reinterpret_cast<const char*>(
+ (reinterpret_cast<size_t>(p) + 15) & static_cast<size_t>(~15));
+ while (p != nextAligned)
+ if (*p == ' ' || *p == '\n' || *p == '\r' || *p == '\t')
+ ++p;
+ else
+ return p;
+
+ // The rest of string using SIMD
+ static const char whitespace[16] = " \n\r\t";
+ const __m128i w =
+ _mm_loadu_si128(reinterpret_cast<const __m128i*>(&whitespace[0]));
+
+ for (;; p += 16) {
+ const __m128i s = _mm_load_si128(reinterpret_cast<const __m128i*>(p));
+ const int r = _mm_cvtsi128_si32(
+ _mm_cmpistrm(w, s,
+ _SIDD_UBYTE_OPS | _SIDD_CMP_EQUAL_ANY | _SIDD_BIT_MASK |
+ _SIDD_NEGATIVE_POLARITY));
+ if (r != 0) { // some of characters is non-whitespace
+#ifdef _MSC_VER // Find the index of first non-whitespace
+ unsigned long offset;
+ _BitScanForward(&offset, r);
+ return p + offset;
+#else
+ return p + __builtin_ffs(r) - 1;
+#endif
+ }
+ }
+}
+
+inline const char* SkipWhitespace_SIMD(const char* p, const char* end) {
+ // Fast return for single non-whitespace
+ if (p != end && (*p == ' ' || *p == '\n' || *p == '\r' || *p == '\t'))
+ ++p;
+ else
+ return p;
+
+ // The middle of string using SIMD
+ static const char whitespace[16] = " \n\r\t";
+ const __m128i w =
+ _mm_loadu_si128(reinterpret_cast<const __m128i*>(&whitespace[0]));
+
+ for (; p <= end - 16; p += 16) {
+ const __m128i s = _mm_loadu_si128(reinterpret_cast<const __m128i*>(p));
+ const int r = _mm_cvtsi128_si32(
+ _mm_cmpistrm(w, s,
+ _SIDD_UBYTE_OPS | _SIDD_CMP_EQUAL_ANY | _SIDD_BIT_MASK |
+ _SIDD_NEGATIVE_POLARITY));
+ if (r != 0) { // some of characters is non-whitespace
+#ifdef _MSC_VER // Find the index of first non-whitespace
+ unsigned long offset;
+ _BitScanForward(&offset, r);
+ return p + offset;
+#else
+ return p + __builtin_ffs(r) - 1;
+#endif
+ }
+ }
+
+ return SkipWhitespace(p, end);
+}
+
+#elif defined(RAPIDJSON_SSE2)
+
+//! Skip whitespace with SSE2 instructions, testing 16 8-byte characters at
+//! once.
+inline const char* SkipWhitespace_SIMD(const char* p) {
+ // Fast return for single non-whitespace
+ if (*p == ' ' || *p == '\n' || *p == '\r' || *p == '\t')
+ ++p;
+ else
+ return p;
+
+ // 16-byte align to the next boundary
+ const char* nextAligned = reinterpret_cast<const char*>(
+ (reinterpret_cast<size_t>(p) + 15) & static_cast<size_t>(~15));
+ while (p != nextAligned)
+ if (*p == ' ' || *p == '\n' || *p == '\r' || *p == '\t')
+ ++p;
+ else
+ return p;
+
+// The rest of string
+#define C16(c) \
+ { c, c, c, c, c, c, c, c, c, c, c, c, c, c, c, c }
+ static const char whitespaces[4][16] = {C16(' '), C16('\n'), C16('\r'),
+ C16('\t')};
+#undef C16
+
+ const __m128i w0 =
+ _mm_loadu_si128(reinterpret_cast<const __m128i*>(&whitespaces[0][0]));
+ const __m128i w1 =
+ _mm_loadu_si128(reinterpret_cast<const __m128i*>(&whitespaces[1][0]));
+ const __m128i w2 =
+ _mm_loadu_si128(reinterpret_cast<const __m128i*>(&whitespaces[2][0]));
+ const __m128i w3 =
+ _mm_loadu_si128(reinterpret_cast<const __m128i*>(&whitespaces[3][0]));
+
+ for (;; p += 16) {
+ const __m128i s = _mm_load_si128(reinterpret_cast<const __m128i*>(p));
+ __m128i x = _mm_cmpeq_epi8(s, w0);
+ x = _mm_or_si128(x, _mm_cmpeq_epi8(s, w1));
+ x = _mm_or_si128(x, _mm_cmpeq_epi8(s, w2));
+ x = _mm_or_si128(x, _mm_cmpeq_epi8(s, w3));
+ unsigned short r = static_cast<unsigned short>(~_mm_movemask_epi8(x));
+ if (r != 0) { // some of characters may be non-whitespace
+#ifdef _MSC_VER // Find the index of first non-whitespace
+ unsigned long offset;
+ _BitScanForward(&offset, r);
+ return p + offset;
+#else
+ return p + __builtin_ffs(r) - 1;
+#endif
+ }
+ }
+}
+
+inline const char* SkipWhitespace_SIMD(const char* p, const char* end) {
+ // Fast return for single non-whitespace
+ if (p != end && (*p == ' ' || *p == '\n' || *p == '\r' || *p == '\t'))
+ ++p;
+ else
+ return p;
+
+// The rest of string
+#define C16(c) \
+ { c, c, c, c, c, c, c, c, c, c, c, c, c, c, c, c }
+ static const char whitespaces[4][16] = {C16(' '), C16('\n'), C16('\r'),
+ C16('\t')};
+#undef C16
+
+ const __m128i w0 =
+ _mm_loadu_si128(reinterpret_cast<const __m128i*>(&whitespaces[0][0]));
+ const __m128i w1 =
+ _mm_loadu_si128(reinterpret_cast<const __m128i*>(&whitespaces[1][0]));
+ const __m128i w2 =
+ _mm_loadu_si128(reinterpret_cast<const __m128i*>(&whitespaces[2][0]));
+ const __m128i w3 =
+ _mm_loadu_si128(reinterpret_cast<const __m128i*>(&whitespaces[3][0]));
+
+ for (; p <= end - 16; p += 16) {
+ const __m128i s = _mm_loadu_si128(reinterpret_cast<const __m128i*>(p));
+ __m128i x = _mm_cmpeq_epi8(s, w0);
+ x = _mm_or_si128(x, _mm_cmpeq_epi8(s, w1));
+ x = _mm_or_si128(x, _mm_cmpeq_epi8(s, w2));
+ x = _mm_or_si128(x, _mm_cmpeq_epi8(s, w3));
+ unsigned short r = static_cast<unsigned short>(~_mm_movemask_epi8(x));
+ if (r != 0) { // some of characters may be non-whitespace
+#ifdef _MSC_VER // Find the index of first non-whitespace
+ unsigned long offset;
+ _BitScanForward(&offset, r);
+ return p + offset;
+#else
+ return p + __builtin_ffs(r) - 1;
+#endif
+ }
+ }
+
+ return SkipWhitespace(p, end);
+}
+
+#endif // RAPIDJSON_SSE2
+
+#ifdef RAPIDJSON_SIMD
+//! Template function specialization for InsituStringStream
+template <>
+inline void SkipWhitespace(InsituStringStream& is) {
+ is.src_ = const_cast<char*>(SkipWhitespace_SIMD(is.src_));
+}
+
+//! Template function specialization for StringStream
+template <>
+inline void SkipWhitespace(StringStream& is) {
+ is.src_ = SkipWhitespace_SIMD(is.src_);
+}
+
+template <>
+inline void SkipWhitespace(EncodedInputStream<UTF8<>, MemoryStream>& is) {
+ is.is_.src_ = SkipWhitespace_SIMD(is.is_.src_, is.is_.end_);
+}
+#endif // RAPIDJSON_SIMD
+
+///////////////////////////////////////////////////////////////////////////////
+// GenericReader
+
+//! SAX-style JSON parser. Use \ref Reader for UTF8 encoding and default
+//! allocator.
+/*! GenericReader parses JSON text from a stream, and send events synchronously
+ to an object implementing Handler concept.
+
+ It needs to allocate a stack for storing a single decoded string during
+ non-destructive parsing.
+
+ For in-situ parsing, the decoded string is directly written to the source
+ text string, no temporary buffer is required.
+
+ A GenericReader object can be reused for parsing multiple JSON text.
+
+ \tparam SourceEncoding Encoding of the input stream.
+ \tparam TargetEncoding Encoding of the parse output.
+ \tparam StackAllocator Allocator type for stack.
+*/
+template <typename SourceEncoding,
+ typename TargetEncoding,
+ typename StackAllocator = CrtAllocator>
+class GenericReader {
+ public:
+ typedef typename SourceEncoding::Ch Ch; //!< SourceEncoding character type
+
+ //! Constructor.
+ /*! \param stackAllocator Optional allocator for allocating stack memory.
+ (Only use for non-destructive parsing) \param stackCapacity stack capacity
+ in bytes for storing a single decoded string. (Only use for
+ non-destructive parsing)
+ */
+ GenericReader(StackAllocator* stackAllocator = 0,
+ size_t stackCapacity = kDefaultStackCapacity)
+ : stack_(stackAllocator, stackCapacity), parseResult_() {}
+
+ //! Parse JSON text.
+ /*! \tparam parseFlags Combination of \ref ParseFlag.
+ \tparam InputStream Type of input stream, implementing Stream concept.
+ \tparam Handler Type of handler, implementing Handler concept.
+ \param is Input stream to be parsed.
+ \param handler The handler to receive events.
+ \return Whether the parsing is successful.
+ */
+ template <unsigned parseFlags, typename InputStream, typename Handler>
+ ParseResult Parse(InputStream& is, Handler& handler) {
+ if (parseFlags & kParseIterativeFlag)
+ return IterativeParse<parseFlags>(is, handler);
+
+ parseResult_.Clear();
+
+ ClearStackOnExit scope(*this);
+
+ SkipWhitespaceAndComments<parseFlags>(is);
+ RAPIDJSON_PARSE_ERROR_EARLY_RETURN(parseResult_);
+
+ if (RAPIDJSON_UNLIKELY(is.Peek() == '\0')) {
+ RAPIDJSON_PARSE_ERROR_NORETURN(kParseErrorDocumentEmpty, is.Tell());
+ RAPIDJSON_PARSE_ERROR_EARLY_RETURN(parseResult_);
+ } else {
+ ParseValue<parseFlags>(is, handler);
+ RAPIDJSON_PARSE_ERROR_EARLY_RETURN(parseResult_);
+
+ if (!(parseFlags & kParseStopWhenDoneFlag)) {
+ SkipWhitespaceAndComments<parseFlags>(is);
+ RAPIDJSON_PARSE_ERROR_EARLY_RETURN(parseResult_);
+
+ if (RAPIDJSON_UNLIKELY(is.Peek() != '\0')) {
+ RAPIDJSON_PARSE_ERROR_NORETURN(kParseErrorDocumentRootNotSingular,
+ is.Tell());
+ RAPIDJSON_PARSE_ERROR_EARLY_RETURN(parseResult_);
+ }
+ }
+ }
+
+ return parseResult_;
+ }
+
+ //! Parse JSON text (with \ref kParseDefaultFlags)
+ /*! \tparam InputStream Type of input stream, implementing Stream concept
+ \tparam Handler Type of handler, implementing Handler concept.
+ \param is Input stream to be parsed.
+ \param handler The handler to receive events.
+ \return Whether the parsing is successful.
+ */
+ template <typename InputStream, typename Handler>
+ ParseResult Parse(InputStream& is, Handler& handler) {
+ return Parse<kParseDefaultFlags>(is, handler);
+ }
+
+ //! Whether a parse error has occured in the last parsing.
+ bool HasParseError() const { return parseResult_.IsError(); }
+
+ //! Get the \ref ParseErrorCode of last parsing.
+ ParseErrorCode GetParseErrorCode() const { return parseResult_.Code(); }
+
+ //! Get the position of last parsing error in input, 0 otherwise.
+ size_t GetErrorOffset() const { return parseResult_.Offset(); }
+
+ protected:
+ void SetParseError(ParseErrorCode code, size_t offset) {
+ parseResult_.Set(code, offset);
+ }
+
+ private:
+ // Prohibit copy constructor & assignment operator.
+ GenericReader(const GenericReader&);
+ GenericReader& operator=(const GenericReader&);
+
+ void ClearStack() { stack_.Clear(); }
+
+ // clear stack on any exit from ParseStream, e.g. due to exception
+ struct ClearStackOnExit {
+ explicit ClearStackOnExit(GenericReader& r) : r_(r) {}
+ ~ClearStackOnExit() { r_.ClearStack(); }
+
+ private:
+ GenericReader& r_;
+ ClearStackOnExit(const ClearStackOnExit&);
+ ClearStackOnExit& operator=(const ClearStackOnExit&);
+ };
+
+ template <unsigned parseFlags, typename InputStream>
+ void SkipWhitespaceAndComments(InputStream& is) {
+ SkipWhitespace(is);
+
+ if (parseFlags & kParseCommentsFlag) {
+ while (RAPIDJSON_UNLIKELY(Consume(is, '/'))) {
+ if (Consume(is, '*')) {
+ while (true) {
+ if (RAPIDJSON_UNLIKELY(is.Peek() == '\0'))
+ RAPIDJSON_PARSE_ERROR(kParseErrorUnspecificSyntaxError,
+ is.Tell());
+ else if (Consume(is, '*')) {
+ if (Consume(is, '/'))
+ break;
+ } else
+ is.Take();
+ }
+ } else if (RAPIDJSON_LIKELY(Consume(is, '/')))
+ while (is.Peek() != '\0' && is.Take() != '\n')
+ ;
+ else
+ RAPIDJSON_PARSE_ERROR(kParseErrorUnspecificSyntaxError, is.Tell());
+
+ SkipWhitespace(is);
+ }
+ }
+ }
+
+ // Parse object: { string : value, ... }
+ template <unsigned parseFlags, typename InputStream, typename Handler>
+ void ParseObject(InputStream& is, Handler& handler) {
+ RAPIDJSON_ASSERT(is.Peek() == '{');
+ is.Take(); // Skip '{'
+
+ if (RAPIDJSON_UNLIKELY(!handler.StartObject()))
+ RAPIDJSON_PARSE_ERROR(kParseErrorTermination, is.Tell());
+
+ SkipWhitespaceAndComments<parseFlags>(is);
+ RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID;
+
+ if (Consume(is, '}')) {
+ if (RAPIDJSON_UNLIKELY(!handler.EndObject(0))) // empty object
+ RAPIDJSON_PARSE_ERROR(kParseErrorTermination, is.Tell());
+ return;
+ }
+
+ for (SizeType memberCount = 0;;) {
+ if (RAPIDJSON_UNLIKELY(is.Peek() != '"'))
+ RAPIDJSON_PARSE_ERROR(kParseErrorObjectMissName, is.Tell());
+
+ ParseString<parseFlags>(is, handler, true);
+ RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID;
+
+ SkipWhitespaceAndComments<parseFlags>(is);
+ RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID;
+
+ if (RAPIDJSON_UNLIKELY(!Consume(is, ':')))
+ RAPIDJSON_PARSE_ERROR(kParseErrorObjectMissColon, is.Tell());
+
+ SkipWhitespaceAndComments<parseFlags>(is);
+ RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID;
+
+ ParseValue<parseFlags>(is, handler);
+ RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID;
+
+ SkipWhitespaceAndComments<parseFlags>(is);
+ RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID;
+
+ ++memberCount;
+
+ switch (is.Peek()) {
+ case ',':
+ is.Take();
+ SkipWhitespaceAndComments<parseFlags>(is);
+ RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID;
+ break;
+ case '}':
+ is.Take();
+ if (RAPIDJSON_UNLIKELY(!handler.EndObject(memberCount)))
+ RAPIDJSON_PARSE_ERROR(kParseErrorTermination, is.Tell());
+ return;
+ default:
+ RAPIDJSON_PARSE_ERROR(kParseErrorObjectMissCommaOrCurlyBracket,
+ is.Tell());
+ break; // This useless break is only for making warning and coverage
+ // happy
+ }
+
+ if (parseFlags & kParseTrailingCommasFlag) {
+ if (is.Peek() == '}') {
+ if (RAPIDJSON_UNLIKELY(!handler.EndObject(memberCount)))
+ RAPIDJSON_PARSE_ERROR(kParseErrorTermination, is.Tell());
+ is.Take();
+ return;
+ }
+ }
+ }
+ }
+
+ // Parse array: [ value, ... ]
+ template <unsigned parseFlags, typename InputStream, typename Handler>
+ void ParseArray(InputStream& is, Handler& handler) {
+ RAPIDJSON_ASSERT(is.Peek() == '[');
+ is.Take(); // Skip '['
+
+ if (RAPIDJSON_UNLIKELY(!handler.StartArray()))
+ RAPIDJSON_PARSE_ERROR(kParseErrorTermination, is.Tell());
+
+ SkipWhitespaceAndComments<parseFlags>(is);
+ RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID;
+
+ if (Consume(is, ']')) {
+ if (RAPIDJSON_UNLIKELY(!handler.EndArray(0))) // empty array
+ RAPIDJSON_PARSE_ERROR(kParseErrorTermination, is.Tell());
+ return;
+ }
+
+ for (SizeType elementCount = 0;;) {
+ ParseValue<parseFlags>(is, handler);
+ RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID;
+
+ ++elementCount;
+ SkipWhitespaceAndComments<parseFlags>(is);
+ RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID;
+
+ if (Consume(is, ',')) {
+ SkipWhitespaceAndComments<parseFlags>(is);
+ RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID;
+ } else if (Consume(is, ']')) {
+ if (RAPIDJSON_UNLIKELY(!handler.EndArray(elementCount)))
+ RAPIDJSON_PARSE_ERROR(kParseErrorTermination, is.Tell());
+ return;
+ } else
+ RAPIDJSON_PARSE_ERROR(kParseErrorArrayMissCommaOrSquareBracket,
+ is.Tell());
+
+ if (parseFlags & kParseTrailingCommasFlag) {
+ if (is.Peek() == ']') {
+ if (RAPIDJSON_UNLIKELY(!handler.EndArray(elementCount)))
+ RAPIDJSON_PARSE_ERROR(kParseErrorTermination, is.Tell());
+ is.Take();
+ return;
+ }
+ }
+ }
+ }
+
+ template <unsigned parseFlags, typename InputStream, typename Handler>
+ void ParseNull(InputStream& is, Handler& handler) {
+ RAPIDJSON_ASSERT(is.Peek() == 'n');
+ is.Take();
+
+ if (RAPIDJSON_LIKELY(Consume(is, 'u') && Consume(is, 'l') &&
+ Consume(is, 'l'))) {
+ if (RAPIDJSON_UNLIKELY(!handler.Null()))
+ RAPIDJSON_PARSE_ERROR(kParseErrorTermination, is.Tell());
+ } else
+ RAPIDJSON_PARSE_ERROR(kParseErrorValueInvalid, is.Tell());
+ }
+
+ template <unsigned parseFlags, typename InputStream, typename Handler>
+ void ParseTrue(InputStream& is, Handler& handler) {
+ RAPIDJSON_ASSERT(is.Peek() == 't');
+ is.Take();
+
+ if (RAPIDJSON_LIKELY(Consume(is, 'r') && Consume(is, 'u') &&
+ Consume(is, 'e'))) {
+ if (RAPIDJSON_UNLIKELY(!handler.Bool(true)))
+ RAPIDJSON_PARSE_ERROR(kParseErrorTermination, is.Tell());
+ } else
+ RAPIDJSON_PARSE_ERROR(kParseErrorValueInvalid, is.Tell());
+ }
+
+ template <unsigned parseFlags, typename InputStream, typename Handler>
+ void ParseFalse(InputStream& is, Handler& handler) {
+ RAPIDJSON_ASSERT(is.Peek() == 'f');
+ is.Take();
+
+ if (RAPIDJSON_LIKELY(Consume(is, 'a') && Consume(is, 'l') &&
+ Consume(is, 's') && Consume(is, 'e'))) {
+ if (RAPIDJSON_UNLIKELY(!handler.Bool(false)))
+ RAPIDJSON_PARSE_ERROR(kParseErrorTermination, is.Tell());
+ } else
+ RAPIDJSON_PARSE_ERROR(kParseErrorValueInvalid, is.Tell());
+ }
+
+ template <typename InputStream>
+ RAPIDJSON_FORCEINLINE static bool Consume(InputStream& is,
+ typename InputStream::Ch expect) {
+ if (RAPIDJSON_LIKELY(is.Peek() == expect)) {
+ is.Take();
+ return true;
+ } else
+ return false;
+ }
+
+ // Helper function to parse four hexidecimal digits in \uXXXX in
+ // ParseString().
+ template <typename InputStream>
+ unsigned ParseHex4(InputStream& is, size_t escapeOffset) {
+ unsigned codepoint = 0;
+ for (int i = 0; i < 4; i++) {
+ Ch c = is.Peek();
+ codepoint <<= 4;
+ codepoint += static_cast<unsigned>(c);
+ if (c >= '0' && c <= '9')
+ codepoint -= '0';
+ else if (c >= 'A' && c <= 'F')
+ codepoint -= 'A' - 10;
+ else if (c >= 'a' && c <= 'f')
+ codepoint -= 'a' - 10;
+ else {
+ RAPIDJSON_PARSE_ERROR_NORETURN(kParseErrorStringUnicodeEscapeInvalidHex,
+ escapeOffset);
+ RAPIDJSON_PARSE_ERROR_EARLY_RETURN(0);
+ }
+ is.Take();
+ }
+ return codepoint;
+ }
+
+ template <typename CharType>
+ class StackStream {
+ public:
+ typedef CharType Ch;
+
+ StackStream(internal::Stack<StackAllocator>& stack)
+ : stack_(stack), length_(0) {}
+ RAPIDJSON_FORCEINLINE void Put(Ch c) {
+ *stack_.template Push<Ch>() = c;
+ ++length_;
+ }
+
+ RAPIDJSON_FORCEINLINE void* Push(SizeType count) {
+ length_ += count;
+ return stack_.template Push<Ch>(count);
+ }
+
+ size_t Length() const { return length_; }
+
+ Ch* Pop() { return stack_.template Pop<Ch>(length_); }
+
+ private:
+ StackStream(const StackStream&);
+ StackStream& operator=(const StackStream&);
+
+ internal::Stack<StackAllocator>& stack_;
+ SizeType length_;
+ };
+
+ // Parse string and generate String event. Different code paths for
+ // kParseInsituFlag.
+ template <unsigned parseFlags, typename InputStream, typename Handler>
+ void ParseString(InputStream& is, Handler& handler, bool isKey = false) {
+ internal::StreamLocalCopy<InputStream> copy(is);
+ InputStream& s(copy.s);
+
+ RAPIDJSON_ASSERT(s.Peek() == '\"');
+ s.Take(); // Skip '\"'
+
+ bool success = false;
+ if (parseFlags & kParseInsituFlag) {
+ typename InputStream::Ch* head = s.PutBegin();
+ ParseStringToStream<parseFlags, SourceEncoding, SourceEncoding>(s, s);
+ RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID;
+ size_t length = s.PutEnd(head) - 1;
+ RAPIDJSON_ASSERT(length <= 0xFFFFFFFF);
+ const typename TargetEncoding::Ch* const str =
+ reinterpret_cast<typename TargetEncoding::Ch*>(head);
+ success = (isKey ? handler.Key(str, SizeType(length), false)
+ : handler.String(str, SizeType(length), false));
+ } else {
+ StackStream<typename TargetEncoding::Ch> stackStream(stack_);
+ ParseStringToStream<parseFlags, SourceEncoding, TargetEncoding>(
+ s, stackStream);
+ RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID;
+ SizeType length = static_cast<SizeType>(stackStream.Length()) - 1;
+ const typename TargetEncoding::Ch* const str = stackStream.Pop();
+ success = (isKey ? handler.Key(str, length, true)
+ : handler.String(str, length, true));
+ }
+ if (RAPIDJSON_UNLIKELY(!success))
+ RAPIDJSON_PARSE_ERROR(kParseErrorTermination, s.Tell());
+ }
+
+ // Parse string to an output is
+ // This function handles the prefix/suffix double quotes, escaping, and
+ // optional encoding validation.
+ template <unsigned parseFlags,
+ typename SEncoding,
+ typename TEncoding,
+ typename InputStream,
+ typename OutputStream>
+ RAPIDJSON_FORCEINLINE void ParseStringToStream(InputStream& is,
+ OutputStream& os) {
+//!@cond RAPIDJSON_HIDDEN_FROM_DOXYGEN
+#define Z16 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+ static const char escape[256] = {
+ Z16, Z16, 0, 0, '\"', 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, '/', Z16, Z16, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, '\\', 0, 0, 0, 0, 0, '\b',
+ 0, 0, 0, '\f', 0, 0, 0, 0, 0, 0, 0, '\n', 0,
+ 0, 0, '\r', 0, '\t', 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, Z16, Z16, Z16, Z16, Z16, Z16, Z16, Z16};
+#undef Z16
+ //!@endcond
+
+ for (;;) {
+ // Scan and copy string before "\\\"" or < 0x20. This is an optional
+ // optimzation.
+ if (!(parseFlags & kParseValidateEncodingFlag))
+ ScanCopyUnescapedString(is, os);
+
+ Ch c = is.Peek();
+ if (RAPIDJSON_UNLIKELY(c == '\\')) { // Escape
+ size_t escapeOffset = is.Tell(); // For invalid escaping, report the
+ // inital '\\' as error offset
+ is.Take();
+ Ch e = is.Peek();
+ if ((sizeof(Ch) == 1 || unsigned(e) < 256) &&
+ RAPIDJSON_LIKELY(escape[static_cast<unsigned char>(e)])) {
+ is.Take();
+ os.Put(static_cast<typename TEncoding::Ch>(
+ escape[static_cast<unsigned char>(e)]));
+ } else if (RAPIDJSON_LIKELY(e == 'u')) { // Unicode
+ is.Take();
+ unsigned codepoint = ParseHex4(is, escapeOffset);
+ RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID;
+ if (RAPIDJSON_UNLIKELY(codepoint >= 0xD800 && codepoint <= 0xDBFF)) {
+ // Handle UTF-16 surrogate pair
+ if (RAPIDJSON_UNLIKELY(!Consume(is, '\\') || !Consume(is, 'u')))
+ RAPIDJSON_PARSE_ERROR(kParseErrorStringUnicodeSurrogateInvalid,
+ escapeOffset);
+ unsigned codepoint2 = ParseHex4(is, escapeOffset);
+ RAPIDJSON_PARSE_ERROR_EARLY_RETURN_VOID;
+ if (RAPIDJSON_UNLIKELY(codepoint2 < 0xDC00 || codepoint2 > 0xDFFF))
+ RAPIDJSON_PARSE_ERROR(kParseErrorStringUnicodeSurrogateInvalid,
+ escapeOffset);
+ codepoint = (((codepoint - 0xD800) << 10) | (codepoint2 - 0xDC00)) +
+ 0x10000;
+ }
+ TEncoding::Encode(os, codepoint);
+ } else
+ RAPIDJSON_PARSE_ERROR(kParseErrorStringEscapeInvalid, escapeOffset);
+ } else if (RAPIDJSON_UNLIKELY(c == '"')) { // Closing double quote
+ is.Take();
+ os.Put('\0'); // null-terminate the string
+ return;
+ } else if (RAPIDJSON_UNLIKELY(static_cast<unsigned>(c) <
+ 0x20)) { // RFC 4627: unescaped = %x20-21 /
+ // %x23-5B / %x5D-10FFFF
+ if (c == '\0')
+ RAPIDJSON_PARSE_ERROR(kParseErrorStringMissQuotationMark, is.Tell());
+ else
+ RAPIDJSON_PARSE_ERROR(kParseErrorStringEscapeInvalid, is.Tell());
+ } else {
+ size_t offset = is.Tell();
+ if (RAPIDJSON_UNLIKELY(
+ (parseFlags & kParseValidateEncodingFlag
+ ? !Transcoder<SEncoding, TEncoding>::Validate(is, os)
+ : !Transcoder<SEncoding, TEncoding>::Transcode(is, os))))
+ RAPIDJSON_PARSE_ERROR(kParseErrorStringInvalidEncoding, offset);
+ }
+ }
+ }
+
+ template <typename InputStream, typename OutputStream>
+ static RAPIDJSON_FORCEINLINE void ScanCopyUnescapedString(InputStream&,
+ OutputStream&) {
+ // Do nothing for generic version
+ }
+
+#if defined(RAPIDJSON_SSE2) || defined(RAPIDJSON_SSE42)
+ // StringStream -> StackStream<char>
+ static RAPIDJSON_FORCEINLINE void ScanCopyUnescapedString(
+ StringStream& is,
+ StackStream<char>& os) {
+ const char* p = is.src_;
+
+ // Scan one by one until alignment (unaligned load may cross page boundary
+ // and cause crash)
+ const char* nextAligned = reinterpret_cast<const char*>(
+ (reinterpret_cast<size_t>(p) + 15) & static_cast<size_t>(~15));
+ while (p != nextAligned)
+ if (RAPIDJSON_UNLIKELY(*p == '\"') || RAPIDJSON_UNLIKELY(*p == '\\') ||
+ RAPIDJSON_UNLIKELY(static_cast<unsigned>(*p) < 0x20)) {
+ is.src_ = p;
+ return;
+ } else
+ os.Put(*p++);
+
+ // The rest of string using SIMD
+ static const char dquote[16] = {'\"', '\"', '\"', '\"', '\"', '\"',
+ '\"', '\"', '\"', '\"', '\"', '\"',
+ '\"', '\"', '\"', '\"'};
+ static const char bslash[16] = {'\\', '\\', '\\', '\\', '\\', '\\',
+ '\\', '\\', '\\', '\\', '\\', '\\',
+ '\\', '\\', '\\', '\\'};
+ static const char space[16] = {0x19, 0x19, 0x19, 0x19, 0x19, 0x19,
+ 0x19, 0x19, 0x19, 0x19, 0x19, 0x19,
+ 0x19, 0x19, 0x19, 0x19};
+ const __m128i dq =
+ _mm_loadu_si128(reinterpret_cast<const __m128i*>(&dquote[0]));
+ const __m128i bs =
+ _mm_loadu_si128(reinterpret_cast<const __m128i*>(&bslash[0]));
+ const __m128i sp =
+ _mm_loadu_si128(reinterpret_cast<const __m128i*>(&space[0]));
+
+ for (;; p += 16) {
+ const __m128i s = _mm_load_si128(reinterpret_cast<const __m128i*>(p));
+ const __m128i t1 = _mm_cmpeq_epi8(s, dq);
+ const __m128i t2 = _mm_cmpeq_epi8(s, bs);
+ const __m128i t3 = _mm_cmpeq_epi8(
+ _mm_max_epu8(s, sp), sp); // s < 0x20 <=> max(s, 0x19) == 0x19
+ const __m128i x = _mm_or_si128(_mm_or_si128(t1, t2), t3);
+ unsigned short r = static_cast<unsigned short>(_mm_movemask_epi8(x));
+ if (RAPIDJSON_UNLIKELY(r != 0)) { // some of characters is escaped
+ SizeType length;
+#ifdef _MSC_VER // Find the index of first escaped
+ unsigned long offset;
+ _BitScanForward(&offset, r);
+ length = offset;
+#else
+ length = static_cast<SizeType>(__builtin_ffs(r) - 1);
+#endif
+ char* q = reinterpret_cast<char*>(os.Push(length));
+ for (size_t i = 0; i < length; i++)
+ q[i] = p[i];
+
+ p += length;
+ break;
+ }
+ _mm_storeu_si128(reinterpret_cast<__m128i*>(os.Push(16)), s);
+ }
+
+ is.src_ = p;
+ }
+
+ // InsituStringStream -> InsituStringStream
+ static RAPIDJSON_FORCEINLINE void ScanCopyUnescapedString(
+ InsituStringStream& is,
+ InsituStringStream& os) {
+ RAPIDJSON_ASSERT(&is == &os);
+ (void)os;
+
+ if (is.src_ == is.dst_) {
+ SkipUnescapedString(is);
+ return;
+ }
+
+ char* p = is.src_;
+ char* q = is.dst_;
+
+ // Scan one by one until alignment (unaligned load may cross page boundary
+ // and cause crash)
+ const char* nextAligned = reinterpret_cast<const char*>(
+ (reinterpret_cast<size_t>(p) + 15) & static_cast<size_t>(~15));
+ while (p != nextAligned)
+ if (RAPIDJSON_UNLIKELY(*p == '\"') || RAPIDJSON_UNLIKELY(*p == '\\') ||
+ RAPIDJSON_UNLIKELY(static_cast<unsigned>(*p) < 0x20)) {
+ is.src_ = p;
+ is.dst_ = q;
+ return;
+ } else
+ *q++ = *p++;
+
+ // The rest of string using SIMD
+ static const char dquote[16] = {'\"', '\"', '\"', '\"', '\"', '\"',
+ '\"', '\"', '\"', '\"', '\"', '\"',
+ '\"', '\"', '\"', '\"'};
+ static const char bslash[16] = {'\\', '\\', '\\', '\\', '\\', '\\',
+ '\\', '\\', '\\', '\\', '\\', '\\',
+ '\\', '\\', '\\', '\\'};
+ static const char space[16] = {0x19, 0x19, 0x19, 0x19, 0x19, 0x19,
+ 0x19, 0x19, 0x19, 0x19, 0x19, 0x19,
+ 0x19, 0x19, 0x19, 0x19};
+ const __m128i dq =
+ _mm_loadu_si128(reinterpret_cast<const __m128i*>(&dquote[0]));
+ const __m128i bs =
+ _mm_loadu_si128(reinterpret_cast<const __m128i*>(&bslash[0]));
+ const __m128i sp =
+ _mm_loadu_si128(reinterpret_cast<const __m128i*>(&space[0]));
+
+ for (;; p += 16, q += 16) {
+ const __m128i s = _mm_load_si128(reinterpret_cast<const __m128i*>(p));
+ const __m128i t1 = _mm_cmpeq_epi8(s, dq);
+ const __m128i t2 = _mm_cmpeq_epi8(s, bs);
+ const __m128i t3 = _mm_cmpeq_epi8(
+ _mm_max_epu8(s, sp), sp); // s < 0x20 <=> max(s, 0x19) == 0x19
+ const __m128i x = _mm_or_si128(_mm_or_si128(t1, t2), t3);
+ unsigned short r = static_cast<unsigned short>(_mm_movemask_epi8(x));
+ if (RAPIDJSON_UNLIKELY(r != 0)) { // some of characters is escaped
+ size_t length;
+#ifdef _MSC_VER // Find the index of first escaped
+ unsigned long offset;
+ _BitScanForward(&offset, r);
+ length = offset;
+#else
+ length = static_cast<size_t>(__builtin_ffs(r) - 1);
+#endif
+ for (const char* pend = p + length; p != pend;)
+ *q++ = *p++;
+ break;
+ }
+ _mm_storeu_si128(reinterpret_cast<__m128i*>(q), s);
+ }
+
+ is.src_ = p;
+ is.dst_ = q;
+ }
+
+ // When read/write pointers are the same for insitu stream, just skip
+ // unescaped characters
+ static RAPIDJSON_FORCEINLINE void SkipUnescapedString(
+ InsituStringStream& is) {
+ RAPIDJSON_ASSERT(is.src_ == is.dst_);
+ char* p = is.src_;
+
+ // Scan one by one until alignment (unaligned load may cross page boundary
+ // and cause crash)
+ const char* nextAligned = reinterpret_cast<const char*>(
+ (reinterpret_cast<size_t>(p) + 15) & static_cast<size_t>(~15));
+ for (; p != nextAligned; p++)
+ if (RAPIDJSON_UNLIKELY(*p == '\"') || RAPIDJSON_UNLIKELY(*p == '\\') ||
+ RAPIDJSON_UNLIKELY(static_cast<unsigned>(*p) < 0x20)) {
+ is.src_ = is.dst_ = p;
+ return;
+ }
+
+ // The rest of string using SIMD
+ static const char dquote[16] = {'\"', '\"', '\"', '\"', '\"', '\"',
+ '\"', '\"', '\"', '\"', '\"', '\"',
+ '\"', '\"', '\"', '\"'};
+ static const char bslash[16] = {'\\', '\\', '\\', '\\', '\\', '\\',
+ '\\', '\\', '\\', '\\', '\\', '\\',
+ '\\', '\\', '\\', '\\'};
+ static const char space[16] = {0x19, 0x19, 0x19, 0x19, 0x19, 0x19,
+ 0x19, 0x19, 0x19, 0x19, 0x19, 0x19,
+ 0x19, 0x19, 0x19, 0x19};
+ const __m128i dq =
+ _mm_loadu_si128(reinterpret_cast<const __m128i*>(&dquote[0]));
+ const __m128i bs =
+ _mm_loadu_si128(reinterpret_cast<const __m128i*>(&bslash[0]));
+ const __m128i sp =
+ _mm_loadu_si128(reinterpret_cast<const __m128i*>(&space[0]));
+
+ for (;; p += 16) {
+ const __m128i s = _mm_load_si128(reinterpret_cast<const __m128i*>(p));
+ const __m128i t1 = _mm_cmpeq_epi8(s, dq);
+ const __m128i t2 = _mm_cmpeq_epi8(s, bs);
+ const __m128i t3 = _mm_cmpeq_epi8(
+ _mm_max_epu8(s, sp), sp); // s < 0x20 <=> max(s, 0x19) == 0x19
+ const __m128i x = _mm_or_si128(_mm_or_si128(t1, t2), t3);
+ unsigned short r = static_cast<unsigned short>(_mm_movemask_epi8(x));
+ if (RAPIDJSON_UNLIKELY(r != 0)) { // some of characters is escaped
+ size_t length;
+#ifdef _MSC_VER // Find the index of first escaped
+ unsigned long offset;
+ _BitScanForward(&offset, r);
+ length = offset;
+#else
+ length = static_cast<size_t>(__builtin_ffs(r) - 1);
+#endif
+ p += length;
+ break;
+ }
+ }
+
+ is.src_ = is.dst_ = p;
+ }
+#endif
+
+ template <typename InputStream, bool backup, bool pushOnTake>
+ class NumberStream;
+
+ template <typename InputStream>
+ class NumberStream<InputStream, false, false> {
+ public:
+ typedef typename InputStream::Ch Ch;
+
+ NumberStream(GenericReader& reader, InputStream& s) : is(s) {
+ (void)reader;
+ }
+ ~NumberStream() {}
+
+ RAPIDJSON_FORCEINLINE Ch Peek() const { return is.Peek(); }
+ RAPIDJSON_FORCEINLINE Ch TakePush() { return is.Take(); }
+ RAPIDJSON_FORCEINLINE Ch Take() { return is.Take(); }
+ RAPIDJSON_FORCEINLINE void Push(char) {}
+
+ size_t Tell() { return is.Tell(); }
+ size_t Length() { return 0; }
+ const char* Pop() { return 0; }
+
+ protected:
+ NumberStream& operator=(const NumberStream&);
+
+ InputStream& is;
+ };
+
+ template <typename InputStream>
+ class NumberStream<InputStream, true, false>
+ : public NumberStream<InputStream, false, false> {
+ typedef NumberStream<InputStream, false, false> Base;
+
+ public:
+ NumberStream(GenericReader& reader, InputStream& is)
+ : Base(reader, is), stackStream(reader.stack_) {}
+ ~NumberStream() {}
+
+ RAPIDJSON_FORCEINLINE Ch TakePush() {
+ stackStream.Put(static_cast<char>(Base::is.Peek()));
+ return Base::is.Take();
+ }
+
+ RAPIDJSON_FORCEINLINE void Push(char c) { stackStream.Put(c); }
+
+ size_t Length() { return stackStream.Length(); }
+
+ const char* Pop() {
+ stackStream.Put('\0');
+ return stackStream.Pop();
+ }
+
+ private:
+ StackStream<char> stackStream;
+ };
+
+ template <typename InputStream>
+ class NumberStream<InputStream, true, true>
+ : public NumberStream<InputStream, true, false> {
+ typedef NumberStream<InputStream, true, false> Base;
+
+ public:
+ NumberStream(GenericReader& reader, InputStream& is) : Base(reader, is) {}
+ ~NumberStream() {}
+
+ RAPIDJSON_FORCEINLINE Ch Take() { return Base::TakePush(); }
+ };
+
+ template <unsigned parseFlags, typename InputStream, typename Handler>
+ void ParseNumber(InputStream& is, Handler& handler) {
+ internal::StreamLocalCopy<InputStream> copy(is);
+ NumberStream<InputStream,
+ ((parseFlags & kParseNumbersAsStringsFlag) != 0)
+ ? ((parseFlags & kParseInsituFlag) == 0)
+ : ((parseFlags & kParseFullPrecisionFlag) != 0),
+ (parseFlags & kParseNumbersAsStringsFlag) != 0 &&
+ (parseFlags & kParseInsituFlag) == 0>
+ s(*this, copy.s);
+
+ size_t startOffset = s.Tell();
+ double d = 0.0;
+ bool useNanOrInf = false;
+
+ // Parse minus
+ bool minus = Consume(s, '-');
+
+ // Parse int: zero / ( digit1-9 *DIGIT )
+ unsigned i = 0;
+ uint64_t i64 = 0;
+ bool use64bit = false;
+ int significandDigit = 0;
+ if (RAPIDJSON_UNLIKELY(s.Peek() == '0')) {
+ i = 0;
+ s.TakePush();
+ } else if (RAPIDJSON_LIKELY(s.Peek() >= '1' && s.Peek() <= '9')) {
+ i = static_cast<unsigned>(s.TakePush() - '0');
+
+ if (minus)
+ while (RAPIDJSON_LIKELY(s.Peek() >= '0' && s.Peek() <= '9')) {
+ if (RAPIDJSON_UNLIKELY(i >= 214748364)) { // 2^31 = 2147483648
+ if (RAPIDJSON_LIKELY(i != 214748364 || s.Peek() > '8')) {
+ i64 = i;
+ use64bit = true;
+ break;
+ }
+ }
+ i = i * 10 + static_cast<unsigned>(s.TakePush() - '0');
+ significandDigit++;
+ }
+ else
+ while (RAPIDJSON_LIKELY(s.Peek() >= '0' && s.Peek() <= '9')) {
+ if (RAPIDJSON_UNLIKELY(i >= 429496729)) { // 2^32 - 1 = 4294967295
+ if (RAPIDJSON_LIKELY(i != 429496729 || s.Peek() > '5')) {
+ i64 = i;
+ use64bit = true;
+ break;
+ }
+ }
+ i = i * 10 + static_cast<unsigned>(s.TakePush() - '0');
+ significandDigit++;
+ }
+ }
+ // Parse NaN or Infinity here
+ else if ((parseFlags & kParseNanAndInfFlag) &&
+ RAPIDJSON_LIKELY((s.Peek() == 'I' || s.Peek() == 'N'))) {
+ useNanOrInf = true;
+ if (RAPIDJSON_LIKELY(Consume(s, 'N') && Consume(s, 'a') &&
+ Consume(s, 'N'))) {
+ d = std::numeric_limits<double>::quiet_NaN();
+ } else if (RAPIDJSON_LIKELY(Consume(s, 'I') && Consume(s, 'n') &&
+ Consume(s, 'f'))) {
+ d = (minus ? -std::numeric_limits<double>::infinity()
+ : std::numeric_limits<double>::infinity());
+ if (RAPIDJSON_UNLIKELY(s.Peek() == 'i' &&
+ !(Consume(s, 'i') && Consume(s, 'n') &&
+ Consume(s, 'i') && Consume(s, 't') &&
+ Consume(s, 'y'))))
+ RAPIDJSON_PARSE_ERROR(kParseErrorValueInvalid, s.Tell());
+ } else
+ RAPIDJSON_PARSE_ERROR(kParseErrorValueInvalid, s.Tell());
+ } else
+ RAPIDJSON_PARSE_ERROR(kParseErrorValueInvalid, s.Tell());
+
+ // Parse 64bit int
+ bool useDouble = false;
+ if (use64bit) {
+ if (minus)
+ while (RAPIDJSON_LIKELY(s.Peek() >= '0' && s.Peek() <= '9')) {
+ if (RAPIDJSON_UNLIKELY(
+ i64 >=
+ RAPIDJSON_UINT64_C2(
+ 0x0CCCCCCC, 0xCCCCCCCC))) // 2^63 = 9223372036854775808
+ if (RAPIDJSON_LIKELY(
+ i64 != RAPIDJSON_UINT64_C2(0x0CCCCCCC, 0xCCCCCCCC) ||
+ s.Peek() > '8')) {
+ d = static_cast<double>(i64);
+ useDouble = true;
+ break;
+ }
+ i64 = i64 * 10 + static_cast<unsigned>(s.TakePush() - '0');
+ significandDigit++;
+ }
+ else
+ while (RAPIDJSON_LIKELY(s.Peek() >= '0' && s.Peek() <= '9')) {
+ if (RAPIDJSON_UNLIKELY(
+ i64 >= RAPIDJSON_UINT64_C2(
+ 0x19999999,
+ 0x99999999))) // 2^64 - 1 = 18446744073709551615
+ if (RAPIDJSON_LIKELY(
+ i64 != RAPIDJSON_UINT64_C2(0x19999999, 0x99999999) ||
+ s.Peek() > '5')) {
+ d = static_cast<double>(i64);
+ useDouble = true;
+ break;
+ }
+ i64 = i64 * 10 + static_cast<unsigned>(s.TakePush() - '0');
+ significandDigit++;
+ }
+ }
+
+ // Force double for big integer
+ if (useDouble) {
+ while (RAPIDJSON_LIKELY(s.Peek() >= '0' && s.Peek() <= '9')) {
+ if (RAPIDJSON_UNLIKELY(d >= 1.7976931348623157e307)) // DBL_MAX / 10.0
+ RAPIDJSON_PARSE_ERROR(kParseErrorNumberTooBig, startOffset);
+ d = d * 10 + (s.TakePush() - '0');
+ }
+ }
+
+ // Parse frac = decimal-point 1*DIGIT
+ int expFrac = 0;
+ size_t decimalPosition;
+ if (Consume(s, '.')) {
+ decimalPosition = s.Length();
+
+ if (RAPIDJSON_UNLIKELY(!(s.Peek() >= '0' && s.Peek() <= '9')))
+ RAPIDJSON_PARSE_ERROR(kParseErrorNumberMissFraction, s.Tell());
+
+ if (!useDouble) {
+#if RAPIDJSON_64BIT
+ // Use i64 to store significand in 64-bit architecture
+ if (!use64bit)
+ i64 = i;
+
+ while (RAPIDJSON_LIKELY(s.Peek() >= '0' && s.Peek() <= '9')) {
+ if (i64 > RAPIDJSON_UINT64_C2(0x1FFFFF,
+ 0xFFFFFFFF)) // 2^53 - 1 for fast path
+ break;
+ else {
+ i64 = i64 * 10 + static_cast<unsigned>(s.TakePush() - '0');
+ --expFrac;
+ if (i64 != 0)
+ significandDigit++;
+ }
+ }
+
+ d = static_cast<double>(i64);
+#else
+ // Use double to store significand in 32-bit architecture
+ d = static_cast<double>(use64bit ? i64 : i);
+#endif
+ useDouble = true;
+ }
+
+ while (RAPIDJSON_LIKELY(s.Peek() >= '0' && s.Peek() <= '9')) {
+ if (significandDigit < 17) {
+ d = d * 10.0 + (s.TakePush() - '0');
+ --expFrac;
+ if (RAPIDJSON_LIKELY(d > 0.0))
+ significandDigit++;
+ } else
+ s.TakePush();
+ }
+ } else
+ decimalPosition = s.Length(); // decimal position at the end of integer.
+
+ // Parse exp = e [ minus / plus ] 1*DIGIT
+ int exp = 0;
+ if (Consume(s, 'e') || Consume(s, 'E')) {
+ if (!useDouble) {
+ d = static_cast<double>(use64bit ? i64 : i);
+ useDouble = true;
+ }
+
+ bool expMinus = false;
+ if (Consume(s, '+'))
+ ;
+ else if (Consume(s, '-'))
+ expMinus = true;
+
+ if (RAPIDJSON_LIKELY(s.Peek() >= '0' && s.Peek() <= '9')) {
+ exp = static_cast<int>(s.Take() - '0');
+ if (expMinus) {
+ while (RAPIDJSON_LIKELY(s.Peek() >= '0' && s.Peek() <= '9')) {
+ exp = exp * 10 + static_cast<int>(s.Take() - '0');
+ if (exp >= 214748364) { // Issue #313: prevent overflow exponent
+ while (RAPIDJSON_UNLIKELY(
+ s.Peek() >= '0' &&
+ s.Peek() <= '9')) // Consume the rest of exponent
+ s.Take();
+ }
+ }
+ } else { // positive exp
+ int maxExp = 308 - expFrac;
+ while (RAPIDJSON_LIKELY(s.Peek() >= '0' && s.Peek() <= '9')) {
+ exp = exp * 10 + static_cast<int>(s.Take() - '0');
+ if (RAPIDJSON_UNLIKELY(exp > maxExp))
+ RAPIDJSON_PARSE_ERROR(kParseErrorNumberTooBig, startOffset);
+ }
+ }
+ } else
+ RAPIDJSON_PARSE_ERROR(kParseErrorNumberMissExponent, s.Tell());
+
+ if (expMinus)
+ exp = -exp;
+ }
+
+ // Finish parsing, call event according to the type of number.
+ bool cont = true;
+
+ if (parseFlags & kParseNumbersAsStringsFlag) {
+ if (parseFlags & kParseInsituFlag) {
+ s.Pop(); // Pop stack no matter if it will be used or not.
+ typename InputStream::Ch* head = is.PutBegin();
+ const size_t length = s.Tell() - startOffset;
+ RAPIDJSON_ASSERT(length <= 0xFFFFFFFF);
+ // unable to insert the \0 character here, it will erase the comma after
+ // this number
+ const typename TargetEncoding::Ch* const str =
+ reinterpret_cast<typename TargetEncoding::Ch*>(head);
+ cont = handler.RawNumber(str, SizeType(length), false);
+ } else {
+ SizeType numCharsToCopy = static_cast<SizeType>(s.Length());
+ StringStream srcStream(s.Pop());
+ StackStream<typename TargetEncoding::Ch> dstStream(stack_);
+ while (numCharsToCopy--) {
+ Transcoder<UTF8<>, TargetEncoding>::Transcode(srcStream, dstStream);
+ }
+ dstStream.Put('\0');
+ const typename TargetEncoding::Ch* str = dstStream.Pop();
+ const SizeType length = static_cast<SizeType>(dstStream.Length()) - 1;
+ cont = handler.RawNumber(str, SizeType(length), true);
+ }
+ } else {
+ size_t length = s.Length();
+ const char* decimal =
+ s.Pop(); // Pop stack no matter if it will be used or not.
+
+ if (useDouble) {
+ int p = exp + expFrac;
+ if (parseFlags & kParseFullPrecisionFlag)
+ d = internal::StrtodFullPrecision(d, p, decimal, length,
+ decimalPosition, exp);
+ else
+ d = internal::StrtodNormalPrecision(d, p);
+
+ cont = handler.Double(minus ? -d : d);
+ } else if (useNanOrInf) {
+ cont = handler.Double(d);
+ } else {
+ if (use64bit) {
+ if (minus)
+ cont = handler.Int64(static_cast<int64_t>(~i64 + 1));
+ else
+ cont = handler.Uint64(i64);
+ } else {
+ if (minus)
+ cont = handler.Int(static_cast<int32_t>(~i + 1));
+ else
+ cont = handler.Uint(i);
+ }
+ }
+ }
+ if (RAPIDJSON_UNLIKELY(!cont))
+ RAPIDJSON_PARSE_ERROR(kParseErrorTermination, startOffset);
+ }
+
+ // Parse any JSON value
+ template <unsigned parseFlags, typename InputStream, typename Handler>
+ void ParseValue(InputStream& is, Handler& handler) {
+ switch (is.Peek()) {
+ case 'n':
+ ParseNull<parseFlags>(is, handler);
+ break;
+ case 't':
+ ParseTrue<parseFlags>(is, handler);
+ break;
+ case 'f':
+ ParseFalse<parseFlags>(is, handler);
+ break;
+ case '"':
+ ParseString<parseFlags>(is, handler);
+ break;
+ case '{':
+ ParseObject<parseFlags>(is, handler);
+ break;
+ case '[':
+ ParseArray<parseFlags>(is, handler);
+ break;
+ default:
+ ParseNumber<parseFlags>(is, handler);
+ break;
+ }
+ }
+
+ // Iterative Parsing
+
+ // States
+ enum IterativeParsingState {
+ IterativeParsingStartState = 0,
+ IterativeParsingFinishState,
+ IterativeParsingErrorState,
+
+ // Object states
+ IterativeParsingObjectInitialState,
+ IterativeParsingMemberKeyState,
+ IterativeParsingKeyValueDelimiterState,
+ IterativeParsingMemberValueState,
+ IterativeParsingMemberDelimiterState,
+ IterativeParsingObjectFinishState,
+
+ // Array states
+ IterativeParsingArrayInitialState,
+ IterativeParsingElementState,
+ IterativeParsingElementDelimiterState,
+ IterativeParsingArrayFinishState,
+
+ // Single value state
+ IterativeParsingValueState
+ };
+
+ enum { cIterativeParsingStateCount = IterativeParsingValueState + 1 };
+
+ // Tokens
+ enum Token {
+ LeftBracketToken = 0,
+ RightBracketToken,
+
+ LeftCurlyBracketToken,
+ RightCurlyBracketToken,
+
+ CommaToken,
+ ColonToken,
+
+ StringToken,
+ FalseToken,
+ TrueToken,
+ NullToken,
+ NumberToken,
+
+ kTokenCount
+ };
+
+ RAPIDJSON_FORCEINLINE Token Tokenize(Ch c) {
+//!@cond RAPIDJSON_HIDDEN_FROM_DOXYGEN
+#define N NumberToken
+#define N16 N, N, N, N, N, N, N, N, N, N, N, N, N, N, N, N
+ // Maps from ASCII to Token
+ static const unsigned char tokenMap[256] = {
+ N16, // 00~0F
+ N16, // 10~1F
+ N, N,
+ StringToken, N,
+ N, N,
+ N, N,
+ N, N,
+ N, N,
+ CommaToken, N,
+ N, N, // 20~2F
+ N, N,
+ N, N,
+ N, N,
+ N, N,
+ N, N,
+ ColonToken, N,
+ N, N,
+ N, N, // 30~3F
+ N16, // 40~4F
+ N, N,
+ N, N,
+ N, N,
+ N, N,
+ N, N,
+ N, LeftBracketToken,
+ N, RightBracketToken,
+ N, N, // 50~5F
+ N, N,
+ N, N,
+ N, N,
+ FalseToken, N,
+ N, N,
+ N, N,
+ N, N,
+ NullToken, N, // 60~6F
+ N, N,
+ N, N,
+ TrueToken, N,
+ N, N,
+ N, N,
+ N, LeftCurlyBracketToken,
+ N, RightCurlyBracketToken,
+ N, N, // 70~7F
+ N16, N16,
+ N16, N16,
+ N16, N16,
+ N16, N16 // 80~FF
+ };
+#undef N
+#undef N16
+ //!@endcond
+
+ if (sizeof(Ch) == 1 || static_cast<unsigned>(c) < 256)
+ return static_cast<Token>(tokenMap[static_cast<unsigned char>(c)]);
+ else
+ return NumberToken;
+ }
+
+ RAPIDJSON_FORCEINLINE IterativeParsingState
+ Predict(IterativeParsingState state, Token token) {
+ // current state x one lookahead token -> new state
+ static const char G[cIterativeParsingStateCount][kTokenCount] = {
+ // Start
+ {
+ IterativeParsingArrayInitialState, // Left bracket
+ IterativeParsingErrorState, // Right bracket
+ IterativeParsingObjectInitialState, // Left curly bracket
+ IterativeParsingErrorState, // Right curly bracket
+ IterativeParsingErrorState, // Comma
+ IterativeParsingErrorState, // Colon
+ IterativeParsingValueState, // String
+ IterativeParsingValueState, // False
+ IterativeParsingValueState, // True
+ IterativeParsingValueState, // Null
+ IterativeParsingValueState // Number
+ },
+ // Finish(sink state)
+ {IterativeParsingErrorState, IterativeParsingErrorState,
+ IterativeParsingErrorState, IterativeParsingErrorState,
+ IterativeParsingErrorState, IterativeParsingErrorState,
+ IterativeParsingErrorState, IterativeParsingErrorState,
+ IterativeParsingErrorState, IterativeParsingErrorState,
+ IterativeParsingErrorState},
+ // Error(sink state)
+ {IterativeParsingErrorState, IterativeParsingErrorState,
+ IterativeParsingErrorState, IterativeParsingErrorState,
+ IterativeParsingErrorState, IterativeParsingErrorState,
+ IterativeParsingErrorState, IterativeParsingErrorState,
+ IterativeParsingErrorState, IterativeParsingErrorState,
+ IterativeParsingErrorState},
+ // ObjectInitial
+ {
+ IterativeParsingErrorState, // Left bracket
+ IterativeParsingErrorState, // Right bracket
+ IterativeParsingErrorState, // Left curly bracket
+ IterativeParsingObjectFinishState, // Right curly bracket
+ IterativeParsingErrorState, // Comma
+ IterativeParsingErrorState, // Colon
+ IterativeParsingMemberKeyState, // String
+ IterativeParsingErrorState, // False
+ IterativeParsingErrorState, // True
+ IterativeParsingErrorState, // Null
+ IterativeParsingErrorState // Number
+ },
+ // MemberKey
+ {
+ IterativeParsingErrorState, // Left bracket
+ IterativeParsingErrorState, // Right bracket
+ IterativeParsingErrorState, // Left curly bracket
+ IterativeParsingErrorState, // Right curly bracket
+ IterativeParsingErrorState, // Comma
+ IterativeParsingKeyValueDelimiterState, // Colon
+ IterativeParsingErrorState, // String
+ IterativeParsingErrorState, // False
+ IterativeParsingErrorState, // True
+ IterativeParsingErrorState, // Null
+ IterativeParsingErrorState // Number
+ },
+ // KeyValueDelimiter
+ {
+ IterativeParsingArrayInitialState, // Left bracket(push MemberValue
+ // state)
+ IterativeParsingErrorState, // Right bracket
+ IterativeParsingObjectInitialState, // Left curly bracket(push
+ // MemberValue state)
+ IterativeParsingErrorState, // Right curly bracket
+ IterativeParsingErrorState, // Comma
+ IterativeParsingErrorState, // Colon
+ IterativeParsingMemberValueState, // String
+ IterativeParsingMemberValueState, // False
+ IterativeParsingMemberValueState, // True
+ IterativeParsingMemberValueState, // Null
+ IterativeParsingMemberValueState // Number
+ },
+ // MemberValue
+ {
+ IterativeParsingErrorState, // Left bracket
+ IterativeParsingErrorState, // Right bracket
+ IterativeParsingErrorState, // Left curly bracket
+ IterativeParsingObjectFinishState, // Right curly bracket
+ IterativeParsingMemberDelimiterState, // Comma
+ IterativeParsingErrorState, // Colon
+ IterativeParsingErrorState, // String
+ IterativeParsingErrorState, // False
+ IterativeParsingErrorState, // True
+ IterativeParsingErrorState, // Null
+ IterativeParsingErrorState // Number
+ },
+ // MemberDelimiter
+ {
+ IterativeParsingErrorState, // Left bracket
+ IterativeParsingErrorState, // Right bracket
+ IterativeParsingErrorState, // Left curly bracket
+ IterativeParsingObjectFinishState, // Right curly bracket
+ IterativeParsingErrorState, // Comma
+ IterativeParsingErrorState, // Colon
+ IterativeParsingMemberKeyState, // String
+ IterativeParsingErrorState, // False
+ IterativeParsingErrorState, // True
+ IterativeParsingErrorState, // Null
+ IterativeParsingErrorState // Number
+ },
+ // ObjectFinish(sink state)
+ {IterativeParsingErrorState, IterativeParsingErrorState,
+ IterativeParsingErrorState, IterativeParsingErrorState,
+ IterativeParsingErrorState, IterativeParsingErrorState,
+ IterativeParsingErrorState, IterativeParsingErrorState,
+ IterativeParsingErrorState, IterativeParsingErrorState,
+ IterativeParsingErrorState},
+ // ArrayInitial
+ {
+ IterativeParsingArrayInitialState, // Left bracket(push Element
+ // state)
+ IterativeParsingArrayFinishState, // Right bracket
+ IterativeParsingObjectInitialState, // Left curly bracket(push
+ // Element state)
+ IterativeParsingErrorState, // Right curly bracket
+ IterativeParsingErrorState, // Comma
+ IterativeParsingErrorState, // Colon
+ IterativeParsingElementState, // String
+ IterativeParsingElementState, // False
+ IterativeParsingElementState, // True
+ IterativeParsingElementState, // Null
+ IterativeParsingElementState // Number
+ },
+ // Element
+ {
+ IterativeParsingErrorState, // Left bracket
+ IterativeParsingArrayFinishState, // Right bracket
+ IterativeParsingErrorState, // Left curly bracket
+ IterativeParsingErrorState, // Right curly bracket
+ IterativeParsingElementDelimiterState, // Comma
+ IterativeParsingErrorState, // Colon
+ IterativeParsingErrorState, // String
+ IterativeParsingErrorState, // False
+ IterativeParsingErrorState, // True
+ IterativeParsingErrorState, // Null
+ IterativeParsingErrorState // Number
+ },
+ // ElementDelimiter
+ {
+ IterativeParsingArrayInitialState, // Left bracket(push Element
+ // state)
+ IterativeParsingArrayFinishState, // Right bracket
+ IterativeParsingObjectInitialState, // Left curly bracket(push
+ // Element state)
+ IterativeParsingErrorState, // Right curly bracket
+ IterativeParsingErrorState, // Comma
+ IterativeParsingErrorState, // Colon
+ IterativeParsingElementState, // String
+ IterativeParsingElementState, // False
+ IterativeParsingElementState, // True
+ IterativeParsingElementState, // Null
+ IterativeParsingElementState // Number
+ },
+ // ArrayFinish(sink state)
+ {IterativeParsingErrorState, IterativeParsingErrorState,
+ IterativeParsingErrorState, IterativeParsingErrorState,
+ IterativeParsingErrorState, IterativeParsingErrorState,
+ IterativeParsingErrorState, IterativeParsingErrorState,
+ IterativeParsingErrorState, IterativeParsingErrorState,
+ IterativeParsingErrorState},
+ // Single Value (sink state)
+ {IterativeParsingErrorState, IterativeParsingErrorState,
+ IterativeParsingErrorState, IterativeParsingErrorState,
+ IterativeParsingErrorState, IterativeParsingErrorState,
+ IterativeParsingErrorState, IterativeParsingErrorState,
+ IterativeParsingErrorState, IterativeParsingErrorState,
+ IterativeParsingErrorState}}; // End of G
+
+ return static_cast<IterativeParsingState>(G[state][token]);
+ }
+
+ // Make an advance in the token stream and state based on the candidate
+ // destination state which was returned by Transit(). May return a new state
+ // on state pop.
+ template <unsigned parseFlags, typename InputStream, typename Handler>
+ RAPIDJSON_FORCEINLINE IterativeParsingState Transit(IterativeParsingState src,
+ Token token,
+ IterativeParsingState dst,
+ InputStream& is,
+ Handler& handler) {
+ (void)token;
+
+ switch (dst) {
+ case IterativeParsingErrorState:
+ return dst;
+
+ case IterativeParsingObjectInitialState:
+ case IterativeParsingArrayInitialState: {
+ // Push the state(Element or MemeberValue) if we are nested in another
+ // array or value of member. In this way we can get the correct state on
+ // ObjectFinish or ArrayFinish by frame pop.
+ IterativeParsingState n = src;
+ if (src == IterativeParsingArrayInitialState ||
+ src == IterativeParsingElementDelimiterState)
+ n = IterativeParsingElementState;
+ else if (src == IterativeParsingKeyValueDelimiterState)
+ n = IterativeParsingMemberValueState;
+ // Push current state.
+ *stack_.template Push<SizeType>(1) = n;
+ // Initialize and push the member/element count.
+ *stack_.template Push<SizeType>(1) = 0;
+ // Call handler
+ bool hr = (dst == IterativeParsingObjectInitialState)
+ ? handler.StartObject()
+ : handler.StartArray();
+ // On handler short circuits the parsing.
+ if (!hr) {
+ RAPIDJSON_PARSE_ERROR_NORETURN(kParseErrorTermination, is.Tell());
+ return IterativeParsingErrorState;
+ } else {
+ is.Take();
+ return dst;
+ }
+ }
+
+ case IterativeParsingMemberKeyState:
+ ParseString<parseFlags>(is, handler, true);
+ if (HasParseError())
+ return IterativeParsingErrorState;
+ else
+ return dst;
+
+ case IterativeParsingKeyValueDelimiterState:
+ RAPIDJSON_ASSERT(token == ColonToken);
+ is.Take();
+ return dst;
+
+ case IterativeParsingMemberValueState:
+ // Must be non-compound value. Or it would be ObjectInitial or
+ // ArrayInitial state.
+ ParseValue<parseFlags>(is, handler);
+ if (HasParseError()) {
+ return IterativeParsingErrorState;
+ }
+ return dst;
+
+ case IterativeParsingElementState:
+ // Must be non-compound value. Or it would be ObjectInitial or
+ // ArrayInitial state.
+ ParseValue<parseFlags>(is, handler);
+ if (HasParseError()) {
+ return IterativeParsingErrorState;
+ }
+ return dst;
+
+ case IterativeParsingMemberDelimiterState:
+ case IterativeParsingElementDelimiterState:
+ is.Take();
+ // Update member/element count.
+ *stack_.template Top<SizeType>() = *stack_.template Top<SizeType>() + 1;
+ return dst;
+
+ case IterativeParsingObjectFinishState: {
+ // Transit from delimiter is only allowed when trailing commas are
+ // enabled
+ if (!(parseFlags & kParseTrailingCommasFlag) &&
+ src == IterativeParsingMemberDelimiterState) {
+ RAPIDJSON_PARSE_ERROR_NORETURN(kParseErrorObjectMissName, is.Tell());
+ return IterativeParsingErrorState;
+ }
+ // Get member count.
+ SizeType c = *stack_.template Pop<SizeType>(1);
+ // If the object is not empty, count the last member.
+ if (src == IterativeParsingMemberValueState)
+ ++c;
+ // Restore the state.
+ IterativeParsingState n = static_cast<IterativeParsingState>(
+ *stack_.template Pop<SizeType>(1));
+ // Transit to Finish state if this is the topmost scope.
+ if (n == IterativeParsingStartState)
+ n = IterativeParsingFinishState;
+ // Call handler
+ bool hr = handler.EndObject(c);
+ // On handler short circuits the parsing.
+ if (!hr) {
+ RAPIDJSON_PARSE_ERROR_NORETURN(kParseErrorTermination, is.Tell());
+ return IterativeParsingErrorState;
+ } else {
+ is.Take();
+ return n;
+ }
+ }
+
+ case IterativeParsingArrayFinishState: {
+ // Transit from delimiter is only allowed when trailing commas are
+ // enabled
+ if (!(parseFlags & kParseTrailingCommasFlag) &&
+ src == IterativeParsingElementDelimiterState) {
+ RAPIDJSON_PARSE_ERROR_NORETURN(kParseErrorValueInvalid, is.Tell());
+ return IterativeParsingErrorState;
+ }
+ // Get element count.
+ SizeType c = *stack_.template Pop<SizeType>(1);
+ // If the array is not empty, count the last element.
+ if (src == IterativeParsingElementState)
+ ++c;
+ // Restore the state.
+ IterativeParsingState n = static_cast<IterativeParsingState>(
+ *stack_.template Pop<SizeType>(1));
+ // Transit to Finish state if this is the topmost scope.
+ if (n == IterativeParsingStartState)
+ n = IterativeParsingFinishState;
+ // Call handler
+ bool hr = handler.EndArray(c);
+ // On handler short circuits the parsing.
+ if (!hr) {
+ RAPIDJSON_PARSE_ERROR_NORETURN(kParseErrorTermination, is.Tell());
+ return IterativeParsingErrorState;
+ } else {
+ is.Take();
+ return n;
+ }
+ }
+
+ default:
+ // This branch is for IterativeParsingValueState actually.
+ // Use `default:` rather than
+ // `case IterativeParsingValueState:` is for code coverage.
+
+ // The IterativeParsingStartState is not enumerated in this switch-case.
+ // It is impossible for that case. And it can be caught by following
+ // assertion.
+
+ // The IterativeParsingFinishState is not enumerated in this switch-case
+ // either. It is a "derivative" state which cannot triggered from
+ // Predict() directly. Therefore it cannot happen here. And it can be
+ // caught by following assertion.
+ RAPIDJSON_ASSERT(dst == IterativeParsingValueState);
+
+ // Must be non-compound value. Or it would be ObjectInitial or
+ // ArrayInitial state.
+ ParseValue<parseFlags>(is, handler);
+ if (HasParseError()) {
+ return IterativeParsingErrorState;
+ }
+ return IterativeParsingFinishState;
+ }
+ }
+
+ template <typename InputStream>
+ void HandleError(IterativeParsingState src, InputStream& is) {
+ if (HasParseError()) {
+ // Error flag has been set.
+ return;
+ }
+
+ switch (src) {
+ case IterativeParsingStartState:
+ RAPIDJSON_PARSE_ERROR(kParseErrorDocumentEmpty, is.Tell());
+ return;
+ case IterativeParsingFinishState:
+ RAPIDJSON_PARSE_ERROR(kParseErrorDocumentRootNotSingular, is.Tell());
+ return;
+ case IterativeParsingObjectInitialState:
+ case IterativeParsingMemberDelimiterState:
+ RAPIDJSON_PARSE_ERROR(kParseErrorObjectMissName, is.Tell());
+ return;
+ case IterativeParsingMemberKeyState:
+ RAPIDJSON_PARSE_ERROR(kParseErrorObjectMissColon, is.Tell());
+ return;
+ case IterativeParsingMemberValueState:
+ RAPIDJSON_PARSE_ERROR(kParseErrorObjectMissCommaOrCurlyBracket,
+ is.Tell());
+ return;
+ case IterativeParsingKeyValueDelimiterState:
+ case IterativeParsingArrayInitialState:
+ case IterativeParsingElementDelimiterState:
+ RAPIDJSON_PARSE_ERROR(kParseErrorValueInvalid, is.Tell());
+ return;
+ default:
+ RAPIDJSON_ASSERT(src == IterativeParsingElementState);
+ RAPIDJSON_PARSE_ERROR(kParseErrorArrayMissCommaOrSquareBracket,
+ is.Tell());
+ return;
+ }
+ }
+
+ template <unsigned parseFlags, typename InputStream, typename Handler>
+ ParseResult IterativeParse(InputStream& is, Handler& handler) {
+ parseResult_.Clear();
+ ClearStackOnExit scope(*this);
+ IterativeParsingState state = IterativeParsingStartState;
+
+ SkipWhitespaceAndComments<parseFlags>(is);
+ RAPIDJSON_PARSE_ERROR_EARLY_RETURN(parseResult_);
+ while (is.Peek() != '\0') {
+ Token t = Tokenize(is.Peek());
+ IterativeParsingState n = Predict(state, t);
+ IterativeParsingState d = Transit<parseFlags>(state, t, n, is, handler);
+
+ if (d == IterativeParsingErrorState) {
+ HandleError(state, is);
+ break;
+ }
+
+ state = d;
+
+ // Do not further consume streams if a root JSON has been parsed.
+ if ((parseFlags & kParseStopWhenDoneFlag) &&
+ state == IterativeParsingFinishState)
+ break;
+
+ SkipWhitespaceAndComments<parseFlags>(is);
+ RAPIDJSON_PARSE_ERROR_EARLY_RETURN(parseResult_);
+ }
+
+ // Handle the end of file.
+ if (state != IterativeParsingFinishState)
+ HandleError(state, is);
+
+ return parseResult_;
+ }
+
+ static const size_t kDefaultStackCapacity =
+ 256; //!< Default stack capacity in bytes for storing a single decoded
+ //!< string.
+ internal::Stack<StackAllocator>
+ stack_; //!< A stack for storing decoded string temporarily during
+ //!< non-destructive parsing.
+ ParseResult parseResult_;
+}; // class GenericReader
+
+//! Reader with UTF8 encoding and default allocator.
+typedef GenericReader<UTF8<>, UTF8<> > Reader;
+
+RAPIDJSON_NAMESPACE_END
+
+#ifdef __clang__
+RAPIDJSON_DIAG_POP
+#endif
+
+#ifdef __GNUC__
+RAPIDJSON_DIAG_POP
+#endif
+
+#ifdef _MSC_VER
+RAPIDJSON_DIAG_POP
+#endif
+
+#endif // RAPIDJSON_READER_H_
diff --git a/third_party/rapidjson/schema.h b/third_party/rapidjson/schema.h
new file mode 100644
index 00000000..36e27332
--- /dev/null
+++ b/third_party/rapidjson/schema.h
@@ -0,0 +1,2399 @@
+// Tencent is pleased to support the open source community by making RapidJSON
+// available->
+//
+// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip-> All
+// rights reserved->
+//
+// Licensed under the MIT License (the "License"); you may not use this file
+// except in compliance with the License-> You may obtain a copy of the License
+// at
+//
+// http://opensource->org/licenses/MIT
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied-> See the
+// License for the specific language governing permissions and limitations under
+// the License->
+
+#ifndef RAPIDJSON_SCHEMA_H_
+#define RAPIDJSON_SCHEMA_H_
+
+#include <cmath> // abs, floor
+#include "document.h"
+#include "pointer.h"
+
+#if !defined(RAPIDJSON_SCHEMA_USE_INTERNALREGEX)
+#define RAPIDJSON_SCHEMA_USE_INTERNALREGEX 1
+#else
+#define RAPIDJSON_SCHEMA_USE_INTERNALREGEX 0
+#endif
+
+#if !RAPIDJSON_SCHEMA_USE_INTERNALREGEX && \
+ !defined(RAPIDJSON_SCHEMA_USE_STDREGEX) && \
+ (__cplusplus >= 201103L || (defined(_MSC_VER) && _MSC_VER >= 1800))
+#define RAPIDJSON_SCHEMA_USE_STDREGEX 1
+#else
+#define RAPIDJSON_SCHEMA_USE_STDREGEX 0
+#endif
+
+#if RAPIDJSON_SCHEMA_USE_INTERNALREGEX
+#include "rapidjson/internal/regex.h"
+#elif RAPIDJSON_SCHEMA_USE_STDREGEX
+#include <regex>
+#endif
+
+#if RAPIDJSON_SCHEMA_USE_INTERNALREGEX || RAPIDJSON_SCHEMA_USE_STDREGEX
+#define RAPIDJSON_SCHEMA_HAS_REGEX 1
+#else
+#define RAPIDJSON_SCHEMA_HAS_REGEX 0
+#endif
+
+#ifndef RAPIDJSON_SCHEMA_VERBOSE
+#define RAPIDJSON_SCHEMA_VERBOSE 0
+#endif
+
+#if RAPIDJSON_SCHEMA_VERBOSE
+#include "stringbuffer.h"
+#endif
+
+RAPIDJSON_DIAG_PUSH
+
+#if defined(__GNUC__)
+RAPIDJSON_DIAG_OFF(effc++)
+#endif
+
+#ifdef __clang__
+RAPIDJSON_DIAG_OFF(weak - vtables)
+RAPIDJSON_DIAG_OFF(exit - time - destructors)
+RAPIDJSON_DIAG_OFF(c++ 98 - compat - pedantic)
+RAPIDJSON_DIAG_OFF(variadic - macros)
+#endif
+
+#ifdef _MSC_VER
+RAPIDJSON_DIAG_OFF(4512) // assignment operator could not be generated
+#endif
+
+RAPIDJSON_NAMESPACE_BEGIN
+
+///////////////////////////////////////////////////////////////////////////////
+// Verbose Utilities
+
+#if RAPIDJSON_SCHEMA_VERBOSE
+
+namespace internal {
+
+inline void PrintInvalidKeyword(const char* keyword) {
+ printf("Fail keyword: %s\n", keyword);
+}
+
+inline void PrintInvalidKeyword(const wchar_t* keyword) {
+ wprintf(L"Fail keyword: %ls\n", keyword);
+}
+
+inline void PrintInvalidDocument(const char* document) {
+ printf("Fail document: %s\n\n", document);
+}
+
+inline void PrintInvalidDocument(const wchar_t* document) {
+ wprintf(L"Fail document: %ls\n\n", document);
+}
+
+inline void PrintValidatorPointers(unsigned depth,
+ const char* s,
+ const char* d) {
+ printf("S: %*s%s\nD: %*s%s\n\n", depth * 4, " ", s, depth * 4, " ", d);
+}
+
+inline void PrintValidatorPointers(unsigned depth,
+ const wchar_t* s,
+ const wchar_t* d) {
+ wprintf(L"S: %*ls%ls\nD: %*ls%ls\n\n", depth * 4, L" ", s, depth * 4, L" ",
+ d);
+}
+
+} // namespace internal
+
+#endif // RAPIDJSON_SCHEMA_VERBOSE
+
+///////////////////////////////////////////////////////////////////////////////
+// RAPIDJSON_INVALID_KEYWORD_RETURN
+
+#if RAPIDJSON_SCHEMA_VERBOSE
+#define RAPIDJSON_INVALID_KEYWORD_VERBOSE(keyword) \
+ internal::PrintInvalidKeyword(keyword)
+#else
+#define RAPIDJSON_INVALID_KEYWORD_VERBOSE(keyword)
+#endif
+
+#define RAPIDJSON_INVALID_KEYWORD_RETURN(keyword) \
+ RAPIDJSON_MULTILINEMACRO_BEGIN \
+ context.invalidKeyword = keyword.GetString(); \
+ RAPIDJSON_INVALID_KEYWORD_VERBOSE(keyword.GetString()); \
+ return false; \
+ RAPIDJSON_MULTILINEMACRO_END
+
+///////////////////////////////////////////////////////////////////////////////
+// Forward declarations
+
+template <typename ValueType, typename Allocator>
+class GenericSchemaDocument;
+
+namespace internal {
+
+template <typename SchemaDocumentType>
+class Schema;
+
+///////////////////////////////////////////////////////////////////////////////
+// ISchemaValidator
+
+class ISchemaValidator {
+ public:
+ virtual ~ISchemaValidator() {}
+ virtual bool IsValid() const = 0;
+};
+
+///////////////////////////////////////////////////////////////////////////////
+// ISchemaStateFactory
+
+template <typename SchemaType>
+class ISchemaStateFactory {
+ public:
+ virtual ~ISchemaStateFactory() {}
+ virtual ISchemaValidator* CreateSchemaValidator(const SchemaType&) = 0;
+ virtual void DestroySchemaValidator(ISchemaValidator* validator) = 0;
+ virtual void* CreateHasher() = 0;
+ virtual uint64_t GetHashCode(void* hasher) = 0;
+ virtual void DestroryHasher(void* hasher) = 0;
+ virtual void* MallocState(size_t size) = 0;
+ virtual void FreeState(void* p) = 0;
+};
+
+///////////////////////////////////////////////////////////////////////////////
+// Hasher
+
+// For comparison of compound value
+template <typename Encoding, typename Allocator>
+class Hasher {
+ public:
+ typedef typename Encoding::Ch Ch;
+
+ Hasher(Allocator* allocator = 0, size_t stackCapacity = kDefaultSize)
+ : stack_(allocator, stackCapacity) {}
+
+ bool Null() { return WriteType(kNullType); }
+ bool Bool(bool b) { return WriteType(b ? kTrueType : kFalseType); }
+ bool Int(int i) {
+ Number n;
+ n.u.i = i;
+ n.d = static_cast<double>(i);
+ return WriteNumber(n);
+ }
+ bool Uint(unsigned u) {
+ Number n;
+ n.u.u = u;
+ n.d = static_cast<double>(u);
+ return WriteNumber(n);
+ }
+ bool Int64(int64_t i) {
+ Number n;
+ n.u.i = i;
+ n.d = static_cast<double>(i);
+ return WriteNumber(n);
+ }
+ bool Uint64(uint64_t u) {
+ Number n;
+ n.u.u = u;
+ n.d = static_cast<double>(u);
+ return WriteNumber(n);
+ }
+ bool Double(double d) {
+ Number n;
+ if (d < 0)
+ n.u.i = static_cast<int64_t>(d);
+ else
+ n.u.u = static_cast<uint64_t>(d);
+ n.d = d;
+ return WriteNumber(n);
+ }
+
+ bool RawNumber(const Ch* str, SizeType len, bool) {
+ WriteBuffer(kNumberType, str, len * sizeof(Ch));
+ return true;
+ }
+
+ bool String(const Ch* str, SizeType len, bool) {
+ WriteBuffer(kStringType, str, len * sizeof(Ch));
+ return true;
+ }
+
+ bool StartObject() { return true; }
+ bool Key(const Ch* str, SizeType len, bool copy) {
+ return String(str, len, copy);
+ }
+ bool EndObject(SizeType memberCount) {
+ uint64_t h = Hash(0, kObjectType);
+ uint64_t* kv = stack_.template Pop<uint64_t>(memberCount * 2);
+ for (SizeType i = 0; i < memberCount; i++)
+ h ^= Hash(kv[i * 2],
+ kv[i * 2 + 1]); // Use xor to achieve member order insensitive
+ *stack_.template Push<uint64_t>() = h;
+ return true;
+ }
+
+ bool StartArray() { return true; }
+ bool EndArray(SizeType elementCount) {
+ uint64_t h = Hash(0, kArrayType);
+ uint64_t* e = stack_.template Pop<uint64_t>(elementCount);
+ for (SizeType i = 0; i < elementCount; i++)
+ h = Hash(h, e[i]); // Use hash to achieve element order sensitive
+ *stack_.template Push<uint64_t>() = h;
+ return true;
+ }
+
+ bool IsValid() const { return stack_.GetSize() == sizeof(uint64_t); }
+
+ uint64_t GetHashCode() const {
+ RAPIDJSON_ASSERT(IsValid());
+ return *stack_.template Top<uint64_t>();
+ }
+
+ private:
+ static const size_t kDefaultSize = 256;
+ struct Number {
+ union U {
+ uint64_t u;
+ int64_t i;
+ } u;
+ double d;
+ };
+
+ bool WriteType(Type type) { return WriteBuffer(type, 0, 0); }
+
+ bool WriteNumber(const Number& n) {
+ return WriteBuffer(kNumberType, &n, sizeof(n));
+ }
+
+ bool WriteBuffer(Type type, const void* data, size_t len) {
+ // FNV-1a from http://isthe.com/chongo/tech/comp/fnv/
+ uint64_t h = Hash(RAPIDJSON_UINT64_C2(0x84222325, 0xcbf29ce4), type);
+ const unsigned char* d = static_cast<const unsigned char*>(data);
+ for (size_t i = 0; i < len; i++)
+ h = Hash(h, d[i]);
+ *stack_.template Push<uint64_t>() = h;
+ return true;
+ }
+
+ static uint64_t Hash(uint64_t h, uint64_t d) {
+ static const uint64_t kPrime = RAPIDJSON_UINT64_C2(0x00000100, 0x000001b3);
+ h ^= d;
+ h *= kPrime;
+ return h;
+ }
+
+ Stack<Allocator> stack_;
+};
+
+///////////////////////////////////////////////////////////////////////////////
+// SchemaValidationContext
+
+template <typename SchemaDocumentType>
+struct SchemaValidationContext {
+ typedef Schema<SchemaDocumentType> SchemaType;
+ typedef ISchemaStateFactory<SchemaType> SchemaValidatorFactoryType;
+ typedef typename SchemaType::ValueType ValueType;
+ typedef typename ValueType::Ch Ch;
+
+ enum PatternValidatorType {
+ kPatternValidatorOnly,
+ kPatternValidatorWithProperty,
+ kPatternValidatorWithAdditionalProperty
+ };
+
+ SchemaValidationContext(SchemaValidatorFactoryType& f, const SchemaType* s)
+ : factory(f),
+ schema(s),
+ valueSchema(),
+ invalidKeyword(),
+ hasher(),
+ arrayElementHashCodes(),
+ validators(),
+ validatorCount(),
+ patternPropertiesValidators(),
+ patternPropertiesValidatorCount(),
+ patternPropertiesSchemas(),
+ patternPropertiesSchemaCount(),
+ valuePatternValidatorType(kPatternValidatorOnly),
+ propertyExist(),
+ inArray(false),
+ valueUniqueness(false),
+ arrayUniqueness(false) {}
+
+ ~SchemaValidationContext() {
+ if (hasher)
+ factory.DestroryHasher(hasher);
+ if (validators) {
+ for (SizeType i = 0; i < validatorCount; i++)
+ factory.DestroySchemaValidator(validators[i]);
+ factory.FreeState(validators);
+ }
+ if (patternPropertiesValidators) {
+ for (SizeType i = 0; i < patternPropertiesValidatorCount; i++)
+ factory.DestroySchemaValidator(patternPropertiesValidators[i]);
+ factory.FreeState(patternPropertiesValidators);
+ }
+ if (patternPropertiesSchemas)
+ factory.FreeState(patternPropertiesSchemas);
+ if (propertyExist)
+ factory.FreeState(propertyExist);
+ }
+
+ SchemaValidatorFactoryType& factory;
+ const SchemaType* schema;
+ const SchemaType* valueSchema;
+ const Ch* invalidKeyword;
+ void* hasher; // Only validator access
+ void* arrayElementHashCodes; // Only validator access this
+ ISchemaValidator** validators;
+ SizeType validatorCount;
+ ISchemaValidator** patternPropertiesValidators;
+ SizeType patternPropertiesValidatorCount;
+ const SchemaType** patternPropertiesSchemas;
+ SizeType patternPropertiesSchemaCount;
+ PatternValidatorType valuePatternValidatorType;
+ PatternValidatorType objectPatternValidatorType;
+ SizeType arrayElementIndex;
+ bool* propertyExist;
+ bool inArray;
+ bool valueUniqueness;
+ bool arrayUniqueness;
+};
+
+///////////////////////////////////////////////////////////////////////////////
+// Schema
+
+template <typename SchemaDocumentType>
+class Schema {
+ public:
+ typedef typename SchemaDocumentType::ValueType ValueType;
+ typedef typename SchemaDocumentType::AllocatorType AllocatorType;
+ typedef typename SchemaDocumentType::PointerType PointerType;
+ typedef typename ValueType::EncodingType EncodingType;
+ typedef typename EncodingType::Ch Ch;
+ typedef SchemaValidationContext<SchemaDocumentType> Context;
+ typedef Schema<SchemaDocumentType> SchemaType;
+ typedef GenericValue<EncodingType, AllocatorType> SValue;
+ friend class GenericSchemaDocument<ValueType, AllocatorType>;
+
+ Schema(SchemaDocumentType* schemaDocument,
+ const PointerType& p,
+ const ValueType& value,
+ const ValueType& document,
+ AllocatorType* allocator)
+ : allocator_(allocator),
+ enum_(),
+ enumCount_(),
+ not_(),
+ type_((1 << kTotalSchemaType) - 1), // typeless
+ validatorCount_(),
+ properties_(),
+ additionalPropertiesSchema_(),
+ patternProperties_(),
+ patternPropertyCount_(),
+ propertyCount_(),
+ minProperties_(),
+ maxProperties_(SizeType(~0)),
+ additionalProperties_(true),
+ hasDependencies_(),
+ hasRequired_(),
+ hasSchemaDependencies_(),
+ additionalItemsSchema_(),
+ itemsList_(),
+ itemsTuple_(),
+ itemsTupleCount_(),
+ minItems_(),
+ maxItems_(SizeType(~0)),
+ additionalItems_(true),
+ uniqueItems_(false),
+ pattern_(),
+ minLength_(0),
+ maxLength_(~SizeType(0)),
+ exclusiveMinimum_(false),
+ exclusiveMaximum_(false) {
+ typedef typename SchemaDocumentType::ValueType ValueType;
+ typedef typename ValueType::ConstValueIterator ConstValueIterator;
+ typedef typename ValueType::ConstMemberIterator ConstMemberIterator;
+
+ if (!value.IsObject())
+ return;
+
+ if (const ValueType* v = GetMember(value, GetTypeString())) {
+ type_ = 0;
+ if (v->IsString())
+ AddType(*v);
+ else if (v->IsArray())
+ for (ConstValueIterator itr = v->Begin(); itr != v->End(); ++itr)
+ AddType(*itr);
+ }
+
+ if (const ValueType* v = GetMember(value, GetEnumString()))
+ if (v->IsArray() && v->Size() > 0) {
+ enum_ = static_cast<uint64_t*>(
+ allocator_->Malloc(sizeof(uint64_t) * v->Size()));
+ for (ConstValueIterator itr = v->Begin(); itr != v->End(); ++itr) {
+ typedef Hasher<EncodingType, MemoryPoolAllocator<> > EnumHasherType;
+ char buffer[256 + 24];
+ MemoryPoolAllocator<> hasherAllocator(buffer, sizeof(buffer));
+ EnumHasherType h(&hasherAllocator, 256);
+ itr->Accept(h);
+ enum_[enumCount_++] = h.GetHashCode();
+ }
+ }
+
+ if (schemaDocument) {
+ AssignIfExist(allOf_, *schemaDocument, p, value, GetAllOfString(),
+ document);
+ AssignIfExist(anyOf_, *schemaDocument, p, value, GetAnyOfString(),
+ document);
+ AssignIfExist(oneOf_, *schemaDocument, p, value, GetOneOfString(),
+ document);
+ }
+
+ if (const ValueType* v = GetMember(value, GetNotString())) {
+ schemaDocument->CreateSchema(&not_, p.Append(GetNotString(), allocator_),
+ *v, document);
+ notValidatorIndex_ = validatorCount_;
+ validatorCount_++;
+ }
+
+ // Object
+
+ const ValueType* properties = GetMember(value, GetPropertiesString());
+ const ValueType* required = GetMember(value, GetRequiredString());
+ const ValueType* dependencies = GetMember(value, GetDependenciesString());
+ {
+ // Gather properties from properties/required/dependencies
+ SValue allProperties(kArrayType);
+
+ if (properties && properties->IsObject())
+ for (ConstMemberIterator itr = properties->MemberBegin();
+ itr != properties->MemberEnd(); ++itr)
+ AddUniqueElement(allProperties, itr->name);
+
+ if (required && required->IsArray())
+ for (ConstValueIterator itr = required->Begin(); itr != required->End();
+ ++itr)
+ if (itr->IsString())
+ AddUniqueElement(allProperties, *itr);
+
+ if (dependencies && dependencies->IsObject())
+ for (ConstMemberIterator itr = dependencies->MemberBegin();
+ itr != dependencies->MemberEnd(); ++itr) {
+ AddUniqueElement(allProperties, itr->name);
+ if (itr->value.IsArray())
+ for (ConstValueIterator i = itr->value.Begin();
+ i != itr->value.End(); ++i)
+ if (i->IsString())
+ AddUniqueElement(allProperties, *i);
+ }
+
+ if (allProperties.Size() > 0) {
+ propertyCount_ = allProperties.Size();
+ properties_ = static_cast<Property*>(
+ allocator_->Malloc(sizeof(Property) * propertyCount_));
+ for (SizeType i = 0; i < propertyCount_; i++) {
+ new (&properties_[i]) Property();
+ properties_[i].name = allProperties[i];
+ properties_[i].schema = GetTypeless();
+ }
+ }
+ }
+
+ if (properties && properties->IsObject()) {
+ PointerType q = p.Append(GetPropertiesString(), allocator_);
+ for (ConstMemberIterator itr = properties->MemberBegin();
+ itr != properties->MemberEnd(); ++itr) {
+ SizeType index;
+ if (FindPropertyIndex(itr->name, &index))
+ schemaDocument->CreateSchema(&properties_[index].schema,
+ q.Append(itr->name, allocator_),
+ itr->value, document);
+ }
+ }
+
+ if (const ValueType* v = GetMember(value, GetPatternPropertiesString())) {
+ PointerType q = p.Append(GetPatternPropertiesString(), allocator_);
+ patternProperties_ = static_cast<PatternProperty*>(
+ allocator_->Malloc(sizeof(PatternProperty) * v->MemberCount()));
+ patternPropertyCount_ = 0;
+
+ for (ConstMemberIterator itr = v->MemberBegin(); itr != v->MemberEnd();
+ ++itr) {
+ new (&patternProperties_[patternPropertyCount_]) PatternProperty();
+ patternProperties_[patternPropertyCount_].pattern =
+ CreatePattern(itr->name);
+ schemaDocument->CreateSchema(
+ &patternProperties_[patternPropertyCount_].schema,
+ q.Append(itr->name, allocator_), itr->value, document);
+ patternPropertyCount_++;
+ }
+ }
+
+ if (required && required->IsArray())
+ for (ConstValueIterator itr = required->Begin(); itr != required->End();
+ ++itr)
+ if (itr->IsString()) {
+ SizeType index;
+ if (FindPropertyIndex(*itr, &index)) {
+ properties_[index].required = true;
+ hasRequired_ = true;
+ }
+ }
+
+ if (dependencies && dependencies->IsObject()) {
+ PointerType q = p.Append(GetDependenciesString(), allocator_);
+ hasDependencies_ = true;
+ for (ConstMemberIterator itr = dependencies->MemberBegin();
+ itr != dependencies->MemberEnd(); ++itr) {
+ SizeType sourceIndex;
+ if (FindPropertyIndex(itr->name, &sourceIndex)) {
+ if (itr->value.IsArray()) {
+ properties_[sourceIndex].dependencies = static_cast<bool*>(
+ allocator_->Malloc(sizeof(bool) * propertyCount_));
+ std::memset(properties_[sourceIndex].dependencies, 0,
+ sizeof(bool) * propertyCount_);
+ for (ConstValueIterator targetItr = itr->value.Begin();
+ targetItr != itr->value.End(); ++targetItr) {
+ SizeType targetIndex;
+ if (FindPropertyIndex(*targetItr, &targetIndex))
+ properties_[sourceIndex].dependencies[targetIndex] = true;
+ }
+ } else if (itr->value.IsObject()) {
+ hasSchemaDependencies_ = true;
+ schemaDocument->CreateSchema(
+ &properties_[sourceIndex].dependenciesSchema,
+ q.Append(itr->name, allocator_), itr->value, document);
+ properties_[sourceIndex].dependenciesValidatorIndex =
+ validatorCount_;
+ validatorCount_++;
+ }
+ }
+ }
+ }
+
+ if (const ValueType* v =
+ GetMember(value, GetAdditionalPropertiesString())) {
+ if (v->IsBool())
+ additionalProperties_ = v->GetBool();
+ else if (v->IsObject())
+ schemaDocument->CreateSchema(
+ &additionalPropertiesSchema_,
+ p.Append(GetAdditionalPropertiesString(), allocator_), *v,
+ document);
+ }
+
+ AssignIfExist(minProperties_, value, GetMinPropertiesString());
+ AssignIfExist(maxProperties_, value, GetMaxPropertiesString());
+
+ // Array
+ if (const ValueType* v = GetMember(value, GetItemsString())) {
+ PointerType q = p.Append(GetItemsString(), allocator_);
+ if (v->IsObject()) // List validation
+ schemaDocument->CreateSchema(&itemsList_, q, *v, document);
+ else if (v->IsArray()) { // Tuple validation
+ itemsTuple_ = static_cast<const Schema**>(
+ allocator_->Malloc(sizeof(const Schema*) * v->Size()));
+ SizeType index = 0;
+ for (ConstValueIterator itr = v->Begin(); itr != v->End();
+ ++itr, index++)
+ schemaDocument->CreateSchema(&itemsTuple_[itemsTupleCount_++],
+ q.Append(index, allocator_), *itr,
+ document);
+ }
+ }
+
+ AssignIfExist(minItems_, value, GetMinItemsString());
+ AssignIfExist(maxItems_, value, GetMaxItemsString());
+
+ if (const ValueType* v = GetMember(value, GetAdditionalItemsString())) {
+ if (v->IsBool())
+ additionalItems_ = v->GetBool();
+ else if (v->IsObject())
+ schemaDocument->CreateSchema(
+ &additionalItemsSchema_,
+ p.Append(GetAdditionalItemsString(), allocator_), *v, document);
+ }
+
+ AssignIfExist(uniqueItems_, value, GetUniqueItemsString());
+
+ // String
+ AssignIfExist(minLength_, value, GetMinLengthString());
+ AssignIfExist(maxLength_, value, GetMaxLengthString());
+
+ if (const ValueType* v = GetMember(value, GetPatternString()))
+ pattern_ = CreatePattern(*v);
+
+ // Number
+ if (const ValueType* v = GetMember(value, GetMinimumString()))
+ if (v->IsNumber())
+ minimum_.CopyFrom(*v, *allocator_);
+
+ if (const ValueType* v = GetMember(value, GetMaximumString()))
+ if (v->IsNumber())
+ maximum_.CopyFrom(*v, *allocator_);
+
+ AssignIfExist(exclusiveMinimum_, value, GetExclusiveMinimumString());
+ AssignIfExist(exclusiveMaximum_, value, GetExclusiveMaximumString());
+
+ if (const ValueType* v = GetMember(value, GetMultipleOfString()))
+ if (v->IsNumber() && v->GetDouble() > 0.0)
+ multipleOf_.CopyFrom(*v, *allocator_);
+ }
+
+ ~Schema() {
+ if (allocator_) {
+ allocator_->Free(enum_);
+ }
+ if (properties_) {
+ for (SizeType i = 0; i < propertyCount_; i++)
+ properties_[i].~Property();
+ AllocatorType::Free(properties_);
+ }
+ if (patternProperties_) {
+ for (SizeType i = 0; i < patternPropertyCount_; i++)
+ patternProperties_[i].~PatternProperty();
+ AllocatorType::Free(patternProperties_);
+ }
+ AllocatorType::Free(itemsTuple_);
+#if RAPIDJSON_SCHEMA_HAS_REGEX
+ if (pattern_) {
+ pattern_->~RegexType();
+ allocator_->Free(pattern_);
+ }
+#endif
+ }
+
+ bool BeginValue(Context& context) const {
+ if (context.inArray) {
+ if (uniqueItems_)
+ context.valueUniqueness = true;
+
+ if (itemsList_)
+ context.valueSchema = itemsList_;
+ else if (itemsTuple_) {
+ if (context.arrayElementIndex < itemsTupleCount_)
+ context.valueSchema = itemsTuple_[context.arrayElementIndex];
+ else if (additionalItemsSchema_)
+ context.valueSchema = additionalItemsSchema_;
+ else if (additionalItems_)
+ context.valueSchema = GetTypeless();
+ else
+ RAPIDJSON_INVALID_KEYWORD_RETURN(GetItemsString());
+ } else
+ context.valueSchema = GetTypeless();
+
+ context.arrayElementIndex++;
+ }
+ return true;
+ }
+
+ RAPIDJSON_FORCEINLINE bool EndValue(Context& context) const {
+ if (context.patternPropertiesValidatorCount > 0) {
+ bool otherValid = false;
+ SizeType count = context.patternPropertiesValidatorCount;
+ if (context.objectPatternValidatorType != Context::kPatternValidatorOnly)
+ otherValid = context.patternPropertiesValidators[--count]->IsValid();
+
+ bool patternValid = true;
+ for (SizeType i = 0; i < count; i++)
+ if (!context.patternPropertiesValidators[i]->IsValid()) {
+ patternValid = false;
+ break;
+ }
+
+ if (context.objectPatternValidatorType ==
+ Context::kPatternValidatorOnly) {
+ if (!patternValid)
+ RAPIDJSON_INVALID_KEYWORD_RETURN(GetPatternPropertiesString());
+ } else if (context.objectPatternValidatorType ==
+ Context::kPatternValidatorWithProperty) {
+ if (!patternValid || !otherValid)
+ RAPIDJSON_INVALID_KEYWORD_RETURN(GetPatternPropertiesString());
+ } else if (!patternValid &&
+ !otherValid) // kPatternValidatorWithAdditionalProperty)
+ RAPIDJSON_INVALID_KEYWORD_RETURN(GetPatternPropertiesString());
+ }
+
+ if (enum_) {
+ const uint64_t h = context.factory.GetHashCode(context.hasher);
+ for (SizeType i = 0; i < enumCount_; i++)
+ if (enum_[i] == h)
+ goto foundEnum;
+ RAPIDJSON_INVALID_KEYWORD_RETURN(GetEnumString());
+ foundEnum:;
+ }
+
+ if (allOf_.schemas)
+ for (SizeType i = allOf_.begin; i < allOf_.begin + allOf_.count; i++)
+ if (!context.validators[i]->IsValid())
+ RAPIDJSON_INVALID_KEYWORD_RETURN(GetAllOfString());
+
+ if (anyOf_.schemas) {
+ for (SizeType i = anyOf_.begin; i < anyOf_.begin + anyOf_.count; i++)
+ if (context.validators[i]->IsValid())
+ goto foundAny;
+ RAPIDJSON_INVALID_KEYWORD_RETURN(GetAnyOfString());
+ foundAny:;
+ }
+
+ if (oneOf_.schemas) {
+ bool oneValid = false;
+ for (SizeType i = oneOf_.begin; i < oneOf_.begin + oneOf_.count; i++)
+ if (context.validators[i]->IsValid()) {
+ if (oneValid)
+ RAPIDJSON_INVALID_KEYWORD_RETURN(GetOneOfString());
+ else
+ oneValid = true;
+ }
+ if (!oneValid)
+ RAPIDJSON_INVALID_KEYWORD_RETURN(GetOneOfString());
+ }
+
+ if (not_ && context.validators[notValidatorIndex_]->IsValid())
+ RAPIDJSON_INVALID_KEYWORD_RETURN(GetNotString());
+
+ return true;
+ }
+
+ bool Null(Context& context) const {
+ if (!(type_ & (1 << kNullSchemaType)))
+ RAPIDJSON_INVALID_KEYWORD_RETURN(GetTypeString());
+ return CreateParallelValidator(context);
+ }
+
+ bool Bool(Context& context, bool) const {
+ if (!(type_ & (1 << kBooleanSchemaType)))
+ RAPIDJSON_INVALID_KEYWORD_RETURN(GetTypeString());
+ return CreateParallelValidator(context);
+ }
+
+ bool Int(Context& context, int i) const {
+ if (!CheckInt(context, i))
+ return false;
+ return CreateParallelValidator(context);
+ }
+
+ bool Uint(Context& context, unsigned u) const {
+ if (!CheckUint(context, u))
+ return false;
+ return CreateParallelValidator(context);
+ }
+
+ bool Int64(Context& context, int64_t i) const {
+ if (!CheckInt(context, i))
+ return false;
+ return CreateParallelValidator(context);
+ }
+
+ bool Uint64(Context& context, uint64_t u) const {
+ if (!CheckUint(context, u))
+ return false;
+ return CreateParallelValidator(context);
+ }
+
+ bool Double(Context& context, double d) const {
+ if (!(type_ & (1 << kNumberSchemaType)))
+ RAPIDJSON_INVALID_KEYWORD_RETURN(GetTypeString());
+
+ if (!minimum_.IsNull() && !CheckDoubleMinimum(context, d))
+ return false;
+
+ if (!maximum_.IsNull() && !CheckDoubleMaximum(context, d))
+ return false;
+
+ if (!multipleOf_.IsNull() && !CheckDoubleMultipleOf(context, d))
+ return false;
+
+ return CreateParallelValidator(context);
+ }
+
+ bool String(Context& context, const Ch* str, SizeType length, bool) const {
+ if (!(type_ & (1 << kStringSchemaType)))
+ RAPIDJSON_INVALID_KEYWORD_RETURN(GetTypeString());
+
+ if (minLength_ != 0 || maxLength_ != SizeType(~0)) {
+ SizeType count;
+ if (internal::CountStringCodePoint<EncodingType>(str, length, &count)) {
+ if (count < minLength_)
+ RAPIDJSON_INVALID_KEYWORD_RETURN(GetMinLengthString());
+ if (count > maxLength_)
+ RAPIDJSON_INVALID_KEYWORD_RETURN(GetMaxLengthString());
+ }
+ }
+
+ if (pattern_ && !IsPatternMatch(pattern_, str, length))
+ RAPIDJSON_INVALID_KEYWORD_RETURN(GetPatternString());
+
+ return CreateParallelValidator(context);
+ }
+
+ bool StartObject(Context& context) const {
+ if (!(type_ & (1 << kObjectSchemaType)))
+ RAPIDJSON_INVALID_KEYWORD_RETURN(GetTypeString());
+
+ if (hasDependencies_ || hasRequired_) {
+ context.propertyExist = static_cast<bool*>(
+ context.factory.MallocState(sizeof(bool) * propertyCount_));
+ std::memset(context.propertyExist, 0, sizeof(bool) * propertyCount_);
+ }
+
+ if (patternProperties_) { // pre-allocate schema array
+ SizeType count =
+ patternPropertyCount_ + 1; // extra for valuePatternValidatorType
+ context.patternPropertiesSchemas = static_cast<const SchemaType**>(
+ context.factory.MallocState(sizeof(const SchemaType*) * count));
+ context.patternPropertiesSchemaCount = 0;
+ std::memset(context.patternPropertiesSchemas, 0,
+ sizeof(SchemaType*) * count);
+ }
+
+ return CreateParallelValidator(context);
+ }
+
+ bool Key(Context& context, const Ch* str, SizeType len, bool) const {
+ if (patternProperties_) {
+ context.patternPropertiesSchemaCount = 0;
+ for (SizeType i = 0; i < patternPropertyCount_; i++)
+ if (patternProperties_[i].pattern &&
+ IsPatternMatch(patternProperties_[i].pattern, str, len))
+ context.patternPropertiesSchemas
+ [context.patternPropertiesSchemaCount++] =
+ patternProperties_[i].schema;
+ }
+
+ SizeType index;
+ if (FindPropertyIndex(ValueType(str, len).Move(), &index)) {
+ if (context.patternPropertiesSchemaCount > 0) {
+ context
+ .patternPropertiesSchemas[context.patternPropertiesSchemaCount++] =
+ properties_[index].schema;
+ context.valueSchema = GetTypeless();
+ context.valuePatternValidatorType =
+ Context::kPatternValidatorWithProperty;
+ } else
+ context.valueSchema = properties_[index].schema;
+
+ if (context.propertyExist)
+ context.propertyExist[index] = true;
+
+ return true;
+ }
+
+ if (additionalPropertiesSchema_) {
+ if (additionalPropertiesSchema_ &&
+ context.patternPropertiesSchemaCount > 0) {
+ context
+ .patternPropertiesSchemas[context.patternPropertiesSchemaCount++] =
+ additionalPropertiesSchema_;
+ context.valueSchema = GetTypeless();
+ context.valuePatternValidatorType =
+ Context::kPatternValidatorWithAdditionalProperty;
+ } else
+ context.valueSchema = additionalPropertiesSchema_;
+ return true;
+ } else if (additionalProperties_) {
+ context.valueSchema = GetTypeless();
+ return true;
+ }
+
+ if (context.patternPropertiesSchemaCount ==
+ 0) // patternProperties are not additional properties
+ RAPIDJSON_INVALID_KEYWORD_RETURN(GetAdditionalPropertiesString());
+
+ return true;
+ }
+
+ bool EndObject(Context& context, SizeType memberCount) const {
+ if (hasRequired_)
+ for (SizeType index = 0; index < propertyCount_; index++)
+ if (properties_[index].required)
+ if (!context.propertyExist[index])
+ RAPIDJSON_INVALID_KEYWORD_RETURN(GetRequiredString());
+
+ if (memberCount < minProperties_)
+ RAPIDJSON_INVALID_KEYWORD_RETURN(GetMinPropertiesString());
+
+ if (memberCount > maxProperties_)
+ RAPIDJSON_INVALID_KEYWORD_RETURN(GetMaxPropertiesString());
+
+ if (hasDependencies_) {
+ for (SizeType sourceIndex = 0; sourceIndex < propertyCount_;
+ sourceIndex++)
+ if (context.propertyExist[sourceIndex]) {
+ if (properties_[sourceIndex].dependencies) {
+ for (SizeType targetIndex = 0; targetIndex < propertyCount_;
+ targetIndex++)
+ if (properties_[sourceIndex].dependencies[targetIndex] &&
+ !context.propertyExist[targetIndex])
+ RAPIDJSON_INVALID_KEYWORD_RETURN(GetDependenciesString());
+ } else if (properties_[sourceIndex].dependenciesSchema)
+ if (!context
+ .validators[properties_[sourceIndex]
+ .dependenciesValidatorIndex]
+ ->IsValid())
+ RAPIDJSON_INVALID_KEYWORD_RETURN(GetDependenciesString());
+ }
+ }
+
+ return true;
+ }
+
+ bool StartArray(Context& context) const {
+ if (!(type_ & (1 << kArraySchemaType)))
+ RAPIDJSON_INVALID_KEYWORD_RETURN(GetTypeString());
+
+ context.arrayElementIndex = 0;
+ context.inArray = true;
+
+ return CreateParallelValidator(context);
+ }
+
+ bool EndArray(Context& context, SizeType elementCount) const {
+ context.inArray = false;
+
+ if (elementCount < minItems_)
+ RAPIDJSON_INVALID_KEYWORD_RETURN(GetMinItemsString());
+
+ if (elementCount > maxItems_)
+ RAPIDJSON_INVALID_KEYWORD_RETURN(GetMaxItemsString());
+
+ return true;
+ }
+
+ // Generate functions for string literal according to Ch
+#define RAPIDJSON_STRING_(name, ...) \
+ static const ValueType& Get##name##String() { \
+ static const Ch s[] = {__VA_ARGS__, '\0'}; \
+ static const ValueType v(s, sizeof(s) / sizeof(Ch) - 1); \
+ return v; \
+ }
+
+ RAPIDJSON_STRING_(Null, 'n', 'u', 'l', 'l')
+ RAPIDJSON_STRING_(Boolean, 'b', 'o', 'o', 'l', 'e', 'a', 'n')
+ RAPIDJSON_STRING_(Object, 'o', 'b', 'j', 'e', 'c', 't')
+ RAPIDJSON_STRING_(Array, 'a', 'r', 'r', 'a', 'y')
+ RAPIDJSON_STRING_(String, 's', 't', 'r', 'i', 'n', 'g')
+ RAPIDJSON_STRING_(Number, 'n', 'u', 'm', 'b', 'e', 'r')
+ RAPIDJSON_STRING_(Integer, 'i', 'n', 't', 'e', 'g', 'e', 'r')
+ RAPIDJSON_STRING_(Type, 't', 'y', 'p', 'e')
+ RAPIDJSON_STRING_(Enum, 'e', 'n', 'u', 'm')
+ RAPIDJSON_STRING_(AllOf, 'a', 'l', 'l', 'O', 'f')
+ RAPIDJSON_STRING_(AnyOf, 'a', 'n', 'y', 'O', 'f')
+ RAPIDJSON_STRING_(OneOf, 'o', 'n', 'e', 'O', 'f')
+ RAPIDJSON_STRING_(Not, 'n', 'o', 't')
+ RAPIDJSON_STRING_(Properties,
+ 'p',
+ 'r',
+ 'o',
+ 'p',
+ 'e',
+ 'r',
+ 't',
+ 'i',
+ 'e',
+ 's')
+ RAPIDJSON_STRING_(Required, 'r', 'e', 'q', 'u', 'i', 'r', 'e', 'd')
+ RAPIDJSON_STRING_(Dependencies,
+ 'd',
+ 'e',
+ 'p',
+ 'e',
+ 'n',
+ 'd',
+ 'e',
+ 'n',
+ 'c',
+ 'i',
+ 'e',
+ 's')
+ RAPIDJSON_STRING_(PatternProperties,
+ 'p',
+ 'a',
+ 't',
+ 't',
+ 'e',
+ 'r',
+ 'n',
+ 'P',
+ 'r',
+ 'o',
+ 'p',
+ 'e',
+ 'r',
+ 't',
+ 'i',
+ 'e',
+ 's')
+ RAPIDJSON_STRING_(AdditionalProperties,
+ 'a',
+ 'd',
+ 'd',
+ 'i',
+ 't',
+ 'i',
+ 'o',
+ 'n',
+ 'a',
+ 'l',
+ 'P',
+ 'r',
+ 'o',
+ 'p',
+ 'e',
+ 'r',
+ 't',
+ 'i',
+ 'e',
+ 's')
+ RAPIDJSON_STRING_(MinProperties,
+ 'm',
+ 'i',
+ 'n',
+ 'P',
+ 'r',
+ 'o',
+ 'p',
+ 'e',
+ 'r',
+ 't',
+ 'i',
+ 'e',
+ 's')
+ RAPIDJSON_STRING_(MaxProperties,
+ 'm',
+ 'a',
+ 'x',
+ 'P',
+ 'r',
+ 'o',
+ 'p',
+ 'e',
+ 'r',
+ 't',
+ 'i',
+ 'e',
+ 's')
+ RAPIDJSON_STRING_(Items, 'i', 't', 'e', 'm', 's')
+ RAPIDJSON_STRING_(MinItems, 'm', 'i', 'n', 'I', 't', 'e', 'm', 's')
+ RAPIDJSON_STRING_(MaxItems, 'm', 'a', 'x', 'I', 't', 'e', 'm', 's')
+ RAPIDJSON_STRING_(AdditionalItems,
+ 'a',
+ 'd',
+ 'd',
+ 'i',
+ 't',
+ 'i',
+ 'o',
+ 'n',
+ 'a',
+ 'l',
+ 'I',
+ 't',
+ 'e',
+ 'm',
+ 's')
+ RAPIDJSON_STRING_(UniqueItems,
+ 'u',
+ 'n',
+ 'i',
+ 'q',
+ 'u',
+ 'e',
+ 'I',
+ 't',
+ 'e',
+ 'm',
+ 's')
+ RAPIDJSON_STRING_(MinLength, 'm', 'i', 'n', 'L', 'e', 'n', 'g', 't', 'h')
+ RAPIDJSON_STRING_(MaxLength, 'm', 'a', 'x', 'L', 'e', 'n', 'g', 't', 'h')
+ RAPIDJSON_STRING_(Pattern, 'p', 'a', 't', 't', 'e', 'r', 'n')
+ RAPIDJSON_STRING_(Minimum, 'm', 'i', 'n', 'i', 'm', 'u', 'm')
+ RAPIDJSON_STRING_(Maximum, 'm', 'a', 'x', 'i', 'm', 'u', 'm')
+ RAPIDJSON_STRING_(ExclusiveMinimum,
+ 'e',
+ 'x',
+ 'c',
+ 'l',
+ 'u',
+ 's',
+ 'i',
+ 'v',
+ 'e',
+ 'M',
+ 'i',
+ 'n',
+ 'i',
+ 'm',
+ 'u',
+ 'm')
+ RAPIDJSON_STRING_(ExclusiveMaximum,
+ 'e',
+ 'x',
+ 'c',
+ 'l',
+ 'u',
+ 's',
+ 'i',
+ 'v',
+ 'e',
+ 'M',
+ 'a',
+ 'x',
+ 'i',
+ 'm',
+ 'u',
+ 'm')
+ RAPIDJSON_STRING_(MultipleOf,
+ 'm',
+ 'u',
+ 'l',
+ 't',
+ 'i',
+ 'p',
+ 'l',
+ 'e',
+ 'O',
+ 'f')
+
+#undef RAPIDJSON_STRING_
+
+ private:
+ enum SchemaValueType {
+ kNullSchemaType,
+ kBooleanSchemaType,
+ kObjectSchemaType,
+ kArraySchemaType,
+ kStringSchemaType,
+ kNumberSchemaType,
+ kIntegerSchemaType,
+ kTotalSchemaType
+ };
+
+#if RAPIDJSON_SCHEMA_USE_INTERNALREGEX
+ typedef internal::GenericRegex<EncodingType> RegexType;
+#elif RAPIDJSON_SCHEMA_USE_STDREGEX
+ typedef std::basic_regex<Ch> RegexType;
+#else
+ typedef char RegexType;
+#endif
+
+ struct SchemaArray {
+ SchemaArray() : schemas(), count() {}
+ ~SchemaArray() { AllocatorType::Free(schemas); }
+ const SchemaType** schemas;
+ SizeType begin; // begin index of context.validators
+ SizeType count;
+ };
+
+ static const SchemaType* GetTypeless() {
+ static SchemaType typeless(0, PointerType(), ValueType(kObjectType).Move(),
+ ValueType(kObjectType).Move(), 0);
+ return &typeless;
+ }
+
+ template <typename V1, typename V2>
+ void AddUniqueElement(V1& a, const V2& v) {
+ for (typename V1::ConstValueIterator itr = a.Begin(); itr != a.End(); ++itr)
+ if (*itr == v)
+ return;
+ V1 c(v, *allocator_);
+ a.PushBack(c, *allocator_);
+ }
+
+ static const ValueType* GetMember(const ValueType& value,
+ const ValueType& name) {
+ typename ValueType::ConstMemberIterator itr = value.FindMember(name);
+ return itr != value.MemberEnd() ? &(itr->value) : 0;
+ }
+
+ static void AssignIfExist(bool& out,
+ const ValueType& value,
+ const ValueType& name) {
+ if (const ValueType* v = GetMember(value, name))
+ if (v->IsBool())
+ out = v->GetBool();
+ }
+
+ static void AssignIfExist(SizeType& out,
+ const ValueType& value,
+ const ValueType& name) {
+ if (const ValueType* v = GetMember(value, name))
+ if (v->IsUint64() && v->GetUint64() <= SizeType(~0))
+ out = static_cast<SizeType>(v->GetUint64());
+ }
+
+ void AssignIfExist(SchemaArray& out,
+ SchemaDocumentType& schemaDocument,
+ const PointerType& p,
+ const ValueType& value,
+ const ValueType& name,
+ const ValueType& document) {
+ if (const ValueType* v = GetMember(value, name)) {
+ if (v->IsArray() && v->Size() > 0) {
+ PointerType q = p.Append(name, allocator_);
+ out.count = v->Size();
+ out.schemas = static_cast<const Schema**>(
+ allocator_->Malloc(out.count * sizeof(const Schema*)));
+ memset(out.schemas, 0, sizeof(Schema*) * out.count);
+ for (SizeType i = 0; i < out.count; i++)
+ schemaDocument.CreateSchema(&out.schemas[i], q.Append(i, allocator_),
+ (*v)[i], document);
+ out.begin = validatorCount_;
+ validatorCount_ += out.count;
+ }
+ }
+ }
+
+#if RAPIDJSON_SCHEMA_USE_INTERNALREGEX
+ template <typename ValueType>
+ RegexType* CreatePattern(const ValueType& value) {
+ if (value.IsString()) {
+ RegexType* r = new (allocator_->Malloc(sizeof(RegexType)))
+ RegexType(value.GetString());
+ if (!r->IsValid()) {
+ r->~RegexType();
+ AllocatorType::Free(r);
+ r = 0;
+ }
+ return r;
+ }
+ return 0;
+ }
+
+ static bool IsPatternMatch(const RegexType* pattern,
+ const Ch* str,
+ SizeType) {
+ return pattern->Search(str);
+ }
+#elif RAPIDJSON_SCHEMA_USE_STDREGEX
+ template <typename ValueType>
+ RegexType* CreatePattern(const ValueType& value) {
+ if (value.IsString())
+ try {
+ return new (allocator_->Malloc(sizeof(RegexType)))
+ RegexType(value.GetString(), std::size_t(value.GetStringLength()),
+ std::regex_constants::ECMAScript);
+ } catch (const std::regex_error&) {
+ }
+ return 0;
+ }
+
+ static bool IsPatternMatch(const RegexType* pattern,
+ const Ch* str,
+ SizeType length) {
+ std::match_results<const Ch*> r;
+ return std::regex_search(str, str + length, r, *pattern);
+ }
+#else
+ template <typename ValueType>
+ RegexType* CreatePattern(const ValueType&) {
+ return 0;
+ }
+
+ static bool IsPatternMatch(const RegexType*, const Ch*, SizeType) {
+ return true;
+ }
+#endif // RAPIDJSON_SCHEMA_USE_STDREGEX
+
+ void AddType(const ValueType& type) {
+ if (type == GetNullString())
+ type_ |= 1 << kNullSchemaType;
+ else if (type == GetBooleanString())
+ type_ |= 1 << kBooleanSchemaType;
+ else if (type == GetObjectString())
+ type_ |= 1 << kObjectSchemaType;
+ else if (type == GetArrayString())
+ type_ |= 1 << kArraySchemaType;
+ else if (type == GetStringString())
+ type_ |= 1 << kStringSchemaType;
+ else if (type == GetIntegerString())
+ type_ |= 1 << kIntegerSchemaType;
+ else if (type == GetNumberString())
+ type_ |= (1 << kNumberSchemaType) | (1 << kIntegerSchemaType);
+ }
+
+ bool CreateParallelValidator(Context& context) const {
+ if (enum_ || context.arrayUniqueness)
+ context.hasher = context.factory.CreateHasher();
+
+ if (validatorCount_) {
+ RAPIDJSON_ASSERT(context.validators == 0);
+ context.validators =
+ static_cast<ISchemaValidator**>(context.factory.MallocState(
+ sizeof(ISchemaValidator*) * validatorCount_));
+ context.validatorCount = validatorCount_;
+
+ if (allOf_.schemas)
+ CreateSchemaValidators(context, allOf_);
+
+ if (anyOf_.schemas)
+ CreateSchemaValidators(context, anyOf_);
+
+ if (oneOf_.schemas)
+ CreateSchemaValidators(context, oneOf_);
+
+ if (not_)
+ context.validators[notValidatorIndex_] =
+ context.factory.CreateSchemaValidator(*not_);
+
+ if (hasSchemaDependencies_) {
+ for (SizeType i = 0; i < propertyCount_; i++)
+ if (properties_[i].dependenciesSchema)
+ context.validators[properties_[i].dependenciesValidatorIndex] =
+ context.factory.CreateSchemaValidator(
+ *properties_[i].dependenciesSchema);
+ }
+ }
+
+ return true;
+ }
+
+ void CreateSchemaValidators(Context& context,
+ const SchemaArray& schemas) const {
+ for (SizeType i = 0; i < schemas.count; i++)
+ context.validators[schemas.begin + i] =
+ context.factory.CreateSchemaValidator(*schemas.schemas[i]);
+ }
+
+ // O(n)
+ bool FindPropertyIndex(const ValueType& name, SizeType* outIndex) const {
+ SizeType len = name.GetStringLength();
+ const Ch* str = name.GetString();
+ for (SizeType index = 0; index < propertyCount_; index++)
+ if (properties_[index].name.GetStringLength() == len &&
+ (std::memcmp(properties_[index].name.GetString(), str,
+ sizeof(Ch) * len) == 0)) {
+ *outIndex = index;
+ return true;
+ }
+ return false;
+ }
+
+ bool CheckInt(Context& context, int64_t i) const {
+ if (!(type_ & ((1 << kIntegerSchemaType) | (1 << kNumberSchemaType))))
+ RAPIDJSON_INVALID_KEYWORD_RETURN(GetTypeString());
+
+ if (!minimum_.IsNull()) {
+ if (minimum_.IsInt64()) {
+ if (exclusiveMinimum_ ? i <= minimum_.GetInt64()
+ : i < minimum_.GetInt64())
+ RAPIDJSON_INVALID_KEYWORD_RETURN(GetMinimumString());
+ } else if (minimum_.IsUint64()) {
+ RAPIDJSON_INVALID_KEYWORD_RETURN(
+ GetMinimumString()); // i <= max(int64_t) < minimum.GetUint64()
+ } else if (!CheckDoubleMinimum(context, static_cast<double>(i)))
+ return false;
+ }
+
+ if (!maximum_.IsNull()) {
+ if (maximum_.IsInt64()) {
+ if (exclusiveMaximum_ ? i >= maximum_.GetInt64()
+ : i > maximum_.GetInt64())
+ RAPIDJSON_INVALID_KEYWORD_RETURN(GetMaximumString());
+ } else if (maximum_.IsUint64())
+ /* do nothing */; // i <= max(int64_t) < maximum_.GetUint64()
+ else if (!CheckDoubleMaximum(context, static_cast<double>(i)))
+ return false;
+ }
+
+ if (!multipleOf_.IsNull()) {
+ if (multipleOf_.IsUint64()) {
+ if (static_cast<uint64_t>(i >= 0 ? i : -i) % multipleOf_.GetUint64() !=
+ 0)
+ RAPIDJSON_INVALID_KEYWORD_RETURN(GetMultipleOfString());
+ } else if (!CheckDoubleMultipleOf(context, static_cast<double>(i)))
+ return false;
+ }
+
+ return true;
+ }
+
+ bool CheckUint(Context& context, uint64_t i) const {
+ if (!(type_ & ((1 << kIntegerSchemaType) | (1 << kNumberSchemaType))))
+ RAPIDJSON_INVALID_KEYWORD_RETURN(GetTypeString());
+
+ if (!minimum_.IsNull()) {
+ if (minimum_.IsUint64()) {
+ if (exclusiveMinimum_ ? i <= minimum_.GetUint64()
+ : i < minimum_.GetUint64())
+ RAPIDJSON_INVALID_KEYWORD_RETURN(GetMinimumString());
+ } else if (minimum_.IsInt64())
+ /* do nothing */; // i >= 0 > minimum.Getint64()
+ else if (!CheckDoubleMinimum(context, static_cast<double>(i)))
+ return false;
+ }
+
+ if (!maximum_.IsNull()) {
+ if (maximum_.IsUint64()) {
+ if (exclusiveMaximum_ ? i >= maximum_.GetUint64()
+ : i > maximum_.GetUint64())
+ RAPIDJSON_INVALID_KEYWORD_RETURN(GetMaximumString());
+ } else if (maximum_.IsInt64())
+ RAPIDJSON_INVALID_KEYWORD_RETURN(
+ GetMaximumString()); // i >= 0 > maximum_
+ else if (!CheckDoubleMaximum(context, static_cast<double>(i)))
+ return false;
+ }
+
+ if (!multipleOf_.IsNull()) {
+ if (multipleOf_.IsUint64()) {
+ if (i % multipleOf_.GetUint64() != 0)
+ RAPIDJSON_INVALID_KEYWORD_RETURN(GetMultipleOfString());
+ } else if (!CheckDoubleMultipleOf(context, static_cast<double>(i)))
+ return false;
+ }
+
+ return true;
+ }
+
+ bool CheckDoubleMinimum(Context& context, double d) const {
+ if (exclusiveMinimum_ ? d <= minimum_.GetDouble()
+ : d < minimum_.GetDouble())
+ RAPIDJSON_INVALID_KEYWORD_RETURN(GetMinimumString());
+ return true;
+ }
+
+ bool CheckDoubleMaximum(Context& context, double d) const {
+ if (exclusiveMaximum_ ? d >= maximum_.GetDouble()
+ : d > maximum_.GetDouble())
+ RAPIDJSON_INVALID_KEYWORD_RETURN(GetMaximumString());
+ return true;
+ }
+
+ bool CheckDoubleMultipleOf(Context& context, double d) const {
+ double a = std::abs(d), b = std::abs(multipleOf_.GetDouble());
+ double q = std::floor(a / b);
+ double r = a - q * b;
+ if (r > 0.0)
+ RAPIDJSON_INVALID_KEYWORD_RETURN(GetMultipleOfString());
+ return true;
+ }
+
+ struct Property {
+ Property()
+ : schema(),
+ dependenciesSchema(),
+ dependenciesValidatorIndex(),
+ dependencies(),
+ required(false) {}
+ ~Property() { AllocatorType::Free(dependencies); }
+ SValue name;
+ const SchemaType* schema;
+ const SchemaType* dependenciesSchema;
+ SizeType dependenciesValidatorIndex;
+ bool* dependencies;
+ bool required;
+ };
+
+ struct PatternProperty {
+ PatternProperty() : schema(), pattern() {}
+ ~PatternProperty() {
+ if (pattern) {
+ pattern->~RegexType();
+ AllocatorType::Free(pattern);
+ }
+ }
+ const SchemaType* schema;
+ RegexType* pattern;
+ };
+
+ AllocatorType* allocator_;
+ uint64_t* enum_;
+ SizeType enumCount_;
+ SchemaArray allOf_;
+ SchemaArray anyOf_;
+ SchemaArray oneOf_;
+ const SchemaType* not_;
+ unsigned type_; // bitmask of kSchemaType
+ SizeType validatorCount_;
+ SizeType notValidatorIndex_;
+
+ Property* properties_;
+ const SchemaType* additionalPropertiesSchema_;
+ PatternProperty* patternProperties_;
+ SizeType patternPropertyCount_;
+ SizeType propertyCount_;
+ SizeType minProperties_;
+ SizeType maxProperties_;
+ bool additionalProperties_;
+ bool hasDependencies_;
+ bool hasRequired_;
+ bool hasSchemaDependencies_;
+
+ const SchemaType* additionalItemsSchema_;
+ const SchemaType* itemsList_;
+ const SchemaType** itemsTuple_;
+ SizeType itemsTupleCount_;
+ SizeType minItems_;
+ SizeType maxItems_;
+ bool additionalItems_;
+ bool uniqueItems_;
+
+ RegexType* pattern_;
+ SizeType minLength_;
+ SizeType maxLength_;
+
+ SValue minimum_;
+ SValue maximum_;
+ SValue multipleOf_;
+ bool exclusiveMinimum_;
+ bool exclusiveMaximum_;
+};
+
+template <typename Stack, typename Ch>
+struct TokenHelper {
+ RAPIDJSON_FORCEINLINE static void AppendIndexToken(Stack& documentStack,
+ SizeType index) {
+ *documentStack.template Push<Ch>() = '/';
+ char buffer[21];
+ size_t length =
+ static_cast<size_t>((sizeof(SizeType) == 4 ? u32toa(index, buffer)
+ : u64toa(index, buffer)) -
+ buffer);
+ for (size_t i = 0; i < length; i++)
+ *documentStack.template Push<Ch>() = buffer[i];
+ }
+};
+
+// Partial specialized version for char to prevent buffer copying.
+template <typename Stack>
+struct TokenHelper<Stack, char> {
+ RAPIDJSON_FORCEINLINE static void AppendIndexToken(Stack& documentStack,
+ SizeType index) {
+ if (sizeof(SizeType) == 4) {
+ char* buffer = documentStack.template Push<char>(1 + 10); // '/' + uint
+ *buffer++ = '/';
+ const char* end = internal::u32toa(index, buffer);
+ documentStack.template Pop<char>(
+ static_cast<size_t>(10 - (end - buffer)));
+ } else {
+ char* buffer = documentStack.template Push<char>(1 + 20); // '/' + uint64
+ *buffer++ = '/';
+ const char* end = internal::u64toa(index, buffer);
+ documentStack.template Pop<char>(
+ static_cast<size_t>(20 - (end - buffer)));
+ }
+ }
+};
+
+} // namespace internal
+
+///////////////////////////////////////////////////////////////////////////////
+// IGenericRemoteSchemaDocumentProvider
+
+template <typename SchemaDocumentType>
+class IGenericRemoteSchemaDocumentProvider {
+ public:
+ typedef typename SchemaDocumentType::Ch Ch;
+
+ virtual ~IGenericRemoteSchemaDocumentProvider() {}
+ virtual const SchemaDocumentType* GetRemoteDocument(const Ch* uri,
+ SizeType length) = 0;
+};
+
+///////////////////////////////////////////////////////////////////////////////
+// GenericSchemaDocument
+
+//! JSON schema document.
+/*!
+ A JSON schema document is a compiled version of a JSON schema.
+ It is basically a tree of internal::Schema.
+
+ \note This is an immutable class (i.e. its instance cannot be modified after
+ construction). \tparam ValueT Type of JSON value (e.g. \c Value ), which also
+ determine the encoding. \tparam Allocator Allocator type for allocating
+ memory of this document.
+*/
+template <typename ValueT, typename Allocator = CrtAllocator>
+class GenericSchemaDocument {
+ public:
+ typedef ValueT ValueType;
+ typedef IGenericRemoteSchemaDocumentProvider<GenericSchemaDocument>
+ IRemoteSchemaDocumentProviderType;
+ typedef Allocator AllocatorType;
+ typedef typename ValueType::EncodingType EncodingType;
+ typedef typename EncodingType::Ch Ch;
+ typedef internal::Schema<GenericSchemaDocument> SchemaType;
+ typedef GenericPointer<ValueType, Allocator> PointerType;
+ friend class internal::Schema<GenericSchemaDocument>;
+ template <typename, typename, typename>
+ friend class GenericSchemaValidator;
+
+ //! Constructor.
+ /*!
+ Compile a JSON document into schema document.
+
+ \param document A JSON document as source.
+ \param remoteProvider An optional remote schema document provider for
+ resolving remote reference. Can be null. \param allocator An optional
+ allocator instance for allocating memory. Can be null.
+ */
+ explicit GenericSchemaDocument(
+ const ValueType& document,
+ IRemoteSchemaDocumentProviderType* remoteProvider = 0,
+ Allocator* allocator = 0)
+ : remoteProvider_(remoteProvider),
+ allocator_(allocator),
+ ownAllocator_(),
+ root_(),
+ schemaMap_(allocator, kInitialSchemaMapSize),
+ schemaRef_(allocator, kInitialSchemaRefSize) {
+ if (!allocator_)
+ ownAllocator_ = allocator_ = RAPIDJSON_NEW(Allocator());
+
+ // Generate root schema, it will call CreateSchema() to create sub-schemas,
+ // And call AddRefSchema() if there are $ref.
+ CreateSchemaRecursive(&root_, PointerType(), document, document);
+
+ // Resolve $ref
+ while (!schemaRef_.Empty()) {
+ SchemaRefEntry* refEntry = schemaRef_.template Pop<SchemaRefEntry>(1);
+ if (const SchemaType* s = GetSchema(refEntry->target)) {
+ if (refEntry->schema)
+ *refEntry->schema = s;
+
+ // Create entry in map if not exist
+ if (!GetSchema(refEntry->source)) {
+ new (schemaMap_.template Push<SchemaEntry>()) SchemaEntry(
+ refEntry->source, const_cast<SchemaType*>(s), false, allocator_);
+ }
+ }
+ refEntry->~SchemaRefEntry();
+ }
+
+ RAPIDJSON_ASSERT(root_ != 0);
+
+ schemaRef_.ShrinkToFit(); // Deallocate all memory for ref
+ }
+
+#if RAPIDJSON_HAS_CXX11_RVALUE_REFS
+ //! Move constructor in C++11
+ GenericSchemaDocument(GenericSchemaDocument&& rhs) RAPIDJSON_NOEXCEPT
+ : remoteProvider_(rhs.remoteProvider_),
+ allocator_(rhs.allocator_),
+ ownAllocator_(rhs.ownAllocator_),
+ root_(rhs.root_),
+ schemaMap_(std::move(rhs.schemaMap_)),
+ schemaRef_(std::move(rhs.schemaRef_)) {
+ rhs.remoteProvider_ = 0;
+ rhs.allocator_ = 0;
+ rhs.ownAllocator_ = 0;
+ }
+#endif
+
+ //! Destructor
+ ~GenericSchemaDocument() {
+ while (!schemaMap_.Empty())
+ schemaMap_.template Pop<SchemaEntry>(1)->~SchemaEntry();
+
+ RAPIDJSON_DELETE(ownAllocator_);
+ }
+
+ //! Get the root schema.
+ const SchemaType& GetRoot() const { return *root_; }
+
+ private:
+ //! Prohibit copying
+ GenericSchemaDocument(const GenericSchemaDocument&);
+ //! Prohibit assignment
+ GenericSchemaDocument& operator=(const GenericSchemaDocument&);
+
+ struct SchemaRefEntry {
+ SchemaRefEntry(const PointerType& s,
+ const PointerType& t,
+ const SchemaType** outSchema,
+ Allocator* allocator)
+ : source(s, allocator), target(t, allocator), schema(outSchema) {}
+ PointerType source;
+ PointerType target;
+ const SchemaType** schema;
+ };
+
+ struct SchemaEntry {
+ SchemaEntry(const PointerType& p,
+ SchemaType* s,
+ bool o,
+ Allocator* allocator)
+ : pointer(p, allocator), schema(s), owned(o) {}
+ ~SchemaEntry() {
+ if (owned) {
+ schema->~SchemaType();
+ Allocator::Free(schema);
+ }
+ }
+ PointerType pointer;
+ SchemaType* schema;
+ bool owned;
+ };
+
+ void CreateSchemaRecursive(const SchemaType** schema,
+ const PointerType& pointer,
+ const ValueType& v,
+ const ValueType& document) {
+ if (schema)
+ *schema = SchemaType::GetTypeless();
+
+ if (v.GetType() == kObjectType) {
+ const SchemaType* s = GetSchema(pointer);
+ if (!s)
+ CreateSchema(schema, pointer, v, document);
+
+ for (typename ValueType::ConstMemberIterator itr = v.MemberBegin();
+ itr != v.MemberEnd(); ++itr)
+ CreateSchemaRecursive(0, pointer.Append(itr->name, allocator_),
+ itr->value, document);
+ } else if (v.GetType() == kArrayType)
+ for (SizeType i = 0; i < v.Size(); i++)
+ CreateSchemaRecursive(0, pointer.Append(i, allocator_), v[i], document);
+ }
+
+ void CreateSchema(const SchemaType** schema,
+ const PointerType& pointer,
+ const ValueType& v,
+ const ValueType& document) {
+ RAPIDJSON_ASSERT(pointer.IsValid());
+ if (v.IsObject()) {
+ if (!HandleRefSchema(pointer, schema, v, document)) {
+ SchemaType* s = new (allocator_->Malloc(sizeof(SchemaType)))
+ SchemaType(this, pointer, v, document, allocator_);
+ new (schemaMap_.template Push<SchemaEntry>())
+ SchemaEntry(pointer, s, true, allocator_);
+ if (schema)
+ *schema = s;
+ }
+ }
+ }
+
+ bool HandleRefSchema(const PointerType& source,
+ const SchemaType** schema,
+ const ValueType& v,
+ const ValueType& document) {
+ static const Ch kRefString[] = {'$', 'r', 'e', 'f', '\0'};
+ static const ValueType kRefValue(kRefString, 4);
+
+ typename ValueType::ConstMemberIterator itr = v.FindMember(kRefValue);
+ if (itr == v.MemberEnd())
+ return false;
+
+ if (itr->value.IsString()) {
+ SizeType len = itr->value.GetStringLength();
+ if (len > 0) {
+ const Ch* s = itr->value.GetString();
+ SizeType i = 0;
+ while (i < len && s[i] != '#') // Find the first #
+ i++;
+
+ if (i > 0) { // Remote reference, resolve immediately
+ if (remoteProvider_) {
+ if (const GenericSchemaDocument* remoteDocument =
+ remoteProvider_->GetRemoteDocument(s, i - 1)) {
+ PointerType pointer(&s[i], len - i, allocator_);
+ if (pointer.IsValid()) {
+ if (const SchemaType* sc = remoteDocument->GetSchema(pointer)) {
+ if (schema)
+ *schema = sc;
+ return true;
+ }
+ }
+ }
+ }
+ } else if (s[i] == '#') { // Local reference, defer resolution
+ PointerType pointer(&s[i], len - i, allocator_);
+ if (pointer.IsValid()) {
+ if (const ValueType* nv = pointer.Get(document))
+ if (HandleRefSchema(source, schema, *nv, document))
+ return true;
+
+ new (schemaRef_.template Push<SchemaRefEntry>())
+ SchemaRefEntry(source, pointer, schema, allocator_);
+ return true;
+ }
+ }
+ }
+ }
+ return false;
+ }
+
+ const SchemaType* GetSchema(const PointerType& pointer) const {
+ for (const SchemaEntry* target = schemaMap_.template Bottom<SchemaEntry>();
+ target != schemaMap_.template End<SchemaEntry>(); ++target)
+ if (pointer == target->pointer)
+ return target->schema;
+ return 0;
+ }
+
+ PointerType GetPointer(const SchemaType* schema) const {
+ for (const SchemaEntry* target = schemaMap_.template Bottom<SchemaEntry>();
+ target != schemaMap_.template End<SchemaEntry>(); ++target)
+ if (schema == target->schema)
+ return target->pointer;
+ return PointerType();
+ }
+
+ static const size_t kInitialSchemaMapSize = 64;
+ static const size_t kInitialSchemaRefSize = 64;
+
+ IRemoteSchemaDocumentProviderType* remoteProvider_;
+ Allocator* allocator_;
+ Allocator* ownAllocator_;
+ const SchemaType* root_; //!< Root schema.
+ internal::Stack<Allocator> schemaMap_; // Stores created Pointer -> Schemas
+ internal::Stack<Allocator>
+ schemaRef_; // Stores Pointer from $ref and schema which holds the $ref
+};
+
+//! GenericSchemaDocument using Value type.
+typedef GenericSchemaDocument<Value> SchemaDocument;
+//! IGenericRemoteSchemaDocumentProvider using SchemaDocument.
+typedef IGenericRemoteSchemaDocumentProvider<SchemaDocument>
+ IRemoteSchemaDocumentProvider;
+
+///////////////////////////////////////////////////////////////////////////////
+// GenericSchemaValidator
+
+//! JSON Schema Validator.
+/*!
+ A SAX style JSON schema validator.
+ It uses a \c GenericSchemaDocument to validate SAX events.
+ It delegates the incoming SAX events to an output handler.
+ The default output handler does nothing.
+ It can be reused multiple times by calling \c Reset().
+
+ \tparam SchemaDocumentType Type of schema document.
+ \tparam OutputHandler Type of output handler. Default handler does nothing.
+ \tparam StateAllocator Allocator for storing the internal validation states.
+*/
+template <typename SchemaDocumentType,
+ typename OutputHandler = BaseReaderHandler<
+ typename SchemaDocumentType::SchemaType::EncodingType>,
+ typename StateAllocator = CrtAllocator>
+class GenericSchemaValidator : public internal::ISchemaStateFactory<
+ typename SchemaDocumentType::SchemaType>,
+ public internal::ISchemaValidator {
+ public:
+ typedef typename SchemaDocumentType::SchemaType SchemaType;
+ typedef typename SchemaDocumentType::PointerType PointerType;
+ typedef typename SchemaType::EncodingType EncodingType;
+ typedef typename EncodingType::Ch Ch;
+
+ //! Constructor without output handler.
+ /*!
+ \param schemaDocument The schema document to conform to.
+ \param allocator Optional allocator for storing internal validation
+ states. \param schemaStackCapacity Optional initial capacity of schema path
+ stack. \param documentStackCapacity Optional initial capacity of document
+ path stack.
+ */
+ GenericSchemaValidator(
+ const SchemaDocumentType& schemaDocument,
+ StateAllocator* allocator = 0,
+ size_t schemaStackCapacity = kDefaultSchemaStackCapacity,
+ size_t documentStackCapacity = kDefaultDocumentStackCapacity)
+ : schemaDocument_(&schemaDocument),
+ root_(schemaDocument.GetRoot()),
+ outputHandler_(GetNullHandler()),
+ stateAllocator_(allocator),
+ ownStateAllocator_(0),
+ schemaStack_(allocator, schemaStackCapacity),
+ documentStack_(allocator, documentStackCapacity),
+ valid_(true)
+#if RAPIDJSON_SCHEMA_VERBOSE
+ ,
+ depth_(0)
+#endif
+ {
+ }
+
+ //! Constructor with output handler.
+ /*!
+ \param schemaDocument The schema document to conform to.
+ \param allocator Optional allocator for storing internal validation
+ states. \param schemaStackCapacity Optional initial capacity of schema path
+ stack. \param documentStackCapacity Optional initial capacity of document
+ path stack.
+ */
+ GenericSchemaValidator(
+ const SchemaDocumentType& schemaDocument,
+ OutputHandler& outputHandler,
+ StateAllocator* allocator = 0,
+ size_t schemaStackCapacity = kDefaultSchemaStackCapacity,
+ size_t documentStackCapacity = kDefaultDocumentStackCapacity)
+ : schemaDocument_(&schemaDocument),
+ root_(schemaDocument.GetRoot()),
+ outputHandler_(outputHandler),
+ stateAllocator_(allocator),
+ ownStateAllocator_(0),
+ schemaStack_(allocator, schemaStackCapacity),
+ documentStack_(allocator, documentStackCapacity),
+ valid_(true)
+#if RAPIDJSON_SCHEMA_VERBOSE
+ ,
+ depth_(0)
+#endif
+ {
+ }
+
+ //! Destructor.
+ ~GenericSchemaValidator() {
+ Reset();
+ RAPIDJSON_DELETE(ownStateAllocator_);
+ }
+
+ //! Reset the internal states.
+ void Reset() {
+ while (!schemaStack_.Empty())
+ PopSchema();
+ documentStack_.Clear();
+ valid_ = true;
+ }
+
+ //! Checks whether the current state is valid.
+ // Implementation of ISchemaValidator
+ virtual bool IsValid() const { return valid_; }
+
+ //! Gets the JSON pointer pointed to the invalid schema.
+ PointerType GetInvalidSchemaPointer() const {
+ return schemaStack_.Empty() ? PointerType()
+ : schemaDocument_->GetPointer(&CurrentSchema());
+ }
+
+ //! Gets the keyword of invalid schema.
+ const Ch* GetInvalidSchemaKeyword() const {
+ return schemaStack_.Empty() ? 0 : CurrentContext().invalidKeyword;
+ }
+
+ //! Gets the JSON pointer pointed to the invalid value.
+ PointerType GetInvalidDocumentPointer() const {
+ return documentStack_.Empty()
+ ? PointerType()
+ : PointerType(documentStack_.template Bottom<Ch>(),
+ documentStack_.GetSize() / sizeof(Ch));
+ }
+
+#if RAPIDJSON_SCHEMA_VERBOSE
+#define RAPIDJSON_SCHEMA_HANDLE_BEGIN_VERBOSE_() \
+ RAPIDJSON_MULTILINEMACRO_BEGIN \
+ *documentStack_.template Push<Ch>() = '\0'; \
+ documentStack_.template Pop<Ch>(1); \
+ internal::PrintInvalidDocument(documentStack_.template Bottom<Ch>()); \
+ RAPIDJSON_MULTILINEMACRO_END
+#else
+#define RAPIDJSON_SCHEMA_HANDLE_BEGIN_VERBOSE_()
+#endif
+
+#define RAPIDJSON_SCHEMA_HANDLE_BEGIN_(method, arg1) \
+ if (!valid_) \
+ return false; \
+ if (!BeginValue() || !CurrentSchema().method arg1) { \
+ RAPIDJSON_SCHEMA_HANDLE_BEGIN_VERBOSE_(); \
+ return valid_ = false; \
+ }
+
+#define RAPIDJSON_SCHEMA_HANDLE_PARALLEL_(method, arg2) \
+ for (Context* context = schemaStack_.template Bottom<Context>(); \
+ context != schemaStack_.template End<Context>(); context++) { \
+ if (context->hasher) \
+ static_cast<HasherType*>(context->hasher)->method arg2; \
+ if (context->validators) \
+ for (SizeType i_ = 0; i_ < context->validatorCount; i_++) \
+ static_cast<GenericSchemaValidator*>(context->validators[i_]) \
+ ->method arg2; \
+ if (context->patternPropertiesValidators) \
+ for (SizeType i_ = 0; i_ < context->patternPropertiesValidatorCount; \
+ i_++) \
+ static_cast<GenericSchemaValidator*>( \
+ context->patternPropertiesValidators[i_]) \
+ ->method arg2; \
+ }
+
+#define RAPIDJSON_SCHEMA_HANDLE_END_(method, arg2) \
+ return valid_ = EndValue() && outputHandler_.method arg2
+
+#define RAPIDJSON_SCHEMA_HANDLE_VALUE_(method, arg1, arg2) \
+ RAPIDJSON_SCHEMA_HANDLE_BEGIN_(method, arg1); \
+ RAPIDJSON_SCHEMA_HANDLE_PARALLEL_(method, arg2); \
+ RAPIDJSON_SCHEMA_HANDLE_END_(method, arg2)
+
+ bool Null() { RAPIDJSON_SCHEMA_HANDLE_VALUE_(Null, (CurrentContext()), ()); }
+ bool Bool(bool b) {
+ RAPIDJSON_SCHEMA_HANDLE_VALUE_(Bool, (CurrentContext(), b), (b));
+ }
+ bool Int(int i) {
+ RAPIDJSON_SCHEMA_HANDLE_VALUE_(Int, (CurrentContext(), i), (i));
+ }
+ bool Uint(unsigned u) {
+ RAPIDJSON_SCHEMA_HANDLE_VALUE_(Uint, (CurrentContext(), u), (u));
+ }
+ bool Int64(int64_t i) {
+ RAPIDJSON_SCHEMA_HANDLE_VALUE_(Int64, (CurrentContext(), i), (i));
+ }
+ bool Uint64(uint64_t u) {
+ RAPIDJSON_SCHEMA_HANDLE_VALUE_(Uint64, (CurrentContext(), u), (u));
+ }
+ bool Double(double d) {
+ RAPIDJSON_SCHEMA_HANDLE_VALUE_(Double, (CurrentContext(), d), (d));
+ }
+ bool RawNumber(const Ch* str, SizeType length, bool copy) {
+ RAPIDJSON_SCHEMA_HANDLE_VALUE_(
+ String, (CurrentContext(), str, length, copy), (str, length, copy));
+ }
+ bool String(const Ch* str, SizeType length, bool copy) {
+ RAPIDJSON_SCHEMA_HANDLE_VALUE_(
+ String, (CurrentContext(), str, length, copy), (str, length, copy));
+ }
+
+ bool StartObject() {
+ RAPIDJSON_SCHEMA_HANDLE_BEGIN_(StartObject, (CurrentContext()));
+ RAPIDJSON_SCHEMA_HANDLE_PARALLEL_(StartObject, ());
+ return valid_ = outputHandler_.StartObject();
+ }
+
+ bool Key(const Ch* str, SizeType len, bool copy) {
+ if (!valid_)
+ return false;
+ AppendToken(str, len);
+ if (!CurrentSchema().Key(CurrentContext(), str, len, copy))
+ return valid_ = false;
+ RAPIDJSON_SCHEMA_HANDLE_PARALLEL_(Key, (str, len, copy));
+ return valid_ = outputHandler_.Key(str, len, copy);
+ }
+
+ bool EndObject(SizeType memberCount) {
+ if (!valid_)
+ return false;
+ RAPIDJSON_SCHEMA_HANDLE_PARALLEL_(EndObject, (memberCount));
+ if (!CurrentSchema().EndObject(CurrentContext(), memberCount))
+ return valid_ = false;
+ RAPIDJSON_SCHEMA_HANDLE_END_(EndObject, (memberCount));
+ }
+
+ bool StartArray() {
+ RAPIDJSON_SCHEMA_HANDLE_BEGIN_(StartArray, (CurrentContext()));
+ RAPIDJSON_SCHEMA_HANDLE_PARALLEL_(StartArray, ());
+ return valid_ = outputHandler_.StartArray();
+ }
+
+ bool EndArray(SizeType elementCount) {
+ if (!valid_)
+ return false;
+ RAPIDJSON_SCHEMA_HANDLE_PARALLEL_(EndArray, (elementCount));
+ if (!CurrentSchema().EndArray(CurrentContext(), elementCount))
+ return valid_ = false;
+ RAPIDJSON_SCHEMA_HANDLE_END_(EndArray, (elementCount));
+ }
+
+#undef RAPIDJSON_SCHEMA_HANDLE_BEGIN_VERBOSE_
+#undef RAPIDJSON_SCHEMA_HANDLE_BEGIN_
+#undef RAPIDJSON_SCHEMA_HANDLE_PARALLEL_
+#undef RAPIDJSON_SCHEMA_HANDLE_VALUE_
+
+ // Implementation of ISchemaStateFactory<SchemaType>
+ virtual ISchemaValidator* CreateSchemaValidator(const SchemaType& root) {
+ return new (GetStateAllocator().Malloc(sizeof(GenericSchemaValidator)))
+ GenericSchemaValidator(*schemaDocument_, root,
+#if RAPIDJSON_SCHEMA_VERBOSE
+ depth_ + 1,
+#endif
+ &GetStateAllocator());
+ }
+
+ virtual void DestroySchemaValidator(ISchemaValidator* validator) {
+ GenericSchemaValidator* v = static_cast<GenericSchemaValidator*>(validator);
+ v->~GenericSchemaValidator();
+ StateAllocator::Free(v);
+ }
+
+ virtual void* CreateHasher() {
+ return new (GetStateAllocator().Malloc(sizeof(HasherType)))
+ HasherType(&GetStateAllocator());
+ }
+
+ virtual uint64_t GetHashCode(void* hasher) {
+ return static_cast<HasherType*>(hasher)->GetHashCode();
+ }
+
+ virtual void DestroryHasher(void* hasher) {
+ HasherType* h = static_cast<HasherType*>(hasher);
+ h->~HasherType();
+ StateAllocator::Free(h);
+ }
+
+ virtual void* MallocState(size_t size) {
+ return GetStateAllocator().Malloc(size);
+ }
+
+ virtual void FreeState(void* p) { return StateAllocator::Free(p); }
+
+ private:
+ typedef typename SchemaType::Context Context;
+ typedef GenericValue<UTF8<>, StateAllocator> HashCodeArray;
+ typedef internal::Hasher<EncodingType, StateAllocator> HasherType;
+
+ GenericSchemaValidator(
+ const SchemaDocumentType& schemaDocument,
+ const SchemaType& root,
+#if RAPIDJSON_SCHEMA_VERBOSE
+ unsigned depth,
+#endif
+ StateAllocator* allocator = 0,
+ size_t schemaStackCapacity = kDefaultSchemaStackCapacity,
+ size_t documentStackCapacity = kDefaultDocumentStackCapacity)
+ : schemaDocument_(&schemaDocument),
+ root_(root),
+ outputHandler_(GetNullHandler()),
+ stateAllocator_(allocator),
+ ownStateAllocator_(0),
+ schemaStack_(allocator, schemaStackCapacity),
+ documentStack_(allocator, documentStackCapacity),
+ valid_(true)
+#if RAPIDJSON_SCHEMA_VERBOSE
+ ,
+ depth_(depth)
+#endif
+ {
+ }
+
+ StateAllocator& GetStateAllocator() {
+ if (!stateAllocator_)
+ stateAllocator_ = ownStateAllocator_ = RAPIDJSON_NEW(StateAllocator());
+ return *stateAllocator_;
+ }
+
+ bool BeginValue() {
+ if (schemaStack_.Empty())
+ PushSchema(root_);
+ else {
+ if (CurrentContext().inArray)
+ internal::TokenHelper<internal::Stack<StateAllocator>,
+ Ch>::AppendIndexToken(documentStack_,
+ CurrentContext()
+ .arrayElementIndex);
+
+ if (!CurrentSchema().BeginValue(CurrentContext()))
+ return false;
+
+ SizeType count = CurrentContext().patternPropertiesSchemaCount;
+ const SchemaType** sa = CurrentContext().patternPropertiesSchemas;
+ typename Context::PatternValidatorType patternValidatorType =
+ CurrentContext().valuePatternValidatorType;
+ bool valueUniqueness = CurrentContext().valueUniqueness;
+ if (CurrentContext().valueSchema)
+ PushSchema(*CurrentContext().valueSchema);
+
+ if (count > 0) {
+ CurrentContext().objectPatternValidatorType = patternValidatorType;
+ ISchemaValidator**& va = CurrentContext().patternPropertiesValidators;
+ SizeType& validatorCount =
+ CurrentContext().patternPropertiesValidatorCount;
+ va = static_cast<ISchemaValidator**>(
+ MallocState(sizeof(ISchemaValidator*) * count));
+ for (SizeType i = 0; i < count; i++)
+ va[validatorCount++] = CreateSchemaValidator(*sa[i]);
+ }
+
+ CurrentContext().arrayUniqueness = valueUniqueness;
+ }
+ return true;
+ }
+
+ bool EndValue() {
+ if (!CurrentSchema().EndValue(CurrentContext()))
+ return false;
+
+#if RAPIDJSON_SCHEMA_VERBOSE
+ GenericStringBuffer<EncodingType> sb;
+ schemaDocument_->GetPointer(&CurrentSchema()).Stringify(sb);
+
+ *documentStack_.template Push<Ch>() = '\0';
+ documentStack_.template Pop<Ch>(1);
+ internal::PrintValidatorPointers(depth_, sb.GetString(),
+ documentStack_.template Bottom<Ch>());
+#endif
+
+ uint64_t h =
+ CurrentContext().arrayUniqueness
+ ? static_cast<HasherType*>(CurrentContext().hasher)->GetHashCode()
+ : 0;
+
+ PopSchema();
+
+ if (!schemaStack_.Empty()) {
+ Context& context = CurrentContext();
+ if (context.valueUniqueness) {
+ HashCodeArray* a =
+ static_cast<HashCodeArray*>(context.arrayElementHashCodes);
+ if (!a)
+ CurrentContext().arrayElementHashCodes = a =
+ new (GetStateAllocator().Malloc(sizeof(HashCodeArray)))
+ HashCodeArray(kArrayType);
+ for (typename HashCodeArray::ConstValueIterator itr = a->Begin();
+ itr != a->End(); ++itr)
+ if (itr->GetUint64() == h)
+ RAPIDJSON_INVALID_KEYWORD_RETURN(
+ SchemaType::GetUniqueItemsString());
+ a->PushBack(h, GetStateAllocator());
+ }
+ }
+
+ // Remove the last token of document pointer
+ while (!documentStack_.Empty() &&
+ *documentStack_.template Pop<Ch>(1) != '/')
+ ;
+
+ return true;
+ }
+
+ void AppendToken(const Ch* str, SizeType len) {
+ documentStack_.template Reserve<Ch>(
+ 1 +
+ len * 2); // worst case all characters are escaped as two characters
+ *documentStack_.template PushUnsafe<Ch>() = '/';
+ for (SizeType i = 0; i < len; i++) {
+ if (str[i] == '~') {
+ *documentStack_.template PushUnsafe<Ch>() = '~';
+ *documentStack_.template PushUnsafe<Ch>() = '0';
+ } else if (str[i] == '/') {
+ *documentStack_.template PushUnsafe<Ch>() = '~';
+ *documentStack_.template PushUnsafe<Ch>() = '1';
+ } else
+ *documentStack_.template PushUnsafe<Ch>() = str[i];
+ }
+ }
+
+ RAPIDJSON_FORCEINLINE void PushSchema(const SchemaType& schema) {
+ new (schemaStack_.template Push<Context>()) Context(*this, &schema);
+ }
+
+ RAPIDJSON_FORCEINLINE void PopSchema() {
+ Context* c = schemaStack_.template Pop<Context>(1);
+ if (HashCodeArray* a =
+ static_cast<HashCodeArray*>(c->arrayElementHashCodes)) {
+ a->~HashCodeArray();
+ StateAllocator::Free(a);
+ }
+ c->~Context();
+ }
+
+ const SchemaType& CurrentSchema() const {
+ return *schemaStack_.template Top<Context>()->schema;
+ }
+ Context& CurrentContext() { return *schemaStack_.template Top<Context>(); }
+ const Context& CurrentContext() const {
+ return *schemaStack_.template Top<Context>();
+ }
+
+ static OutputHandler& GetNullHandler() {
+ static OutputHandler nullHandler;
+ return nullHandler;
+ }
+
+ static const size_t kDefaultSchemaStackCapacity = 1024;
+ static const size_t kDefaultDocumentStackCapacity = 256;
+ const SchemaDocumentType* schemaDocument_;
+ const SchemaType& root_;
+ OutputHandler& outputHandler_;
+ StateAllocator* stateAllocator_;
+ StateAllocator* ownStateAllocator_;
+ internal::Stack<StateAllocator>
+ schemaStack_; //!< stack to store the current path of schema
+ //!< (BaseSchemaType *)
+ internal::Stack<StateAllocator>
+ documentStack_; //!< stack to store the current path of validating
+ //!< document (Ch)
+ bool valid_;
+#if RAPIDJSON_SCHEMA_VERBOSE
+ unsigned depth_;
+#endif
+};
+
+typedef GenericSchemaValidator<SchemaDocument> SchemaValidator;
+
+///////////////////////////////////////////////////////////////////////////////
+// SchemaValidatingReader
+
+//! A helper class for parsing with validation.
+/*!
+ This helper class is a functor, designed as a parameter of \ref
+ GenericDocument::Populate().
+
+ \tparam parseFlags Combination of \ref ParseFlag.
+ \tparam InputStream Type of input stream, implementing Stream concept.
+ \tparam SourceEncoding Encoding of the input stream.
+ \tparam SchemaDocumentType Type of schema document.
+ \tparam StackAllocator Allocator type for stack.
+*/
+template <unsigned parseFlags,
+ typename InputStream,
+ typename SourceEncoding,
+ typename SchemaDocumentType = SchemaDocument,
+ typename StackAllocator = CrtAllocator>
+class SchemaValidatingReader {
+ public:
+ typedef typename SchemaDocumentType::PointerType PointerType;
+ typedef typename InputStream::Ch Ch;
+
+ //! Constructor
+ /*!
+ \param is Input stream.
+ \param sd Schema document.
+ */
+ SchemaValidatingReader(InputStream& is, const SchemaDocumentType& sd)
+ : is_(is), sd_(sd), invalidSchemaKeyword_(), isValid_(true) {}
+
+ template <typename Handler>
+ bool operator()(Handler& handler) {
+ GenericReader<SourceEncoding, typename SchemaDocumentType::EncodingType,
+ StackAllocator>
+ reader;
+ GenericSchemaValidator<SchemaDocumentType, Handler> validator(sd_, handler);
+ parseResult_ = reader.template Parse<parseFlags>(is_, validator);
+
+ isValid_ = validator.IsValid();
+ if (isValid_) {
+ invalidSchemaPointer_ = PointerType();
+ invalidSchemaKeyword_ = 0;
+ invalidDocumentPointer_ = PointerType();
+ } else {
+ invalidSchemaPointer_ = validator.GetInvalidSchemaPointer();
+ invalidSchemaKeyword_ = validator.GetInvalidSchemaKeyword();
+ invalidDocumentPointer_ = validator.GetInvalidDocumentPointer();
+ }
+
+ return parseResult_;
+ }
+
+ const ParseResult& GetParseResult() const { return parseResult_; }
+ bool IsValid() const { return isValid_; }
+ const PointerType& GetInvalidSchemaPointer() const {
+ return invalidSchemaPointer_;
+ }
+ const Ch* GetInvalidSchemaKeyword() const { return invalidSchemaKeyword_; }
+ const PointerType& GetInvalidDocumentPointer() const {
+ return invalidDocumentPointer_;
+ }
+
+ private:
+ InputStream& is_;
+ const SchemaDocumentType& sd_;
+
+ ParseResult parseResult_;
+ PointerType invalidSchemaPointer_;
+ const Ch* invalidSchemaKeyword_;
+ PointerType invalidDocumentPointer_;
+ bool isValid_;
+};
+
+RAPIDJSON_NAMESPACE_END
+RAPIDJSON_DIAG_POP
+
+#endif // RAPIDJSON_SCHEMA_H_
diff --git a/include/rapidjson/stream.h b/third_party/rapidjson/stream.h
index fef82c25..fef82c25 100644
--- a/include/rapidjson/stream.h
+++ b/third_party/rapidjson/stream.h
diff --git a/third_party/rapidjson/stringbuffer.h b/third_party/rapidjson/stringbuffer.h
new file mode 100644
index 00000000..733dc789
--- /dev/null
+++ b/third_party/rapidjson/stringbuffer.h
@@ -0,0 +1,127 @@
+// Tencent is pleased to support the open source community by making RapidJSON
+// available.
+//
+// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All
+// rights reserved.
+//
+// Licensed under the MIT License (the "License"); you may not use this file
+// except in compliance with the License. You may obtain a copy of the License
+// at
+//
+// http://opensource.org/licenses/MIT
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+// License for the specific language governing permissions and limitations under
+// the License.
+
+#ifndef RAPIDJSON_STRINGBUFFER_H_
+#define RAPIDJSON_STRINGBUFFER_H_
+
+#include "rapidjson/internal/stack.h"
+#include "stream.h"
+
+#if RAPIDJSON_HAS_CXX11_RVALUE_REFS
+#include <utility> // std::move
+#endif
+
+#include "rapidjson/internal/stack.h"
+
+#if defined(__clang__)
+RAPIDJSON_DIAG_PUSH
+RAPIDJSON_DIAG_OFF(c++ 98 - compat)
+#endif
+
+RAPIDJSON_NAMESPACE_BEGIN
+
+//! Represents an in-memory output stream.
+/*!
+ \tparam Encoding Encoding of the stream.
+ \tparam Allocator type for allocating memory buffer.
+ \note implements Stream concept
+*/
+template <typename Encoding, typename Allocator = CrtAllocator>
+class GenericStringBuffer {
+ public:
+ typedef typename Encoding::Ch Ch;
+
+ GenericStringBuffer(Allocator* allocator = 0,
+ size_t capacity = kDefaultCapacity)
+ : stack_(allocator, capacity) {}
+
+#if RAPIDJSON_HAS_CXX11_RVALUE_REFS
+ GenericStringBuffer(GenericStringBuffer&& rhs)
+ : stack_(std::move(rhs.stack_)) {}
+ GenericStringBuffer& operator=(GenericStringBuffer&& rhs) {
+ if (&rhs != this)
+ stack_ = std::move(rhs.stack_);
+ return *this;
+ }
+#endif
+
+ void Put(Ch c) { *stack_.template Push<Ch>() = c; }
+ void PutUnsafe(Ch c) { *stack_.template PushUnsafe<Ch>() = c; }
+ void Flush() {}
+
+ void Clear() { stack_.Clear(); }
+ void ShrinkToFit() {
+ // Push and pop a null terminator. This is safe.
+ *stack_.template Push<Ch>() = '\0';
+ stack_.ShrinkToFit();
+ stack_.template Pop<Ch>(1);
+ }
+
+ void Reserve(size_t count) { stack_.template Reserve<Ch>(count); }
+ Ch* Push(size_t count) { return stack_.template Push<Ch>(count); }
+ Ch* PushUnsafe(size_t count) { return stack_.template PushUnsafe<Ch>(count); }
+ void Pop(size_t count) { stack_.template Pop<Ch>(count); }
+
+ const Ch* GetString() const {
+ // Push and pop a null terminator. This is safe.
+ *stack_.template Push<Ch>() = '\0';
+ stack_.template Pop<Ch>(1);
+
+ return stack_.template Bottom<Ch>();
+ }
+
+ size_t GetSize() const { return stack_.GetSize(); }
+
+ static const size_t kDefaultCapacity = 256;
+ mutable internal::Stack<Allocator> stack_;
+
+ private:
+ // Prohibit copy constructor & assignment operator.
+ GenericStringBuffer(const GenericStringBuffer&);
+ GenericStringBuffer& operator=(const GenericStringBuffer&);
+};
+
+//! String buffer with UTF8 encoding
+typedef GenericStringBuffer<UTF8<> > StringBuffer;
+
+template <typename Encoding, typename Allocator>
+inline void PutReserve(GenericStringBuffer<Encoding, Allocator>& stream,
+ size_t count) {
+ stream.Reserve(count);
+}
+
+template <typename Encoding, typename Allocator>
+inline void PutUnsafe(GenericStringBuffer<Encoding, Allocator>& stream,
+ typename Encoding::Ch c) {
+ stream.PutUnsafe(c);
+}
+
+//! Implement specialized version of PutN() with memset() for better
+//! performance.
+template <>
+inline void PutN(GenericStringBuffer<UTF8<> >& stream, char c, size_t n) {
+ std::memset(stream.stack_.Push<char>(n), c, n * sizeof(c));
+}
+
+RAPIDJSON_NAMESPACE_END
+
+#if defined(__clang__)
+RAPIDJSON_DIAG_POP
+#endif
+
+#endif // RAPIDJSON_STRINGBUFFER_H_
diff --git a/third_party/rapidjson/writer.h b/third_party/rapidjson/writer.h
new file mode 100644
index 00000000..a8096191
--- /dev/null
+++ b/third_party/rapidjson/writer.h
@@ -0,0 +1,715 @@
+// Tencent is pleased to support the open source community by making RapidJSON
+// available.
+//
+// Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All
+// rights reserved.
+//
+// Licensed under the MIT License (the "License"); you may not use this file
+// except in compliance with the License. You may obtain a copy of the License
+// at
+//
+// http://opensource.org/licenses/MIT
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+// License for the specific language governing permissions and limitations under
+// the License.
+
+#ifndef RAPIDJSON_WRITER_H_
+#define RAPIDJSON_WRITER_H_
+
+#include <new> // placement new
+#include "rapidjson/internal/dtoa.h"
+#include "rapidjson/internal/itoa.h"
+#include "rapidjson/internal/stack.h"
+#include "rapidjson/internal/strfunc.h"
+#include "stream.h"
+#include "stringbuffer.h"
+
+#if defined(RAPIDJSON_SIMD) && defined(_MSC_VER)
+#include <intrin.h>
+#pragma intrinsic(_BitScanForward)
+#endif
+#ifdef RAPIDJSON_SSE42
+#include <nmmintrin.h>
+#elif defined(RAPIDJSON_SSE2)
+#include <emmintrin.h>
+#endif
+
+#ifdef _MSC_VER
+RAPIDJSON_DIAG_PUSH
+RAPIDJSON_DIAG_OFF(4127) // conditional expression is constant
+#endif
+
+#ifdef __clang__
+RAPIDJSON_DIAG_PUSH
+RAPIDJSON_DIAG_OFF(padded)
+RAPIDJSON_DIAG_OFF(unreachable - code)
+#endif
+
+RAPIDJSON_NAMESPACE_BEGIN
+
+///////////////////////////////////////////////////////////////////////////////
+// WriteFlag
+
+/*! \def RAPIDJSON_WRITE_DEFAULT_FLAGS
+ \ingroup RAPIDJSON_CONFIG
+ \brief User-defined kWriteDefaultFlags definition.
+
+ User can define this as any \c WriteFlag combinations.
+*/
+#ifndef RAPIDJSON_WRITE_DEFAULT_FLAGS
+#define RAPIDJSON_WRITE_DEFAULT_FLAGS kWriteNoFlags
+#endif
+
+//! Combination of writeFlags
+enum WriteFlag {
+ kWriteNoFlags = 0, //!< No flags are set.
+ kWriteValidateEncodingFlag = 1, //!< Validate encoding of JSON strings.
+ kWriteNanAndInfFlag = 2, //!< Allow writing of Infinity, -Infinity and NaN.
+ kWriteDefaultFlags =
+ RAPIDJSON_WRITE_DEFAULT_FLAGS //!< Default write flags. Can be customized
+ //!< by defining
+ //!< RAPIDJSON_WRITE_DEFAULT_FLAGS
+};
+
+//! JSON writer
+/*! Writer implements the concept Handler.
+ It generates JSON text by events to an output os.
+
+ User may programmatically calls the functions of a writer to generate JSON
+ text.
+
+ On the other side, a writer can also be passed to objects that generates
+ events,
+
+ for example Reader::Parse() and Document::Accept().
+
+ \tparam OutputStream Type of output stream.
+ \tparam SourceEncoding Encoding of source string.
+ \tparam TargetEncoding Encoding of output stream.
+ \tparam StackAllocator Type of allocator for allocating memory of stack.
+ \note implements Handler concept
+*/
+template <typename OutputStream,
+ typename SourceEncoding = UTF8<>,
+ typename TargetEncoding = UTF8<>,
+ typename StackAllocator = CrtAllocator,
+ unsigned writeFlags = kWriteDefaultFlags>
+class Writer {
+ public:
+ typedef typename SourceEncoding::Ch Ch;
+
+ static const int kDefaultMaxDecimalPlaces = 324;
+
+ //! Constructor
+ /*! \param os Output stream.
+ \param stackAllocator User supplied allocator. If it is null, it will
+ create a private one. \param levelDepth Initial capacity of stack.
+ */
+ explicit Writer(OutputStream& os,
+ StackAllocator* stackAllocator = 0,
+ size_t levelDepth = kDefaultLevelDepth)
+ : os_(&os),
+ level_stack_(stackAllocator, levelDepth * sizeof(Level)),
+ maxDecimalPlaces_(kDefaultMaxDecimalPlaces),
+ hasRoot_(false) {}
+
+ explicit Writer(StackAllocator* allocator = 0,
+ size_t levelDepth = kDefaultLevelDepth)
+ : os_(0),
+ level_stack_(allocator, levelDepth * sizeof(Level)),
+ maxDecimalPlaces_(kDefaultMaxDecimalPlaces),
+ hasRoot_(false) {}
+
+ //! Reset the writer with a new stream.
+ /*!
+ This function reset the writer with a new stream and default settings,
+ in order to make a Writer object reusable for output multiple JSONs.
+
+ \param os New output stream.
+ \code
+ Writer<OutputStream> writer(os1);
+ writer.StartObject();
+ // ...
+ writer.EndObject();
+
+ writer.Reset(os2);
+ writer.StartObject();
+ // ...
+ writer.EndObject();
+ \endcode
+ */
+ void Reset(OutputStream& os) {
+ os_ = &os;
+ hasRoot_ = false;
+ level_stack_.Clear();
+ }
+
+ //! Checks whether the output is a complete JSON.
+ /*!
+ A complete JSON has a complete root object or array.
+ */
+ bool IsComplete() const { return hasRoot_ && level_stack_.Empty(); }
+
+ int GetMaxDecimalPlaces() const { return maxDecimalPlaces_; }
+
+ //! Sets the maximum number of decimal places for double output.
+ /*!
+ This setting truncates the output with specified number of decimal places.
+
+ For example,
+
+ \code
+ writer.SetMaxDecimalPlaces(3);
+ writer.StartArray();
+ writer.Double(0.12345); // "0.123"
+ writer.Double(0.0001); // "0.0"
+ writer.Double(1.234567890123456e30); // "1.234567890123456e30" (do not
+ truncate significand for positive exponent) writer.Double(1.23e-4); //
+ "0.0" (do truncate significand for negative exponent)
+ writer.EndArray();
+ \endcode
+
+ The default setting does not truncate any decimal places. You can restore
+ to this setting by calling \code
+ writer.SetMaxDecimalPlaces(Writer::kDefaultMaxDecimalPlaces);
+ \endcode
+ */
+ void SetMaxDecimalPlaces(int maxDecimalPlaces) {
+ maxDecimalPlaces_ = maxDecimalPlaces;
+ }
+
+ /*!@name Implementation of Handler
+ \see Handler
+ */
+ //@{
+
+ bool Null() {
+ Prefix(kNullType);
+ return EndValue(WriteNull());
+ }
+ bool Bool(bool b) {
+ Prefix(b ? kTrueType : kFalseType);
+ return EndValue(WriteBool(b));
+ }
+ bool Int(int i) {
+ Prefix(kNumberType);
+ return EndValue(WriteInt(i));
+ }
+ bool Uint(unsigned u) {
+ Prefix(kNumberType);
+ return EndValue(WriteUint(u));
+ }
+ bool Int64(int64_t i64) {
+ Prefix(kNumberType);
+ return EndValue(WriteInt64(i64));
+ }
+ bool Uint64(uint64_t u64) {
+ Prefix(kNumberType);
+ return EndValue(WriteUint64(u64));
+ }
+
+ //! Writes the given \c double value to the stream
+ /*!
+ \param d The value to be written.
+ \return Whether it is succeed.
+ */
+ bool Double(double d) {
+ Prefix(kNumberType);
+ return EndValue(WriteDouble(d));
+ }
+
+ bool RawNumber(const Ch* str, SizeType length, bool copy = false) {
+ (void)copy;
+ Prefix(kNumberType);
+ return EndValue(WriteString(str, length));
+ }
+
+ bool String(const Ch* str, SizeType length, bool copy = false) {
+ (void)copy;
+ Prefix(kStringType);
+ return EndValue(WriteString(str, length));
+ }
+
+#if RAPIDJSON_HAS_STDSTRING
+ bool String(const std::basic_string<Ch>& str) {
+ return String(str.data(), SizeType(str.size()));
+ }
+#endif
+
+ bool StartObject() {
+ Prefix(kObjectType);
+ new (level_stack_.template Push<Level>()) Level(false);
+ return WriteStartObject();
+ }
+
+ bool Key(const Ch* str, SizeType length, bool copy = false) {
+ return String(str, length, copy);
+ }
+
+ bool EndObject(SizeType memberCount = 0) {
+ (void)memberCount;
+ RAPIDJSON_ASSERT(level_stack_.GetSize() >= sizeof(Level));
+ RAPIDJSON_ASSERT(!level_stack_.template Top<Level>()->inArray);
+ level_stack_.template Pop<Level>(1);
+ return EndValue(WriteEndObject());
+ }
+
+ bool StartArray() {
+ Prefix(kArrayType);
+ new (level_stack_.template Push<Level>()) Level(true);
+ return WriteStartArray();
+ }
+
+ bool EndArray(SizeType elementCount = 0) {
+ (void)elementCount;
+ RAPIDJSON_ASSERT(level_stack_.GetSize() >= sizeof(Level));
+ RAPIDJSON_ASSERT(level_stack_.template Top<Level>()->inArray);
+ level_stack_.template Pop<Level>(1);
+ return EndValue(WriteEndArray());
+ }
+ //@}
+
+ /*! @name Convenience extensions */
+ //@{
+
+ //! Simpler but slower overload.
+ bool String(const Ch* str) { return String(str, internal::StrLen(str)); }
+ bool Key(const Ch* str) { return Key(str, internal::StrLen(str)); }
+
+ //@}
+
+ //! Write a raw JSON value.
+ /*!
+ For user to write a stringified JSON as a value.
+
+ \param json A well-formed JSON value. It should not contain null character
+ within [0, length - 1] range. \param length Length of the json. \param type
+ Type of the root of json.
+ */
+ bool RawValue(const Ch* json, size_t length, Type type) {
+ Prefix(type);
+ return EndValue(WriteRawValue(json, length));
+ }
+
+ protected:
+ //! Information for each nested level
+ struct Level {
+ Level(bool inArray_) : valueCount(0), inArray(inArray_) {}
+ size_t valueCount; //!< number of values in this level
+ bool inArray; //!< true if in array, otherwise in object
+ };
+
+ static const size_t kDefaultLevelDepth = 32;
+
+ bool WriteNull() {
+ PutReserve(*os_, 4);
+ PutUnsafe(*os_, 'n');
+ PutUnsafe(*os_, 'u');
+ PutUnsafe(*os_, 'l');
+ PutUnsafe(*os_, 'l');
+ return true;
+ }
+
+ bool WriteBool(bool b) {
+ if (b) {
+ PutReserve(*os_, 4);
+ PutUnsafe(*os_, 't');
+ PutUnsafe(*os_, 'r');
+ PutUnsafe(*os_, 'u');
+ PutUnsafe(*os_, 'e');
+ } else {
+ PutReserve(*os_, 5);
+ PutUnsafe(*os_, 'f');
+ PutUnsafe(*os_, 'a');
+ PutUnsafe(*os_, 'l');
+ PutUnsafe(*os_, 's');
+ PutUnsafe(*os_, 'e');
+ }
+ return true;
+ }
+
+ bool WriteInt(int i) {
+ char buffer[11];
+ const char* end = internal::i32toa(i, buffer);
+ PutReserve(*os_, static_cast<size_t>(end - buffer));
+ for (const char* p = buffer; p != end; ++p)
+ PutUnsafe(*os_, static_cast<typename TargetEncoding::Ch>(*p));
+ return true;
+ }
+
+ bool WriteUint(unsigned u) {
+ char buffer[10];
+ const char* end = internal::u32toa(u, buffer);
+ PutReserve(*os_, static_cast<size_t>(end - buffer));
+ for (const char* p = buffer; p != end; ++p)
+ PutUnsafe(*os_, static_cast<typename TargetEncoding::Ch>(*p));
+ return true;
+ }
+
+ bool WriteInt64(int64_t i64) {
+ char buffer[21];
+ const char* end = internal::i64toa(i64, buffer);
+ PutReserve(*os_, static_cast<size_t>(end - buffer));
+ for (const char* p = buffer; p != end; ++p)
+ PutUnsafe(*os_, static_cast<typename TargetEncoding::Ch>(*p));
+ return true;
+ }
+
+ bool WriteUint64(uint64_t u64) {
+ char buffer[20];
+ char* end = internal::u64toa(u64, buffer);
+ PutReserve(*os_, static_cast<size_t>(end - buffer));
+ for (char* p = buffer; p != end; ++p)
+ PutUnsafe(*os_, static_cast<typename TargetEncoding::Ch>(*p));
+ return true;
+ }
+
+ bool WriteDouble(double d) {
+ if (internal::Double(d).IsNanOrInf()) {
+ if (!(writeFlags & kWriteNanAndInfFlag))
+ return false;
+ if (internal::Double(d).IsNan()) {
+ PutReserve(*os_, 3);
+ PutUnsafe(*os_, 'N');
+ PutUnsafe(*os_, 'a');
+ PutUnsafe(*os_, 'N');
+ return true;
+ }
+ if (internal::Double(d).Sign()) {
+ PutReserve(*os_, 9);
+ PutUnsafe(*os_, '-');
+ } else
+ PutReserve(*os_, 8);
+ PutUnsafe(*os_, 'I');
+ PutUnsafe(*os_, 'n');
+ PutUnsafe(*os_, 'f');
+ PutUnsafe(*os_, 'i');
+ PutUnsafe(*os_, 'n');
+ PutUnsafe(*os_, 'i');
+ PutUnsafe(*os_, 't');
+ PutUnsafe(*os_, 'y');
+ return true;
+ }
+
+ char buffer[25];
+ char* end = internal::dtoa(d, buffer, maxDecimalPlaces_);
+ PutReserve(*os_, static_cast<size_t>(end - buffer));
+ for (char* p = buffer; p != end; ++p)
+ PutUnsafe(*os_, static_cast<typename TargetEncoding::Ch>(*p));
+ return true;
+ }
+
+ bool WriteString(const Ch* str, SizeType length) {
+ static const typename TargetEncoding::Ch hexDigits[16] = {
+ '0', '1', '2', '3', '4', '5', '6', '7',
+ '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'};
+ static const char escape[256] = {
+#define Z16 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+ // 0 1 2 3 4 5 6 7 8 9 A B C D E
+ // F
+ 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'b', 't',
+ 'n', 'u', 'f', 'r', 'u', 'u', // 00
+ 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u',
+ 'u', 'u', 'u', 'u', 'u', 'u', // 10
+ 0, 0, '"', 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, // 20
+ Z16, Z16, // 30~4F
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, '\\', 0, 0, 0, // 50
+ Z16, Z16, Z16, Z16, Z16, Z16, Z16, Z16, Z16, Z16 // 60~FF
+#undef Z16
+ };
+
+ if (TargetEncoding::supportUnicode)
+ PutReserve(*os_, 2 + length * 6); // "\uxxxx..."
+ else
+ PutReserve(*os_, 2 + length * 12); // "\uxxxx\uyyyy..."
+
+ PutUnsafe(*os_, '\"');
+ GenericStringStream<SourceEncoding> is(str);
+ while (ScanWriteUnescapedString(is, length)) {
+ const Ch c = is.Peek();
+ if (!TargetEncoding::supportUnicode && static_cast<unsigned>(c) >= 0x80) {
+ // Unicode escaping
+ unsigned codepoint;
+ if (RAPIDJSON_UNLIKELY(!SourceEncoding::Decode(is, &codepoint)))
+ return false;
+ PutUnsafe(*os_, '\\');
+ PutUnsafe(*os_, 'u');
+ if (codepoint <= 0xD7FF ||
+ (codepoint >= 0xE000 && codepoint <= 0xFFFF)) {
+ PutUnsafe(*os_, hexDigits[(codepoint >> 12) & 15]);
+ PutUnsafe(*os_, hexDigits[(codepoint >> 8) & 15]);
+ PutUnsafe(*os_, hexDigits[(codepoint >> 4) & 15]);
+ PutUnsafe(*os_, hexDigits[(codepoint)&15]);
+ } else {
+ RAPIDJSON_ASSERT(codepoint >= 0x010000 && codepoint <= 0x10FFFF);
+ // Surrogate pair
+ unsigned s = codepoint - 0x010000;
+ unsigned lead = (s >> 10) + 0xD800;
+ unsigned trail = (s & 0x3FF) + 0xDC00;
+ PutUnsafe(*os_, hexDigits[(lead >> 12) & 15]);
+ PutUnsafe(*os_, hexDigits[(lead >> 8) & 15]);
+ PutUnsafe(*os_, hexDigits[(lead >> 4) & 15]);
+ PutUnsafe(*os_, hexDigits[(lead)&15]);
+ PutUnsafe(*os_, '\\');
+ PutUnsafe(*os_, 'u');
+ PutUnsafe(*os_, hexDigits[(trail >> 12) & 15]);
+ PutUnsafe(*os_, hexDigits[(trail >> 8) & 15]);
+ PutUnsafe(*os_, hexDigits[(trail >> 4) & 15]);
+ PutUnsafe(*os_, hexDigits[(trail)&15]);
+ }
+ } else if ((sizeof(Ch) == 1 || static_cast<unsigned>(c) < 256) &&
+ RAPIDJSON_UNLIKELY(escape[static_cast<unsigned char>(c)])) {
+ is.Take();
+ PutUnsafe(*os_, '\\');
+ PutUnsafe(*os_, static_cast<typename TargetEncoding::Ch>(
+ escape[static_cast<unsigned char>(c)]));
+ if (escape[static_cast<unsigned char>(c)] == 'u') {
+ PutUnsafe(*os_, '0');
+ PutUnsafe(*os_, '0');
+ PutUnsafe(*os_, hexDigits[static_cast<unsigned char>(c) >> 4]);
+ PutUnsafe(*os_, hexDigits[static_cast<unsigned char>(c) & 0xF]);
+ }
+ } else if (RAPIDJSON_UNLIKELY(!(
+ writeFlags & kWriteValidateEncodingFlag
+ ? Transcoder<SourceEncoding, TargetEncoding>::Validate(
+ is, *os_)
+ : Transcoder<SourceEncoding,
+ TargetEncoding>::TranscodeUnsafe(is,
+ *os_))))
+ return false;
+ }
+ PutUnsafe(*os_, '\"');
+ return true;
+ }
+
+ bool ScanWriteUnescapedString(GenericStringStream<SourceEncoding>& is,
+ size_t length) {
+ return RAPIDJSON_LIKELY(is.Tell() < length);
+ }
+
+ bool WriteStartObject() {
+ os_->Put('{');
+ return true;
+ }
+ bool WriteEndObject() {
+ os_->Put('}');
+ return true;
+ }
+ bool WriteStartArray() {
+ os_->Put('[');
+ return true;
+ }
+ bool WriteEndArray() {
+ os_->Put(']');
+ return true;
+ }
+
+ bool WriteRawValue(const Ch* json, size_t length) {
+ PutReserve(*os_, length);
+ for (size_t i = 0; i < length; i++) {
+ RAPIDJSON_ASSERT(json[i] != '\0');
+ PutUnsafe(*os_, json[i]);
+ }
+ return true;
+ }
+
+ void Prefix(Type type) {
+ (void)type;
+ if (RAPIDJSON_LIKELY(level_stack_.GetSize() !=
+ 0)) { // this value is not at root
+ Level* level = level_stack_.template Top<Level>();
+ if (level->valueCount > 0) {
+ if (level->inArray)
+ os_->Put(','); // add comma if it is not the first element in array
+ else // in object
+ os_->Put((level->valueCount % 2 == 0) ? ',' : ':');
+ }
+ if (!level->inArray && level->valueCount % 2 == 0)
+ RAPIDJSON_ASSERT(type == kStringType); // if it's in object, then even
+ // number should be a name
+ level->valueCount++;
+ } else {
+ RAPIDJSON_ASSERT(!hasRoot_); // Should only has one and only one root.
+ hasRoot_ = true;
+ }
+ }
+
+ // Flush the value if it is the top level one.
+ bool EndValue(bool ret) {
+ if (RAPIDJSON_UNLIKELY(level_stack_.Empty())) // end of json text
+ os_->Flush();
+ return ret;
+ }
+
+ OutputStream* os_;
+ internal::Stack<StackAllocator> level_stack_;
+ int maxDecimalPlaces_;
+ bool hasRoot_;
+
+ private:
+ // Prohibit copy constructor & assignment operator.
+ Writer(const Writer&);
+ Writer& operator=(const Writer&);
+};
+
+// Full specialization for StringStream to prevent memory copying
+
+template <>
+inline bool Writer<StringBuffer>::WriteInt(int i) {
+ char* buffer = os_->Push(11);
+ const char* end = internal::i32toa(i, buffer);
+ os_->Pop(static_cast<size_t>(11 - (end - buffer)));
+ return true;
+}
+
+template <>
+inline bool Writer<StringBuffer>::WriteUint(unsigned u) {
+ char* buffer = os_->Push(10);
+ const char* end = internal::u32toa(u, buffer);
+ os_->Pop(static_cast<size_t>(10 - (end - buffer)));
+ return true;
+}
+
+template <>
+inline bool Writer<StringBuffer>::WriteInt64(int64_t i64) {
+ char* buffer = os_->Push(21);
+ const char* end = internal::i64toa(i64, buffer);
+ os_->Pop(static_cast<size_t>(21 - (end - buffer)));
+ return true;
+}
+
+template <>
+inline bool Writer<StringBuffer>::WriteUint64(uint64_t u) {
+ char* buffer = os_->Push(20);
+ const char* end = internal::u64toa(u, buffer);
+ os_->Pop(static_cast<size_t>(20 - (end - buffer)));
+ return true;
+}
+
+template <>
+inline bool Writer<StringBuffer>::WriteDouble(double d) {
+ if (internal::Double(d).IsNanOrInf()) {
+ // Note: This code path can only be reached if
+ // (RAPIDJSON_WRITE_DEFAULT_FLAGS & kWriteNanAndInfFlag).
+ if (!(kWriteDefaultFlags & kWriteNanAndInfFlag))
+ return false;
+ if (internal::Double(d).IsNan()) {
+ PutReserve(*os_, 3);
+ PutUnsafe(*os_, 'N');
+ PutUnsafe(*os_, 'a');
+ PutUnsafe(*os_, 'N');
+ return true;
+ }
+ if (internal::Double(d).Sign()) {
+ PutReserve(*os_, 9);
+ PutUnsafe(*os_, '-');
+ } else
+ PutReserve(*os_, 8);
+ PutUnsafe(*os_, 'I');
+ PutUnsafe(*os_, 'n');
+ PutUnsafe(*os_, 'f');
+ PutUnsafe(*os_, 'i');
+ PutUnsafe(*os_, 'n');
+ PutUnsafe(*os_, 'i');
+ PutUnsafe(*os_, 't');
+ PutUnsafe(*os_, 'y');
+ return true;
+ }
+
+ char* buffer = os_->Push(25);
+ char* end = internal::dtoa(d, buffer, maxDecimalPlaces_);
+ os_->Pop(static_cast<size_t>(25 - (end - buffer)));
+ return true;
+}
+
+#if defined(RAPIDJSON_SSE2) || defined(RAPIDJSON_SSE42)
+template <>
+inline bool Writer<StringBuffer>::ScanWriteUnescapedString(StringStream& is,
+ size_t length) {
+ if (length < 16)
+ return RAPIDJSON_LIKELY(is.Tell() < length);
+
+ if (!RAPIDJSON_LIKELY(is.Tell() < length))
+ return false;
+
+ const char* p = is.src_;
+ const char* end = is.head_ + length;
+ const char* nextAligned = reinterpret_cast<const char*>(
+ (reinterpret_cast<size_t>(p) + 15) & static_cast<size_t>(~15));
+ const char* endAligned = reinterpret_cast<const char*>(
+ reinterpret_cast<size_t>(end) & static_cast<size_t>(~15));
+ if (nextAligned > end)
+ return true;
+
+ while (p != nextAligned)
+ if (*p < 0x20 || *p == '\"' || *p == '\\') {
+ is.src_ = p;
+ return RAPIDJSON_LIKELY(is.Tell() < length);
+ } else
+ os_->PutUnsafe(*p++);
+
+ // The rest of string using SIMD
+ static const char dquote[16] = {'\"', '\"', '\"', '\"', '\"', '\"',
+ '\"', '\"', '\"', '\"', '\"', '\"',
+ '\"', '\"', '\"', '\"'};
+ static const char bslash[16] = {'\\', '\\', '\\', '\\', '\\', '\\',
+ '\\', '\\', '\\', '\\', '\\', '\\',
+ '\\', '\\', '\\', '\\'};
+ static const char space[16] = {0x19, 0x19, 0x19, 0x19, 0x19, 0x19,
+ 0x19, 0x19, 0x19, 0x19, 0x19, 0x19,
+ 0x19, 0x19, 0x19, 0x19};
+ const __m128i dq =
+ _mm_loadu_si128(reinterpret_cast<const __m128i*>(&dquote[0]));
+ const __m128i bs =
+ _mm_loadu_si128(reinterpret_cast<const __m128i*>(&bslash[0]));
+ const __m128i sp =
+ _mm_loadu_si128(reinterpret_cast<const __m128i*>(&space[0]));
+
+ for (; p != endAligned; p += 16) {
+ const __m128i s = _mm_load_si128(reinterpret_cast<const __m128i*>(p));
+ const __m128i t1 = _mm_cmpeq_epi8(s, dq);
+ const __m128i t2 = _mm_cmpeq_epi8(s, bs);
+ const __m128i t3 = _mm_cmpeq_epi8(_mm_max_epu8(s, sp),
+ sp); // s < 0x20 <=> max(s, 0x19) == 0x19
+ const __m128i x = _mm_or_si128(_mm_or_si128(t1, t2), t3);
+ unsigned short r = static_cast<unsigned short>(_mm_movemask_epi8(x));
+ if (RAPIDJSON_UNLIKELY(r != 0)) { // some of characters is escaped
+ SizeType len;
+#ifdef _MSC_VER // Find the index of first escaped
+ unsigned long offset;
+ _BitScanForward(&offset, r);
+ len = offset;
+#else
+ len = static_cast<SizeType>(__builtin_ffs(r) - 1);
+#endif
+ char* q = reinterpret_cast<char*>(os_->PushUnsafe(len));
+ for (size_t i = 0; i < len; i++)
+ q[i] = p[i];
+
+ p += len;
+ break;
+ }
+ _mm_storeu_si128(reinterpret_cast<__m128i*>(os_->PushUnsafe(16)), s);
+ }
+
+ is.src_ = p;
+ return RAPIDJSON_LIKELY(is.Tell() < length);
+}
+#endif // defined(RAPIDJSON_SSE2) || defined(RAPIDJSON_SSE42)
+
+RAPIDJSON_NAMESPACE_END
+
+#ifdef _MSC_VER
+RAPIDJSON_DIAG_POP
+#endif
+
+#ifdef __clang__
+RAPIDJSON_DIAG_POP
+#endif
+
+#endif // RAPIDJSON_RAPIDJSON_H_