aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--.clang-format168
-rw-r--r--.github/workflows/codeql-analysis.yml151
-rw-r--r--.github/workflows/debug.yml28
-rw-r--r--.github/workflows/release-ci.yml39
-rw-r--r--.github/workflows/release.yml47
-rw-r--r--.gitignore11
-rw-r--r--CMakeLists.txt251
-rw-r--r--include/GpgFrontend.h (renamed from include/GpgFrontend.h.in)2
-rw-r--r--include/GpgFrontendBuildInfo.h54
-rw-r--r--include/MainWindow.h415
-rw-r--r--include/gpg/GpgConstants.h43
-rw-r--r--include/gpg/GpgContext.h227
-rw-r--r--include/gpg/GpgFileOpera.h51
-rw-r--r--include/gpg/GpgGenKeyInfo.h199
-rw-r--r--include/gpg/GpgKey.h87
-rw-r--r--include/gpg/GpgKeySignature.h67
-rw-r--r--include/gpg/GpgSubKey.h64
-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
-rw-r--r--include/server/ComUtils.h79
-rwxr-xr-xinclude/ui/FileEncryptionDialog.h116
-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/KeyNewUIDDialog.h66
-rw-r--r--include/ui/keypair_details/KeyPairDetailTab.h101
-rw-r--r--include/ui/keypair_details/KeyPairSubkeyTab.h90
-rw-r--r--include/ui/keypair_details/KeyPairUIDTab.h98
-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--resource/conf/gpgfrontend.ini53
-rw-r--r--resource/gpgfrontend/usr/share/applications/gpgfrontend.desktop2
-rw-r--r--resource/gpgfrontend/usr/share/icons/hicolor/128x128/apps/GpgFrontend.pngbin0 -> 3819 bytes
-rwxr-xr-xresource/gpgfrontend/usr/share/icons/hicolor/200x200/apps/gpgfrontend-appimage-icon.pngbin5651 -> 0 bytes
-rw-r--r--resource/gpgfrontend/usr/share/icons/hicolor/256x256/apps/GpgFrontend.pngbin0 -> 9155 bytes
-rw-r--r--resource/ts/gpgfrontend_en_us.ts3854
-rw-r--r--resource/ts/gpgfrontend_es.ts3854
-rw-r--r--resource/ts/gpgfrontend_fr.ts3854
-rw-r--r--resource/ts/gpgfrontend_ru.ts3854
-rw-r--r--resource/ts/gpgfrontend_zh_cn.ts3854
-rw-r--r--src/CMakeLists.txt366
-rw-r--r--src/GpgFrontend.h.in63
-rw-r--r--src/GpgFrontendBuildInfo.h.in (renamed from include/GpgFrontendBuildInfo.h.in)4
-rw-r--r--src/MainWindow.cpp245
-rw-r--r--src/advance/UnknownSignersChecker.cpp86
-rw-r--r--src/advance/UnknownSignersChecker.h (renamed from include/advance/UnknownSignersChecker.h)33
-rw-r--r--src/gpg/CMakeLists.txt46
-rw-r--r--src/gpg/GpgConstants.cpp163
-rw-r--r--src/gpg/GpgConstants.h101
-rw-r--r--src/gpg/GpgContext.cpp127
-rw-r--r--src/gpg/GpgContext.h95
-rw-r--r--src/gpg/GpgFileOpera.cpp249
-rw-r--r--src/gpg/GpgFunctionObject.h138
-rw-r--r--src/gpg/GpgGenKeyInfo.cpp258
-rw-r--r--src/gpg/GpgGenKeyInfo.h167
-rw-r--r--src/gpg/GpgInfo.cpp4
-rw-r--r--src/gpg/GpgInfo.h (renamed from include/gpg/GpgInfo.h)22
-rw-r--r--src/gpg/GpgKey.cpp274
-rw-r--r--src/gpg/GpgKeySignature.cpp34
-rw-r--r--src/gpg/GpgModel.h71
-rw-r--r--src/gpg/GpgSubKey.cpp51
-rw-r--r--src/gpg/GpgUID.cpp38
-rw-r--r--src/gpg/function/BasicOperator.cpp206
-rw-r--r--src/gpg/function/BasicOperator.h69
-rw-r--r--src/gpg/function/GpgCommandExecutor.cpp59
-rw-r--r--src/gpg/function/GpgCommandExecutor.h52
-rw-r--r--src/gpg/function/GpgFileOpera.cpp162
-rw-r--r--src/gpg/function/GpgFileOpera.h58
-rw-r--r--src/gpg/function/GpgKeyGetter.cpp75
-rw-r--r--src/gpg/function/GpgKeyGetter.h52
-rw-r--r--src/gpg/function/GpgKeyImportExportor.cpp117
-rw-r--r--src/gpg/function/GpgKeyImportExportor.h100
-rw-r--r--src/gpg/function/GpgKeyManager.cpp88
-rw-r--r--src/gpg/function/GpgKeyManager.h58
-rw-r--r--src/gpg/function/GpgKeyOpera.cpp217
-rw-r--r--src/gpg/function/GpgKeyOpera.h54
-rw-r--r--src/gpg/function/UidOperator.cpp64
-rw-r--r--src/gpg/function/UidOperator.h76
-rw-r--r--src/gpg/gpg_context/GpgContext.cpp410
-rw-r--r--src/gpg/gpg_context/GpgContextBasicOpera.cpp315
-rw-r--r--src/gpg/gpg_context/GpgContextKeyInfo.cpp110
-rw-r--r--src/gpg/gpg_context/GpgContextKeyOpera.cpp410
-rw-r--r--src/gpg/gpg_context/GpgContextSubkeyOpera.cpp61
-rw-r--r--src/gpg/gpg_context/GpgContextUIDOpera.cpp80
-rw-r--r--src/gpg/model/GpgData.cpp74
-rw-r--r--src/gpg/model/GpgData.h54
-rw-r--r--src/gpg/model/GpgKey.cpp108
-rw-r--r--src/gpg/model/GpgKey.h162
-rw-r--r--src/gpg/model/GpgKeySignature.cpp28
-rw-r--r--src/gpg/model/GpgKeySignature.h85
-rw-r--r--src/gpg/model/GpgSubKey.cpp27
-rw-r--r--src/gpg/model/GpgSubKey.h102
-rw-r--r--src/gpg/model/GpgUID.cpp28
-rw-r--r--src/gpg/model/GpgUID.h81
-rw-r--r--src/gpg/result_analyse/DecryptResultAnalyse.cpp99
-rw-r--r--src/gpg/result_analyse/DecryptResultAnalyse.h (renamed from include/gpg/result_analyse/DecryptResultAnalyse.h)25
-rw-r--r--src/gpg/result_analyse/EncryptResultAnalyse.cpp65
-rw-r--r--src/gpg/result_analyse/EncryptResultAnalyse.h (renamed from include/gpg/result_analyse/EncryptResultAnalyse.h)21
-rw-r--r--src/gpg/result_analyse/ResultAnalyse.cpp22
-rw-r--r--src/gpg/result_analyse/ResultAnalyse.h (renamed from include/gpg/result_analyse/ResultAnalyse.h)39
-rw-r--r--src/gpg/result_analyse/SignResultAnalyse.cpp143
-rw-r--r--src/gpg/result_analyse/SignResultAnalyse.h (renamed from include/gpg/result_analyse/SignResultAnalyse.h)25
-rw-r--r--src/gpg/result_analyse/VerifyResultAnalyse.cpp291
-rw-r--r--src/gpg/result_analyse/VerifyResultAnalyse.h (renamed from include/gpg/result_analyse/VerifyResultAnalyse.h)28
-rw-r--r--src/main.cpp192
-rw-r--r--src/server/BaseAPI.cpp55
-rw-r--r--src/server/BaseAPI.h (renamed from include/server/BaseAPI.h)51
-rw-r--r--src/server/ComUtils.cpp286
-rw-r--r--src/server/ComUtils.h88
-rw-r--r--src/server/api/PubkeyGetter.cpp117
-rw-r--r--src/server/api/PubkeyGetter.h (renamed from include/server/api/PubkeyGetter.h)29
-rw-r--r--src/server/api/PubkeyUploader.cpp148
-rw-r--r--src/server/api/PubkeyUploader.h (renamed from include/server/api/PubkeyUploader.h)31
-rw-r--r--src/smtp/SmtpMime (renamed from include/smtp/SmtpMime)0
-rw-r--r--src/smtp/emailaddress.h (renamed from include/smtp/emailaddress.h)0
-rw-r--r--src/smtp/mimeattachment.h (renamed from include/smtp/mimeattachment.h)0
-rw-r--r--src/smtp/mimecontentformatter.h (renamed from include/smtp/mimecontentformatter.h)0
-rw-r--r--src/smtp/mimefile.h (renamed from include/smtp/mimefile.h)0
-rw-r--r--src/smtp/mimehtml.h (renamed from include/smtp/mimehtml.h)0
-rw-r--r--src/smtp/mimeinlinefile.h (renamed from include/smtp/mimeinlinefile.h)0
-rw-r--r--src/smtp/mimemessage.cpp426
-rw-r--r--src/smtp/mimemessage.h (renamed from include/smtp/mimemessage.h)0
-rw-r--r--src/smtp/mimemultipart.cpp51
-rw-r--r--src/smtp/mimemultipart.h (renamed from include/smtp/mimemultipart.h)0
-rw-r--r--src/smtp/mimepart.cpp155
-rw-r--r--src/smtp/mimepart.h (renamed from include/smtp/mimepart.h)0
-rw-r--r--src/smtp/mimetext.h (renamed from include/smtp/mimetext.h)0
-rw-r--r--src/smtp/quotedprintable.h (renamed from include/smtp/quotedprintable.h)0
-rw-r--r--src/smtp/smtpclient.h (renamed from include/smtp/smtpclient.h)0
-rw-r--r--src/smtp/smtpexports.h (renamed from include/smtp/smtpexports.h)20
-rw-r--r--src/ui/CMakeLists.txt9
-rwxr-xr-xsrc/ui/FileEncryptionDialog.cpp467
-rwxr-xr-xsrc/ui/FileEncryptionDialog.h114
-rw-r--r--src/ui/FindWidget.cpp241
-rw-r--r--src/ui/FindWidget.h (renamed from include/ui/FindWidget.h)55
-rw-r--r--src/ui/GpgFrontendUI.h53
-rw-r--r--src/ui/KeyImportDetailDialog.cpp264
-rw-r--r--src/ui/KeyImportDetailDialog.h (renamed from include/ui/KeyImportDetailDialog.h)48
-rwxr-xr-xsrc/ui/KeyMgmt.cpp627
-rwxr-xr-xsrc/ui/KeyMgmt.h102
-rw-r--r--src/ui/KeyServerImportDialog.cpp853
-rw-r--r--src/ui/KeyServerImportDialog.h93
-rw-r--r--src/ui/KeyUploadDialog.cpp182
-rw-r--r--src/ui/KeyUploadDialog.h (renamed from include/ui/KeyUploadDialog.h)40
-rw-r--r--src/ui/MainWindow.cpp380
-rw-r--r--src/ui/MainWindow.h437
-rwxr-xr-xsrc/ui/QuitDialog.cpp205
-rwxr-xr-xsrc/ui/QuitDialog.h (renamed from include/ui/QuitDialog.h)32
-rw-r--r--src/ui/SendMailDialog.cpp173
-rw-r--r--src/ui/ShowCopyDialog.cpp56
-rw-r--r--src/ui/ShowCopyDialog.h (renamed from include/ui/ShowCopyDialog.h)30
-rw-r--r--src/ui/SignalStation.cpp34
-rw-r--r--src/ui/SignalStation.h41
-rw-r--r--src/ui/UserInterfaceUtils.cpp171
-rw-r--r--src/ui/UserInterfaceUtils.h82
-rw-r--r--src/ui/VerifyDetailsDialog.cpp108
-rw-r--r--src/ui/VerifyDetailsDialog.h (renamed from include/ui/VerifyDetailsDialog.h)48
-rw-r--r--src/ui/WaitingDialog.cpp87
-rw-r--r--src/ui/WaitingDialog.h46
-rw-r--r--src/ui/Wizard.cpp482
-rw-r--r--src/ui/Wizard.h114
-rw-r--r--src/ui/function/FileReadThread.cpp68
-rw-r--r--src/ui/function/FileReadThread.h52
-rw-r--r--src/ui/function/VersionCheckThread.cpp77
-rw-r--r--src/ui/function/VersionCheckThread.h (renamed from include/ui/help/VersionCheckThread.h)34
-rw-r--r--src/ui/help/AboutDialog.cpp331
-rw-r--r--src/ui/help/AboutDialog.h (renamed from include/ui/help/AboutDialog.h)65
-rw-r--r--src/ui/help/VersionCheckThread.cpp75
-rw-r--r--src/ui/keygen/KeygenDialog.cpp555
-rw-r--r--src/ui/keygen/KeygenDialog.h117
-rw-r--r--src/ui/keygen/SubkeyGenerateDialog.cpp439
-rw-r--r--src/ui/keygen/SubkeyGenerateDialog.h97
-rw-r--r--src/ui/keypair_details/EditSubKeyDialog.cpp4
-rw-r--r--src/ui/keypair_details/EditSubKeyDialog.h (renamed from include/ui/keypair_details/EditSubKeyDialog.h)12
-rw-r--r--src/ui/keypair_details/KeyDetailsDialog.cpp37
-rw-r--r--src/ui/keypair_details/KeyDetailsDialog.h (renamed from include/ui/keypair_details/KeyDetailsDialog.h)27
-rw-r--r--src/ui/keypair_details/KeyNewUIDDialog.cpp147
-rw-r--r--src/ui/keypair_details/KeyNewUIDDialog.h64
-rw-r--r--src/ui/keypair_details/KeyPairDetailTab.cpp606
-rw-r--r--src/ui/keypair_details/KeyPairDetailTab.h105
-rw-r--r--src/ui/keypair_details/KeyPairSubkeyTab.cpp449
-rw-r--r--src/ui/keypair_details/KeyPairSubkeyTab.h86
-rw-r--r--src/ui/keypair_details/KeyPairUIDTab.cpp791
-rw-r--r--src/ui/keypair_details/KeyPairUIDTab.h100
-rw-r--r--src/ui/keypair_details/KeySetExpireDateDialog.cpp134
-rw-r--r--src/ui/keypair_details/KeySetExpireDateDialog.h (renamed from include/ui/keypair_details/KeySetExpireDateDialog.h)55
-rw-r--r--src/ui/keypair_details/KeyUIDSignDialog.cpp179
-rw-r--r--src/ui/keypair_details/KeyUIDSignDialog.h (renamed from include/ui/keypair_details/KeyUIDSignDialog.h)44
-rw-r--r--src/ui/main_window/MainWindowFileSlotFunction.cpp912
-rw-r--r--src/ui/main_window/MainWindowServerSlotFunction.cpp374
-rw-r--r--src/ui/main_window/MainWindowSlotFunction.cpp933
-rw-r--r--src/ui/main_window/MainWindowSlotUI.cpp280
-rw-r--r--src/ui/main_window/MainWindowUI.cpp872
-rw-r--r--src/ui/settings/GlobalSettingStation.cpp94
-rw-r--r--src/ui/settings/GlobalSettingStation.h90
-rw-r--r--src/ui/settings/SettingsAdvanced.cpp73
-rw-r--r--src/ui/settings/SettingsAdvanced.h54
-rw-r--r--src/ui/settings/SettingsAppearance.cpp352
-rw-r--r--src/ui/settings/SettingsAppearance.h61
-rw-r--r--src/ui/settings/SettingsDialog.cpp276
-rwxr-xr-xsrc/ui/settings/SettingsDialog.h86
-rw-r--r--src/ui/settings/SettingsGeneral.cpp635
-rw-r--r--src/ui/settings/SettingsGeneral.h85
-rw-r--r--src/ui/settings/SettingsKeyServer.cpp240
-rw-r--r--src/ui/settings/SettingsKeyServer.h (renamed from include/gpg/GpgUID.h)49
-rw-r--r--src/ui/settings/SettingsSendMail.cpp302
-rw-r--r--src/ui/settings/SettingsSendMail.h46
-rw-r--r--src/ui/smtp/SendMailDialog.cpp195
-rw-r--r--src/ui/smtp/SendMailDialog.h71
-rw-r--r--src/ui/widgets/EditorPage.cpp173
-rw-r--r--src/ui/widgets/EditorPage.h113
-rw-r--r--src/ui/widgets/FilePage.cpp408
-rw-r--r--src/ui/widgets/FilePage.h90
-rw-r--r--src/ui/widgets/GroupKeyList.cpp25
-rw-r--r--src/ui/widgets/GroupKeyList.h (renamed from include/ui/WaitingDialog.h)24
-rw-r--r--src/ui/widgets/HelpPage.cpp75
-rw-r--r--src/ui/widgets/HelpPage.h (renamed from include/ui/widgets/HelpPage.h)29
-rw-r--r--src/ui/widgets/InfoBoardWidget.cpp299
-rw-r--r--src/ui/widgets/InfoBoardWidget.h115
-rw-r--r--src/ui/widgets/KeyList.cpp637
-rw-r--r--src/ui/widgets/KeyList.h124
-rw-r--r--src/ui/widgets/SignersPicker.cpp60
-rw-r--r--src/ui/widgets/SignersPicker.h (renamed from include/ui/widgets/SignersPicker.h)24
-rw-r--r--src/ui/widgets/TextEdit.cpp270
-rw-r--r--src/ui/widgets/TextEdit.h282
-rw-r--r--src/ui/widgets/VerifyKeyDetailBox.cpp332
-rw-r--r--src/ui/widgets/VerifyKeyDetailBox.h (renamed from include/ui/widgets/VerifyKeyDetailBox.h)34
-rw-r--r--test/CMakeLists.txt20
-rw-r--r--test/GpgCoreTestBasicOpera.cpp174
-rw-r--r--test/GpgCoreTestImportExport.cpp34
-rw-r--r--test/GpgCoreTestKeyModel.cpp169
-rw-r--r--test/GpgFrontendTest.h129
-rw-r--r--test/conf/core.cfg24
-rw-r--r--test/data/pv1.key82
-rw-r--r--test/data/pv2.key41
-rw-r--r--test/data/pv3.key106
-rw-r--r--test/data/pv4.key82
-rw-r--r--third_party/CMakeLists.txt4
-rw-r--r--third_party/easyloggingpp/CMakeLists.txt4
-rw-r--r--third_party/easyloggingpp/easylogging++.cc3526
-rw-r--r--third_party/easyloggingpp/easylogging++.h4576
-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
298 files changed, 39488 insertions, 45060 deletions
diff --git a/.clang-format b/.clang-format
new file mode 100644
index 00000000..f2dd0de3
--- /dev/null
+++ b/.clang-format
@@ -0,0 +1,168 @@
+---
+Language: Cpp
+# BasedOnStyle: Google
+AccessModifierOffset: -1
+AlignAfterOpenBracket: Align
+AlignConsecutiveMacros: false
+AlignConsecutiveAssignments: false
+AlignConsecutiveDeclarations: false
+AlignEscapedNewlines: Left
+AlignOperands: true
+AlignTrailingComments: true
+AllowAllArgumentsOnNextLine: true
+AllowAllConstructorInitializersOnNextLine: true
+AllowAllParametersOfDeclarationOnNextLine: true
+AllowShortBlocksOnASingleLine: Never
+AllowShortCaseLabelsOnASingleLine: false
+AllowShortFunctionsOnASingleLine: All
+AllowShortLambdasOnASingleLine: All
+AllowShortIfStatementsOnASingleLine: WithoutElse
+AllowShortLoopsOnASingleLine: true
+AlwaysBreakAfterDefinitionReturnType: None
+AlwaysBreakAfterReturnType: None
+AlwaysBreakBeforeMultilineStrings: true
+AlwaysBreakTemplateDeclarations: Yes
+BinPackArguments: true
+BinPackParameters: true
+BraceWrapping:
+ AfterCaseLabel: false
+ AfterClass: false
+ AfterControlStatement: false
+ AfterEnum: false
+ AfterFunction: false
+ AfterNamespace: false
+ AfterObjCDeclaration: false
+ AfterStruct: false
+ AfterUnion: false
+ AfterExternBlock: false
+ BeforeCatch: false
+ BeforeElse: false
+ IndentBraces: false
+ SplitEmptyFunction: true
+ SplitEmptyRecord: true
+ SplitEmptyNamespace: true
+BreakBeforeBinaryOperators: None
+BreakBeforeBraces: Attach
+BreakBeforeInheritanceComma: false
+BreakInheritanceList: BeforeColon
+BreakBeforeTernaryOperators: true
+BreakConstructorInitializersBeforeComma: false
+BreakConstructorInitializers: BeforeColon
+BreakAfterJavaFieldAnnotations: false
+BreakStringLiterals: true
+ColumnLimit: 80
+CommentPragmas: '^ IWYU pragma:'
+CompactNamespaces: false
+ConstructorInitializerAllOnOneLineOrOnePerLine: true
+ConstructorInitializerIndentWidth: 4
+ContinuationIndentWidth: 4
+Cpp11BracedListStyle: true
+DeriveLineEnding: true
+DerivePointerAlignment: true
+DisableFormat: false
+ExperimentalAutoDetectBinPacking: false
+FixNamespaceComments: true
+ForEachMacros:
+ - foreach
+ - Q_FOREACH
+ - BOOST_FOREACH
+IncludeBlocks: Regroup
+IncludeCategories:
+ - Regex: '^<ext/.*\.h>'
+ Priority: 2
+ SortPriority: 0
+ - Regex: '^<.*\.h>'
+ Priority: 1
+ SortPriority: 0
+ - Regex: '^<.*'
+ Priority: 2
+ SortPriority: 0
+ - Regex: '.*'
+ Priority: 3
+ SortPriority: 0
+IncludeIsMainRegex: '([-_](test|unittest))?$'
+IncludeIsMainSourceRegex: ''
+IndentCaseLabels: true
+IndentGotoLabels: true
+IndentPPDirectives: None
+IndentWidth: 2
+IndentWrappedFunctionNames: false
+JavaScriptQuotes: Leave
+JavaScriptWrapImports: true
+KeepEmptyLinesAtTheStartOfBlocks: false
+MacroBlockBegin: ''
+MacroBlockEnd: ''
+MaxEmptyLinesToKeep: 1
+NamespaceIndentation: None
+ObjCBinPackProtocolList: Never
+ObjCBlockIndentWidth: 2
+ObjCSpaceAfterProperty: false
+ObjCSpaceBeforeProtocolList: true
+PenaltyBreakAssignment: 2
+PenaltyBreakBeforeFirstCallParameter: 1
+PenaltyBreakComment: 300
+PenaltyBreakFirstLessLess: 120
+PenaltyBreakString: 1000
+PenaltyBreakTemplateDeclaration: 10
+PenaltyExcessCharacter: 1000000
+PenaltyReturnTypeOnItsOwnLine: 200
+PointerAlignment: Left
+RawStringFormats:
+ - Language: Cpp
+ Delimiters:
+ - cc
+ - CC
+ - cpp
+ - Cpp
+ - CPP
+ - 'c++'
+ - 'C++'
+ CanonicalDelimiter: ''
+ BasedOnStyle: google
+ - Language: TextProto
+ Delimiters:
+ - pb
+ - PB
+ - proto
+ - PROTO
+ EnclosingFunctions:
+ - EqualsProto
+ - EquivToProto
+ - PARSE_PARTIAL_TEXT_PROTO
+ - PARSE_TEST_PROTO
+ - PARSE_TEXT_PROTO
+ - ParseTextOrDie
+ - ParseTextProtoOrDie
+ CanonicalDelimiter: ''
+ BasedOnStyle: google
+ReflowComments: true
+SortIncludes: true
+SortUsingDeclarations: true
+SpaceAfterCStyleCast: false
+SpaceAfterLogicalNot: false
+SpaceAfterTemplateKeyword: true
+SpaceBeforeAssignmentOperators: true
+SpaceBeforeCpp11BracedList: false
+SpaceBeforeCtorInitializerColon: true
+SpaceBeforeInheritanceColon: true
+SpaceBeforeParens: ControlStatements
+SpaceBeforeRangeBasedForLoopColon: true
+SpaceInEmptyBlock: false
+SpaceInEmptyParentheses: false
+SpacesBeforeTrailingComments: 2
+SpacesInAngles: false
+SpacesInConditionalStatement: false
+SpacesInContainerLiterals: true
+SpacesInCStyleCastParentheses: false
+SpacesInParentheses: false
+SpacesInSquareBrackets: false
+SpaceBeforeSquareBrackets: false
+Standard: Auto
+StatementMacros:
+ - Q_UNUSED
+ - QT_REQUIRE_VERSION
+TabWidth: 8
+UseCRLF: false
+UseTab: Never
+...
+
diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml
index c50377b9..31a0dfa0 100644
--- a/.github/workflows/codeql-analysis.yml
+++ b/.github/workflows/codeql-analysis.yml
@@ -19,7 +19,7 @@ on:
branches: [ main ]
schedule:
- cron: '19 14 * * 2'
-
+
env:
# Customize the CMake build type here (Release, Debug, RelWithDebInfo, etc.)
BUILD_TYPE: Debug
@@ -43,86 +43,87 @@ jobs:
# https://docs.github.com/en/free-pro-team@latest/github/finding-security-vulnerabilities-and-errors-in-your-code/configuring-code-scanning#changing-the-languages-that-are-analyzed
steps:
- - name: Checkout repository
- uses: actions/checkout@v2
-
- # Initializes the CodeQL tools for scanning.
- - name: Initialize CodeQL
- uses: github/codeql-action/init@v1
- with:
- languages: ${{ matrix.language }}
- # If you wish to specify custom queries, you can do so here or in a config file.
- # By default, queries listed here will override any specified in a config file.
- # Prefix the list here with "+" to use these queries and those in the config file.
- # queries: ./path/to/local/query, your-org/your-repo/queries@main
-
- - name: Install Dependence (Linux)
- run: |
- sudo apt-get update
- sudo apt-get -y install build-essential binutils git autoconf automake gettext texinfo
- sudo apt-get -y install gcc g++
- sudo apt-get -y install gpgsm
- - name: Cache Qt
- id: cache-qt
- uses: actions/cache@v1
- with:
- path: ../Qt
- key: ${{ runner.os }}-QtCache
-
- - name: Install Qt
- uses: jurplel/install-qt-action@v2
- with:
- cached: ${{ steps.cache-qt.outputs.cache-hit }}
+ - name: Checkout repository
+ uses: actions/checkout@v2
+
+ # Initializes the CodeQL tools for scanning.
+ - name: Initialize CodeQL
+ uses: github/codeql-action/init@v1
+ with:
+ languages: ${{ matrix.language }}
+ # If you wish to specify custom queries, you can do so here or in a config file.
+ # By default, queries listed here will override any specified in a config file.
+ # Prefix the list here with "+" to use these queries and those in the config file.
+ # queries: ./path/to/local/query, your-org/your-repo/queries@main
- - name: Build gpg-error (Linux)
- run: |
- cd ${{github.workspace}}/..
- git clone https://github.com/saturneric/libgpg-error
- cd libgpg-error
- ./autogen.sh
- ./configure --enable-maintainer-mode --enable-static=yes && make -j2
- sudo make install
- cd ${{github.workspace}}
+ - name: Install Dependence
+ run: |
+ sudo apt-get update
+ sudo apt-get -y install build-essential binutils git autoconf automake gettext texinfo
+ sudo apt-get -y install gcc g++ libconfig++-dev libboost-all-dev
+ sudo apt-get -y install gpgsm
- - name: Build assuan (Linux)
- run: |
- cd ${{github.workspace}}/..
- git clone https://github.com/saturneric/libassuan
- cd libassuan
- ./autogen.sh
- ./configure --enable-maintainer-mode --enable-static=yes && make -j2
- sudo make install
- cd ${{github.workspace}}
+ - name: Cache Qt
+ id: cache-qt
+ uses: actions/cache@v1
+ with:
+ path: ../Qt
+ key: ${{ runner.os }}-QtCache
- - name: Build GpgME (Linux)
- run: |
- cd ${{github.workspace}}/..
- git clone https://github.com/saturneric/gpgme
- cd gpgme
- ./autogen.sh
- ./configure --enable-maintainer-mode --enable-static=yes --enable-languages=cpp && make -j2
- sudo make install
- cd ${{github.workspace}}
+ - name: Install Qt
+ uses: jurplel/install-qt-action@v2
+ with:
+ cached: ${{ steps.cache-qt.outputs.cache-hit }}
- - name: Configure CMake
- # Configure CMake in a 'build' subdirectory. `CMAKE_BUILD_TYPE` is only required if you are using a single-configuration generator such as make.
- # See https://cmake.org/cmake/help/latest/variable/CMAKE_BUILD_TYPE.html?highlight=cmake_build_type
- run: cmake -B ${{github.workspace}}/build -DCMAKE_BUILD_TYPE=${{env.BUILD_TYPE}} -DEXECUTABLE_OUTPUT_PATH=${{env.EXECUTABLE_OUTPUT_PATH}}
+ - name: Build gpg-error (Linux)
+ run: |
+ cd ${{github.workspace}}/..
+ git clone https://github.com/saturneric/libgpg-error
+ cd libgpg-error
+ ./autogen.sh
+ ./configure --enable-maintainer-mode --enable-static=yes && make -j2
+ sudo make install
+ cd ${{github.workspace}}
- - name: Build GpgFrontend
- # Build your program with the given configuration
- run: cmake --build ${{github.workspace}}/build --config {{$env.BUILD_TYPE}} -- -j 2
+ - name: Build assuan (Linux)
+ run: |
+ cd ${{github.workspace}}/..
+ git clone https://github.com/saturneric/libassuan
+ cd libassuan
+ ./autogen.sh
+ ./configure --enable-maintainer-mode --enable-static=yes && make -j2
+ sudo make install
+ cd ${{github.workspace}}
- # ℹ️ Command-line programs to run using the OS shell.
- # 📚 https://git.io/JvXDl
+ - name: Build GpgME (Linux)
+ run: |
+ cd ${{github.workspace}}/..
+ git clone https://github.com/saturneric/gpgme
+ cd gpgme
+ ./autogen.sh
+ ./configure --enable-maintainer-mode --enable-static=yes --enable-languages=cpp && make -j2
+ sudo make install
+ cd ${{github.workspace}}
- # ✏️ If the Autobuild fails above, remove it and uncomment the following three lines
- # and modify them (or add more) to build your code if your project
- # uses a compiled language
+ - name: Configure CMake
+ # Configure CMake in a 'build' subdirectory. `CMAKE_BUILD_TYPE` is only required if you are using a single-configuration generator such as make.
+ # See https://cmake.org/cmake/help/latest/variable/CMAKE_BUILD_TYPE.html?highlight=cmake_build_type
+ run: cmake -B ${{github.workspace}}/build -DCMAKE_BUILD_TYPE=${{env.BUILD_TYPE}} -DEXECUTABLE_OUTPUT_PATH=${{env.EXECUTABLE_OUTPUT_PATH}}
- #- run: |
- # make bootstrap
- # make release
+ - name: Build GpgFrontend
+ # Build your program with the given configuration
+ run: cmake --build ${{github.workspace}}/build --config {{$env.BUILD_TYPE}} -- -j 2
+
+ # ℹ️ Command-line programs to run using the OS shell.
+ # 📚 https://git.io/JvXDl
+
+ # ✏️ If the Autobuild fails above, remove it and uncomment the following three lines
+ # and modify them (or add more) to build your code if your project
+ # uses a compiled language
+
+ #- run: |
+ # make bootstrap
+ # make release
- - name: Perform CodeQL Analysis
- uses: github/codeql-action/analyze@v1
+ - name: Perform CodeQL Analysis
+ uses: github/codeql-action/analyze@v1
diff --git a/.github/workflows/debug.yml b/.github/workflows/debug.yml
index 11194af0..f00a3dad 100644
--- a/.github/workflows/debug.yml
+++ b/.github/workflows/debug.yml
@@ -35,13 +35,29 @@ jobs:
run: |
sudo apt-get update
sudo apt-get -y install build-essential binutils git autoconf automake gettext texinfo
- sudo apt-get -y install gcc g++
- sudo apt-get -y install libgpgme-dev gpg
+ sudo apt-get -y install gcc g++ libconfig++-dev libboost-all-dev
+ sudo apt-get -y install gpgsm
if: matrix.os == 'ubuntu-latest'
+ - name: Codesign Configuration (macOS)
+ run: |
+ echo ${{secrets.MACOS_CERTIFICATE}} | base64 --decode > certificate.p12
+ security create-keychain -p gpgfrontend build.keychain
+ security default-keychain -s build.keychain
+ security unlock-keychain -p gpgfrontend build.keychain
+ security import certificate.p12 -k build.keychain -P ${{secrets.MAOS_CERTIFICATE_PWD}} -T /usr/bin/codesign
+ security set-key-partition-list -S apple-tool:,apple:,codesign: -s -k gpgfrontend build.keychain
+ security set-keychain-settings -lut 3600
+ if: matrix.os == 'macos-latest'
+
- name: Install Dependence (macOS)
run: |
- brew install cmake git autoconf automake qt@5 gcc texinfo gettext libgpg-error libassuan gpgme
+ brew install cmake git autoconf automake qt@5 gcc texinfo gettext libgpg-error libassuan gpgme openssl
+ brew install boost libconfig gettext
+ brew unlink gettext && brew link --force gettext
+ brew link qt@5
+ brew link gcc
+ brew link openssl --force
if: matrix.os == 'macos-latest'
- name: Cache Qt
@@ -69,7 +85,7 @@ jobs:
shell: msys2 {0}
run: |
pacman --noconfirm -S --needed mingw-w64-x86_64-gcc mingw-w64-x86_64-make mingw-w64-x86_64-cmake autoconf automake mingw-w64-x86_64-qt-creator mingw-w64-x86_64-gpgme
- pacman --noconfirm -S --needed make texinfo
+ pacman --noconfirm -S --needed make texinfo mingw-w64-x86_64-libconfig mingw-w64-x86_64-boost mingw-w64-x86_64-gnupg gettext-devel libintl msys2-runtime-devel
if: matrix.os == 'windows-latest'
- name: Build gpg-error (Linux)
@@ -111,7 +127,7 @@ jobs:
git clone https://github.com/saturneric/gpgme
cd gpgme
./autogen.sh
- ./configure --enable-maintainer-mode --enable-static=yes --enable-languages=cpp LDFLAGS="-static" && make -j2
+ ./configure --enable-maintainer-mode --enable-static=yes --disable-gpg-test --enable-languages=cpp LDFLAGS="-static" && make -j2
make install
if: matrix.os == 'windows-latest'
@@ -123,7 +139,7 @@ jobs:
- name: Build GpgFrontend
# Build your program with the given configuration
- run: cmake --build ${{github.workspace}}/build --config {{$env.BUILD_TYPE}} -- -j 2
+ run: cmake --build ${{github.workspace}}/build --config $env.BUILD_TYPE}} -- -j 2
if: matrix.os == 'ubuntu-latest' || matrix.os == 'macos-latest'
- name: Configure CMake & Build Binary(Windows)
diff --git a/.github/workflows/release-ci.yml b/.github/workflows/release-ci.yml
index 2823e056..3eabc44e 100644
--- a/.github/workflows/release-ci.yml
+++ b/.github/workflows/release-ci.yml
@@ -25,7 +25,7 @@ jobs:
build:
strategy:
matrix:
- os: [ 'ubuntu-16.04', 'macos-latest', 'windows-latest' ]
+ os: [ 'ubuntu-18.04', 'macos-latest', 'windows-latest' ]
runs-on: ${{ matrix.os }}
steps:
@@ -35,12 +35,12 @@ jobs:
run: |
sudo apt-get update
sudo apt-get -y install build-essential binutils git autoconf automake gettext texinfo
- sudo apt-get -y install gcc g++
+ sudo apt-get -y install gcc g++ libconfig++-dev libboost-all-dev
sudo apt-get -y install gpgsm libxcb-xinerama0 libxcb-icccm4-dev libcups2-dev libdrm-dev libegl1-mesa-dev
sudo apt-get -y install libgcrypt11-dev libnss3-dev libpci-dev libpulse-dev libudev-dev libxtst-dev gyp ninja-build
sudo apt-get -y install libglu1-mesa-dev libfontconfig1-dev libx11-xcb-dev libicu-dev libxcb-image0
sudo apt-get -y install libglu1-mesa-dev libfontconfig1-dev libx11-xcb-dev libicu-dev libxcb-*
- if: matrix.os == 'ubuntu-16.04'
+ if: matrix.os == 'ubuntu-18.04'
- name: Codesign Configuration (macOS)
run: |
@@ -50,11 +50,14 @@ jobs:
security unlock-keychain -p gpgfrontend build.keychain
security import certificate.p12 -k build.keychain -P ${{secrets.MAOS_CERTIFICATE_PWD}} -T /usr/bin/codesign
security set-key-partition-list -S apple-tool:,apple:,codesign: -s -k gpgfrontend build.keychain
+ security set-keychain-settings -lut 3600
if: matrix.os == 'macos-latest'
-
+
- name: Install Dependence (macOS)
run: |
- brew install cmake git autoconf automake qt@5 gcc texinfo gettext libgpg-error libassuan gpgme openssl
+ brew install cmake git autoconf automake qt@5 gcc texinfo gettext libgpg-error libassuan gpgme openssl
+ brew install boost libconfig gettext
+ brew unlink gettext && brew link --force gettext
brew link qt@5
brew link gcc
brew link openssl --force
@@ -66,13 +69,13 @@ jobs:
with:
path: ../Qt
key: ${{ runner.os }}-QtCache
- if: matrix.os == 'ubuntu-16.04'
+ if: matrix.os == 'ubuntu-18.04'
- name: Install Qt
uses: jurplel/install-qt-action@v2
with:
cached: ${{ steps.cache-qt.outputs.cache-hit }}
- if: matrix.os == 'ubuntu-16.04'
+ if: matrix.os == 'ubuntu-18.04'
- name: Set up MinGW (Windows)
uses: msys2/setup-msys2@v2
@@ -85,7 +88,7 @@ jobs:
shell: msys2 {0}
run: |
pacman --noconfirm -S --needed mingw-w64-x86_64-gcc mingw-w64-x86_64-make mingw-w64-x86_64-cmake autoconf automake mingw-w64-x86_64-qt-creator mingw-w64-x86_64-gpgme
- pacman --noconfirm -S --needed make texinfo
+ pacman --noconfirm -S --needed make texinfo mingw-w64-x86_64-libconfig mingw-w64-x86_64-boost mingw-w64-x86_64-gnupg gettext-devel libintl msys2-runtime-devel
if: matrix.os == 'windows-latest'
- name: Build gpg-error (Linux)
@@ -97,7 +100,7 @@ jobs:
./configure --enable-maintainer-mode --enable-static=yes && make -j2
sudo make install
cd ${{github.workspace}}
- if: matrix.os == 'ubuntu-16.04'
+ if: matrix.os == 'ubuntu-18.04'
- name: Build assuan (Linux)
run: |
@@ -108,7 +111,7 @@ jobs:
./configure --enable-maintainer-mode --enable-static=yes && make -j2
sudo make install
cd ${{github.workspace}}
- if: matrix.os == 'ubuntu-16.04'
+ if: matrix.os == 'ubuntu-18.04'
- name: Build GpgME (Linux)
run: |
@@ -119,7 +122,7 @@ jobs:
./configure --enable-maintainer-mode --enable-static=yes --enable-languages=cpp && make -j2
sudo make install
cd ${{github.workspace}}
- if: matrix.os == 'ubuntu-16.04'
+ if: matrix.os == 'ubuntu-18.04'
- name: Build GpgME (Windows)
shell: msys2 {0}
@@ -127,7 +130,7 @@ jobs:
git clone https://github.com/saturneric/gpgme
cd gpgme
./autogen.sh
- ./configure --enable-maintainer-mode --enable-static=yes --enable-languages=cpp LDFLAGS="-static" && make -j2
+ ./configure --enable-maintainer-mode --enable-static=yes --disable-gpg-test --enable-languages=cpp LDFLAGS="-static" && make -j2
make install
if: matrix.os == 'windows-latest'
@@ -135,15 +138,16 @@ jobs:
# Configure CMake in a 'build' subdirectory. `CMAKE_BUILD_TYPE` is only required if you are using a single-configuration generator such as make.
# See https://cmake.org/cmake/help/latest/variable/CMAKE_BUILD_TYPE.html?highlight=cmake_build_type
run: cmake -B ${{github.workspace}}/build -DCMAKE_BUILD_TYPE=${{env.BUILD_TYPE}} -DEXECUTABLE_OUTPUT_PATH=${{env.EXECUTABLE_OUTPUT_PATH}}
- if: matrix.os == 'ubuntu-16.04' || matrix.os == 'macos-latest'
+ if: matrix.os == 'ubuntu-18.04' || matrix.os == 'macos-latest'
- name: Build GpgFrontend
# Build your program with the given configuration
run: cmake --build ${{github.workspace}}/build --config $env.BUILD_TYPE}} -- -j 2
- if: matrix.os == 'ubuntu-16.04' || matrix.os == 'macos-latest'
+ if: matrix.os == 'ubuntu-18.04' || matrix.os == 'macos-latest'
- name: Build & Sign App Bundle (macOS)
run: |
+ security -v unlock-keychain -p gpgfrontend
macdeployqt ${{github.workspace}}/build/release/GpgFrontend.app
codesign --deep --force --options=runtime -s "Developer ID Application: Yu Hu (4279AWUL3X)" ${{github.workspace}}/build/release/GpgFrontend.app -v
mkdir ${{github.workspace}}/build/tmp/
@@ -151,11 +155,12 @@ jobs:
- name: Package & Sign App Bundle (macOS)
run: |
+ security -v unlock-keychain -p gpgfrontend
hdiutil create ${{github.workspace}}/build/tmp/tmp.dmg -ov -volname "GpgFrontend" -fs HFS+ -srcfolder ${{github.workspace}}/build/release/
mkdir ${{github.workspace}}/build/artifactOut
hdiutil convert ${{github.workspace}}/build/tmp/tmp.dmg -format UDZO -o ${{github.workspace}}/build/artifactOut/GpgFrontend.dmg
codesign -s "Developer ID Application: Yu Hu (4279AWUL3X)" ${{github.workspace}}/build/artifactOut/GpgFrontend.dmg
- mv ${{github.workspace}}/build/artifactOut/GpgFrontend.dmg ${{github.workspace}}/build/artifactOut/GpgFrontend-${{steps.vars.outputs.sha_short}}-x86_64.dmg
+ mv ${{github.workspace}}/build/artifactOut/GpgFrontend.dmg ${{github.workspace}}/build/artifactOut/GpgFrontend-${{steps.vars.outputs.sha_short}}-x86_64.dmg
if: matrix.os == 'macos-latest'
- name: Notarize Release Build (macOS)
@@ -170,7 +175,7 @@ jobs:
wget -c -nv https://github.com/probonopd/linuxdeployqt/releases/download/continuous/linuxdeployqt-continuous-x86_64.AppImage
chmod u+x linuxdeployqt-continuous-x86_64.AppImage
./linuxdeployqt-continuous-x86_64.AppImage ${{github.workspace}}/build/release/gpgfrontend/usr/share/applications/*.desktop -appimage
- if: matrix.os == 'ubuntu-16.04'
+ if: matrix.os == 'ubuntu-18.04'
- name: Configure CMake & Build Binary(Windows)
shell: msys2 {0}
@@ -191,7 +196,7 @@ jobs:
with:
name: gpgfrontend-${{matrix.os}}-${{env.BUILD_TYPE}}-${{steps.vars.outputs.sha_short}}
path: ${{github.workspace}}/build/artifactOut/GpgFrontend*.AppImage*
- if: matrix.os == 'ubuntu-16.04'
+ if: matrix.os == 'ubuntu-18.04'
- name: Upload Artifact(macOS)
uses: actions/upload-artifact@master
diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml
index 31e2babb..24f323d8 100644
--- a/.github/workflows/release.yml
+++ b/.github/workflows/release.yml
@@ -25,7 +25,7 @@ jobs:
build:
strategy:
matrix:
- os: [ 'ubuntu-16.04', 'macos-latest', 'windows-latest' ]
+ os: [ 'ubuntu-18.04', 'macos-latest', 'windows-latest' ]
runs-on: ${{ matrix.os }}
steps:
@@ -35,12 +35,12 @@ jobs:
run: |
sudo apt-get update
sudo apt-get -y install build-essential binutils git autoconf automake gettext texinfo
- sudo apt-get -y install gcc g++
+ sudo apt-get -y install gcc g++ libconfig++-dev libboost-all-dev
sudo apt-get -y install gpgsm libxcb-xinerama0 libxcb-icccm4-dev libcups2-dev libdrm-dev libegl1-mesa-dev
sudo apt-get -y install libgcrypt11-dev libnss3-dev libpci-dev libpulse-dev libudev-dev libxtst-dev gyp ninja-build
sudo apt-get -y install libglu1-mesa-dev libfontconfig1-dev libx11-xcb-dev libicu-dev libxcb-image0
sudo apt-get -y install libglu1-mesa-dev libfontconfig1-dev libx11-xcb-dev libicu-dev libxcb-*
- if: matrix.os == 'ubuntu-16.04'
+ if: matrix.os == 'ubuntu-18.04'
- name: Codesign Configuration (macOS)
run: |
@@ -50,11 +50,14 @@ jobs:
security unlock-keychain -p gpgfrontend build.keychain
security import certificate.p12 -k build.keychain -P ${{secrets.MAOS_CERTIFICATE_PWD}} -T /usr/bin/codesign
security set-key-partition-list -S apple-tool:,apple:,codesign: -s -k gpgfrontend build.keychain
+ security set-keychain-settings -lut 3600
if: matrix.os == 'macos-latest'
- name: Install Dependence (macOS)
run: |
- brew install cmake git autoconf automake qt@5 gcc texinfo gettext libgpg-error libassuan gpgme openssl
+ brew install cmake git autoconf automake qt@5 gcc texinfo gettext libgpg-error libassuan gpgme openssl
+ brew install boost libconfig gettext
+ brew unlink gettext && brew link --force gettext
brew link qt@5
brew link gcc
brew link openssl --force
@@ -66,13 +69,13 @@ jobs:
with:
path: ../Qt
key: ${{ runner.os }}-QtCache
- if: matrix.os == 'ubuntu-16.04'
+ if: matrix.os == 'ubuntu-18.04'
- name: Install Qt
uses: jurplel/install-qt-action@v2
with:
cached: ${{ steps.cache-qt.outputs.cache-hit }}
- if: matrix.os == 'ubuntu-16.04'
+ if: matrix.os == 'ubuntu-18.04'
- name: Set up MinGW (Windows)
uses: msys2/setup-msys2@v2
@@ -85,7 +88,7 @@ jobs:
shell: msys2 {0}
run: |
pacman --noconfirm -S --needed mingw-w64-x86_64-gcc mingw-w64-x86_64-make mingw-w64-x86_64-cmake autoconf automake mingw-w64-x86_64-qt-creator mingw-w64-x86_64-gpgme
- pacman --noconfirm -S --needed make texinfo zip
+ pacman --noconfirm -S --needed make texinfo mingw-w64-x86_64-libconfig mingw-w64-x86_64-boost mingw-w64-x86_64-gnupg gettext-devel libintl msys2-runtime-devel
if: matrix.os == 'windows-latest'
- name: Build gpg-error (Linux)
@@ -97,7 +100,7 @@ jobs:
./configure --enable-maintainer-mode --enable-static=yes && make -j2
sudo make install
cd ${{github.workspace}}
- if: matrix.os == 'ubuntu-16.04'
+ if: matrix.os == 'ubuntu-18.04'
- name: Build assuan (Linux)
run: |
@@ -108,7 +111,7 @@ jobs:
./configure --enable-maintainer-mode --enable-static=yes && make -j2
sudo make install
cd ${{github.workspace}}
- if: matrix.os == 'ubuntu-16.04'
+ if: matrix.os == 'ubuntu-18.04'
- name: Build GpgME (Linux)
run: |
@@ -119,7 +122,7 @@ jobs:
./configure --enable-maintainer-mode --enable-static=yes --enable-languages=cpp && make -j2
sudo make install
cd ${{github.workspace}}
- if: matrix.os == 'ubuntu-16.04'
+ if: matrix.os == 'ubuntu-18.04'
- name: Build GpgME (Windows)
shell: msys2 {0}
@@ -127,7 +130,7 @@ jobs:
git clone https://github.com/saturneric/gpgme
cd gpgme
./autogen.sh
- ./configure --enable-maintainer-mode --enable-static=yes --enable-languages=cpp LDFLAGS="-static" && make -j2
+ ./configure --enable-maintainer-mode --enable-static=yes --disable-gpg-test --enable-languages=cpp LDFLAGS="-static" && make -j2
make install
if: matrix.os == 'windows-latest'
@@ -135,19 +138,16 @@ jobs:
# Configure CMake in a 'build' subdirectory. `CMAKE_BUILD_TYPE` is only required if you are using a single-configuration generator such as make.
# See https://cmake.org/cmake/help/latest/variable/CMAKE_BUILD_TYPE.html?highlight=cmake_build_type
run: cmake -B ${{github.workspace}}/build -DCMAKE_BUILD_TYPE=${{env.BUILD_TYPE}} -DEXECUTABLE_OUTPUT_PATH=${{env.EXECUTABLE_OUTPUT_PATH}}
- if: matrix.os == 'ubuntu-16.04' || matrix.os == 'macos-latest'
+ if: matrix.os == 'ubuntu-18.04' || matrix.os == 'macos-latest'
- name: Build GpgFrontend
# Build your program with the given configuration
- run: cmake --build ${{github.workspace}}/build --config {{$env.BUILD_TYPE}} -- -j 2
- if: matrix.os == 'ubuntu-16.04' || matrix.os == 'macos-latest'
-
- - name: Get Short SHA of Commit
- id: vars
- run: echo "::set-output name=sha_short::$(git rev-parse --short HEAD)"
+ run: cmake --build ${{github.workspace}}/build --config $env.BUILD_TYPE}} -- -j 2
+ if: matrix.os == 'ubuntu-18.04' || matrix.os == 'macos-latest'
- name: Build & Sign App Bundle (macOS)
run: |
+ security -v unlock-keychain -p gpgfrontend
macdeployqt ${{github.workspace}}/build/release/GpgFrontend.app
codesign --deep --force --options=runtime -s "Developer ID Application: Yu Hu (4279AWUL3X)" ${{github.workspace}}/build/release/GpgFrontend.app -v
mkdir ${{github.workspace}}/build/tmp/
@@ -155,6 +155,7 @@ jobs:
- name: Package & Sign App Bundle (macOS)
run: |
+ security -v unlock-keychain -p gpgfrontend
hdiutil create ${{github.workspace}}/build/tmp/tmp.dmg -ov -volname "GpgFrontend" -fs HFS+ -srcfolder ${{github.workspace}}/build/release/
mkdir ${{github.workspace}}/build/artifactOut
hdiutil convert ${{github.workspace}}/build/tmp/tmp.dmg -format UDZO -o ${{github.workspace}}/build/artifactOut/GpgFrontend.dmg
@@ -174,9 +175,9 @@ jobs:
wget -c -nv https://github.com/probonopd/linuxdeployqt/releases/download/continuous/linuxdeployqt-continuous-x86_64.AppImage
chmod u+x linuxdeployqt-continuous-x86_64.AppImage
./linuxdeployqt-continuous-x86_64.AppImage ${{github.workspace}}/build/release/gpgfrontend/usr/share/applications/*.desktop -appimage
- if: matrix.os == 'ubuntu-16.04'
+ if: matrix.os == 'ubuntu-18.04'
- - name: Configure CMake & Build Binary (Windows)
+ - name: Configure CMake & Build Binary(Windows)
shell: msys2 {0}
run: |
cd $(echo "/${{github.workspace}}" | sed 's/\\/\//g' | sed 's/://')
@@ -186,12 +187,16 @@ jobs:
cmake --build . --config ${{env.BUILD_TYPE}} -- -j 2
if: matrix.os == 'windows-latest'
+ - name: Get Short SHA of Commit
+ id: vars
+ run: echo "::set-output name=sha_short::$(git rev-parse --short HEAD)"
+
- name: Upload Artifact(Linux)
uses: actions/upload-artifact@master
with:
name: gpgfrontend-${{matrix.os}}-${{env.BUILD_TYPE}}-${{steps.vars.outputs.sha_short}}
path: ${{github.workspace}}/build/artifactOut/GpgFrontend*.AppImage*
- if: matrix.os == 'ubuntu-16.04'
+ if: matrix.os == 'ubuntu-18.04'
- name: Upload Artifact(macOS)
uses: actions/upload-artifact@master
diff --git a/.gitignore b/.gitignore
index 986db60c..25a5372f 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,6 +1,12 @@
# Project
-include/GpgFrontend.h
-include/GpgFrontendBuildInfo.h
+src/GpgFrontend.h
+src/GpgFrontendBuildInfo.h
+
+# gettext
+*.mo
+
+#Vscode
+.vscode/*
#CLion
.idea/*
@@ -10,7 +16,6 @@ include/GpgFrontendBuildInfo.h
# Clangd
.cache/
-test/
# C++
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 8f4db662..9cad474a 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -1,58 +1,125 @@
cmake_minimum_required(VERSION 3.16)
-project(GpgFrontend VERSION 1.3.1 LANGUAGES CXX)
+project(GpgFrontend VERSION 2.0.1 LANGUAGES CXX)
-message(STATUS "GPGFrontend Build Configuration Started CMAKE Version ${CMAKE_VERSION}")
+message(STATUS "GpgFrontend Build Configuration Started CMAKE Version ${CMAKE_VERSION}")
# C++
+#Detect Compiler
+if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang")
+ # using Clang
+ message(STATUS "Using Complier Clang")
+ set(USING_COMPILER_CLANG 1)
+elseif ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU")
+ # using GCC
+ message(STATUS "Using Complier Gcc")
+ set(USING_COMPILER_GCC 1)
+elseif ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "Intel")
+ # using Intel C++
+ message(STATUS "Using Complier Intel")
+elseif ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "MSVC")
+ # using Visual Studio C++
+ message(STATUS "Using Complier Msvc")
+endif ()
+
+# Using Standard C++-17 (Consider compatibility)
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
+set(CMAKE_CXX_EXTENSIONS OFF)
set(CMAKE_POSITION_INDEPENDENT_CODE ON)
-# Qt
-set(CMAKE_AUTOMOC ON)
-set(CMAKE_AUTORCC ON)
-set(CMAKE_AUTOUIC ON)
-
+# CMake
set(CMAKE_INCLUDE_CURRENT_DIR ON)
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()
-
-if(EXECUTABLE_OUTPUT_PATH)
+endif ()
+
+# Specify different compilation modes
+if (BUILD_CONFIG)
+ # Test Build
+ 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")
+ message(STATUS "Switch TEST_COVERAGE_BUILD")
+ set(TEST_BUILD 1)
+ if (USING_COMPILER_CLANG OR USING_COMPILER_GCC)
+ set(TEST_COVERAGE_BUILD 1)
+ set(CMAKE_CXX_OUTPUT_EXTENSION_REPLACE 1)
+ else ()
+ message(WARNING "Branch testing is disabled")
+ message(WARNING "Please use gcc or clang for branch coverage test.")
+ endif ()
+ set(AppName GpgFrontendTest)
+ # Test Build with minimum UI
+ elseif (${BUILD_CONFIG} STREQUAL "test_ui")
+ message(STATUS "Switch TEST_MINIMUM_UI_BUILD")
+ set(MINIMUM_APPLICATION_BUILD 1)
+ set(AppName GpgFrontend)
+ elseif (${BUILD_CONFIG} STREQUAL "test_all")
+ message(STATUS "Switch FULL_APPLICATION_BUILD")
+ set(FULL_APPLICATION_BUILD 1)
+ set(AppName GpgFrontend)
+ endif ()
+else ()
+ message(STATUS "Switch Default STABLE_APPLICATION_BUILD")
+ set(STABLE_APPLICATION_BUILD 1)
+ set(AppName GpgFrontend)
+endif ()
+
+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)
+ ADD_DEFINITIONS(-DRELEASE)
message(STATUS "Build Type RELEASE")
- set(CMAKE_CXX_FLAGS_RELEASE_INIT "-O2")
-else()
+ set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -O2")
+ # Release Version Build MINIMUM_APPLICATION_BUILD
+ set(FULL_APPLICATION_BUILD 0)
+ set(MINIMUM_APPLICATION_BUILD 1)
+else ()
set(BUILD_FLAG 1)
+ ADD_DEFINITIONS(-DDEBUG)
message(STATUS "Build Type DEBUG")
- set(CMAKE_CXX_FLAGS_DEBUG_INIT "-Wall")
-endif()
+ set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -g")
+ # Generate branch coverage information using 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)
+ message(STATUS "Set branch coverage test parameters for Clang")
+ set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fprofile-instr-generate -fcoverage-mapping")
+ endif ()
+ endif ()
+endif ()
+
+message(STATUS "Build Flags " ${CMAKE_CXX_FLAGS})
# Get Git Information
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
@@ -67,12 +134,10 @@ 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})
-set(AppName GpgFrontend)
string(TIMESTAMP BUILD_TIMESTAMP "%Y-%m-%d %H:%M:%S")
message(STATUS "Build Timestamp ${BUILD_TIMESTAMP}")
@@ -80,70 +145,154 @@ message(STATUS "Build Version ${BUILD_VERSION}")
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)
+ add_definitions(-DWINDOWS)
+ set(Boost_USE_STATIC_LIBS ON)
set(CMAKE_EXE_LINKER_FLAGS "-static-libgcc -static-libstdc++ -static")
include_directories(
- include
- /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")
set(OS_PLATFORM 1)
+ ADD_DEFINITIONS(-DMACOS)
set(ENV{Qt5_DIR} /usr/local/opt/qt5/lib/cmake)
include_directories(
- include
- /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)
+ ADD_DEFINITIONS(-DLINUX)
include_directories(
- include
- /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}")
-find_package(Qt5 COMPONENTS Core Test Widgets PrintSupport Network LinguistTools REQUIRED)
-
+find_package(Boost COMPONENTS date_time filesystem REQUIRED)
+
+# Basic Envirnoment Configure
+set(BASIC_ENV_CONFIG 1)
+set(QT_MOC_CONFIG 1)
+set(ESAY_LOGGING_PP 1)
+
+if (FULL_APPLICATION_BUILD)
+ message(STATUS "Build Full Application")
+ set(QT5_ENV_SUPPORT 1)
+ set(QT_MOC_CONFIG 1)
+ set(GPG_CORE 1)
+ set(UI_CORE 1)
+ set(SMTP_SUPPORT 1)
+ set(SERVER_SUPPORT 1)
+ set(ADVANCE_SUPPORT 1)
+ set(APPLICATION_BUILD 1)
+ set(BASIC_ENV_CONFIG 1)
+ # Disable Qt MULTI_LANG_SUPPORT
+ # set(MULTI_LANG_SUPPORT 1)
+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)
+ set(MULTI_LANG_SUPPORT 1)
+elseif (STABLE_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 ()
+ message(STATUS "Build Default Modules")
+ set(GPG_CORE 1)
+ endif ()
+
+endif ()
+
+if (QT5_ENV_SUPPORT)
+ # Support Qt version Both 5.12.x and 5.15.x
+ find_package(Qt5 COMPONENTS Core Test Widgets PrintSupport Network REQUIRED)
+ # find_package(Qt5 5.15.2 EXACT COMPONENTS Core Test Widgets PrintSupport Network LinguistTools REQUIRED)
+ # Qt configuration
+ set(CMAKE_AUTOMOC ON)
+ set(CMAKE_AUTORCC ON)
+ set(CMAKE_AUTOUIC ON)
+endif ()
+
+
+if (SMTP_SUPPORT)
+ add_compile_definitions(SMTP_SUPPORT)
+endif ()
+
+if (SERVER_SUPPORT)
+ add_compile_definitions(SERVER_SUPPORT)
+endif ()
+
+if (ADVANCE_SUPPORT)
+ add_compile_definitions(ADVANCE_SUPPORT)
+endif ()
+
+
+if (MULTI_LANG_SUPPORT)
+ add_compile_definitions(MULTI_LANG_SUPPORT)
+endif ()
+
+
+add_subdirectory(third_party)
add_subdirectory(src)
-
-
+if (TEST_BUILD)
+ include(CTest)
+ enable_testing()
+ add_subdirectory(test)
+endif ()
diff --git a/include/GpgFrontend.h.in b/include/GpgFrontend.h
index 6460967c..e7250d27 100644
--- a/include/GpgFrontend.h.in
+++ b/include/GpgFrontend.h
@@ -56,7 +56,7 @@
#define MACOS 1
#define LINUX 2
-#define OS_PLATFORM @OS_PLATFORM@
+#define OS_PLATFORM 1
/**
* Build Options Vars
diff --git a/include/GpgFrontendBuildInfo.h b/include/GpgFrontendBuildInfo.h
new file mode 100644
index 00000000..3f75ebd6
--- /dev/null
+++ b/include/GpgFrontendBuildInfo.h
@@ -0,0 +1,54 @@
+/**
+ * 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_BUILD_INFO_H_IN
+#define GPGFRONTEND_BUILD_INFO_H_IN
+
+/**
+ * Logic Version (*.*.*)
+ */
+#define VERSION_MAJOR 1
+#define VERSION_MINOR 3
+#define VERSION_PATCH 1
+
+/**
+ * Code Version (According to Git)
+ */
+#define GIT_BRANCH_NAME "main"
+#define GIT_COMMIT_HASH "d0146c8c640b2a7ec9a62c3c87a8f5e7c84f1fe7"
+
+/**
+ * Generated Information (According to CMake)
+ */
+#define PROJECT_NAME "GpgFrontend"
+#define BUILD_VERSION "1.3.1_Darwin-20.5.0_x86_64_Debug"
+#define GIT_VERSION "main_d0146c8c640b2a7ec9a62c3c87a8f5e7c84f1fe7"
+
+/**
+ * Build Information
+ */
+#define BUILD_FLAG 1
+#define BUILD_TIMESTAMP "2021-08-28 12:37:33"
+
+#endif // GPGFRONTEND_BUILD_INFO_H_IN
diff --git a/include/MainWindow.h b/include/MainWindow.h
deleted file mode 100644
index 176a8914..00000000
--- a/include/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;
- GpgME::GpgContext *mCtx;
- KeyMgmt *keyMgmt;
- KeyServerImportDialog *importDialog; /**< TODO */
-
- QNetworkAccessManager *networkAccessManager;
-
- bool attachmentDockCreated;
- bool restartNeeded;
-};
-
-#endif // __GPGWIN_H__
diff --git a/include/gpg/GpgConstants.h b/include/gpg/GpgConstants.h
deleted file mode 100644
index 61037170..00000000
--- a/include/gpg/GpgConstants.h
+++ /dev/null
@@ -1,43 +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 GPG_CONSTANTS_H
-#define GPG_CONSTANTS_H
-
-class QString;
-
-const int RESTART_CODE = 1000;
-
-class GpgConstants {
-public:
- static const char *PGP_CRYPT_BEGIN;
- static const char *PGP_CRYPT_END;
- static const char *PGP_SIGNED_BEGIN;
- static const char *PGP_SIGNED_END;
- static const char *PGP_SIGNATURE_BEGIN;
- static const char *PGP_SIGNATURE_END;
- static const char *GPG_FRONTEND_SHORT_CRYPTO_HEAD;
-};
-
-#endif // CONSTANTS_H
diff --git a/include/gpg/GpgContext.h b/include/gpg/GpgContext.h
deleted file mode 100644
index 75949f25..00000000
--- a/include/gpg/GpgContext.h
+++ /dev/null
@@ -1,227 +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 __SGPGMEPP_CONTEXT_H__
-#define __SGPGMEPP_CONTEXT_H__
-
-#include "GpgFrontend.h"
-
-#include "GpgConstants.h"
-#include "GpgGenKeyInfo.h"
-#include "GpgKey.h"
-#include "GpgInfo.h"
-
-using GpgKeyList = std::list<GpgKey>;
-
-class GpgImportedKey {
-public:
- QString fpr;
- int importStatus;
-};
-
-typedef std::list<GpgImportedKey> GpgImportedKeyList;
-
-class GpgImportInformation {
-public:
- GpgImportInformation() = default;
-
- int considered = 0;
- int no_user_id = 0;
- int imported = 0;
- int imported_rsa = 0;
- int unchanged = 0;
- int new_user_ids = 0;
- int new_sub_keys = 0;
- int new_signatures = 0;
- int new_revocations = 0;
- int secret_read = 0;
- int secret_imported = 0;
- int secret_unchanged = 0;
- int not_imported = 0;
- GpgImportedKeyList importedKeys;
-};
-
-namespace GpgME {
-
- /**
- * Custom Encapsulation of GpgME APIs
- */
- class GpgContext : public QObject {
- Q_OBJECT
-
- public:
-
- GpgContext();
-
- ~GpgContext() override;
-
- [[nodiscard]] bool isGood() const;
-
- GpgImportInformation importKey(QByteArray inBuffer);
-
- [[nodiscard]] const GpgKeyList &getKeys() const;
-
- bool exportKeys(QStringList *uidList, QByteArray *outBuffer);
-
- bool exportKeys(const QVector<GpgKey> &keys, QByteArray &outBuffer);
-
- gpgme_error_t generateKey(GenKeyInfo *params);
-
- gpgme_error_t generateSubkey(const GpgKey &key, GenKeyInfo *params);
-
- void deleteKeys(QStringList *uidList);
-
- gpg_error_t encrypt(QVector<GpgKey> &keys, const QByteArray &inBuffer, QByteArray *outBuffer,
- gpgme_encrypt_result_t *result);
-
- gpgme_error_t encryptSign(QVector<GpgKey> &keys, QVector<GpgKey> &signers, const QByteArray &inBuffer,
- QByteArray *outBuffer, gpgme_encrypt_result_t *encr_result,
- gpgme_sign_result_t *sign_result);
-
- gpgme_error_t decrypt(const QByteArray &inBuffer, QByteArray *outBuffer, gpgme_decrypt_result_t *result);
-
- gpgme_error_t
- decryptVerify(const QByteArray &inBuffer, QByteArray *outBuffer, gpgme_decrypt_result_t *decrypt_result,
- gpgme_verify_result_t *verify_result);
-
- void clearPasswordCache();
-
- bool exportSecretKey(const GpgKey &key, QByteArray *outBuffer);
-
- void getSigners(QVector<GpgKey> &signer, gpgme_ctx_t ctx);
-
- static void setSigners(const QVector<GpgKey> &keys, gpgme_ctx_t ctx);
-
- bool signKey(const GpgKey &target, const QVector<GpgKey> &keys, const QString &uid,
- const QDateTime *expires);
-
- bool revSign(const GpgKey &key, const GpgKeySignature &signature);
-
- gpgme_error_t verify(QByteArray *inBuffer, QByteArray *sigBuffer, gpgme_verify_result_t *result);
-
- gpg_error_t
- sign(const QVector<GpgKey> &keys, const QByteArray &inBuffer, QByteArray *outBuffer,
- gpgme_sig_mode_t mode, gpgme_sign_result_t *result = nullptr, bool default_ctx = true);
-
- bool addUID(const GpgKey &key, const GpgUID &uid);
-
- bool revUID(const GpgKey &key, const GpgUID &uid);
-
- bool setPrimaryUID(const GpgKey &key, const GpgUID &uid);
-
- bool setExpire(const GpgKey &key, const GpgSubKey *subkey, QDateTime *expires);
-
- void generateRevokeCert(const GpgKey &key, const QString &outputFileName);
-
- static bool checkIfKeyCanSign(const GpgKey &key);
-
- static bool checkIfKeyCanCert(const GpgKey &key);
-
- static bool checkIfKeyCanAuth(const GpgKey &key);
-
- static bool checkIfKeyCanEncr(const GpgKey &key);
-
-
- /**
- * @details If text contains PGP-message, put a linebreak before the message,
- * so that gpgme can decrypt correctly
- *
- * @param in Pointer to the QBytearray to check.
- */
- static void preventNoDataErr(QByteArray *in);
-
- GpgKey getKeyByFpr(const QString &fpr);
-
- GpgKey getKeyById(const QString &id);
-
- static QString gpgErrString(gpgme_error_t err);
-
- static QString getGpgmeVersion();
-
- /**
- * @brief
- *
- * @param text
- * @return \li 2, if the text is completly signed,
- * \li 1, if the text is partially signed,
- * \li 0, if the text is not signed at all.
- */
- static int textIsSigned(const QByteArray &text);
-
- static QString beautifyFingerprint(QString fingerprint);
-
- signals:
-
- void signalKeyDBChanged();
-
- void signalKeyUpdated(QString key_id);
-
- void signalKeyInfoChanged();
-
- private slots:
-
- void slotRefreshKeyList();
-
- void slotUpdateKeyList(const QString &key_id);
-
- private:
-
- GpgInfo info;
-
- gpgme_ctx_t mCtx{};
- gpgme_data_t in{};
- gpgme_error_t err;
- bool debug;
- bool good = true;
-
- QByteArray mPasswordCache;
- QSettings settings;
- GpgKeyList mKeyList;
-
- QMap<QString, GpgKey *> mKeyMap;
-
- gpgme_ctx_t create_ctx();
-
- static gpgme_error_t readToBuffer(gpgme_data_t dataIn, QByteArray *outBuffer);
-
- void fetch_keys();
-
- static void checkErr(gpgme_error_t gpgmeError);
-
- static void checkErr(gpgme_error_t gpgmeError, const QString &comment);
-
- static gpgme_error_t passphraseCb(void *hook, const char *uid_hint,
- const char *passphrase_info,
- int last_was_bad, int fd);
-
- gpgme_error_t passphrase(const char *uid_hint,
- const char *passphrase_info,
- int last_was_bad, int fd);
-
- void executeGpgCommand(const QStringList &arguments, const std::function<void(QProcess *)> &interactFunc);
-
- };
-} // namespace GpgME
-
-#endif // __SGPGMEPP_CONTEXT_H__
diff --git a/include/gpg/GpgFileOpera.h b/include/gpg/GpgFileOpera.h
deleted file mode 100644
index 9b5e118c..00000000
--- a/include/gpg/GpgFileOpera.h
+++ /dev/null
@@ -1,51 +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_GPGFILEOPERA_H
-#define GPGFRONTEND_GPGFILEOPERA_H
-
-#include "GpgFrontend.h"
-#include "gpg/GpgContext.h"
-
-class GpgFileOpera {
-public:
- static gpgme_error_t encryptFile(GpgME::GpgContext *ctx, QVector<GpgKey> &keys, const QString &mPath,
- gpgme_encrypt_result_t *result);
-
- static gpgme_error_t decryptFile(GpgME::GpgContext *ctx, const QString &mPath, gpgme_decrypt_result_t *result);
-
- static gpgme_error_t signFile(GpgME::GpgContext *ctx, QVector<GpgKey> &keys, const QString &mPath,
- gpgme_sign_result_t *result);
-
- static gpgme_error_t verifyFile(GpgME::GpgContext *ctx, const QString &mPath, gpgme_verify_result_t *result);
-
- static gpg_error_t
- encryptSignFile(GpgME::GpgContext *ctx, QVector<GpgKey> &keys, const QString &mPath, gpgme_encrypt_result_t *encr_res, gpgme_sign_result_t *sign_res);
-
- static gpg_error_t decryptVerifyFile(GpgME::GpgContext *ctx, const QString &mPath, gpgme_decrypt_result_t *decr_res, gpgme_verify_result_t *verify_res);
-
-};
-
-
-#endif //GPGFRONTEND_GPGFILEOPERA_H
diff --git a/include/gpg/GpgGenKeyInfo.h b/include/gpg/GpgGenKeyInfo.h
deleted file mode 100644
index a5936207..00000000
--- a/include/gpg/GpgGenKeyInfo.h
+++ /dev/null
@@ -1,199 +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 GPG4USB_GPGGENKEYINFO_H
-#define GPG4USB_GPGGENKEYINFO_H
-
-#include "GpgFrontend.h"
-
-class GenKeyInfo {
-
- bool subKey = true;
- QString userid;
- QString algo;
- int keySize = 2048;
- QDateTime expired = QDateTime::currentDateTime().addYears(2);
- bool nonExpired = false;
-
- bool noPassPhrase = false;
- bool allowNoPassPhrase = true;
-
- int suggestMaxKeySize = 1024;
- int suggestSizeAdditionStep = 1024;
- int suggestMinKeySize = 4096;
-
- QString passPhrase;
-
-public:
-
- static const QVector<QString> SupportedKeyAlgo;
-
- static const QVector<QString> SupportedSubkeyAlgo;
-
- [[nodiscard]] bool isSubKey() const {
- return subKey;
- }
-
- void setIsSubKey(bool m_sub_key) {
- GenKeyInfo::subKey = m_sub_key;
- }
-
- [[nodiscard]] const QString &getUserid() const {
- return userid;
- }
-
- void setUserid(const QString &m_userid) {
- GenKeyInfo::userid = m_userid;
- }
-
- [[nodiscard]] const QString &getAlgo() const {
- return algo;
- }
-
- void setAlgo(const QString &m_algo);
-
- [[nodiscard]] QString getKeySizeStr() const;
-
- [[nodiscard]] int getKeySize() const {
- return keySize;
-
- }
-
- void setKeySize(int m_key_size);
-
- [[nodiscard]] const QDateTime &getExpired() const {
- return expired;
- }
-
- void setExpired(const QDateTime &m_expired);
-
- [[nodiscard]] bool isNonExpired() const {
- return nonExpired;
- }
-
- void setNonExpired(bool m_non_expired);
-
- [[nodiscard]] bool isNoPassPhrase() const {
- return this->noPassPhrase;
- }
-
- void setNonPassPhrase(bool m_non_pass_phrase) {
- GenKeyInfo::noPassPhrase = m_non_pass_phrase;
- }
-
- [[nodiscard]] bool isAllowSigning() const {
- return allowSigning;
- }
-
- [[nodiscard]] bool isAllowNoPassPhrase() const {
- return allowNoPassPhrase;
- }
-
- void setAllowSigning(bool m_allow_signing) {
- if(allowChangeSigning)
- GenKeyInfo::allowSigning = m_allow_signing;
- }
-
- [[nodiscard]] bool isAllowEncryption() const {
- return allowEncryption;
- }
-
- void setAllowEncryption(bool m_allow_encryption);
-
- [[nodiscard]] bool isAllowCertification() const {
- return allowCertification;
- }
-
- void setAllowCertification(bool m_allow_certification);
-
- [[nodiscard]] bool isAllowAuthentication() const {
- return allowAuthentication;
- }
-
- void setAllowAuthentication(bool m_allow_authentication) {
- if(allowChangeAuthentication)
- GenKeyInfo::allowAuthentication = m_allow_authentication;
- }
-
- [[nodiscard]] const QString &getPassPhrase() const {
- return passPhrase;
- }
-
- void setPassPhrase(const QString &m_pass_phrase) {
- GenKeyInfo::passPhrase = m_pass_phrase;
- }
-
- [[nodiscard]] bool isAllowChangeSigning() const {
- return allowChangeSigning;
- }
- [[nodiscard]] bool isAllowChangeEncryption() const {
- return allowChangeEncryption;
- }
-
- [[nodiscard]] bool isAllowChangeCertification() const {
- return allowChangeCertification;
- }
-
- [[nodiscard]] bool isAllowChangeAuthentication() const {
- return allowChangeAuthentication;
- }
-
- [[nodiscard]] int getSuggestMaxKeySize() const {
- return suggestMaxKeySize;
- }
-
- [[nodiscard]] int getSuggestMinKeySize() const {
- return suggestMinKeySize;
- }
-
- [[nodiscard]] int getSizeChangeStep() const {
- return suggestSizeAdditionStep;
- }
-
-
-private:
- bool allowEncryption = true;
- bool allowChangeEncryption = true;
-
- bool allowCertification = true;
- bool allowChangeCertification = true;
-
- bool allowAuthentication = true;
- bool allowChangeAuthentication = true;
-
- bool allowSigning = true;
- bool allowChangeSigning = true;
-
- void reset_options();
-
-public:
-
- explicit GenKeyInfo(bool m_is_sub_key = false) : subKey(m_is_sub_key) {
- setAlgo("rsa");
- }
-
-
-};
-
-#endif //GPG4USB_GPGGENKEYINFO_H
diff --git a/include/gpg/GpgKey.h b/include/gpg/GpgKey.h
deleted file mode 100644
index 9bf33111..00000000
--- a/include/gpg/GpgKey.h
+++ /dev/null
@@ -1,87 +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_GPGKEY_H
-#define GPGFRONTEND_GPGKEY_H
-
-#include "GpgUID.h"
-#include "GpgSubKey.h"
-
-class GpgKey {
-public:
-
- QString id;
- QString name;
- QString email;
- QString comment;
- QString fpr;
- QString protocol;
- QString owner_trust;
- QString pubkey_algo;
- QDateTime last_update;
- QDateTime expires;
- QDateTime create_time;
-
- unsigned int length{};
-
- bool can_encrypt{};
- bool can_sign{};
- bool can_certify{};
- bool can_authenticate{};
-
-
- bool is_private_key{};
- bool expired{};
- bool revoked{};
- bool disabled{};
-
- bool has_master_key{};
-
- bool good = false;
-
- QVector<GpgSubKey> subKeys;
-
- QVector<GpgUID> uids;
-
- gpgme_key_t key_refer = nullptr;
-
- explicit GpgKey(gpgme_key_t key = nullptr);
-
- GpgKey(const GpgKey &k);
-
- GpgKey(GpgKey &&k) noexcept;
-
- GpgKey& operator=(const GpgKey &k);
-
- GpgKey& operator=(GpgKey &&k) noexcept;
-
- ~GpgKey();
-
- void parse(gpgme_key_t key);
-
- void swapKeyRefer(gpgme_key_t key);
-};
-
-
-#endif //GPGFRONTEND_GPGKEY_H
diff --git a/include/gpg/GpgKeySignature.h b/include/gpg/GpgKeySignature.h
deleted file mode 100644
index 0dd2f893..00000000
--- a/include/gpg/GpgKeySignature.h
+++ /dev/null
@@ -1,67 +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_GPGKEYSIGNATURE_H
-#define GPGFRONTEND_GPGKEYSIGNATURE_H
-
-#include "GpgFrontend.h"
-
-struct GpgKeySignature {
-
- bool revoked{};
- bool expired{};
- bool invalid{};
- bool exportable{};
-
- gpgme_error_t status{};
-
- QString keyid;
- QString pubkey_algo;
-
- QDateTime create_time;
- QDateTime expire_time;
-
- QString uid;
- QString name;
- QString email;
- QString comment;
-
- gpgme_sigsum_t summary;
-
- GpgKeySignature() = default;
-
- explicit GpgKeySignature(gpgme_key_sig_t key_sig);
-
- GpgKeySignature(GpgKeySignature &&) noexcept = default;
-
- GpgKeySignature(const GpgKeySignature &) = default;
-
- GpgKeySignature &operator=(GpgKeySignature &&) noexcept = default;
-
- GpgKeySignature &operator=(const GpgKeySignature &) = default;
-
-};
-
-
-#endif //GPGFRONTEND_GPGKEYSIGNATURE_H
diff --git a/include/gpg/GpgSubKey.h b/include/gpg/GpgSubKey.h
deleted file mode 100644
index f2da9e9e..00000000
--- a/include/gpg/GpgSubKey.h
+++ /dev/null
@@ -1,64 +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_GPGSUBKEY_H
-#define GPGFRONTEND_GPGSUBKEY_H
-
-#include "GpgFrontend.h"
-
-struct GpgSubKey {
-
- QString id;
- QString fpr;
-
- QString pubkey_algo;
-
- unsigned int length;
-
- bool can_encrypt{};
- bool can_sign{};
- bool can_certify{};
- bool can_authenticate{};
-
-
- bool is_private_key{};
- bool expired{};
- bool revoked{};
- bool disabled{};
- bool secret{};
- bool is_cardkey{};
-
- QDateTime timestamp;
- QDateTime expires;
-
- explicit GpgSubKey(gpgme_subkey_t key = nullptr);
-
- GpgSubKey(GpgSubKey &&) noexcept = default;
- GpgSubKey(const GpgSubKey &) = default;
- GpgSubKey& operator=(GpgSubKey &&) noexcept = default;
- GpgSubKey& operator=(const GpgSubKey &) = default;
-
-};
-
-
-#endif //GPGFRONTEND_GPGSUBKEY_H
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/server/ComUtils.h b/include/server/ComUtils.h
deleted file mode 100644
index a4cf543f..00000000
--- a/include/server/ComUtils.h
+++ /dev/null
@@ -1,79 +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_ZH_CN_TS_COMUTILS_H
-#define GPGFRONTEND_ZH_CN_TS_COMUTILS_H
-
-#include "GpgFrontend.h"
-#include "gpg/GpgContext.h"
-#include "rapidjson/document.h"
-
-class ComUtils : public QWidget {
-Q_OBJECT
-public:
-
- enum ServiceType { GetServiceToken, ShortenCryptText, GetFullCryptText, UploadPubkey, GetPubkey };
-
- explicit ComUtils(QWidget *parent) : QWidget(parent), appPath(qApp->applicationDirPath()),
- settings(RESOURCE_DIR(appPath) + "/conf/gpgfrontend.ini",
- QSettings::IniFormat) {
-
- }
-
- [[nodiscard]] QString getUrl(ServiceType type) const;
-
- bool checkServerReply(const QByteArray &reply);
-
- [[nodiscard]] QString getDataValueStr(const QString &key) const;
-
- [[nodiscard]] bool checkDataValueStr(const QString &key) const;
-
- [[nodiscard]] const rapidjson::Value &getDataValue(const QString &key) const;
-
- [[nodiscard]] bool checkDataValue(const QString &key) const;
-
- [[nodiscard]] bool checkServiceTokenFormat(const QString& serviceToken) const;
-
- static QByteArray getSignStringBase64(GpgME::GpgContext *ctx, const QString &str, const GpgKey& key);
-
- [[nodiscard]] bool good() const { return is_good; }
-
- QNetworkAccessManager &getNetworkManager() {return networkMgr;}
-
- void clear();
-
-private:
-
- QString appPath;
- QSettings settings;
- rapidjson::Document replyDoc;
- rapidjson::Value dataVal;
- QNetworkAccessManager networkMgr;
- QRegularExpression re_uuid{R"(\b[0-9a-f]{8}\b-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-\b[0-9a-f]{12}\b)"};
-
- bool is_good = false;
-};
-
-
-#endif //GPGFRONTEND_ZH_CN_TS_COMUTILS_H
diff --git a/include/ui/FileEncryptionDialog.h b/include/ui/FileEncryptionDialog.h
deleted file mode 100755
index be9ddd22..00000000
--- a/include/ui/FileEncryptionDialog.h
+++ /dev/null
@@ -1,116 +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 __FILEENCRYPTIONDIALOG_H__
-#define __FILEENCRYPTIONDIALOG_H__
-
-#include "gpg/GpgContext.h"
-#include "ui/widgets/KeyList.h"
-#include "VerifyDetailsDialog.h"
-
-
-/**
- * @brief
- *
- * @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(GpgME::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:
- GpgME::GpgContext *mCtx;
- KeyList *mKeyList;
-
-};
-
-#endif // __FILEENCRYPTIONDIALOG_H__
diff --git a/include/ui/KeyMgmt.h b/include/ui/KeyMgmt.h
deleted file mode 100755
index fa352149..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(GpgME::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;
- GpgME::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 6fd45fc5..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(GpgME::GpgContext *ctx, KeyList *keyList, bool automatic,
- QWidget *parent);
-
- KeyServerImportDialog(GpgME::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;
-
- GpgME::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 72f80917..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(GpgME::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;
- GpgME::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(GpgME::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;
- GpgME::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 79c7e321..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(GpgME::GpgContext *ctx, KeyMgmt *keyMgmt, QWidget *parent = nullptr);
-
-private:
- GpgME::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(GpgME::GpgContext *ctx, QWidget *parent = nullptr);
-
- [[nodiscard]] int nextId() const override;
-
-private slots:
-
- void slotGenerateKeyDialog();
-
-private:
- GpgME::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 4a37590a..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(GpgME::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])+)\]))"};
-
- GpgME::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 a1cfcf55..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(GpgME::GpgContext *ctx, const GpgKey &key, QWidget *parent = nullptr);
-
-private:
-
- GpgME::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/KeyNewUIDDialog.h b/include/ui/keypair_details/KeyNewUIDDialog.h
deleted file mode 100644
index fd8be03b..00000000
--- a/include/ui/keypair_details/KeyNewUIDDialog.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]><[email protected]> starting on May 12, 2021.
- *
- */
-
-#ifndef GPGFRONTEND_KEYNEWUIDDIALOG_H
-#define GPGFRONTEND_KEYNEWUIDDIALOG_H
-
-#include "GpgFrontend.h"
-
-#include "gpg/GpgContext.h"
-
-class KeyNewUIDDialog : public QDialog {
-Q_OBJECT
-
-public:
-
- KeyNewUIDDialog(GpgME::GpgContext *ctx, const GpgKey &key ,QWidget *parent = nullptr);
-
-
-private slots:
-
- void slotCreateNewUID();
-
-private:
-
- GpgME::GpgContext *mCtx;
- const GpgKey &mKey;
-
- QLineEdit *name{};
- QLineEdit *email{};
- QLineEdit *comment{};
-
- QPushButton *createButton{};
-
- 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);
-
-};
-
-
-#endif //GPGFRONTEND_KEYNEWUIDDIALOG_H
diff --git a/include/ui/keypair_details/KeyPairDetailTab.h b/include/ui/keypair_details/KeyPairDetailTab.h
deleted file mode 100644
index bb364718..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 */
-
- GpgME::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(GpgME::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 41bb0648..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(GpgME::GpgContext *ctx, const GpgKey &key, QWidget *parent);
-
-private:
-
- void createSubkeyList();
-
- void createSubkeyOperaMenu();
-
- const GpgSubKey *getSelectedSubkey();
-
- GpgME::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/keypair_details/KeyPairUIDTab.h b/include/ui/keypair_details/KeyPairUIDTab.h
deleted file mode 100644
index 6042ec29..00000000
--- a/include/ui/keypair_details/KeyPairUIDTab.h
+++ /dev/null
@@ -1,98 +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_KEYPAIRUIDTAB_H
-#define GPGFRONTEND_KEYPAIRUIDTAB_H
-
-#include "GpgFrontend.h"
-#include "gpg/GpgContext.h"
-
-#include "KeyUIDSignDialog.h"
-#include "KeyNewUIDDialog.h"
-
-class KeyPairUIDTab : public QWidget {
-Q_OBJECT
-
-public:
-
- KeyPairUIDTab(GpgME::GpgContext *ctx, const GpgKey &key, QWidget *parent);
-
-private:
-
- void createUIDList();
-
- void createSignList();
-
- void createManageUIDMenu();
-
- void createUIDPopupMenu();
-
- void createSignPopupMenu();
-
- void getUIDChecked(QVector<GpgUID> &uids);
-
- bool getUIDSelected(GpgUID &uid);
-
- bool getSignSelected(GpgKeySignature &signature);
-
- GpgME::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;
-
-private slots:
-
- void slotRefreshUIDList();
-
- void slotRefreshSigList();
-
- void slotAddSign();
-
- void slotAddSignSingle();
-
- void slotAddUID();
-
- void slotDelUID();
-
- void slotDelUIDSingle();
-
- void slotSetPrimaryUID();
-
- void slotDelSign();
-
- static void slotAddUIDResult(int result);
-
-protected:
-
- void contextMenuEvent(QContextMenuEvent *event) override;
-
-};
-
-
-#endif //GPGFRONTEND_KEYPAIRUIDTAB_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 334ef55a..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, GpgME::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;
- GpgME::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 231255b6..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(GpgME::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;
-
- GpgME::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/resource/conf/gpgfrontend.ini b/resource/conf/gpgfrontend.ini
deleted file mode 100644
index f606531f..00000000
--- a/resource/conf/gpgfrontend.ini
+++ /dev/null
@@ -1,53 +0,0 @@
-[keyserver]
-keyServerList=http://keys.gnupg.net, https://keyserver.ubuntu.com, http://pool.sks-keyservers.net
-defaultKeyServer=https://keyserver.ubuntu.com
-
-[int]
-lang=en_us
-
-[keys]
-saveKeyChecked=true
-
-[wizard]
-showWizard=true
-
-[window]
-windowState=@ByteArray(\0\0\0\xff\0\0\0\0\xfd\0\0\0\x2\0\0\0\x1\0\0\x1\xcc\0\0\x2V\xfc\x2\0\0\0\x1\xfb\0\0\0\x16\0\x45\0n\0\x63\0r\0y\0p\0t\0\x44\0o\0\x63\0k\x1\0\0\0I\0\0\x2V\0\0\0]\0\xff\xff\xff\0\0\0\x3\0\0\x2\xe0\0\0\0\xf5\xfc\x1\0\0\0\x1\xfb\0\0\0\"\0I\0n\0\x66\0o\0r\0m\0\x61\0t\0i\0o\0n\0 \0\x42\0o\0\x61\0r\0\x64\x1\0\0\0\0\0\0\x2\xe0\0\0\x1\xe0\0\xff\xff\xff\0\0\x2\xe0\0\0\x1]\0\0\0\x4\0\0\0\x4\0\0\0\x1\0\0\0\x2\xfc\0\0\0\x1\0\0\0\x2\0\0\0\x5\0\0\0\x16\0\x66\0i\0l\0\x65\0T\0o\0o\0l\0\x42\0\x61\0r\0\0\0\0\0\xff\xff\xff\xff\0\0\0\0\0\0\0\0\0\0\0\x18\0\x63\0r\0y\0p\0t\0T\0o\0o\0l\0\x42\0\x61\0r\x1\0\0\0\0\xff\xff\xff\xff\0\0\0\0\0\0\0\0\0\0\0\x14\0k\0\x65\0y\0T\0o\0o\0l\0\x42\0\x61\0r\x1\0\0\x1z\xff\xff\xff\xff\0\0\0\0\0\0\0\0\0\0\0\x16\0\x65\0\x64\0i\0t\0T\0o\0o\0l\0\x42\0\x61\0r\x1\0\0\x2\f\xff\xff\xff\xff\0\0\0\0\0\0\0\0\0\0\0$\0s\0p\0\x65\0\x63\0i\0\x61\0l\0\x45\0\x64\0i\0t\0T\0o\0o\0l\0\x42\0\x61\0r\0\0\0\0\0\xff\xff\xff\xff\0\0\0\0\0\0\0\0)
-pos=@Point(100 100)
-size=@Size(1200 700)
-windowSave=false
-
-[advanced]
-steganography=false
-autoPubkeyExchange=true
-
-[gpgpaths]
-keydbpath=.
-
-[sendMail]
-smtpAddress=
-username=
-password=
-port=25
-connectionType=None
-defaultSender=
-enable=false
-
-[toolbar]
-iconsize=@Size(24 24)
-iconstyle=3
-
-[%General]
-currentGpgfrontendServer=service.gpgfrontend.pub
-gpgfrontendServerList=service.gpgfrontend.pub, localhost
-ownKeyId=
-serviceToken=
-confirmImportKeys=true
-
-[keymgmt]
-pos=@Point(100 100)
-size=@Size(900 600)
-setWindowSize=true
-
-[informationBoard]
-fontSize=10 \ No newline at end of file
diff --git a/resource/gpgfrontend/usr/share/applications/gpgfrontend.desktop b/resource/gpgfrontend/usr/share/applications/gpgfrontend.desktop
index bce3dc62..8530e1d6 100644
--- a/resource/gpgfrontend/usr/share/applications/gpgfrontend.desktop
+++ b/resource/gpgfrontend/usr/share/applications/gpgfrontend.desktop
@@ -3,5 +3,5 @@ Type=Application
Name=GpgFrontend
Comment=A Cross-Platform OpenPGP Frontend Software
Exec=GpgFrontend
-Icon=gpgfrontend-appimage-icon
+Icon=GpgFrontend
Categories=Utility;
diff --git a/resource/gpgfrontend/usr/share/icons/hicolor/128x128/apps/GpgFrontend.png b/resource/gpgfrontend/usr/share/icons/hicolor/128x128/apps/GpgFrontend.png
new file mode 100644
index 00000000..5c24791f
--- /dev/null
+++ b/resource/gpgfrontend/usr/share/icons/hicolor/128x128/apps/GpgFrontend.png
Binary files differ
diff --git a/resource/gpgfrontend/usr/share/icons/hicolor/200x200/apps/gpgfrontend-appimage-icon.png b/resource/gpgfrontend/usr/share/icons/hicolor/200x200/apps/gpgfrontend-appimage-icon.png
deleted file mode 100755
index 7366dc97..00000000
--- a/resource/gpgfrontend/usr/share/icons/hicolor/200x200/apps/gpgfrontend-appimage-icon.png
+++ /dev/null
Binary files differ
diff --git a/resource/gpgfrontend/usr/share/icons/hicolor/256x256/apps/GpgFrontend.png b/resource/gpgfrontend/usr/share/icons/hicolor/256x256/apps/GpgFrontend.png
new file mode 100644
index 00000000..b3268b01
--- /dev/null
+++ b/resource/gpgfrontend/usr/share/icons/hicolor/256x256/apps/GpgFrontend.png
Binary files differ
diff --git a/resource/ts/gpgfrontend_en_us.ts b/resource/ts/gpgfrontend_en_us.ts
deleted file mode 100644
index 77d5e02b..00000000
--- a/resource/ts/gpgfrontend_en_us.ts
+++ /dev/null
@@ -1,3854 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!DOCTYPE TS>
-<TS version="2.1" language="en_US">
-<context>
- <name>AboutDialog</name>
- <message>
- <location filename="../../src/ui/help/AboutDialog.cpp" line="35"/>
- <source>About </source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/help/AboutDialog.cpp" line="42"/>
- <source>General</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/help/AboutDialog.cpp" line="43"/>
- <source>Translators</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/help/AboutDialog.cpp" line="44"/>
- <source>Update</source>
- <translation type="unfinished"></translation>
- </message>
-</context>
-<context>
- <name>AdvancedTab</name>
- <message>
- <location filename="../../src/ui/settings/SettingsAdvanced.cpp" line="34"/>
- <source>Show Steganography Options</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/settings/SettingsAdvanced.cpp" line="36"/>
- <source>Show Steganographic Options.</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/settings/SettingsAdvanced.cpp" line="40"/>
- <source>Pubkey Exchange</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/settings/SettingsAdvanced.cpp" line="42"/>
- <source>Auto Pubkey Exchange</source>
- <translation type="unfinished"></translation>
- </message>
-</context>
-<context>
- <name>AppearanceTab</name>
- <message>
- <location filename="../../src/ui/settings/SettingsAppearance.cpp" line="34"/>
- <source>Iconsize</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/settings/SettingsAppearance.cpp" line="36"/>
- <source>small</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/settings/SettingsAppearance.cpp" line="37"/>
- <source>medium</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/settings/SettingsAppearance.cpp" line="38"/>
- <source>large</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/settings/SettingsAppearance.cpp" line="54"/>
- <source>Iconstyle</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/settings/SettingsAppearance.cpp" line="56"/>
- <source>just text</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/settings/SettingsAppearance.cpp" line="57"/>
- <source>just icons</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/settings/SettingsAppearance.cpp" line="58"/>
- <source>text and icons</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/settings/SettingsAppearance.cpp" line="74"/>
- <source>Windowstate</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/settings/SettingsAppearance.cpp" line="77"/>
- <source>Save window size and position on exit.</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/settings/SettingsAppearance.cpp" line="85"/>
- <source>Information Board</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/settings/SettingsAppearance.cpp" line="91"/>
- <source> Front Size</source>
- <translation type="unfinished"></translation>
- </message>
-</context>
-<context>
- <name>ChoosePage</name>
- <message>
- <location filename="../../src/ui/Wizard.cpp" line="121"/>
- <source>Choose your action...</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/Wizard.cpp" line="122"/>
- <source>...by clicking on the appropriate link.</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/Wizard.cpp" line="124"/>
- <source>If you have never used GPGFrontend before and also don&apos;t own a gpg key yet you may possibly want to read how to</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/Wizard.cpp" line="127"/>
- <source>Generate Key</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/Wizard.cpp" line="134"/>
- <source>If you want to learn how to encrypt, decrypt, sign and verify text, you can read </source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/Wizard.cpp" line="136"/>
- <source>Encrypt &amp; Decrypt Text</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/Wizard.cpp" line="136"/>
- <location filename="../../src/ui/Wizard.cpp" line="149"/>
- <source>or</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/Wizard.cpp" line="138"/>
- <source>Sign &amp; Verify Text</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/Wizard.cpp" line="146"/>
- <source>If you want to operate file, you can read </source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/Wizard.cpp" line="149"/>
- <source>Encrypt &amp; Sign File</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/Wizard.cpp" line="152"/>
- <source>Sign &amp; Verify File</source>
- <translation type="unfinished"></translation>
- </message>
-</context>
-<context>
- <name>ComUtils</name>
- <message>
- <location filename="../../src/server/ComUtils.cpp" line="35"/>
- <location filename="../../src/server/ComUtils.cpp" line="55"/>
- <source>Error</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/server/ComUtils.cpp" line="35"/>
- <source>Nothing Reply. Please check the Internet connection.</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/server/ComUtils.cpp" line="55"/>
- <source>Unknown Error</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/server/ComUtils.cpp" line="75"/>
- <location filename="../../src/server/ComUtils.cpp" line="90"/>
- <source>Network Error</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/server/ComUtils.cpp" line="75"/>
- <source>Outdated Reply</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/server/ComUtils.cpp" line="87"/>
- <source>Unknown Reason</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/server/ComUtils.cpp" line="90"/>
- <source>Unknown Reply Format</source>
- <translation type="unfinished"></translation>
- </message>
-</context>
-<context>
- <name>ConclusionPage</name>
- <message>
- <location filename="../../src/ui/Wizard.cpp" line="224"/>
- <source>Ready.</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/Wizard.cpp" line="225"/>
- <source>Have fun with GPGFrontend!</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/Wizard.cpp" line="227"/>
- <source>You are ready to use GPGFrontend now.&lt;br&gt;&lt;br&gt;</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/Wizard.cpp" line="229"/>
- <source>The Online Document</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/Wizard.cpp" line="231"/>
- <source> will get you started with GPGFrontend. It will open in the main window.&lt;br&gt;</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/Wizard.cpp" line="238"/>
- <source>Open offline help.</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/Wizard.cpp" line="241"/>
- <source>Dont show the wizard again.</source>
- <translation type="unfinished"></translation>
- </message>
-</context>
-<context>
- <name>DecryptResultAnalyse</name>
- <message>
- <location filename="../../src/gpg/result_analyse/DecryptResultAnalyse.cpp" line="30"/>
- <source>[#] Decrypt Operation </source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/gpg/result_analyse/DecryptResultAnalyse.cpp" line="33"/>
- <source>[Success]</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/gpg/result_analyse/DecryptResultAnalyse.cpp" line="35"/>
- <source>[Failed] </source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/gpg/result_analyse/DecryptResultAnalyse.cpp" line="39"/>
- <source>Unsupported Algo: </source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/gpg/result_analyse/DecryptResultAnalyse.cpp" line="46"/>
- <source>File Name: </source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/gpg/result_analyse/DecryptResultAnalyse.cpp" line="52"/>
- <source>Recipient(s): </source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/gpg/result_analyse/DecryptResultAnalyse.cpp" line="82"/>
- <source> Keu ID: </source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/gpg/result_analyse/DecryptResultAnalyse.cpp" line="83"/>
- <source> Public Algo: </source>
- <translation type="unfinished"></translation>
- </message>
-</context>
-<context>
- <name>EncryptResultAnalyse</name>
- <message>
- <location filename="../../src/gpg/result_analyse/EncryptResultAnalyse.cpp" line="43"/>
- <source>Invalid Recipients: </source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/gpg/result_analyse/EncryptResultAnalyse.cpp" line="46"/>
- <source>Fingerprint: </source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/gpg/result_analyse/EncryptResultAnalyse.cpp" line="47"/>
- <source>Reason: </source>
- <translation type="unfinished"></translation>
- </message>
-</context>
-<context>
- <name>FileEncryptionDialog</name>
- <message>
- <location filename="../../src/ui/FileEncryptionDialog.cpp" line="32"/>
- <source>Decrypt File</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/FileEncryptionDialog.cpp" line="34"/>
- <source>Encrypt File</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/FileEncryptionDialog.cpp" line="36"/>
- <source>Sign File</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/FileEncryptionDialog.cpp" line="38"/>
- <source>Verify File</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/FileEncryptionDialog.cpp" line="47"/>
- <source>Input Parameters</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/FileEncryptionDialog.cpp" line="53"/>
- <source>Target File</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/FileEncryptionDialog.cpp" line="59"/>
- <source>Output File</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/FileEncryptionDialog.cpp" line="75"/>
- <source>Signature File(.sig) Path</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/FileEncryptionDialog.cpp" line="134"/>
- <location filename="../../src/ui/FileEncryptionDialog.cpp" line="177"/>
- <source>Open File</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/FileEncryptionDialog.cpp" line="165"/>
- <source>Save File</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/FileEncryptionDialog.cpp" line="194"/>
- <location filename="../../src/ui/FileEncryptionDialog.cpp" line="245"/>
- <source>Couldn&apos;t open file</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/FileEncryptionDialog.cpp" line="213"/>
- <location filename="../../src/ui/FileEncryptionDialog.cpp" line="224"/>
- <location filename="../../src/ui/FileEncryptionDialog.cpp" line="235"/>
- <source>Error</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/FileEncryptionDialog.cpp" line="214"/>
- <source>Error Occurred During Encryption</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/FileEncryptionDialog.cpp" line="225"/>
- <source>Error Occurred During Decryption</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/FileEncryptionDialog.cpp" line="236"/>
- <source>Error Occurred During Signature</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/FileEncryptionDialog.cpp" line="259"/>
- <location filename="../../src/ui/FileEncryptionDialog.cpp" line="268"/>
- <source>File</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/FileEncryptionDialog.cpp" line="260"/>
- <source>File exists! Do you want to overwrite it?</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/FileEncryptionDialog.cpp" line="269"/>
- <source>Cannot write file %1:
-%2.</source>
- <translation type="unfinished"></translation>
- </message>
-</context>
-<context>
- <name>FilePage</name>
- <message>
- <location filename="../../src/ui/widgets/FilePage.cpp" line="161"/>
- <source>Open</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/widgets/FilePage.cpp" line="163"/>
- <source>Delete</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/widgets/FilePage.cpp" line="165"/>
- <source>Encrypt and Sign</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/widgets/FilePage.cpp" line="167"/>
- <source>Decrypt and Verify</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/widgets/FilePage.cpp" line="169"/>
- <source>Only Sign</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/widgets/FilePage.cpp" line="171"/>
- <source>Only Verify</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/widgets/FilePage.cpp" line="222"/>
- <source>Warning</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/widgets/FilePage.cpp" line="223"/>
- <source>Are you sure you want to delete it?</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/widgets/FilePage.cpp" line="233"/>
- <source>Error</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/widgets/FilePage.cpp" line="234"/>
- <source>Unable to delete the file or folder.</source>
- <translation type="unfinished"></translation>
- </message>
-</context>
-<context>
- <name>FindWidget</name>
- <message>
- <location filename="../../src/ui/FindWidget.cpp" line="38"/>
- <source>Find:</source>
- <translation type="unfinished"></translation>
- </message>
-</context>
-<context>
- <name>GeneralTab</name>
- <message>
- <location filename="../../src/ui/settings/SettingsGeneral.cpp" line="40"/>
- <source>GpgFrontend Server</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/settings/SettingsGeneral.cpp" line="45"/>
- <source>Server that provides short key and key exchange services</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/settings/SettingsGeneral.cpp" line="52"/>
- <source>Save Checked Keys</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/settings/SettingsGeneral.cpp" line="55"/>
- <source>Save checked private keys on exit and restore them on next start.</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/settings/SettingsGeneral.cpp" line="64"/>
- <source>Confirm drag&apos;n&apos;drop key import</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/settings/SettingsGeneral.cpp" line="67"/>
- <source>Import files dropped on the keylist without confirmation.</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/settings/SettingsGeneral.cpp" line="74"/>
- <source>Language</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/settings/SettingsGeneral.cpp" line="83"/>
- <source>&lt;b&gt;NOTE: &lt;/b&gt; GpgFrontend will restart automatically if you change the language!</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/settings/SettingsGeneral.cpp" line="92"/>
- <source>Own key</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/settings/SettingsGeneral.cpp" line="96"/>
- <source>Get Service Token</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/settings/SettingsGeneral.cpp" line="97"/>
- <location filename="../../src/ui/settings/SettingsGeneral.cpp" line="235"/>
- <source>No Service Token Found</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/settings/SettingsGeneral.cpp" line="104"/>
- <source>&lt;none&gt;</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/settings/SettingsGeneral.cpp" line="121"/>
- <source>Key pair for synchronization and identity authentication</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/settings/SettingsGeneral.cpp" line="253"/>
- <source>Invalid Operation</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/settings/SettingsGeneral.cpp" line="254"/>
- <source>Own Key can not be None while getting service token.</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/settings/SettingsGeneral.cpp" line="266"/>
- <location filename="../../src/ui/settings/SettingsGeneral.cpp" line="337"/>
- <location filename="../../src/ui/settings/SettingsGeneral.cpp" line="354"/>
- <source>Error</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/settings/SettingsGeneral.cpp" line="267"/>
- <source>Key Not Exists</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/settings/SettingsGeneral.cpp" line="338"/>
- <source>The communication content with the server does not meet the requirements</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/settings/SettingsGeneral.cpp" line="351"/>
- <source>Notice</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/settings/SettingsGeneral.cpp" line="352"/>
- <source>Succeed in getting service token</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/settings/SettingsGeneral.cpp" line="354"/>
- <source>There is a problem with the communication with the server</source>
- <translation type="unfinished"></translation>
- </message>
-</context>
-<context>
- <name>GpgME::GpgContext</name>
- <message>
- <location filename="../../src/gpg/gpg_context/GpgContext.cpp" line="182"/>
- <source>Wrong password</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/gpg/gpg_context/GpgContext.cpp" line="190"/>
- <source>Enter Password for</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/gpg/gpg_context/GpgContext.cpp" line="194"/>
- <source>Enter Password</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/gpg/gpg_context/GpgContext.cpp" line="256"/>
- <source>Processing</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/gpg/gpg_context/GpgContextBasicOpera.cpp" line="169"/>
- <source>Key Selection</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/gpg/gpg_context/GpgContextBasicOpera.cpp" line="169"/>
- <source>No Private Key Selected</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/gpg/gpg_context/GpgContextBasicOpera.cpp" line="200"/>
- <source>Error in signing:</source>
- <translation type="unfinished"></translation>
- </message>
-</context>
-<context>
- <name>GpgPathsTab</name>
- <message>
- <location filename="../../src/ui/settings/SettingsDialog.cpp" line="139"/>
- <source>Relative path to keydb</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/settings/SettingsDialog.cpp" line="152"/>
- <source>Current keydb path: </source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/settings/SettingsDialog.cpp" line="157"/>
- <source>&lt;b&gt;NOTE: &lt;/b&gt; Gpg4usb will restart automatically if you change the keydb path!</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/settings/SettingsDialog.cpp" line="186"/>
- <source>Choose keydb directory</source>
- <translation type="unfinished"></translation>
- </message>
-</context>
-<context>
- <name>InfoBoardWidget</name>
- <message>
- <location filename="../../src/ui/widgets/InfoBoardWidget.cpp" line="40"/>
- <source>Import missing key from Keyserver</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/widgets/InfoBoardWidget.cpp" line="57"/>
- <source>Optional Actions</source>
- <translation type="unfinished"></translation>
- </message>
-</context>
-<context>
- <name>InfoTab</name>
- <message>
- <location filename="../../src/ui/help/AboutDialog.cpp" line="76"/>
- <source>&lt;br&gt;&lt;center&gt;GPGFrontend is an easy-to-use, compact, cross-platform, &lt;br&gt;and installation-free gpg front-end tool.&lt;br&gt;It visualizes most of the common operations of gpg commands.&lt;br&gt;It&apos;s licensed under the GPL v3&lt;br&gt;&lt;br&gt;&lt;b&gt;Developer:&lt;/b&gt;&lt;br&gt;Saturneric&lt;br&gt;&lt;br&gt;If you have any questions or suggestions, raise an issue&lt;br/&gt;at &lt;a href=&quot;https://github.com/saturneric/GpgFrontend&quot;&gt;GitHub&lt;/a&gt; or send a mail to my mailing list at &lt;a href=&quot;mailto:[email protected]&quot;&gt;[email protected]&lt;/a&gt;.</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/help/AboutDialog.cpp" line="84"/>
- <source>&lt;br&gt;&lt;br&gt; Built with Qt </source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/help/AboutDialog.cpp" line="85"/>
- <source> and GPGME </source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/help/AboutDialog.cpp" line="86"/>
- <source>&lt;br&gt;Built at </source>
- <translation type="unfinished"></translation>
- </message>
-</context>
-<context>
- <name>IntroPage</name>
- <message>
- <location filename="../../src/ui/Wizard.cpp" line="66"/>
- <source>Getting Started...</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/Wizard.cpp" line="67"/>
- <source>... with GPGFrontend</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/Wizard.cpp" line="69"/>
- <source>Welcome to use GPGFrontend for decrypting and signing text or file!</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/Wizard.cpp" line="71"/>
- <source>is a Powerful, Easy-to-Use, Compact, Cross-Platform, and Installation-Free OpenPGP Crypto Tool.</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/Wizard.cpp" line="72"/>
- <source>For brief information have a look at the</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/Wizard.cpp" line="74"/>
- <source>Overview</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/Wizard.cpp" line="75"/>
- <source>by clicking the link, the page will open in the web browser</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/Wizard.cpp" line="83"/>
- <source>Choose a Language</source>
- <translation type="unfinished"></translation>
- </message>
-</context>
-<context>
- <name>KeyDetailsDialog</name>
- <message>
- <location filename="../../src/ui/keypair_details/KeyDetailsDialog.cpp" line="31"/>
- <source>KeyPair</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keypair_details/KeyDetailsDialog.cpp" line="32"/>
- <source>UIDs</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keypair_details/KeyDetailsDialog.cpp" line="33"/>
- <source>Subkeys</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keypair_details/KeyDetailsDialog.cpp" line="40"/>
- <source>Key Details</source>
- <translation type="unfinished"></translation>
- </message>
-</context>
-<context>
- <name>KeyGenDialog</name>
- <message>
- <location filename="../../src/ui/keygen/KeygenDialog.cpp" line="33"/>
- <source>Generate Key</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keygen/KeygenDialog.cpp" line="69"/>
- <source> Name must contain at least five characters.
-</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keygen/KeygenDialog.cpp" line="71"/>
- <source> Please give a email address.
-</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keygen/KeygenDialog.cpp" line="78"/>
- <source> Expiration time no more than 2 years.
-</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keygen/KeygenDialog.cpp" line="112"/>
- <source>Success</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keygen/KeygenDialog.cpp" line="112"/>
- <source>The new key pair has been generated.</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keygen/KeygenDialog.cpp" line="116"/>
- <source>Failure</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keygen/KeygenDialog.cpp" line="145"/>
- <source>Key Usage</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keygen/KeygenDialog.cpp" line="147"/>
- <source>Encryption</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keygen/KeygenDialog.cpp" line="150"/>
- <source>Signing</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keygen/KeygenDialog.cpp" line="153"/>
- <source>Certification</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keygen/KeygenDialog.cpp" line="156"/>
- <source>Authentication</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keygen/KeygenDialog.cpp" line="338"/>
- <source>Name:</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keygen/KeygenDialog.cpp" line="339"/>
- <source>Email Address:</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keygen/KeygenDialog.cpp" line="340"/>
- <source>Comment:</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keygen/KeygenDialog.cpp" line="341"/>
- <source>Expiration Date:</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keygen/KeygenDialog.cpp" line="342"/>
- <source>Never Expire</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keygen/KeygenDialog.cpp" line="343"/>
- <source>KeySize (in Bit):</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keygen/KeygenDialog.cpp" line="344"/>
- <source>Key Type:</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keygen/KeygenDialog.cpp" line="345"/>
- <source>Non Pass Phrase</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keygen/KeygenDialog.cpp" line="358"/>
- <source>Basic Information</source>
- <translation type="unfinished"></translation>
- </message>
-</context>
-<context>
- <name>KeyGenPage</name>
- <message>
- <location filename="../../src/ui/Wizard.cpp" line="183"/>
- <source>Create a keypair...</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/Wizard.cpp" line="184"/>
- <source>...for decrypting and signing messages</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/Wizard.cpp" line="185"/>
- <source>You should create a new keypair.The pair consists of a public and a private key.&lt;br&gt;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.&lt;br&gt;For more information have a look at the offline tutorial (which then is shown in the main window):</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/Wizard.cpp" line="192"/>
- <source>Offline tutorial</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/Wizard.cpp" line="199"/>
- <source>Create New Key</source>
- <translation type="unfinished"></translation>
- </message>
-</context>
-<context>
- <name>KeyImportDetailDialog</name>
- <message>
- <location filename="../../src/ui/KeyImportDetailDialog.cpp" line="34"/>
- <location filename="../../src/ui/KeyImportDetailDialog.cpp" line="53"/>
- <source>Key Update Details</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/KeyImportDetailDialog.cpp" line="34"/>
- <source>No keys found</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/KeyImportDetailDialog.cpp" line="36"/>
- <location filename="../../src/ui/KeyImportDetailDialog.cpp" line="55"/>
- <source>Key Import Details</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/KeyImportDetailDialog.cpp" line="36"/>
- <source>No keys found to import</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/KeyImportDetailDialog.cpp" line="64"/>
- <source>General key info</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/KeyImportDetailDialog.cpp" line="67"/>
- <source>Considered:</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/KeyImportDetailDialog.cpp" line="71"/>
- <source>Public unchanged:</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/KeyImportDetailDialog.cpp" line="76"/>
- <source>Imported:</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/KeyImportDetailDialog.cpp" line="81"/>
- <source>Not imported:</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/KeyImportDetailDialog.cpp" line="86"/>
- <source>Private read:</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/KeyImportDetailDialog.cpp" line="91"/>
- <source>Private imported:</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/KeyImportDetailDialog.cpp" line="96"/>
- <source>Private unchanged:</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/KeyImportDetailDialog.cpp" line="111"/>
- <source>Name</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/KeyImportDetailDialog.cpp" line="111"/>
- <source>Email</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/KeyImportDetailDialog.cpp" line="111"/>
- <source>Status</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/KeyImportDetailDialog.cpp" line="111"/>
- <source>Fingerprint</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/KeyImportDetailDialog.cpp" line="135"/>
- <source>private</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/KeyImportDetailDialog.cpp" line="138"/>
- <source>public</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/KeyImportDetailDialog.cpp" line="141"/>
- <source>unchanged</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/KeyImportDetailDialog.cpp" line="144"/>
- <source>new key</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/KeyImportDetailDialog.cpp" line="147"/>
- <source>new subkey</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/KeyImportDetailDialog.cpp" line="151"/>
- <source>new signature</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/KeyImportDetailDialog.cpp" line="155"/>
- <source>new uid</source>
- <translation type="unfinished"></translation>
- </message>
-</context>
-<context>
- <name>KeyList</name>
- <message>
- <location filename="../../src/ui/widgets/KeyList.cpp" line="76"/>
- <source>Select</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/widgets/KeyList.cpp" line="76"/>
- <source>Type</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/widgets/KeyList.cpp" line="76"/>
- <source>Name</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/widgets/KeyList.cpp" line="76"/>
- <source>Email Address</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/widgets/KeyList.cpp" line="77"/>
- <source>Usage</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/widgets/KeyList.cpp" line="77"/>
- <source>Validity</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/widgets/KeyList.cpp" line="77"/>
- <source>Finger Print</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/widgets/KeyList.cpp" line="302"/>
- <source>Import Keys</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/widgets/KeyList.cpp" line="305"/>
- <source>You&apos;ve dropped something on the table.
- GpgFrontend will now try to import key(s).</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/widgets/KeyList.cpp" line="308"/>
- <source>Always import without bothering.</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/widgets/KeyList.cpp" line="341"/>
- <source>Couldn&apos;t Open File: </source>
- <translation type="unfinished"></translation>
- </message>
-</context>
-<context>
- <name>KeyMgmt</name>
- <message>
- <location filename="../../src/ui/KeyMgmt.cpp" line="82"/>
- <source>Key Pair Management</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/KeyMgmt.cpp" line="88"/>
- <source>&amp;Open</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/KeyMgmt.cpp" line="89"/>
- <source>Ctrl+O</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/KeyMgmt.cpp" line="90"/>
- <source>Open Key File</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/KeyMgmt.cpp" line="93"/>
- <source>&amp;Close</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/KeyMgmt.cpp" line="94"/>
- <source>Ctrl+Q</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/KeyMgmt.cpp" line="96"/>
- <source>Close</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/KeyMgmt.cpp" line="99"/>
- <source>New Keypair</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/KeyMgmt.cpp" line="100"/>
- <source>Ctrl+N</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/KeyMgmt.cpp" line="102"/>
- <source>Generate KeyPair</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/KeyMgmt.cpp" line="105"/>
- <source>New Subkey</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/KeyMgmt.cpp" line="106"/>
- <source>Ctrl+Shift+N</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/KeyMgmt.cpp" line="108"/>
- <source>Generate Subkey For Selected KeyPair</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/KeyMgmt.cpp" line="111"/>
- <location filename="../../src/ui/KeyMgmt.cpp" line="151"/>
- <source>&amp;File</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/KeyMgmt.cpp" line="113"/>
- <source>Import New Key From File</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/KeyMgmt.cpp" line="116"/>
- <source>&amp;Clipboard</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/KeyMgmt.cpp" line="118"/>
- <source>Import New Key From Clipboard</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/KeyMgmt.cpp" line="121"/>
- <source>&amp;Keyserver</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/KeyMgmt.cpp" line="123"/>
- <source>Import New Key From Keyserver</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/KeyMgmt.cpp" line="126"/>
- <source>Export To &amp;Clipboard</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/KeyMgmt.cpp" line="128"/>
- <source>Export Selected Key(s) To Clipboard</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/KeyMgmt.cpp" line="131"/>
- <source>Export To &amp;File</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/KeyMgmt.cpp" line="133"/>
- <source>Export Selected Key(s) To File</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/KeyMgmt.cpp" line="136"/>
- <source>Delete Selected Key(s)</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/KeyMgmt.cpp" line="137"/>
- <source>Delete the Selected keys</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/KeyMgmt.cpp" line="140"/>
- <source>Delete Checked Key(s)</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/KeyMgmt.cpp" line="141"/>
- <source>Delete the Checked keys</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/KeyMgmt.cpp" line="145"/>
- <source>Show Key Details</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/KeyMgmt.cpp" line="146"/>
- <source>Show Details for this Key</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/KeyMgmt.cpp" line="155"/>
- <source>&amp;Key</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/KeyMgmt.cpp" line="156"/>
- <source>&amp;Generate Key</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/KeyMgmt.cpp" line="160"/>
- <source>&amp;Import Key</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/KeyMgmt.cpp" line="171"/>
- <source>Key</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/KeyMgmt.cpp" line="179"/>
- <source>Generate</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/KeyMgmt.cpp" line="180"/>
- <source>Generate A New Keypair or Subkey</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/KeyMgmt.cpp" line="189"/>
- <source>Import key</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/KeyMgmt.cpp" line="190"/>
- <source>Import Key</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/KeyMgmt.cpp" line="209"/>
- <source>Open Key</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/KeyMgmt.cpp" line="210"/>
- <location filename="../../src/ui/KeyMgmt.cpp" line="302"/>
- <source>Key Files</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/KeyMgmt.cpp" line="210"/>
- <source>Keyring files</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/KeyMgmt.cpp" line="216"/>
- <source>Couldn&apos;t Open File: </source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/KeyMgmt.cpp" line="262"/>
- <source>Deleting Keys</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/KeyMgmt.cpp" line="263"/>
- <source>Are you sure that you want to delete the following keys?</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/KeyMgmt.cpp" line="265"/>
- <source>The action can not be undone.</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/KeyMgmt.cpp" line="281"/>
- <location filename="../../src/ui/KeyMgmt.cpp" line="296"/>
- <location filename="../../src/ui/KeyMgmt.cpp" line="344"/>
- <source>Error</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/KeyMgmt.cpp" line="281"/>
- <location filename="../../src/ui/KeyMgmt.cpp" line="296"/>
- <location filename="../../src/ui/KeyMgmt.cpp" line="344"/>
- <source>Key Not Found.</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/KeyMgmt.cpp" line="301"/>
- <source>Export Key To File</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/KeyMgmt.cpp" line="312"/>
- <source>key(s) exported</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/KeyMgmt.cpp" line="338"/>
- <location filename="../../src/ui/KeyMgmt.cpp" line="349"/>
- <source>Invalid Operation</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/KeyMgmt.cpp" line="339"/>
- <source>Please select one KeyPair before doing this operation.</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/KeyMgmt.cpp" line="350"/>
- <source>If a key pair does not have a private key then it will not be able to generate sub-keys.</source>
- <translation type="unfinished"></translation>
- </message>
-</context>
-<context>
- <name>KeyNewUIDDialog</name>
- <message>
- <location filename="../../src/ui/keypair_details/KeyNewUIDDialog.cpp" line="40"/>
- <source>Name</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keypair_details/KeyNewUIDDialog.cpp" line="41"/>
- <source>Email</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keypair_details/KeyNewUIDDialog.cpp" line="42"/>
- <source>Comment</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keypair_details/KeyNewUIDDialog.cpp" line="55"/>
- <source>Create New UID</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keypair_details/KeyNewUIDDialog.cpp" line="68"/>
- <source> Name must contain at least five characters.
-</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keypair_details/KeyNewUIDDialog.cpp" line="70"/>
- <source> Please give a email address.
-</source>
- <translation type="unfinished"></translation>
- </message>
-</context>
-<context>
- <name>KeyPairDetailTab</name>
- <message>
- <location filename="../../src/ui/keypair_details/KeyPairDetailTab.cpp" line="34"/>
- <source>Owner</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keypair_details/KeyPairDetailTab.cpp" line="35"/>
- <source>Master Key</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keypair_details/KeyPairDetailTab.cpp" line="36"/>
- <source>Fingerprint</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keypair_details/KeyPairDetailTab.cpp" line="37"/>
- <source>Additional UIDs</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keypair_details/KeyPairDetailTab.cpp" line="58"/>
- <source>Exists</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keypair_details/KeyPairDetailTab.cpp" line="58"/>
- <source>Not Exists</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keypair_details/KeyPairDetailTab.cpp" line="83"/>
- <source>Name:</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keypair_details/KeyPairDetailTab.cpp" line="84"/>
- <source>Email Address:</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keypair_details/KeyPairDetailTab.cpp" line="85"/>
- <source>Comment:</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keypair_details/KeyPairDetailTab.cpp" line="90"/>
- <source>Key ID: </source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keypair_details/KeyPairDetailTab.cpp" line="91"/>
- <source>Algorithm: </source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keypair_details/KeyPairDetailTab.cpp" line="92"/>
- <source>Key Size:</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keypair_details/KeyPairDetailTab.cpp" line="93"/>
- <source>Nominal Usage: </source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keypair_details/KeyPairDetailTab.cpp" line="94"/>
- <source>Actual Usage: </source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keypair_details/KeyPairDetailTab.cpp" line="95"/>
- <source>Expires on: </source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keypair_details/KeyPairDetailTab.cpp" line="96"/>
- <source>Last Update: </source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keypair_details/KeyPairDetailTab.cpp" line="97"/>
- <source>Secret Key Existence: </source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keypair_details/KeyPairDetailTab.cpp" line="121"/>
- <source>Copy</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keypair_details/KeyPairDetailTab.cpp" line="123"/>
- <source>copy fingerprint to clipboard</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keypair_details/KeyPairDetailTab.cpp" line="133"/>
- <source>Operations</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keypair_details/KeyPairDetailTab.cpp" line="136"/>
- <source>Export Private Key (Include Subkey)</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keypair_details/KeyPairDetailTab.cpp" line="141"/>
- <source>Modify Expiration Datetime (Master Key)</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keypair_details/KeyPairDetailTab.cpp" line="146"/>
- <source>Key Server Operation (Pubkey)</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keypair_details/KeyPairDetailTab.cpp" line="149"/>
- <source>Generate Revoke Certificate</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keypair_details/KeyPairDetailTab.cpp" line="174"/>
- <source>Warning: The Master Key has expired.</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keypair_details/KeyPairDetailTab.cpp" line="177"/>
- <source>Warning: The Master Key has been revoked</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keypair_details/KeyPairDetailTab.cpp" line="201"/>
- <source>Exporting private Key</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keypair_details/KeyPairDetailTab.cpp" line="202"/>
- <source>You are about to export your</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keypair_details/KeyPairDetailTab.cpp" line="203"/>
- <source>PRIVATE KEY</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keypair_details/KeyPairDetailTab.cpp" line="204"/>
- <source>This is NOT your Public Key, so DON&apos;T give it away.</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keypair_details/KeyPairDetailTab.cpp" line="205"/>
- <source>Do you REALLY want to export your PRIVATE KEY?</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keypair_details/KeyPairDetailTab.cpp" line="219"/>
- <source>Error</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keypair_details/KeyPairDetailTab.cpp" line="219"/>
- <source>Key Not Found.</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keypair_details/KeyPairDetailTab.cpp" line="224"/>
- <source>Export Key To File</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keypair_details/KeyPairDetailTab.cpp" line="225"/>
- <source>Key Files</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keypair_details/KeyPairDetailTab.cpp" line="228"/>
- <source>Export Error</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keypair_details/KeyPairDetailTab.cpp" line="228"/>
- <source>Couldn&apos;t open %1 for writing</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keypair_details/KeyPairDetailTab.cpp" line="298"/>
- <source>Never Expire</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keypair_details/KeyPairDetailTab.cpp" line="318"/>
- <source>Upload Key Pair to Key Server</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keypair_details/KeyPairDetailTab.cpp" line="320"/>
- <source>Update Key Pair</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keypair_details/KeyPairDetailTab.cpp" line="343"/>
- <source>Generate revocation certificate</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keypair_details/KeyPairDetailTab.cpp" line="346"/>
- <source>Revocation Certificates</source>
- <translation type="unfinished"></translation>
- </message>
-</context>
-<context>
- <name>KeyPairSubkeyTab</name>
- <message>
- <location filename="../../src/ui/keypair_details/KeyPairSubkeyTab.cpp" line="37"/>
- <source>Generate A New Subkey</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keypair_details/KeyPairSubkeyTab.cpp" line="54"/>
- <source>Key ID: </source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keypair_details/KeyPairSubkeyTab.cpp" line="55"/>
- <source>Algorithm: </source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keypair_details/KeyPairSubkeyTab.cpp" line="56"/>
- <source>Key Size:</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keypair_details/KeyPairSubkeyTab.cpp" line="57"/>
- <source>Usage: </source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keypair_details/KeyPairSubkeyTab.cpp" line="58"/>
- <source>Expires On </source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keypair_details/KeyPairSubkeyTab.cpp" line="59"/>
- <source>Last Update: </source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keypair_details/KeyPairSubkeyTab.cpp" line="60"/>
- <source>Existence: </source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keypair_details/KeyPairSubkeyTab.cpp" line="61"/>
- <source>Fingerprint: </source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keypair_details/KeyPairSubkeyTab.cpp" line="121"/>
- <source>Subkey ID</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keypair_details/KeyPairSubkeyTab.cpp" line="121"/>
- <source>Key Size</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keypair_details/KeyPairSubkeyTab.cpp" line="121"/>
- <source>Algo</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keypair_details/KeyPairSubkeyTab.cpp" line="121"/>
- <source>Create Date</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keypair_details/KeyPairSubkeyTab.cpp" line="121"/>
- <source>Expire Date</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keypair_details/KeyPairSubkeyTab.cpp" line="160"/>
- <source>Never Expire</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keypair_details/KeyPairSubkeyTab.cpp" line="184"/>
- <source>Never Expires</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keypair_details/KeyPairSubkeyTab.cpp" line="230"/>
- <source>Edit Expire Date</source>
- <translation type="unfinished"></translation>
- </message>
-</context>
-<context>
- <name>KeyPairUIDTab</name>
- <message>
- <location filename="../../src/ui/keypair_details/KeyPairUIDTab.cpp" line="39"/>
- <source>New UID</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keypair_details/KeyPairUIDTab.cpp" line="40"/>
- <source>UID Management</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keypair_details/KeyPairUIDTab.cpp" line="59"/>
- <source>UIDs</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keypair_details/KeyPairUIDTab.cpp" line="67"/>
- <source>Signature of Selected UID</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keypair_details/KeyPairUIDTab.cpp" line="103"/>
- <source>Select</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keypair_details/KeyPairUIDTab.cpp" line="103"/>
- <location filename="../../src/ui/keypair_details/KeyPairUIDTab.cpp" line="126"/>
- <source>Name</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keypair_details/KeyPairUIDTab.cpp" line="103"/>
- <location filename="../../src/ui/keypair_details/KeyPairUIDTab.cpp" line="126"/>
- <source>Email</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keypair_details/KeyPairUIDTab.cpp" line="103"/>
- <source>Comment</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keypair_details/KeyPairUIDTab.cpp" line="126"/>
- <source>Key ID</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keypair_details/KeyPairUIDTab.cpp" line="126"/>
- <source>Create Date</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keypair_details/KeyPairUIDTab.cpp" line="126"/>
- <source>Expired Date</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keypair_details/KeyPairUIDTab.cpp" line="219"/>
- <source>Never Expires</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keypair_details/KeyPairUIDTab.cpp" line="237"/>
- <location filename="../../src/ui/keypair_details/KeyPairUIDTab.cpp" line="300"/>
- <location filename="../../src/ui/keypair_details/KeyPairUIDTab.cpp" line="425"/>
- <location filename="../../src/ui/keypair_details/KeyPairUIDTab.cpp" line="440"/>
- <location filename="../../src/ui/keypair_details/KeyPairUIDTab.cpp" line="480"/>
- <location filename="../../src/ui/keypair_details/KeyPairUIDTab.cpp" line="487"/>
- <source>Invalid Operation</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keypair_details/KeyPairUIDTab.cpp" line="238"/>
- <location filename="../../src/ui/keypair_details/KeyPairUIDTab.cpp" line="301"/>
- <source>Please select one or more UIDs before doing this operation.</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keypair_details/KeyPairUIDTab.cpp" line="263"/>
- <source>Sign Selected UID(s)</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keypair_details/KeyPairUIDTab.cpp" line="265"/>
- <source>Delete Selected UID(s)</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keypair_details/KeyPairUIDTab.cpp" line="284"/>
- <source>Successful Operation</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keypair_details/KeyPairUIDTab.cpp" line="285"/>
- <source>Successfully added a new UID.</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keypair_details/KeyPairUIDTab.cpp" line="288"/>
- <location filename="../../src/ui/keypair_details/KeyPairUIDTab.cpp" line="330"/>
- <location filename="../../src/ui/keypair_details/KeyPairUIDTab.cpp" line="363"/>
- <location filename="../../src/ui/keypair_details/KeyPairUIDTab.cpp" line="460"/>
- <location filename="../../src/ui/keypair_details/KeyPairUIDTab.cpp" line="507"/>
- <source>Operation Failed</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keypair_details/KeyPairUIDTab.cpp" line="289"/>
- <location filename="../../src/ui/keypair_details/KeyPairUIDTab.cpp" line="331"/>
- <location filename="../../src/ui/keypair_details/KeyPairUIDTab.cpp" line="364"/>
- <location filename="../../src/ui/keypair_details/KeyPairUIDTab.cpp" line="461"/>
- <location filename="../../src/ui/keypair_details/KeyPairUIDTab.cpp" line="508"/>
- <source>An error occurred during the operation.</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keypair_details/KeyPairUIDTab.cpp" line="313"/>
- <source>Deleting UIDs</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keypair_details/KeyPairUIDTab.cpp" line="314"/>
- <source>Are you sure that you want to delete the following uids?</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keypair_details/KeyPairUIDTab.cpp" line="315"/>
- <location filename="../../src/ui/keypair_details/KeyPairUIDTab.cpp" line="357"/>
- <location filename="../../src/ui/keypair_details/KeyPairUIDTab.cpp" line="454"/>
- <location filename="../../src/ui/keypair_details/KeyPairUIDTab.cpp" line="501"/>
- <source>The action can not be undone.</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keypair_details/KeyPairUIDTab.cpp" line="355"/>
- <source>Set Primary UID</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keypair_details/KeyPairUIDTab.cpp" line="356"/>
- <source>Are you sure that you want to set the Primary UID to?</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keypair_details/KeyPairUIDTab.cpp" line="395"/>
- <source>Set As Primary</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keypair_details/KeyPairUIDTab.cpp" line="397"/>
- <source>Sign UID</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keypair_details/KeyPairUIDTab.cpp" line="399"/>
- <source>Delete UID</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keypair_details/KeyPairUIDTab.cpp" line="426"/>
- <location filename="../../src/ui/keypair_details/KeyPairUIDTab.cpp" line="441"/>
- <source>Please select one UID before doing this operation.</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keypair_details/KeyPairUIDTab.cpp" line="452"/>
- <source>Deleting UID</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keypair_details/KeyPairUIDTab.cpp" line="453"/>
- <source>Are you sure that you want to delete the following uid?</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keypair_details/KeyPairUIDTab.cpp" line="469"/>
- <source>Delete(Revoke) Key Signature</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keypair_details/KeyPairUIDTab.cpp" line="481"/>
- <source>Please select one Key Signature before doing this operation.</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keypair_details/KeyPairUIDTab.cpp" line="488"/>
- <source>To delete the signature, you need to have its corresponding public key in the local database.</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keypair_details/KeyPairUIDTab.cpp" line="499"/>
- <source>Deleting Key Signature</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keypair_details/KeyPairUIDTab.cpp" line="500"/>
- <source>Are you sure that you want to delete the following signature?</source>
- <translation type="unfinished"></translation>
- </message>
-</context>
-<context>
- <name>KeyServerImportDialog</name>
- <message>
- <location filename="../../src/ui/KeyServerImportDialog.cpp" line="40"/>
- <source>&amp;Close</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/KeyServerImportDialog.cpp" line="41"/>
- <source>&amp;Import ALL</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/KeyServerImportDialog.cpp" line="42"/>
- <source>&amp;Search</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/KeyServerImportDialog.cpp" line="45"/>
- <source>Search String:</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/KeyServerImportDialog.cpp" line="49"/>
- <source>Key Server:</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/KeyServerImportDialog.cpp" line="97"/>
- <source>Update Keys from Keyserver</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/KeyServerImportDialog.cpp" line="99"/>
- <source>Import Keys from Keyserver</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/KeyServerImportDialog.cpp" line="158"/>
- <source>UID</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/KeyServerImportDialog.cpp" line="158"/>
- <source>Creation date</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/KeyServerImportDialog.cpp" line="158"/>
- <source>KeyID</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/KeyServerImportDialog.cpp" line="158"/>
- <source>Tag</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/KeyServerImportDialog.cpp" line="179"/>
- <source>Text is empty.</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/KeyServerImportDialog.cpp" line="213"/>
- <source>Not Key Found</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/KeyServerImportDialog.cpp" line="216"/>
- <location filename="../../src/ui/KeyServerImportDialog.cpp" line="386"/>
- <source>Timeout</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/KeyServerImportDialog.cpp" line="219"/>
- <location filename="../../src/ui/KeyServerImportDialog.cpp" line="389"/>
- <source>Key Server Not Found</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/KeyServerImportDialog.cpp" line="222"/>
- <location filename="../../src/ui/KeyServerImportDialog.cpp" line="392"/>
- <source>Connection Error</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/KeyServerImportDialog.cpp" line="230"/>
- <source>Too many responses from keyserver!</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/KeyServerImportDialog.cpp" line="237"/>
- <source>No keys found, input may be kexId, retrying search with 0x.</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/KeyServerImportDialog.cpp" line="242"/>
- <source>No keys found containing the search string!</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/KeyServerImportDialog.cpp" line="246"/>
- <source>Insufficiently specific search string!</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/KeyServerImportDialog.cpp" line="274"/>
- <source>revoked</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/KeyServerImportDialog.cpp" line="277"/>
- <source>disabled</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/KeyServerImportDialog.cpp" line="317"/>
- <source>&lt;h4&gt;%1 keys found. Double click a key to import it.&lt;/h4&gt;</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/KeyServerImportDialog.cpp" line="383"/>
- <source>Key Not Found</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/KeyServerImportDialog.cpp" line="410"/>
- <source>&lt;h4&gt;Key Updated&lt;/h4&gt;</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/KeyServerImportDialog.cpp" line="412"/>
- <source>&lt;h4&gt;Key Imported&lt;/h4&gt;</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/KeyServerImportDialog.cpp" line="473"/>
- <source>Upload Keys from Keyserver</source>
- <translation type="unfinished"></translation>
- </message>
-</context>
-<context>
- <name>KeySetExpireDateDialog</name>
- <message>
- <location filename="../../src/ui/keypair_details/KeySetExpireDateDialog.cpp" line="36"/>
- <source>Confirm</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keypair_details/KeySetExpireDateDialog.cpp" line="41"/>
- <source>Never Expire</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keypair_details/KeySetExpireDateDialog.cpp" line="61"/>
- <source>Operation Failed</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keypair_details/KeySetExpireDateDialog.cpp" line="62"/>
- <source>An error occurred during the operation.</source>
- <translation type="unfinished"></translation>
- </message>
-</context>
-<context>
- <name>KeyUIDSignDialog</name>
- <message>
- <location filename="../../src/ui/keypair_details/KeyUIDSignDialog.cpp" line="72"/>
- <source>Expire Date</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keypair_details/KeyUIDSignDialog.cpp" line="81"/>
- <source>Sign For Key&apos;s UID(s)</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keypair_details/KeyUIDSignDialog.cpp" line="99"/>
- <source>Unsuccessful Operation</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keypair_details/KeyUIDSignDialog.cpp" line="100"/>
- <source>Signature operation failed for UID </source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keypair_details/KeyUIDSignDialog.cpp" line="107"/>
- <source>Operation Complete</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keypair_details/KeyUIDSignDialog.cpp" line="108"/>
- <source>The signature operation of the UID is complete</source>
- <translation type="unfinished"></translation>
- </message>
-</context>
-<context>
- <name>KeyUploadDialog</name>
- <message>
- <location filename="../../src/ui/KeyUploadDialog.cpp" line="47"/>
- <source>Uploading Public Key</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/KeyUploadDialog.cpp" line="110"/>
- <source>Key Not Found</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/KeyUploadDialog.cpp" line="113"/>
- <source>Timeout</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/KeyUploadDialog.cpp" line="116"/>
- <source>Key Server Not Found</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/KeyUploadDialog.cpp" line="119"/>
- <source>Connection Error</source>
- <translation type="unfinished"></translation>
- </message>
-</context>
-<context>
- <name>KeyserverTab</name>
- <message>
- <location filename="../../src/ui/settings/SettingsKeyServer.cpp" line="32"/>
- <source>General</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/settings/SettingsKeyServer.cpp" line="53"/>
- <source>No.</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/settings/SettingsKeyServer.cpp" line="53"/>
- <source>Address</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/settings/SettingsKeyServer.cpp" line="53"/>
- <source>Available</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/settings/SettingsKeyServer.cpp" line="57"/>
- <source>Default Key Server for Import:</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/settings/SettingsKeyServer.cpp" line="67"/>
- <source>Add</source>
- <translation type="unfinished"></translation>
- </message>
-</context>
-<context>
- <name>MainWindow</name>
- <message>
- <location filename="../../src/MainWindow.cpp" line="35"/>
- <source>Loading Gnupg</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/MainWindow.cpp" line="62"/>
- <source>ENV Loading Failed</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/MainWindow.cpp" line="63"/>
- <source>Gnupg is not installed correctly, please follow the ReadME instructions to install gnupg and then open GPGFrontend.</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowFileSlotFunction.cpp" line="36"/>
- <location filename="../../src/ui/main_window/MainWindowFileSlotFunction.cpp" line="40"/>
- <location filename="../../src/ui/main_window/MainWindowFileSlotFunction.cpp" line="44"/>
- <location filename="../../src/ui/main_window/MainWindowFileSlotFunction.cpp" line="114"/>
- <location filename="../../src/ui/main_window/MainWindowFileSlotFunction.cpp" line="127"/>
- <location filename="../../src/ui/main_window/MainWindowFileSlotFunction.cpp" line="131"/>
- <location filename="../../src/ui/main_window/MainWindowFileSlotFunction.cpp" line="135"/>
- <location filename="../../src/ui/main_window/MainWindowFileSlotFunction.cpp" line="196"/>
- <location filename="../../src/ui/main_window/MainWindowFileSlotFunction.cpp" line="212"/>
- <location filename="../../src/ui/main_window/MainWindowFileSlotFunction.cpp" line="216"/>
- <location filename="../../src/ui/main_window/MainWindowFileSlotFunction.cpp" line="220"/>
- <location filename="../../src/ui/main_window/MainWindowFileSlotFunction.cpp" line="294"/>
- <location filename="../../src/ui/main_window/MainWindowFileSlotFunction.cpp" line="326"/>
- <location filename="../../src/ui/main_window/MainWindowFileSlotFunction.cpp" line="331"/>
- <location filename="../../src/ui/main_window/MainWindowFileSlotFunction.cpp" line="335"/>
- <location filename="../../src/ui/main_window/MainWindowFileSlotFunction.cpp" line="383"/>
- <location filename="../../src/ui/main_window/MainWindowFileSlotFunction.cpp" line="396"/>
- <location filename="../../src/ui/main_window/MainWindowFileSlotFunction.cpp" line="400"/>
- <location filename="../../src/ui/main_window/MainWindowFileSlotFunction.cpp" line="404"/>
- <location filename="../../src/ui/main_window/MainWindowFileSlotFunction.cpp" line="501"/>
- <location filename="../../src/ui/main_window/MainWindowFileSlotFunction.cpp" line="513"/>
- <location filename="../../src/ui/main_window/MainWindowFileSlotFunction.cpp" line="517"/>
- <location filename="../../src/ui/main_window/MainWindowFileSlotFunction.cpp" line="521"/>
- <location filename="../../src/ui/main_window/MainWindowFileSlotFunction.cpp" line="583"/>
- <location filename="../../src/ui/main_window/MainWindowServerSlotFunction.cpp" line="53"/>
- <location filename="../../src/ui/main_window/MainWindowServerSlotFunction.cpp" line="111"/>
- <location filename="../../src/ui/main_window/MainWindowServerSlotFunction.cpp" line="125"/>
- <location filename="../../src/ui/main_window/MainWindowServerSlotFunction.cpp" line="217"/>
- <location filename="../../src/ui/main_window/MainWindowServerSlotFunction.cpp" line="232"/>
- <location filename="../../src/ui/main_window/MainWindowSlotFunction.cpp" line="521"/>
- <location filename="../../src/ui/main_window/MainWindowSlotFunction.cpp" line="537"/>
- <source>Error</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowFileSlotFunction.cpp" line="36"/>
- <location filename="../../src/ui/main_window/MainWindowFileSlotFunction.cpp" line="127"/>
- <location filename="../../src/ui/main_window/MainWindowFileSlotFunction.cpp" line="212"/>
- <location filename="../../src/ui/main_window/MainWindowFileSlotFunction.cpp" line="396"/>
- <source>Select a file before doing it.</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowFileSlotFunction.cpp" line="40"/>
- <location filename="../../src/ui/main_window/MainWindowFileSlotFunction.cpp" line="131"/>
- <location filename="../../src/ui/main_window/MainWindowFileSlotFunction.cpp" line="216"/>
- <location filename="../../src/ui/main_window/MainWindowFileSlotFunction.cpp" line="400"/>
- <location filename="../../src/ui/main_window/MainWindowFileSlotFunction.cpp" line="517"/>
- <source>No permission to read this file.</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowFileSlotFunction.cpp" line="44"/>
- <location filename="../../src/ui/main_window/MainWindowFileSlotFunction.cpp" line="135"/>
- <location filename="../../src/ui/main_window/MainWindowFileSlotFunction.cpp" line="220"/>
- <location filename="../../src/ui/main_window/MainWindowFileSlotFunction.cpp" line="404"/>
- <location filename="../../src/ui/main_window/MainWindowFileSlotFunction.cpp" line="521"/>
- <source>No permission to create file.</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowFileSlotFunction.cpp" line="49"/>
- <location filename="../../src/ui/main_window/MainWindowFileSlotFunction.cpp" line="150"/>
- <location filename="../../src/ui/main_window/MainWindowFileSlotFunction.cpp" line="226"/>
- <location filename="../../src/ui/main_window/MainWindowFileSlotFunction.cpp" line="409"/>
- <source>Warning</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowFileSlotFunction.cpp" line="50"/>
- <location filename="../../src/ui/main_window/MainWindowFileSlotFunction.cpp" line="151"/>
- <location filename="../../src/ui/main_window/MainWindowFileSlotFunction.cpp" line="227"/>
- <location filename="../../src/ui/main_window/MainWindowFileSlotFunction.cpp" line="410"/>
- <source>The target file already exists, do you need to overwrite it?</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowFileSlotFunction.cpp" line="62"/>
- <location filename="../../src/ui/main_window/MainWindowFileSlotFunction.cpp" line="239"/>
- <location filename="../../src/ui/main_window/MainWindowFileSlotFunction.cpp" line="422"/>
- <location filename="../../src/ui/main_window/MainWindowSlotFunction.cpp" line="45"/>
- <location filename="../../src/ui/main_window/MainWindowSlotFunction.cpp" line="125"/>
- <location filename="../../src/ui/main_window/MainWindowSlotFunction.cpp" line="296"/>
- <source>No Key Selected</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowFileSlotFunction.cpp" line="69"/>
- <location filename="../../src/ui/main_window/MainWindowFileSlotFunction.cpp" line="246"/>
- <location filename="../../src/ui/main_window/MainWindowSlotFunction.cpp" line="52"/>
- <location filename="../../src/ui/main_window/MainWindowSlotFunction.cpp" line="132"/>
- <source>Invalid Operation</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowFileSlotFunction.cpp" line="70"/>
- <location filename="../../src/ui/main_window/MainWindowFileSlotFunction.cpp" line="247"/>
- <location filename="../../src/ui/main_window/MainWindowSlotFunction.cpp" line="53"/>
- <source>The selected key contains a key that does not actually have a encrypt usage.&lt;br/&gt;</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowFileSlotFunction.cpp" line="71"/>
- <location filename="../../src/ui/main_window/MainWindowFileSlotFunction.cpp" line="248"/>
- <location filename="../../src/ui/main_window/MainWindowFileSlotFunction.cpp" line="436"/>
- <location filename="../../src/ui/main_window/MainWindowSlotFunction.cpp" line="54"/>
- <location filename="../../src/ui/main_window/MainWindowSlotFunction.cpp" line="134"/>
- <location filename="../../src/ui/main_window/MainWindowSlotFunction.cpp" line="307"/>
- <source>&lt;br/&gt;For example the Following Key: &lt;br/&gt;</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowFileSlotFunction.cpp" line="91"/>
- <location filename="../../src/ui/main_window/MainWindowSlotFunction.cpp" line="72"/>
- <source>Encrypting</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowFileSlotFunction.cpp" line="114"/>
- <location filename="../../src/ui/main_window/MainWindowFileSlotFunction.cpp" line="196"/>
- <location filename="../../src/ui/main_window/MainWindowFileSlotFunction.cpp" line="294"/>
- <location filename="../../src/ui/main_window/MainWindowFileSlotFunction.cpp" line="383"/>
- <location filename="../../src/ui/main_window/MainWindowFileSlotFunction.cpp" line="501"/>
- <location filename="../../src/ui/main_window/MainWindowFileSlotFunction.cpp" line="583"/>
- <source>An error occurred during operation.</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowFileSlotFunction.cpp" line="268"/>
- <location filename="../../src/ui/main_window/MainWindowSlotFunction.cpp" line="150"/>
- <source>Signing</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowFileSlotFunction.cpp" line="327"/>
- <source>Please select the appropriate target file or signature file. Ensure that both are in this directory.</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowFileSlotFunction.cpp" line="331"/>
- <source>No permission to read target file.</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowFileSlotFunction.cpp" line="335"/>
- <source>No permission to read signature file.</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowFileSlotFunction.cpp" line="353"/>
- <location filename="../../src/ui/main_window/MainWindowSlotFunction.cpp" line="258"/>
- <source>Verifying</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowFileSlotFunction.cpp" line="434"/>
- <location filename="../../src/ui/main_window/MainWindowSlotFunction.cpp" line="305"/>
- <source>Invalid KeyPair</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowFileSlotFunction.cpp" line="435"/>
- <source>The selected keypair cannot be used for signing and encryption at the same time.&lt;br/&gt;</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowFileSlotFunction.cpp" line="446"/>
- <location filename="../../src/ui/main_window/MainWindowFileSlotFunction.cpp" line="453"/>
- <source>Incomplete Operation</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowFileSlotFunction.cpp" line="447"/>
- <source>None of the selected key pairs can provide the encryption function.</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowFileSlotFunction.cpp" line="454"/>
- <source>None of the selected key pairs can provide the signature function.</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowFileSlotFunction.cpp" line="473"/>
- <location filename="../../src/ui/main_window/MainWindowSlotFunction.cpp" line="345"/>
- <source>Encrypting and Signing</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowFileSlotFunction.cpp" line="513"/>
- <source>Select a file(.gpg/.asc) before doing it.</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowFileSlotFunction.cpp" line="551"/>
- <location filename="../../src/ui/main_window/MainWindowSlotFunction.cpp" line="440"/>
- <source>Decrypting and Verifying</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowServerSlotFunction.cpp" line="43"/>
- <location filename="../../src/ui/main_window/MainWindowServerSlotFunction.cpp" line="154"/>
- <source>Invalid Own Key</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowServerSlotFunction.cpp" line="154"/>
- <source>Own Key can not be use to do any operation.</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowServerSlotFunction.cpp" line="54"/>
- <source>Please obtain a Service Token from the server in the settings.</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowServerSlotFunction.cpp" line="44"/>
- <source>Own Key can not be use to do any operation. Please go to the setting interface to select an OwnKey and get a ServiceToken.</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowServerSlotFunction.cpp" line="90"/>
- <source>Getting Cpt From Server</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowServerSlotFunction.cpp" line="112"/>
- <location filename="../../src/ui/main_window/MainWindowServerSlotFunction.cpp" line="218"/>
- <source>The communication content with the server does not meet the requirements</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowServerSlotFunction.cpp" line="125"/>
- <source>Invalid short ciphertext</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowServerSlotFunction.cpp" line="143"/>
- <source>Invalid Service Token</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowServerSlotFunction.cpp" line="144"/>
- <source>Please go to the setting interface to get a ServiceToken.</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowServerSlotFunction.cpp" line="202"/>
- <source>Getting Scpt From Server</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowServerSlotFunction.cpp" line="228"/>
- <source>Notice: Use Decrypt &amp; Verify operation to decrypt this short crypto text.</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowServerSlotFunction.cpp" line="232"/>
- <source>There is a problem with the communication with the server</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowSlotFunction.cpp" line="102"/>
- <location filename="../../src/ui/main_window/MainWindowSlotFunction.cpp" line="394"/>
- <source>Function Disabled</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowSlotFunction.cpp" line="103"/>
- <location filename="../../src/ui/main_window/MainWindowSlotFunction.cpp" line="395"/>
- <source>Please go to the settings interface to enable and configure this function.</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowSlotFunction.cpp" line="133"/>
- <source>The selected key contains a key that does not actually have a signature usage.&lt;br/&gt;</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowSlotFunction.cpp" line="185"/>
- <source>Notice</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowSlotFunction.cpp" line="185"/>
- <source>Short Crypto Text only supports Decrypt &amp; Verify.</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowSlotFunction.cpp" line="199"/>
- <source>Decrypting</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowSlotFunction.cpp" line="306"/>
- <source>The selected keypair cannot be used for encryption.&lt;br/&gt;</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowSlotFunction.cpp" line="355"/>
- <source>Automatic Key Exchange Warning</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowSlotFunction.cpp" line="356"/>
- <source>Part of the automatic key exchange failed, which may be related to your key.</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowSlotFunction.cpp" line="358"/>
- <source>If possible, try to use the RSA algorithm compatible with the server for signing.</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowSlotFunction.cpp" line="401"/>
- <source>Service Token Empty</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowSlotFunction.cpp" line="402"/>
- <source>Please go to the settings interface to set Own Key and get Service Token.</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowSlotFunction.cpp" line="521"/>
- <location filename="../../src/ui/main_window/MainWindowSlotFunction.cpp" line="537"/>
- <source>Key Not Found.</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowSlotFunction.cpp" line="568"/>
- <source>Outdated Version</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowSlotFunction.cpp" line="569"/>
- <source>This version(%1) is out of date, please update the latest version in time. </source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowSlotFunction.cpp" line="571"/>
- <location filename="../../src/ui/main_window/MainWindowSlotFunction.cpp" line="578"/>
- <source>You can download the latest version(%1) on Github Releases Page.&lt;br/&gt;</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowSlotFunction.cpp" line="575"/>
- <source>Unreleased Version</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowSlotFunction.cpp" line="576"/>
- <source>This version(%1) has not been officially released and is not recommended for use in a production environment. &lt;br/&gt;</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowSlotUI.cpp" line="58"/>
- <source>There is one unencrypted file in attachment folder</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowSlotUI.cpp" line="60"/>
- <source>There are </source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowSlotUI.cpp" line="60"/>
- <source> unencrypted files in attachment folder</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowUI.cpp" line="30"/>
- <source>&amp;New</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowUI.cpp" line="36"/>
- <source>Open a new file</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowUI.cpp" line="39"/>
- <source>&amp;Open...</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowUI.cpp" line="42"/>
- <source>Open an existing file</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowUI.cpp" line="45"/>
- <source>&amp;Browser</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowUI.cpp" line="47"/>
- <source>Open a file browser</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowUI.cpp" line="50"/>
- <source>&amp;Save</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowUI.cpp" line="53"/>
- <source>Save the current File</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowUI.cpp" line="56"/>
- <source>Save &amp;As</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowUI.cpp" line="59"/>
- <source>Save the current File as...</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowUI.cpp" line="62"/>
- <source>&amp;Print</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowUI.cpp" line="65"/>
- <source>Print Document</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowUI.cpp" line="68"/>
- <source>&amp;Close</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowUI.cpp" line="70"/>
- <source>Close file</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowUI.cpp" line="73"/>
- <source>&amp;Quit</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowUI.cpp" line="76"/>
- <source>Quit Program</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowUI.cpp" line="81"/>
- <source>&amp;Undo</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowUI.cpp" line="83"/>
- <source>Undo Last Edit Action</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowUI.cpp" line="86"/>
- <source>&amp;Redo</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowUI.cpp" line="88"/>
- <source>Redo Last Edit Action</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowUI.cpp" line="91"/>
- <source>Zoom In</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowUI.cpp" line="95"/>
- <source>Zoom Out</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowUI.cpp" line="99"/>
- <source>&amp;Paste</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowUI.cpp" line="102"/>
- <source>Paste Text From Clipboard</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowUI.cpp" line="105"/>
- <source>Cu&amp;t</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowUI.cpp" line="108"/>
- <source>Cut the current selection&apos;s contents to the clipboard</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowUI.cpp" line="112"/>
- <source>&amp;Copy</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowUI.cpp" line="115"/>
- <source>Copy the current selection&apos;s contents to the clipboard</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowUI.cpp" line="119"/>
- <source>&amp;Quote</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowUI.cpp" line="121"/>
- <source>Quote whole text</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowUI.cpp" line="124"/>
- <source>Select &amp;All</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowUI.cpp" line="127"/>
- <source>Select the whole text</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowUI.cpp" line="130"/>
- <source>&amp;Find</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowUI.cpp" line="132"/>
- <source>Find a word</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowUI.cpp" line="135"/>
- <source>Remove &amp;spacing</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowUI.cpp" line="138"/>
- <source>Remove double linebreaks, e.g. in pasted text from webmailer</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowUI.cpp" line="141"/>
- <source>Se&amp;ttings</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowUI.cpp" line="142"/>
- <source>Open settings dialog</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowUI.cpp" line="148"/>
- <source>&amp;Encrypt</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowUI.cpp" line="151"/>
- <source>Encrypt Message</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowUI.cpp" line="154"/>
- <source>&amp;Encrypt &amp;Sign</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowUI.cpp" line="157"/>
- <source>Encrypt and Sign Message</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowUI.cpp" line="160"/>
- <source>&amp;Decrypt</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowUI.cpp" line="163"/>
- <source>Decrypt Message</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowUI.cpp" line="166"/>
- <source>&amp;Decrypt &amp;Verify</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowUI.cpp" line="169"/>
- <source>Decrypt and Verify Message</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowUI.cpp" line="175"/>
- <source>&amp;Encrypt File</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowUI.cpp" line="176"/>
- <source>Encrypt File</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowUI.cpp" line="179"/>
- <source>&amp;Decrypt File</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowUI.cpp" line="180"/>
- <source>Decrypt File</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowUI.cpp" line="183"/>
- <source>&amp;Sign File</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowUI.cpp" line="184"/>
- <source>Sign File</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowUI.cpp" line="187"/>
- <source>&amp;Verify File</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowUI.cpp" line="188"/>
- <source>Verify File</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowUI.cpp" line="192"/>
- <source>&amp;Sign</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowUI.cpp" line="195"/>
- <source>Sign Message</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowUI.cpp" line="198"/>
- <source>&amp;Verify</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowUI.cpp" line="201"/>
- <source>Verify Message</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowUI.cpp" line="207"/>
- <source>&amp;Editor</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowUI.cpp" line="209"/>
- <source>Import New Key From Editor</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowUI.cpp" line="212"/>
- <source>Manage &amp;Keys</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowUI.cpp" line="214"/>
- <source>Open Keymanagement</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowUI.cpp" line="220"/>
- <source>&amp;About</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowUI.cpp" line="222"/>
- <source>Show the application&apos;s About box</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowUI.cpp" line="228"/>
- <source>&amp;Check for Updates</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowUI.cpp" line="230"/>
- <source>Check for updates</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowUI.cpp" line="233"/>
- <source>Open &amp;Wizard</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowUI.cpp" line="234"/>
- <source>Open the wizard</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowUI.cpp" line="239"/>
- <source>Append Selected Key(s) To Text</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowUI.cpp" line="240"/>
- <source>Append The Selected Keys To Text in Editor</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowUI.cpp" line="243"/>
- <source>Copy Email</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowUI.cpp" line="244"/>
- <source>Copy selected Email to clipboard</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowUI.cpp" line="248"/>
- <source>Show Key Details</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowUI.cpp" line="249"/>
- <source>Show Details for this Key</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowUI.cpp" line="252"/>
- <source>Refresh Key From Key Server</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowUI.cpp" line="253"/>
- <source>Refresh key from default key server</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowUI.cpp" line="256"/>
- <source>Upload Public Key(s) To Server</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowUI.cpp" line="257"/>
- <source>Upload The Selected Public Keys To Server</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowUI.cpp" line="272"/>
- <source>Remove PGP Header</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowUI.cpp" line="275"/>
- <source>Add PGP Header</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowUI.cpp" line="280"/>
- <source>&amp;File</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowUI.cpp" line="293"/>
- <source>&amp;Edit</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowUI.cpp" line="311"/>
- <source>&amp;File...</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowUI.cpp" line="317"/>
- <source>&amp;Crypt</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowUI.cpp" line="328"/>
- <source>&amp;Keys</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowUI.cpp" line="329"/>
- <source>&amp;Import Key</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowUI.cpp" line="338"/>
- <source>&amp;Steganography</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowUI.cpp" line="347"/>
- <source>&amp;View</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowUI.cpp" line="349"/>
- <source>&amp;Help</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowUI.cpp" line="358"/>
- <source>File</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowUI.cpp" line="366"/>
- <source>Crypt</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowUI.cpp" line="376"/>
- <source>Key</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowUI.cpp" line="381"/>
- <source>Edit</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowUI.cpp" line="388"/>
- <source>Special Edit</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowUI.cpp" line="400"/>
- <source>Import key from...</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowUI.cpp" line="401"/>
- <source>Import key</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowUI.cpp" line="409"/>
- <source>Browser to view and operate file</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowUI.cpp" line="410"/>
- <source>Browser</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowUI.cpp" line="428"/>
- <source>Ready</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowUI.cpp" line="435"/>
- <source>Key ToolBox</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowUI.cpp" line="443"/>
- <source>Information Board</source>
- <translation type="unfinished"></translation>
- </message>
-</context>
-<context>
- <name>PubkeyGetter</name>
- <message>
- <location filename="../../src/server/api/PubkeyGetter.cpp" line="66"/>
- <location filename="../../src/server/api/PubkeyGetter.cpp" line="90"/>
- <source>Error</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/server/api/PubkeyGetter.cpp" line="67"/>
- <location filename="../../src/server/api/PubkeyGetter.cpp" line="91"/>
- <source>The communication content with the server does not meet the requirements</source>
- <translation type="unfinished"></translation>
- </message>
-</context>
-<context>
- <name>PubkeyUploader</name>
- <message>
- <location filename="../../src/server/api/PubkeyUploader.cpp" line="95"/>
- <source>Error</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/server/api/PubkeyUploader.cpp" line="96"/>
- <source>The communication content with the server does not meet the requirements</source>
- <translation type="unfinished"></translation>
- </message>
-</context>
-<context>
- <name>QApplication</name>
- <message>
- <location filename="../../src/gpg/result_analyse/DecryptResultAnalyse.cpp" line="66"/>
- <source> {&gt;} Recipient: </source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/gpg/result_analyse/VerifyResultAnalyse.cpp" line="63"/>
- <source>One or More Bad Signatures.</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/gpg/result_analyse/VerifyResultAnalyse.cpp" line="68"/>
- <source>A </source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/gpg/result_analyse/VerifyResultAnalyse.cpp" line="70"/>
- <source>Good </source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/gpg/result_analyse/VerifyResultAnalyse.cpp" line="73"/>
- <source>Bad </source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/gpg/result_analyse/VerifyResultAnalyse.cpp" line="76"/>
- <source>Expired </source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/gpg/result_analyse/VerifyResultAnalyse.cpp" line="79"/>
- <source>Missing Key&apos;s </source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/gpg/result_analyse/VerifyResultAnalyse.cpp" line="82"/>
- <source>Revoked Key&apos;s </source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/gpg/result_analyse/VerifyResultAnalyse.cpp" line="85"/>
- <source>Expired Key&apos;s </source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/gpg/result_analyse/VerifyResultAnalyse.cpp" line="88"/>
- <source>Missing CRL&apos;s </source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/gpg/result_analyse/VerifyResultAnalyse.cpp" line="92"/>
- <source>Signature Fully Valid.</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/gpg/result_analyse/VerifyResultAnalyse.cpp" line="94"/>
- <source>Signature Not Fully Valid.</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/gpg/result_analyse/VerifyResultAnalyse.cpp" line="100"/>
- <source>Key is NOT present with ID 0x</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/gpg/result_analyse/VerifyResultAnalyse.cpp" line="107"/>
- <source>A signature could NOT be verified due to a Missing Key
-</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/gpg/result_analyse/VerifyResultAnalyse.cpp" line="111"/>
- <source>A signature is valid but the key used to verify the signature has been revoked
-</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/gpg/result_analyse/VerifyResultAnalyse.cpp" line="119"/>
- <source>A signature is valid but expired
-</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/gpg/result_analyse/VerifyResultAnalyse.cpp" line="126"/>
- <source>A signature is valid but the key used to verify the signature has expired.
-</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/gpg/result_analyse/VerifyResultAnalyse.cpp" line="133"/>
- <source>There was some other error which prevented the signature verification.
-</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/gpg/result_analyse/VerifyResultAnalyse.cpp" line="139"/>
- <source>Error for key with fingerprint </source>
- <translation type="unfinished"></translation>
- </message>
-</context>
-<context>
- <name>QuitDialog</name>
- <message>
- <location filename="../../src/ui/QuitDialog.cpp" line="29"/>
- <source>Unsaved Files</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/QuitDialog.cpp" line="77"/>
- <source>%1 files contain unsaved information.&lt;br/&gt;Save the changes before closing?</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/QuitDialog.cpp" line="88"/>
- <source>Check the files you want to save:</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/QuitDialog.cpp" line="89"/>
- <source>&lt;b&gt;Note:&lt;/b&gt; If you don&apos;t save these files, all changes are lost.&lt;br/&gt;</source>
- <translation type="unfinished"></translation>
- </message>
-</context>
-<context>
- <name>SendMailDialog</name>
- <message>
- <location filename="../../src/ui/SendMailDialog.cpp" line="35"/>
- <source>Incomplete configuration</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/SendMailDialog.cpp" line="36"/>
- <source>The SMTP address is empty, please go to the setting interface to complete the configuration.</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/SendMailDialog.cpp" line="86"/>
- <source> Recipient cannot be empty
-</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/SendMailDialog.cpp" line="91"/>
- <source> One or more Recipient&apos;s Email Address is invalid
-</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/SendMailDialog.cpp" line="97"/>
- <source> Sender cannot be empty
-</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/SendMailDialog.cpp" line="99"/>
- <source> Sender&apos;s Email Address is invalid
-</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/SendMailDialog.cpp" line="155"/>
- <location filename="../../src/ui/SendMailDialog.cpp" line="160"/>
- <location filename="../../src/ui/SendMailDialog.cpp" line="165"/>
- <source>Fail</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/SendMailDialog.cpp" line="155"/>
- <source>Fail to Connect SMTP Server</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/SendMailDialog.cpp" line="160"/>
- <source>Fail to Login into SMTP Server</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/SendMailDialog.cpp" line="165"/>
- <source>Fail to Send Mail to SMTP Server</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/SendMailDialog.cpp" line="171"/>
- <source>Success</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/SendMailDialog.cpp" line="171"/>
- <source>Succeed in Sending Mail to SMTP Server</source>
- <translation type="unfinished"></translation>
- </message>
-</context>
-<context>
- <name>SendMailTab</name>
- <message>
- <location filename="../../src/ui/settings/SettingsSendMail.cpp" line="33"/>
- <source>Enable</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/settings/SettingsSendMail.cpp" line="51"/>
- <source>Check Connection</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/settings/SettingsSendMail.cpp" line="53"/>
- <source>General</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/settings/SettingsSendMail.cpp" line="54"/>
- <source>Connection</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/settings/SettingsSendMail.cpp" line="55"/>
- <source>Preference</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/settings/SettingsSendMail.cpp" line="61"/>
- <source>SMTP Address</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/settings/SettingsSendMail.cpp" line="63"/>
- <source>Username</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/settings/SettingsSendMail.cpp" line="65"/>
- <source>Password</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/settings/SettingsSendMail.cpp" line="67"/>
- <source>Port</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/settings/SettingsSendMail.cpp" line="69"/>
- <source>Connection Security</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/settings/SettingsSendMail.cpp" line="75"/>
- <source>Default Sender</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/settings/SettingsSendMail.cpp" line="161"/>
- <location filename="../../src/ui/settings/SettingsSendMail.cpp" line="165"/>
- <source>Fail</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/settings/SettingsSendMail.cpp" line="161"/>
- <source>Fail to Connect SMTP Server</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/settings/SettingsSendMail.cpp" line="165"/>
- <source>Fail to Login</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/settings/SettingsSendMail.cpp" line="170"/>
- <source>Success</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/settings/SettingsSendMail.cpp" line="170"/>
- <source>Succeed in connecting and login</source>
- <translation type="unfinished"></translation>
- </message>
-</context>
-<context>
- <name>SettingsDialog</name>
- <message>
- <location filename="../../src/ui/settings/SettingsDialog.cpp" line="39"/>
- <source>General</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/settings/SettingsDialog.cpp" line="40"/>
- <source>Appearance</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/settings/SettingsDialog.cpp" line="41"/>
- <source>Send Mail</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/settings/SettingsDialog.cpp" line="42"/>
- <source>Key Server</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/settings/SettingsDialog.cpp" line="44"/>
- <source>Advanced</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/settings/SettingsDialog.cpp" line="59"/>
- <source>Settings</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/settings/SettingsDialog.cpp" line="105"/>
- <source>System Default</source>
- <translation type="unfinished"></translation>
- </message>
-</context>
-<context>
- <name>SignResultAnalyse</name>
- <message>
- <location filename="../../src/gpg/result_analyse/SignResultAnalyse.cpp" line="31"/>
- <source>[#] Sign Operation </source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/gpg/result_analyse/SignResultAnalyse.cpp" line="34"/>
- <source>[Success]</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/gpg/result_analyse/SignResultAnalyse.cpp" line="36"/>
- <source>[Failed] </source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/gpg/result_analyse/SignResultAnalyse.cpp" line="47"/>
- <source>[&gt;] New Signature: </source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/gpg/result_analyse/SignResultAnalyse.cpp" line="51"/>
- <source> Sign Mode: </source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/gpg/result_analyse/SignResultAnalyse.cpp" line="53"/>
- <source>Normal</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/gpg/result_analyse/SignResultAnalyse.cpp" line="55"/>
- <source>Clear</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/gpg/result_analyse/SignResultAnalyse.cpp" line="57"/>
- <source>Detach</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/gpg/result_analyse/SignResultAnalyse.cpp" line="63"/>
- <location filename="../../src/gpg/result_analyse/SignResultAnalyse.cpp" line="65"/>
- <source> Signer: </source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/gpg/result_analyse/SignResultAnalyse.cpp" line="65"/>
- <source>&lt;unknown&gt;</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/gpg/result_analyse/SignResultAnalyse.cpp" line="67"/>
- <source> Public Key Algo: </source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/gpg/result_analyse/SignResultAnalyse.cpp" line="68"/>
- <source> Hash Algo: </source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/gpg/result_analyse/SignResultAnalyse.cpp" line="69"/>
- <source> Date &amp; Time: </source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/gpg/result_analyse/SignResultAnalyse.cpp" line="81"/>
- <source>Invalid Signers: </source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/gpg/result_analyse/SignResultAnalyse.cpp" line="85"/>
- <source>[&gt;] Signer: </source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/gpg/result_analyse/SignResultAnalyse.cpp" line="86"/>
- <source> Fingerprint: </source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/gpg/result_analyse/SignResultAnalyse.cpp" line="87"/>
- <source> Reason: </source>
- <translation type="unfinished"></translation>
- </message>
-</context>
-<context>
- <name>SignersPicker</name>
- <message>
- <location filename="../../src/ui/widgets/SignersPicker.cpp" line="28"/>
- <source>Confirm</source>
- <translation type="unfinished"></translation>
- </message>
-</context>
-<context>
- <name>SubkeyGenerateDialog</name>
- <message>
- <location filename="../../src/ui/keygen/SubkeyGenerateDialog.cpp" line="47"/>
- <source>Generate New Subkey</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keygen/SubkeyGenerateDialog.cpp" line="62"/>
- <source>Encryption</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keygen/SubkeyGenerateDialog.cpp" line="65"/>
- <source>Signing</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keygen/SubkeyGenerateDialog.cpp" line="68"/>
- <source>Certification</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keygen/SubkeyGenerateDialog.cpp" line="71"/>
- <source>Authentication</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keygen/SubkeyGenerateDialog.cpp" line="115"/>
- <source>Expiration Date:</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keygen/SubkeyGenerateDialog.cpp" line="116"/>
- <source>Never Expire</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keygen/SubkeyGenerateDialog.cpp" line="117"/>
- <source>KeySize (in Bit):</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keygen/SubkeyGenerateDialog.cpp" line="118"/>
- <source>Key Type:</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keygen/SubkeyGenerateDialog.cpp" line="127"/>
- <source>Basic Information</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keygen/SubkeyGenerateDialog.cpp" line="215"/>
- <source> Expiration time no more than 2 years. </source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keygen/SubkeyGenerateDialog.cpp" line="244"/>
- <source>Success</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keygen/SubkeyGenerateDialog.cpp" line="244"/>
- <source>The new subkey has been generated.</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keygen/SubkeyGenerateDialog.cpp" line="247"/>
- <source>Failure</source>
- <translation type="unfinished"></translation>
- </message>
-</context>
-<context>
- <name>TextEdit</name>
- <message>
- <location filename="../../src/ui/widgets/TextEdit.cpp" line="53"/>
- <source>untitled</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/widgets/TextEdit.cpp" line="120"/>
- <location filename="../../src/ui/widgets/TextEdit.cpp" line="200"/>
- <source>Warning</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/widgets/TextEdit.cpp" line="121"/>
- <location filename="../../src/ui/widgets/TextEdit.cpp" line="201"/>
- <location filename="../../src/ui/widgets/TextEdit.cpp" line="482"/>
- <source>Cannot read file %1:
-%2.</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/widgets/TextEdit.cpp" line="175"/>
- <source>Open file</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/widgets/TextEdit.cpp" line="251"/>
- <source>File</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/widgets/TextEdit.cpp" line="252"/>
- <source>Cannot write file %1:
-%2.</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/widgets/TextEdit.cpp" line="270"/>
- <source>Save file</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/widgets/TextEdit.cpp" line="333"/>
- <source>Unsaved document</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/widgets/TextEdit.cpp" line="334"/>
- <source>The document &quot;%1&quot; has been modified. Do you want to save your changes?&lt;br/&gt;</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/widgets/TextEdit.cpp" line="337"/>
- <source>&lt;b&gt;Note:&lt;/b&gt; If you don&apos;t save these files, all changes are lost.&lt;br/&gt;</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/widgets/TextEdit.cpp" line="481"/>
- <source>Application</source>
- <translation type="unfinished"></translation>
- </message>
-</context>
-<context>
- <name>UpdateTab</name>
- <message>
- <location filename="../../src/ui/help/AboutDialog.cpp" line="129"/>
- <source>It is recommended that you always check the version of GpgFrontend and upgrade to the latest version.</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/help/AboutDialog.cpp" line="131"/>
- <source>New versions not only represent new features, but also often represent functional and security fixes.</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/help/AboutDialog.cpp" line="135"/>
- <source>Current Version: </source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/help/AboutDialog.cpp" line="143"/>
- <source>The current version is inconsistent with the latest version on github.</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/help/AboutDialog.cpp" line="145"/>
- <source>Please click &lt;a href=&quot;https://github.com/saturneric/GpgFrontend/releases&quot;&gt;here&lt;/a&gt; to download the latest version.</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/help/AboutDialog.cpp" line="199"/>
- <location filename="../../src/ui/help/AboutDialog.cpp" line="214"/>
- <source>Latest Version From Github: </source>
- <translation type="unfinished"></translation>
- </message>
-</context>
-<context>
- <name>VerifyDetailsDialog</name>
- <message>
- <location filename="../../src/ui/VerifyDetailsDialog.cpp" line="32"/>
- <source>Signature Details</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/VerifyDetailsDialog.cpp" line="53"/>
- <source>Status: </source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/VerifyDetailsDialog.cpp" line="56"/>
- <source>No valid input found</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/VerifyDetailsDialog.cpp" line="67"/>
- <source>Error Validating signature</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/VerifyDetailsDialog.cpp" line="70"/>
- <source>File was signed on %1 &lt;br/&gt; It Contains:&lt;br/&gt;&lt;br/&gt;</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/VerifyDetailsDialog.cpp" line="72"/>
- <source>Signed on %1 &lt;br/&gt; It Contains:&lt;br /&gt;&lt;br/&gt;</source>
- <translation type="unfinished"></translation>
- </message>
-</context>
-<context>
- <name>VerifyKeyDetailBox</name>
- <message>
- <location filename="../../src/ui/widgets/VerifyKeyDetailBox.cpp" line="36"/>
- <source>Import from keyserver</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/widgets/VerifyKeyDetailBox.cpp" line="39"/>
- <source>Key not present with id 0x</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/widgets/VerifyKeyDetailBox.cpp" line="43"/>
- <source>Status:</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/widgets/VerifyKeyDetailBox.cpp" line="45"/>
- <source>Key not present in keylist</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/widgets/VerifyKeyDetailBox.cpp" line="58"/>
- <location filename="../../src/ui/widgets/VerifyKeyDetailBox.cpp" line="72"/>
- <location filename="../../src/ui/widgets/VerifyKeyDetailBox.cpp" line="86"/>
- <location filename="../../src/ui/widgets/VerifyKeyDetailBox.cpp" line="101"/>
- <location filename="../../src/ui/widgets/VerifyKeyDetailBox.cpp" line="115"/>
- <location filename="../../src/ui/widgets/VerifyKeyDetailBox.cpp" line="129"/>
- <source>Key Information is NOT Available</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/widgets/VerifyKeyDetailBox.cpp" line="60"/>
- <location filename="../../src/ui/widgets/VerifyKeyDetailBox.cpp" line="74"/>
- <location filename="../../src/ui/widgets/VerifyKeyDetailBox.cpp" line="88"/>
- <location filename="../../src/ui/widgets/VerifyKeyDetailBox.cpp" line="103"/>
- <location filename="../../src/ui/widgets/VerifyKeyDetailBox.cpp" line="117"/>
- <location filename="../../src/ui/widgets/VerifyKeyDetailBox.cpp" line="131"/>
- <source>Fingerprint: </source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/widgets/VerifyKeyDetailBox.cpp" line="67"/>
- <source>Status: Cert Revoked</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/widgets/VerifyKeyDetailBox.cpp" line="81"/>
- <location filename="../../src/ui/widgets/VerifyKeyDetailBox.cpp" line="95"/>
- <source>Status: Signature Expired</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/widgets/VerifyKeyDetailBox.cpp" line="96"/>
- <source>Status: Key Expired</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/widgets/VerifyKeyDetailBox.cpp" line="110"/>
- <source>Status: General Error</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/widgets/VerifyKeyDetailBox.cpp" line="124"/>
- <source>Status: Unknown Error</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/widgets/VerifyKeyDetailBox.cpp" line="159"/>
- <source>Signer Name:</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/widgets/VerifyKeyDetailBox.cpp" line="160"/>
- <source>Signer Email:</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/widgets/VerifyKeyDetailBox.cpp" line="161"/>
- <source>Key&apos;s Fingerprint:</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/widgets/VerifyKeyDetailBox.cpp" line="162"/>
- <source>Valid:</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/widgets/VerifyKeyDetailBox.cpp" line="163"/>
- <source>Flags:</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/widgets/VerifyKeyDetailBox.cpp" line="171"/>
- <source>Fully Valid</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/widgets/VerifyKeyDetailBox.cpp" line="173"/>
- <source>NOT Fully Valid</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/widgets/VerifyKeyDetailBox.cpp" line="180"/>
- <source>Good </source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/widgets/VerifyKeyDetailBox.cpp" line="183"/>
- <source>Bad </source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/widgets/VerifyKeyDetailBox.cpp" line="186"/>
- <source>Expired </source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/widgets/VerifyKeyDetailBox.cpp" line="189"/>
- <source>Missing Key </source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/widgets/VerifyKeyDetailBox.cpp" line="192"/>
- <source>Revoked Key </source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/widgets/VerifyKeyDetailBox.cpp" line="195"/>
- <source>Expired Key </source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/widgets/VerifyKeyDetailBox.cpp" line="198"/>
- <source>Missing CRL </source>
- <translation type="unfinished"></translation>
- </message>
-</context>
-<context>
- <name>VerifyResultAnalyse</name>
- <message>
- <location filename="../../src/gpg/result_analyse/VerifyResultAnalyse.cpp" line="33"/>
- <source>[#] Verify Operation </source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/gpg/result_analyse/VerifyResultAnalyse.cpp" line="36"/>
- <source>[Success]</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/gpg/result_analyse/VerifyResultAnalyse.cpp" line="38"/>
- <source>[Failed] </source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/gpg/result_analyse/VerifyResultAnalyse.cpp" line="157"/>
- <location filename="../../src/gpg/result_analyse/VerifyResultAnalyse.cpp" line="161"/>
- <source> Signed By: </source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/gpg/result_analyse/VerifyResultAnalyse.cpp" line="157"/>
- <source>&lt;unknown&gt;</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/gpg/result_analyse/VerifyResultAnalyse.cpp" line="163"/>
- <source> Public Key Algo: </source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/gpg/result_analyse/VerifyResultAnalyse.cpp" line="164"/>
- <source> Hash Algo: </source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/gpg/result_analyse/VerifyResultAnalyse.cpp" line="165"/>
- <source> Date &amp; Time: </source>
- <translation type="unfinished"></translation>
- </message>
-</context>
-<context>
- <name>Wizard</name>
- <message>
- <location filename="../../src/ui/Wizard.cpp" line="40"/>
- <source>First Start Wizard</source>
- <translation type="unfinished"></translation>
- </message>
-</context>
-</TS>
diff --git a/resource/ts/gpgfrontend_es.ts b/resource/ts/gpgfrontend_es.ts
deleted file mode 100644
index 872d7d96..00000000
--- a/resource/ts/gpgfrontend_es.ts
+++ /dev/null
@@ -1,3854 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!DOCTYPE TS>
-<TS version="2.1" language="es_ES">
-<context>
- <name>AboutDialog</name>
- <message>
- <location filename="../../src/ui/help/AboutDialog.cpp" line="35"/>
- <source>About </source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/help/AboutDialog.cpp" line="42"/>
- <source>General</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/help/AboutDialog.cpp" line="43"/>
- <source>Translators</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/help/AboutDialog.cpp" line="44"/>
- <source>Update</source>
- <translation type="unfinished"></translation>
- </message>
-</context>
-<context>
- <name>AdvancedTab</name>
- <message>
- <location filename="../../src/ui/settings/SettingsAdvanced.cpp" line="34"/>
- <source>Show Steganography Options</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/settings/SettingsAdvanced.cpp" line="36"/>
- <source>Show Steganographic Options.</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/settings/SettingsAdvanced.cpp" line="40"/>
- <source>Pubkey Exchange</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/settings/SettingsAdvanced.cpp" line="42"/>
- <source>Auto Pubkey Exchange</source>
- <translation type="unfinished"></translation>
- </message>
-</context>
-<context>
- <name>AppearanceTab</name>
- <message>
- <location filename="../../src/ui/settings/SettingsAppearance.cpp" line="34"/>
- <source>Iconsize</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/settings/SettingsAppearance.cpp" line="36"/>
- <source>small</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/settings/SettingsAppearance.cpp" line="37"/>
- <source>medium</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/settings/SettingsAppearance.cpp" line="38"/>
- <source>large</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/settings/SettingsAppearance.cpp" line="54"/>
- <source>Iconstyle</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/settings/SettingsAppearance.cpp" line="56"/>
- <source>just text</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/settings/SettingsAppearance.cpp" line="57"/>
- <source>just icons</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/settings/SettingsAppearance.cpp" line="58"/>
- <source>text and icons</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/settings/SettingsAppearance.cpp" line="74"/>
- <source>Windowstate</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/settings/SettingsAppearance.cpp" line="77"/>
- <source>Save window size and position on exit.</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/settings/SettingsAppearance.cpp" line="85"/>
- <source>Information Board</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/settings/SettingsAppearance.cpp" line="91"/>
- <source> Front Size</source>
- <translation type="unfinished"></translation>
- </message>
-</context>
-<context>
- <name>ChoosePage</name>
- <message>
- <location filename="../../src/ui/Wizard.cpp" line="121"/>
- <source>Choose your action...</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/Wizard.cpp" line="122"/>
- <source>...by clicking on the appropriate link.</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/Wizard.cpp" line="124"/>
- <source>If you have never used GPGFrontend before and also don&apos;t own a gpg key yet you may possibly want to read how to</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/Wizard.cpp" line="127"/>
- <source>Generate Key</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/Wizard.cpp" line="134"/>
- <source>If you want to learn how to encrypt, decrypt, sign and verify text, you can read </source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/Wizard.cpp" line="136"/>
- <source>Encrypt &amp; Decrypt Text</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/Wizard.cpp" line="136"/>
- <location filename="../../src/ui/Wizard.cpp" line="149"/>
- <source>or</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/Wizard.cpp" line="138"/>
- <source>Sign &amp; Verify Text</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/Wizard.cpp" line="146"/>
- <source>If you want to operate file, you can read </source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/Wizard.cpp" line="149"/>
- <source>Encrypt &amp; Sign File</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/Wizard.cpp" line="152"/>
- <source>Sign &amp; Verify File</source>
- <translation type="unfinished"></translation>
- </message>
-</context>
-<context>
- <name>ComUtils</name>
- <message>
- <location filename="../../src/server/ComUtils.cpp" line="35"/>
- <location filename="../../src/server/ComUtils.cpp" line="55"/>
- <source>Error</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/server/ComUtils.cpp" line="35"/>
- <source>Nothing Reply. Please check the Internet connection.</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/server/ComUtils.cpp" line="55"/>
- <source>Unknown Error</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/server/ComUtils.cpp" line="75"/>
- <location filename="../../src/server/ComUtils.cpp" line="90"/>
- <source>Network Error</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/server/ComUtils.cpp" line="75"/>
- <source>Outdated Reply</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/server/ComUtils.cpp" line="87"/>
- <source>Unknown Reason</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/server/ComUtils.cpp" line="90"/>
- <source>Unknown Reply Format</source>
- <translation type="unfinished"></translation>
- </message>
-</context>
-<context>
- <name>ConclusionPage</name>
- <message>
- <location filename="../../src/ui/Wizard.cpp" line="224"/>
- <source>Ready.</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/Wizard.cpp" line="225"/>
- <source>Have fun with GPGFrontend!</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/Wizard.cpp" line="227"/>
- <source>You are ready to use GPGFrontend now.&lt;br&gt;&lt;br&gt;</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/Wizard.cpp" line="229"/>
- <source>The Online Document</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/Wizard.cpp" line="231"/>
- <source> will get you started with GPGFrontend. It will open in the main window.&lt;br&gt;</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/Wizard.cpp" line="238"/>
- <source>Open offline help.</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/Wizard.cpp" line="241"/>
- <source>Dont show the wizard again.</source>
- <translation type="unfinished"></translation>
- </message>
-</context>
-<context>
- <name>DecryptResultAnalyse</name>
- <message>
- <location filename="../../src/gpg/result_analyse/DecryptResultAnalyse.cpp" line="30"/>
- <source>[#] Decrypt Operation </source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/gpg/result_analyse/DecryptResultAnalyse.cpp" line="33"/>
- <source>[Success]</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/gpg/result_analyse/DecryptResultAnalyse.cpp" line="35"/>
- <source>[Failed] </source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/gpg/result_analyse/DecryptResultAnalyse.cpp" line="39"/>
- <source>Unsupported Algo: </source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/gpg/result_analyse/DecryptResultAnalyse.cpp" line="46"/>
- <source>File Name: </source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/gpg/result_analyse/DecryptResultAnalyse.cpp" line="52"/>
- <source>Recipient(s): </source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/gpg/result_analyse/DecryptResultAnalyse.cpp" line="82"/>
- <source> Keu ID: </source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/gpg/result_analyse/DecryptResultAnalyse.cpp" line="83"/>
- <source> Public Algo: </source>
- <translation type="unfinished"></translation>
- </message>
-</context>
-<context>
- <name>EncryptResultAnalyse</name>
- <message>
- <location filename="../../src/gpg/result_analyse/EncryptResultAnalyse.cpp" line="43"/>
- <source>Invalid Recipients: </source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/gpg/result_analyse/EncryptResultAnalyse.cpp" line="46"/>
- <source>Fingerprint: </source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/gpg/result_analyse/EncryptResultAnalyse.cpp" line="47"/>
- <source>Reason: </source>
- <translation type="unfinished"></translation>
- </message>
-</context>
-<context>
- <name>FileEncryptionDialog</name>
- <message>
- <location filename="../../src/ui/FileEncryptionDialog.cpp" line="32"/>
- <source>Decrypt File</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/FileEncryptionDialog.cpp" line="34"/>
- <source>Encrypt File</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/FileEncryptionDialog.cpp" line="36"/>
- <source>Sign File</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/FileEncryptionDialog.cpp" line="38"/>
- <source>Verify File</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/FileEncryptionDialog.cpp" line="47"/>
- <source>Input Parameters</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/FileEncryptionDialog.cpp" line="53"/>
- <source>Target File</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/FileEncryptionDialog.cpp" line="59"/>
- <source>Output File</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/FileEncryptionDialog.cpp" line="75"/>
- <source>Signature File(.sig) Path</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/FileEncryptionDialog.cpp" line="134"/>
- <location filename="../../src/ui/FileEncryptionDialog.cpp" line="177"/>
- <source>Open File</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/FileEncryptionDialog.cpp" line="165"/>
- <source>Save File</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/FileEncryptionDialog.cpp" line="194"/>
- <location filename="../../src/ui/FileEncryptionDialog.cpp" line="245"/>
- <source>Couldn&apos;t open file</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/FileEncryptionDialog.cpp" line="213"/>
- <location filename="../../src/ui/FileEncryptionDialog.cpp" line="224"/>
- <location filename="../../src/ui/FileEncryptionDialog.cpp" line="235"/>
- <source>Error</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/FileEncryptionDialog.cpp" line="214"/>
- <source>Error Occurred During Encryption</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/FileEncryptionDialog.cpp" line="225"/>
- <source>Error Occurred During Decryption</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/FileEncryptionDialog.cpp" line="236"/>
- <source>Error Occurred During Signature</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/FileEncryptionDialog.cpp" line="259"/>
- <location filename="../../src/ui/FileEncryptionDialog.cpp" line="268"/>
- <source>File</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/FileEncryptionDialog.cpp" line="260"/>
- <source>File exists! Do you want to overwrite it?</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/FileEncryptionDialog.cpp" line="269"/>
- <source>Cannot write file %1:
-%2.</source>
- <translation type="unfinished"></translation>
- </message>
-</context>
-<context>
- <name>FilePage</name>
- <message>
- <location filename="../../src/ui/widgets/FilePage.cpp" line="161"/>
- <source>Open</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/widgets/FilePage.cpp" line="163"/>
- <source>Delete</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/widgets/FilePage.cpp" line="165"/>
- <source>Encrypt and Sign</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/widgets/FilePage.cpp" line="167"/>
- <source>Decrypt and Verify</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/widgets/FilePage.cpp" line="169"/>
- <source>Only Sign</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/widgets/FilePage.cpp" line="171"/>
- <source>Only Verify</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/widgets/FilePage.cpp" line="222"/>
- <source>Warning</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/widgets/FilePage.cpp" line="223"/>
- <source>Are you sure you want to delete it?</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/widgets/FilePage.cpp" line="233"/>
- <source>Error</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/widgets/FilePage.cpp" line="234"/>
- <source>Unable to delete the file or folder.</source>
- <translation type="unfinished"></translation>
- </message>
-</context>
-<context>
- <name>FindWidget</name>
- <message>
- <location filename="../../src/ui/FindWidget.cpp" line="38"/>
- <source>Find:</source>
- <translation type="unfinished"></translation>
- </message>
-</context>
-<context>
- <name>GeneralTab</name>
- <message>
- <location filename="../../src/ui/settings/SettingsGeneral.cpp" line="40"/>
- <source>GpgFrontend Server</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/settings/SettingsGeneral.cpp" line="45"/>
- <source>Server that provides short key and key exchange services</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/settings/SettingsGeneral.cpp" line="52"/>
- <source>Save Checked Keys</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/settings/SettingsGeneral.cpp" line="55"/>
- <source>Save checked private keys on exit and restore them on next start.</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/settings/SettingsGeneral.cpp" line="64"/>
- <source>Confirm drag&apos;n&apos;drop key import</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/settings/SettingsGeneral.cpp" line="67"/>
- <source>Import files dropped on the keylist without confirmation.</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/settings/SettingsGeneral.cpp" line="74"/>
- <source>Language</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/settings/SettingsGeneral.cpp" line="83"/>
- <source>&lt;b&gt;NOTE: &lt;/b&gt; GpgFrontend will restart automatically if you change the language!</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/settings/SettingsGeneral.cpp" line="92"/>
- <source>Own key</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/settings/SettingsGeneral.cpp" line="96"/>
- <source>Get Service Token</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/settings/SettingsGeneral.cpp" line="97"/>
- <location filename="../../src/ui/settings/SettingsGeneral.cpp" line="235"/>
- <source>No Service Token Found</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/settings/SettingsGeneral.cpp" line="104"/>
- <source>&lt;none&gt;</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/settings/SettingsGeneral.cpp" line="121"/>
- <source>Key pair for synchronization and identity authentication</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/settings/SettingsGeneral.cpp" line="253"/>
- <source>Invalid Operation</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/settings/SettingsGeneral.cpp" line="254"/>
- <source>Own Key can not be None while getting service token.</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/settings/SettingsGeneral.cpp" line="266"/>
- <location filename="../../src/ui/settings/SettingsGeneral.cpp" line="337"/>
- <location filename="../../src/ui/settings/SettingsGeneral.cpp" line="354"/>
- <source>Error</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/settings/SettingsGeneral.cpp" line="267"/>
- <source>Key Not Exists</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/settings/SettingsGeneral.cpp" line="338"/>
- <source>The communication content with the server does not meet the requirements</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/settings/SettingsGeneral.cpp" line="351"/>
- <source>Notice</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/settings/SettingsGeneral.cpp" line="352"/>
- <source>Succeed in getting service token</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/settings/SettingsGeneral.cpp" line="354"/>
- <source>There is a problem with the communication with the server</source>
- <translation type="unfinished"></translation>
- </message>
-</context>
-<context>
- <name>GpgME::GpgContext</name>
- <message>
- <location filename="../../src/gpg/gpg_context/GpgContext.cpp" line="182"/>
- <source>Wrong password</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/gpg/gpg_context/GpgContext.cpp" line="190"/>
- <source>Enter Password for</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/gpg/gpg_context/GpgContext.cpp" line="194"/>
- <source>Enter Password</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/gpg/gpg_context/GpgContext.cpp" line="256"/>
- <source>Processing</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/gpg/gpg_context/GpgContextBasicOpera.cpp" line="169"/>
- <source>Key Selection</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/gpg/gpg_context/GpgContextBasicOpera.cpp" line="169"/>
- <source>No Private Key Selected</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/gpg/gpg_context/GpgContextBasicOpera.cpp" line="200"/>
- <source>Error in signing:</source>
- <translation type="unfinished"></translation>
- </message>
-</context>
-<context>
- <name>GpgPathsTab</name>
- <message>
- <location filename="../../src/ui/settings/SettingsDialog.cpp" line="139"/>
- <source>Relative path to keydb</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/settings/SettingsDialog.cpp" line="152"/>
- <source>Current keydb path: </source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/settings/SettingsDialog.cpp" line="157"/>
- <source>&lt;b&gt;NOTE: &lt;/b&gt; Gpg4usb will restart automatically if you change the keydb path!</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/settings/SettingsDialog.cpp" line="186"/>
- <source>Choose keydb directory</source>
- <translation type="unfinished"></translation>
- </message>
-</context>
-<context>
- <name>InfoBoardWidget</name>
- <message>
- <location filename="../../src/ui/widgets/InfoBoardWidget.cpp" line="40"/>
- <source>Import missing key from Keyserver</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/widgets/InfoBoardWidget.cpp" line="57"/>
- <source>Optional Actions</source>
- <translation type="unfinished"></translation>
- </message>
-</context>
-<context>
- <name>InfoTab</name>
- <message>
- <location filename="../../src/ui/help/AboutDialog.cpp" line="76"/>
- <source>&lt;br&gt;&lt;center&gt;GPGFrontend is an easy-to-use, compact, cross-platform, &lt;br&gt;and installation-free gpg front-end tool.&lt;br&gt;It visualizes most of the common operations of gpg commands.&lt;br&gt;It&apos;s licensed under the GPL v3&lt;br&gt;&lt;br&gt;&lt;b&gt;Developer:&lt;/b&gt;&lt;br&gt;Saturneric&lt;br&gt;&lt;br&gt;If you have any questions or suggestions, raise an issue&lt;br/&gt;at &lt;a href=&quot;https://github.com/saturneric/GpgFrontend&quot;&gt;GitHub&lt;/a&gt; or send a mail to my mailing list at &lt;a href=&quot;mailto:[email protected]&quot;&gt;[email protected]&lt;/a&gt;.</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/help/AboutDialog.cpp" line="84"/>
- <source>&lt;br&gt;&lt;br&gt; Built with Qt </source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/help/AboutDialog.cpp" line="85"/>
- <source> and GPGME </source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/help/AboutDialog.cpp" line="86"/>
- <source>&lt;br&gt;Built at </source>
- <translation type="unfinished"></translation>
- </message>
-</context>
-<context>
- <name>IntroPage</name>
- <message>
- <location filename="../../src/ui/Wizard.cpp" line="66"/>
- <source>Getting Started...</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/Wizard.cpp" line="67"/>
- <source>... with GPGFrontend</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/Wizard.cpp" line="69"/>
- <source>Welcome to use GPGFrontend for decrypting and signing text or file!</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/Wizard.cpp" line="71"/>
- <source>is a Powerful, Easy-to-Use, Compact, Cross-Platform, and Installation-Free OpenPGP Crypto Tool.</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/Wizard.cpp" line="72"/>
- <source>For brief information have a look at the</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/Wizard.cpp" line="74"/>
- <source>Overview</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/Wizard.cpp" line="75"/>
- <source>by clicking the link, the page will open in the web browser</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/Wizard.cpp" line="83"/>
- <source>Choose a Language</source>
- <translation type="unfinished"></translation>
- </message>
-</context>
-<context>
- <name>KeyDetailsDialog</name>
- <message>
- <location filename="../../src/ui/keypair_details/KeyDetailsDialog.cpp" line="31"/>
- <source>KeyPair</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keypair_details/KeyDetailsDialog.cpp" line="32"/>
- <source>UIDs</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keypair_details/KeyDetailsDialog.cpp" line="33"/>
- <source>Subkeys</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keypair_details/KeyDetailsDialog.cpp" line="40"/>
- <source>Key Details</source>
- <translation type="unfinished"></translation>
- </message>
-</context>
-<context>
- <name>KeyGenDialog</name>
- <message>
- <location filename="../../src/ui/keygen/KeygenDialog.cpp" line="33"/>
- <source>Generate Key</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keygen/KeygenDialog.cpp" line="69"/>
- <source> Name must contain at least five characters.
-</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keygen/KeygenDialog.cpp" line="71"/>
- <source> Please give a email address.
-</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keygen/KeygenDialog.cpp" line="78"/>
- <source> Expiration time no more than 2 years.
-</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keygen/KeygenDialog.cpp" line="112"/>
- <source>Success</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keygen/KeygenDialog.cpp" line="112"/>
- <source>The new key pair has been generated.</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keygen/KeygenDialog.cpp" line="116"/>
- <source>Failure</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keygen/KeygenDialog.cpp" line="145"/>
- <source>Key Usage</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keygen/KeygenDialog.cpp" line="147"/>
- <source>Encryption</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keygen/KeygenDialog.cpp" line="150"/>
- <source>Signing</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keygen/KeygenDialog.cpp" line="153"/>
- <source>Certification</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keygen/KeygenDialog.cpp" line="156"/>
- <source>Authentication</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keygen/KeygenDialog.cpp" line="338"/>
- <source>Name:</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keygen/KeygenDialog.cpp" line="339"/>
- <source>Email Address:</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keygen/KeygenDialog.cpp" line="340"/>
- <source>Comment:</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keygen/KeygenDialog.cpp" line="341"/>
- <source>Expiration Date:</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keygen/KeygenDialog.cpp" line="342"/>
- <source>Never Expire</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keygen/KeygenDialog.cpp" line="343"/>
- <source>KeySize (in Bit):</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keygen/KeygenDialog.cpp" line="344"/>
- <source>Key Type:</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keygen/KeygenDialog.cpp" line="345"/>
- <source>Non Pass Phrase</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keygen/KeygenDialog.cpp" line="358"/>
- <source>Basic Information</source>
- <translation type="unfinished"></translation>
- </message>
-</context>
-<context>
- <name>KeyGenPage</name>
- <message>
- <location filename="../../src/ui/Wizard.cpp" line="183"/>
- <source>Create a keypair...</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/Wizard.cpp" line="184"/>
- <source>...for decrypting and signing messages</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/Wizard.cpp" line="185"/>
- <source>You should create a new keypair.The pair consists of a public and a private key.&lt;br&gt;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.&lt;br&gt;For more information have a look at the offline tutorial (which then is shown in the main window):</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/Wizard.cpp" line="192"/>
- <source>Offline tutorial</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/Wizard.cpp" line="199"/>
- <source>Create New Key</source>
- <translation type="unfinished"></translation>
- </message>
-</context>
-<context>
- <name>KeyImportDetailDialog</name>
- <message>
- <location filename="../../src/ui/KeyImportDetailDialog.cpp" line="34"/>
- <location filename="../../src/ui/KeyImportDetailDialog.cpp" line="53"/>
- <source>Key Update Details</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/KeyImportDetailDialog.cpp" line="34"/>
- <source>No keys found</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/KeyImportDetailDialog.cpp" line="36"/>
- <location filename="../../src/ui/KeyImportDetailDialog.cpp" line="55"/>
- <source>Key Import Details</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/KeyImportDetailDialog.cpp" line="36"/>
- <source>No keys found to import</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/KeyImportDetailDialog.cpp" line="64"/>
- <source>General key info</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/KeyImportDetailDialog.cpp" line="67"/>
- <source>Considered:</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/KeyImportDetailDialog.cpp" line="71"/>
- <source>Public unchanged:</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/KeyImportDetailDialog.cpp" line="76"/>
- <source>Imported:</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/KeyImportDetailDialog.cpp" line="81"/>
- <source>Not imported:</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/KeyImportDetailDialog.cpp" line="86"/>
- <source>Private read:</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/KeyImportDetailDialog.cpp" line="91"/>
- <source>Private imported:</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/KeyImportDetailDialog.cpp" line="96"/>
- <source>Private unchanged:</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/KeyImportDetailDialog.cpp" line="111"/>
- <source>Name</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/KeyImportDetailDialog.cpp" line="111"/>
- <source>Email</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/KeyImportDetailDialog.cpp" line="111"/>
- <source>Status</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/KeyImportDetailDialog.cpp" line="111"/>
- <source>Fingerprint</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/KeyImportDetailDialog.cpp" line="135"/>
- <source>private</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/KeyImportDetailDialog.cpp" line="138"/>
- <source>public</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/KeyImportDetailDialog.cpp" line="141"/>
- <source>unchanged</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/KeyImportDetailDialog.cpp" line="144"/>
- <source>new key</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/KeyImportDetailDialog.cpp" line="147"/>
- <source>new subkey</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/KeyImportDetailDialog.cpp" line="151"/>
- <source>new signature</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/KeyImportDetailDialog.cpp" line="155"/>
- <source>new uid</source>
- <translation type="unfinished"></translation>
- </message>
-</context>
-<context>
- <name>KeyList</name>
- <message>
- <location filename="../../src/ui/widgets/KeyList.cpp" line="76"/>
- <source>Select</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/widgets/KeyList.cpp" line="76"/>
- <source>Type</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/widgets/KeyList.cpp" line="76"/>
- <source>Name</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/widgets/KeyList.cpp" line="76"/>
- <source>Email Address</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/widgets/KeyList.cpp" line="77"/>
- <source>Usage</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/widgets/KeyList.cpp" line="77"/>
- <source>Validity</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/widgets/KeyList.cpp" line="77"/>
- <source>Finger Print</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/widgets/KeyList.cpp" line="302"/>
- <source>Import Keys</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/widgets/KeyList.cpp" line="305"/>
- <source>You&apos;ve dropped something on the table.
- GpgFrontend will now try to import key(s).</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/widgets/KeyList.cpp" line="308"/>
- <source>Always import without bothering.</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/widgets/KeyList.cpp" line="341"/>
- <source>Couldn&apos;t Open File: </source>
- <translation type="unfinished"></translation>
- </message>
-</context>
-<context>
- <name>KeyMgmt</name>
- <message>
- <location filename="../../src/ui/KeyMgmt.cpp" line="82"/>
- <source>Key Pair Management</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/KeyMgmt.cpp" line="88"/>
- <source>&amp;Open</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/KeyMgmt.cpp" line="89"/>
- <source>Ctrl+O</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/KeyMgmt.cpp" line="90"/>
- <source>Open Key File</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/KeyMgmt.cpp" line="93"/>
- <source>&amp;Close</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/KeyMgmt.cpp" line="94"/>
- <source>Ctrl+Q</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/KeyMgmt.cpp" line="96"/>
- <source>Close</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/KeyMgmt.cpp" line="99"/>
- <source>New Keypair</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/KeyMgmt.cpp" line="100"/>
- <source>Ctrl+N</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/KeyMgmt.cpp" line="102"/>
- <source>Generate KeyPair</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/KeyMgmt.cpp" line="105"/>
- <source>New Subkey</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/KeyMgmt.cpp" line="106"/>
- <source>Ctrl+Shift+N</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/KeyMgmt.cpp" line="108"/>
- <source>Generate Subkey For Selected KeyPair</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/KeyMgmt.cpp" line="111"/>
- <location filename="../../src/ui/KeyMgmt.cpp" line="151"/>
- <source>&amp;File</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/KeyMgmt.cpp" line="113"/>
- <source>Import New Key From File</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/KeyMgmt.cpp" line="116"/>
- <source>&amp;Clipboard</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/KeyMgmt.cpp" line="118"/>
- <source>Import New Key From Clipboard</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/KeyMgmt.cpp" line="121"/>
- <source>&amp;Keyserver</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/KeyMgmt.cpp" line="123"/>
- <source>Import New Key From Keyserver</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/KeyMgmt.cpp" line="126"/>
- <source>Export To &amp;Clipboard</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/KeyMgmt.cpp" line="128"/>
- <source>Export Selected Key(s) To Clipboard</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/KeyMgmt.cpp" line="131"/>
- <source>Export To &amp;File</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/KeyMgmt.cpp" line="133"/>
- <source>Export Selected Key(s) To File</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/KeyMgmt.cpp" line="136"/>
- <source>Delete Selected Key(s)</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/KeyMgmt.cpp" line="137"/>
- <source>Delete the Selected keys</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/KeyMgmt.cpp" line="140"/>
- <source>Delete Checked Key(s)</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/KeyMgmt.cpp" line="141"/>
- <source>Delete the Checked keys</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/KeyMgmt.cpp" line="145"/>
- <source>Show Key Details</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/KeyMgmt.cpp" line="146"/>
- <source>Show Details for this Key</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/KeyMgmt.cpp" line="155"/>
- <source>&amp;Key</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/KeyMgmt.cpp" line="156"/>
- <source>&amp;Generate Key</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/KeyMgmt.cpp" line="160"/>
- <source>&amp;Import Key</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/KeyMgmt.cpp" line="171"/>
- <source>Key</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/KeyMgmt.cpp" line="179"/>
- <source>Generate</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/KeyMgmt.cpp" line="180"/>
- <source>Generate A New Keypair or Subkey</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/KeyMgmt.cpp" line="189"/>
- <source>Import key</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/KeyMgmt.cpp" line="190"/>
- <source>Import Key</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/KeyMgmt.cpp" line="209"/>
- <source>Open Key</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/KeyMgmt.cpp" line="210"/>
- <location filename="../../src/ui/KeyMgmt.cpp" line="302"/>
- <source>Key Files</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/KeyMgmt.cpp" line="210"/>
- <source>Keyring files</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/KeyMgmt.cpp" line="216"/>
- <source>Couldn&apos;t Open File: </source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/KeyMgmt.cpp" line="262"/>
- <source>Deleting Keys</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/KeyMgmt.cpp" line="263"/>
- <source>Are you sure that you want to delete the following keys?</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/KeyMgmt.cpp" line="265"/>
- <source>The action can not be undone.</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/KeyMgmt.cpp" line="281"/>
- <location filename="../../src/ui/KeyMgmt.cpp" line="296"/>
- <location filename="../../src/ui/KeyMgmt.cpp" line="344"/>
- <source>Error</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/KeyMgmt.cpp" line="281"/>
- <location filename="../../src/ui/KeyMgmt.cpp" line="296"/>
- <location filename="../../src/ui/KeyMgmt.cpp" line="344"/>
- <source>Key Not Found.</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/KeyMgmt.cpp" line="301"/>
- <source>Export Key To File</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/KeyMgmt.cpp" line="312"/>
- <source>key(s) exported</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/KeyMgmt.cpp" line="338"/>
- <location filename="../../src/ui/KeyMgmt.cpp" line="349"/>
- <source>Invalid Operation</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/KeyMgmt.cpp" line="339"/>
- <source>Please select one KeyPair before doing this operation.</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/KeyMgmt.cpp" line="350"/>
- <source>If a key pair does not have a private key then it will not be able to generate sub-keys.</source>
- <translation type="unfinished"></translation>
- </message>
-</context>
-<context>
- <name>KeyNewUIDDialog</name>
- <message>
- <location filename="../../src/ui/keypair_details/KeyNewUIDDialog.cpp" line="40"/>
- <source>Name</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keypair_details/KeyNewUIDDialog.cpp" line="41"/>
- <source>Email</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keypair_details/KeyNewUIDDialog.cpp" line="42"/>
- <source>Comment</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keypair_details/KeyNewUIDDialog.cpp" line="55"/>
- <source>Create New UID</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keypair_details/KeyNewUIDDialog.cpp" line="68"/>
- <source> Name must contain at least five characters.
-</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keypair_details/KeyNewUIDDialog.cpp" line="70"/>
- <source> Please give a email address.
-</source>
- <translation type="unfinished"></translation>
- </message>
-</context>
-<context>
- <name>KeyPairDetailTab</name>
- <message>
- <location filename="../../src/ui/keypair_details/KeyPairDetailTab.cpp" line="34"/>
- <source>Owner</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keypair_details/KeyPairDetailTab.cpp" line="35"/>
- <source>Master Key</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keypair_details/KeyPairDetailTab.cpp" line="36"/>
- <source>Fingerprint</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keypair_details/KeyPairDetailTab.cpp" line="37"/>
- <source>Additional UIDs</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keypair_details/KeyPairDetailTab.cpp" line="58"/>
- <source>Exists</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keypair_details/KeyPairDetailTab.cpp" line="58"/>
- <source>Not Exists</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keypair_details/KeyPairDetailTab.cpp" line="83"/>
- <source>Name:</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keypair_details/KeyPairDetailTab.cpp" line="84"/>
- <source>Email Address:</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keypair_details/KeyPairDetailTab.cpp" line="85"/>
- <source>Comment:</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keypair_details/KeyPairDetailTab.cpp" line="90"/>
- <source>Key ID: </source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keypair_details/KeyPairDetailTab.cpp" line="91"/>
- <source>Algorithm: </source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keypair_details/KeyPairDetailTab.cpp" line="92"/>
- <source>Key Size:</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keypair_details/KeyPairDetailTab.cpp" line="93"/>
- <source>Nominal Usage: </source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keypair_details/KeyPairDetailTab.cpp" line="94"/>
- <source>Actual Usage: </source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keypair_details/KeyPairDetailTab.cpp" line="95"/>
- <source>Expires on: </source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keypair_details/KeyPairDetailTab.cpp" line="96"/>
- <source>Last Update: </source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keypair_details/KeyPairDetailTab.cpp" line="97"/>
- <source>Secret Key Existence: </source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keypair_details/KeyPairDetailTab.cpp" line="121"/>
- <source>Copy</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keypair_details/KeyPairDetailTab.cpp" line="123"/>
- <source>copy fingerprint to clipboard</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keypair_details/KeyPairDetailTab.cpp" line="133"/>
- <source>Operations</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keypair_details/KeyPairDetailTab.cpp" line="136"/>
- <source>Export Private Key (Include Subkey)</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keypair_details/KeyPairDetailTab.cpp" line="141"/>
- <source>Modify Expiration Datetime (Master Key)</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keypair_details/KeyPairDetailTab.cpp" line="146"/>
- <source>Key Server Operation (Pubkey)</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keypair_details/KeyPairDetailTab.cpp" line="149"/>
- <source>Generate Revoke Certificate</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keypair_details/KeyPairDetailTab.cpp" line="174"/>
- <source>Warning: The Master Key has expired.</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keypair_details/KeyPairDetailTab.cpp" line="177"/>
- <source>Warning: The Master Key has been revoked</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keypair_details/KeyPairDetailTab.cpp" line="201"/>
- <source>Exporting private Key</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keypair_details/KeyPairDetailTab.cpp" line="202"/>
- <source>You are about to export your</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keypair_details/KeyPairDetailTab.cpp" line="203"/>
- <source>PRIVATE KEY</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keypair_details/KeyPairDetailTab.cpp" line="204"/>
- <source>This is NOT your Public Key, so DON&apos;T give it away.</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keypair_details/KeyPairDetailTab.cpp" line="205"/>
- <source>Do you REALLY want to export your PRIVATE KEY?</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keypair_details/KeyPairDetailTab.cpp" line="219"/>
- <source>Error</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keypair_details/KeyPairDetailTab.cpp" line="219"/>
- <source>Key Not Found.</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keypair_details/KeyPairDetailTab.cpp" line="224"/>
- <source>Export Key To File</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keypair_details/KeyPairDetailTab.cpp" line="225"/>
- <source>Key Files</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keypair_details/KeyPairDetailTab.cpp" line="228"/>
- <source>Export Error</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keypair_details/KeyPairDetailTab.cpp" line="228"/>
- <source>Couldn&apos;t open %1 for writing</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keypair_details/KeyPairDetailTab.cpp" line="298"/>
- <source>Never Expire</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keypair_details/KeyPairDetailTab.cpp" line="318"/>
- <source>Upload Key Pair to Key Server</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keypair_details/KeyPairDetailTab.cpp" line="320"/>
- <source>Update Key Pair</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keypair_details/KeyPairDetailTab.cpp" line="343"/>
- <source>Generate revocation certificate</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keypair_details/KeyPairDetailTab.cpp" line="346"/>
- <source>Revocation Certificates</source>
- <translation type="unfinished"></translation>
- </message>
-</context>
-<context>
- <name>KeyPairSubkeyTab</name>
- <message>
- <location filename="../../src/ui/keypair_details/KeyPairSubkeyTab.cpp" line="37"/>
- <source>Generate A New Subkey</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keypair_details/KeyPairSubkeyTab.cpp" line="54"/>
- <source>Key ID: </source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keypair_details/KeyPairSubkeyTab.cpp" line="55"/>
- <source>Algorithm: </source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keypair_details/KeyPairSubkeyTab.cpp" line="56"/>
- <source>Key Size:</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keypair_details/KeyPairSubkeyTab.cpp" line="57"/>
- <source>Usage: </source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keypair_details/KeyPairSubkeyTab.cpp" line="58"/>
- <source>Expires On </source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keypair_details/KeyPairSubkeyTab.cpp" line="59"/>
- <source>Last Update: </source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keypair_details/KeyPairSubkeyTab.cpp" line="60"/>
- <source>Existence: </source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keypair_details/KeyPairSubkeyTab.cpp" line="61"/>
- <source>Fingerprint: </source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keypair_details/KeyPairSubkeyTab.cpp" line="121"/>
- <source>Subkey ID</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keypair_details/KeyPairSubkeyTab.cpp" line="121"/>
- <source>Key Size</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keypair_details/KeyPairSubkeyTab.cpp" line="121"/>
- <source>Algo</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keypair_details/KeyPairSubkeyTab.cpp" line="121"/>
- <source>Create Date</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keypair_details/KeyPairSubkeyTab.cpp" line="121"/>
- <source>Expire Date</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keypair_details/KeyPairSubkeyTab.cpp" line="160"/>
- <source>Never Expire</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keypair_details/KeyPairSubkeyTab.cpp" line="184"/>
- <source>Never Expires</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keypair_details/KeyPairSubkeyTab.cpp" line="230"/>
- <source>Edit Expire Date</source>
- <translation type="unfinished"></translation>
- </message>
-</context>
-<context>
- <name>KeyPairUIDTab</name>
- <message>
- <location filename="../../src/ui/keypair_details/KeyPairUIDTab.cpp" line="39"/>
- <source>New UID</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keypair_details/KeyPairUIDTab.cpp" line="40"/>
- <source>UID Management</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keypair_details/KeyPairUIDTab.cpp" line="59"/>
- <source>UIDs</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keypair_details/KeyPairUIDTab.cpp" line="67"/>
- <source>Signature of Selected UID</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keypair_details/KeyPairUIDTab.cpp" line="103"/>
- <source>Select</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keypair_details/KeyPairUIDTab.cpp" line="103"/>
- <location filename="../../src/ui/keypair_details/KeyPairUIDTab.cpp" line="126"/>
- <source>Name</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keypair_details/KeyPairUIDTab.cpp" line="103"/>
- <location filename="../../src/ui/keypair_details/KeyPairUIDTab.cpp" line="126"/>
- <source>Email</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keypair_details/KeyPairUIDTab.cpp" line="103"/>
- <source>Comment</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keypair_details/KeyPairUIDTab.cpp" line="126"/>
- <source>Key ID</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keypair_details/KeyPairUIDTab.cpp" line="126"/>
- <source>Create Date</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keypair_details/KeyPairUIDTab.cpp" line="126"/>
- <source>Expired Date</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keypair_details/KeyPairUIDTab.cpp" line="219"/>
- <source>Never Expires</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keypair_details/KeyPairUIDTab.cpp" line="237"/>
- <location filename="../../src/ui/keypair_details/KeyPairUIDTab.cpp" line="300"/>
- <location filename="../../src/ui/keypair_details/KeyPairUIDTab.cpp" line="425"/>
- <location filename="../../src/ui/keypair_details/KeyPairUIDTab.cpp" line="440"/>
- <location filename="../../src/ui/keypair_details/KeyPairUIDTab.cpp" line="480"/>
- <location filename="../../src/ui/keypair_details/KeyPairUIDTab.cpp" line="487"/>
- <source>Invalid Operation</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keypair_details/KeyPairUIDTab.cpp" line="238"/>
- <location filename="../../src/ui/keypair_details/KeyPairUIDTab.cpp" line="301"/>
- <source>Please select one or more UIDs before doing this operation.</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keypair_details/KeyPairUIDTab.cpp" line="263"/>
- <source>Sign Selected UID(s)</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keypair_details/KeyPairUIDTab.cpp" line="265"/>
- <source>Delete Selected UID(s)</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keypair_details/KeyPairUIDTab.cpp" line="284"/>
- <source>Successful Operation</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keypair_details/KeyPairUIDTab.cpp" line="285"/>
- <source>Successfully added a new UID.</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keypair_details/KeyPairUIDTab.cpp" line="288"/>
- <location filename="../../src/ui/keypair_details/KeyPairUIDTab.cpp" line="330"/>
- <location filename="../../src/ui/keypair_details/KeyPairUIDTab.cpp" line="363"/>
- <location filename="../../src/ui/keypair_details/KeyPairUIDTab.cpp" line="460"/>
- <location filename="../../src/ui/keypair_details/KeyPairUIDTab.cpp" line="507"/>
- <source>Operation Failed</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keypair_details/KeyPairUIDTab.cpp" line="289"/>
- <location filename="../../src/ui/keypair_details/KeyPairUIDTab.cpp" line="331"/>
- <location filename="../../src/ui/keypair_details/KeyPairUIDTab.cpp" line="364"/>
- <location filename="../../src/ui/keypair_details/KeyPairUIDTab.cpp" line="461"/>
- <location filename="../../src/ui/keypair_details/KeyPairUIDTab.cpp" line="508"/>
- <source>An error occurred during the operation.</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keypair_details/KeyPairUIDTab.cpp" line="313"/>
- <source>Deleting UIDs</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keypair_details/KeyPairUIDTab.cpp" line="314"/>
- <source>Are you sure that you want to delete the following uids?</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keypair_details/KeyPairUIDTab.cpp" line="315"/>
- <location filename="../../src/ui/keypair_details/KeyPairUIDTab.cpp" line="357"/>
- <location filename="../../src/ui/keypair_details/KeyPairUIDTab.cpp" line="454"/>
- <location filename="../../src/ui/keypair_details/KeyPairUIDTab.cpp" line="501"/>
- <source>The action can not be undone.</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keypair_details/KeyPairUIDTab.cpp" line="355"/>
- <source>Set Primary UID</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keypair_details/KeyPairUIDTab.cpp" line="356"/>
- <source>Are you sure that you want to set the Primary UID to?</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keypair_details/KeyPairUIDTab.cpp" line="395"/>
- <source>Set As Primary</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keypair_details/KeyPairUIDTab.cpp" line="397"/>
- <source>Sign UID</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keypair_details/KeyPairUIDTab.cpp" line="399"/>
- <source>Delete UID</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keypair_details/KeyPairUIDTab.cpp" line="426"/>
- <location filename="../../src/ui/keypair_details/KeyPairUIDTab.cpp" line="441"/>
- <source>Please select one UID before doing this operation.</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keypair_details/KeyPairUIDTab.cpp" line="452"/>
- <source>Deleting UID</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keypair_details/KeyPairUIDTab.cpp" line="453"/>
- <source>Are you sure that you want to delete the following uid?</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keypair_details/KeyPairUIDTab.cpp" line="469"/>
- <source>Delete(Revoke) Key Signature</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keypair_details/KeyPairUIDTab.cpp" line="481"/>
- <source>Please select one Key Signature before doing this operation.</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keypair_details/KeyPairUIDTab.cpp" line="488"/>
- <source>To delete the signature, you need to have its corresponding public key in the local database.</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keypair_details/KeyPairUIDTab.cpp" line="499"/>
- <source>Deleting Key Signature</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keypair_details/KeyPairUIDTab.cpp" line="500"/>
- <source>Are you sure that you want to delete the following signature?</source>
- <translation type="unfinished"></translation>
- </message>
-</context>
-<context>
- <name>KeyServerImportDialog</name>
- <message>
- <location filename="../../src/ui/KeyServerImportDialog.cpp" line="40"/>
- <source>&amp;Close</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/KeyServerImportDialog.cpp" line="41"/>
- <source>&amp;Import ALL</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/KeyServerImportDialog.cpp" line="42"/>
- <source>&amp;Search</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/KeyServerImportDialog.cpp" line="45"/>
- <source>Search String:</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/KeyServerImportDialog.cpp" line="49"/>
- <source>Key Server:</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/KeyServerImportDialog.cpp" line="97"/>
- <source>Update Keys from Keyserver</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/KeyServerImportDialog.cpp" line="99"/>
- <source>Import Keys from Keyserver</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/KeyServerImportDialog.cpp" line="158"/>
- <source>UID</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/KeyServerImportDialog.cpp" line="158"/>
- <source>Creation date</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/KeyServerImportDialog.cpp" line="158"/>
- <source>KeyID</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/KeyServerImportDialog.cpp" line="158"/>
- <source>Tag</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/KeyServerImportDialog.cpp" line="179"/>
- <source>Text is empty.</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/KeyServerImportDialog.cpp" line="213"/>
- <source>Not Key Found</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/KeyServerImportDialog.cpp" line="216"/>
- <location filename="../../src/ui/KeyServerImportDialog.cpp" line="386"/>
- <source>Timeout</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/KeyServerImportDialog.cpp" line="219"/>
- <location filename="../../src/ui/KeyServerImportDialog.cpp" line="389"/>
- <source>Key Server Not Found</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/KeyServerImportDialog.cpp" line="222"/>
- <location filename="../../src/ui/KeyServerImportDialog.cpp" line="392"/>
- <source>Connection Error</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/KeyServerImportDialog.cpp" line="230"/>
- <source>Too many responses from keyserver!</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/KeyServerImportDialog.cpp" line="237"/>
- <source>No keys found, input may be kexId, retrying search with 0x.</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/KeyServerImportDialog.cpp" line="242"/>
- <source>No keys found containing the search string!</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/KeyServerImportDialog.cpp" line="246"/>
- <source>Insufficiently specific search string!</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/KeyServerImportDialog.cpp" line="274"/>
- <source>revoked</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/KeyServerImportDialog.cpp" line="277"/>
- <source>disabled</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/KeyServerImportDialog.cpp" line="317"/>
- <source>&lt;h4&gt;%1 keys found. Double click a key to import it.&lt;/h4&gt;</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/KeyServerImportDialog.cpp" line="383"/>
- <source>Key Not Found</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/KeyServerImportDialog.cpp" line="410"/>
- <source>&lt;h4&gt;Key Updated&lt;/h4&gt;</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/KeyServerImportDialog.cpp" line="412"/>
- <source>&lt;h4&gt;Key Imported&lt;/h4&gt;</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/KeyServerImportDialog.cpp" line="473"/>
- <source>Upload Keys from Keyserver</source>
- <translation type="unfinished"></translation>
- </message>
-</context>
-<context>
- <name>KeySetExpireDateDialog</name>
- <message>
- <location filename="../../src/ui/keypair_details/KeySetExpireDateDialog.cpp" line="36"/>
- <source>Confirm</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keypair_details/KeySetExpireDateDialog.cpp" line="41"/>
- <source>Never Expire</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keypair_details/KeySetExpireDateDialog.cpp" line="61"/>
- <source>Operation Failed</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keypair_details/KeySetExpireDateDialog.cpp" line="62"/>
- <source>An error occurred during the operation.</source>
- <translation type="unfinished"></translation>
- </message>
-</context>
-<context>
- <name>KeyUIDSignDialog</name>
- <message>
- <location filename="../../src/ui/keypair_details/KeyUIDSignDialog.cpp" line="72"/>
- <source>Expire Date</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keypair_details/KeyUIDSignDialog.cpp" line="81"/>
- <source>Sign For Key&apos;s UID(s)</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keypair_details/KeyUIDSignDialog.cpp" line="99"/>
- <source>Unsuccessful Operation</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keypair_details/KeyUIDSignDialog.cpp" line="100"/>
- <source>Signature operation failed for UID </source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keypair_details/KeyUIDSignDialog.cpp" line="107"/>
- <source>Operation Complete</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keypair_details/KeyUIDSignDialog.cpp" line="108"/>
- <source>The signature operation of the UID is complete</source>
- <translation type="unfinished"></translation>
- </message>
-</context>
-<context>
- <name>KeyUploadDialog</name>
- <message>
- <location filename="../../src/ui/KeyUploadDialog.cpp" line="47"/>
- <source>Uploading Public Key</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/KeyUploadDialog.cpp" line="110"/>
- <source>Key Not Found</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/KeyUploadDialog.cpp" line="113"/>
- <source>Timeout</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/KeyUploadDialog.cpp" line="116"/>
- <source>Key Server Not Found</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/KeyUploadDialog.cpp" line="119"/>
- <source>Connection Error</source>
- <translation type="unfinished"></translation>
- </message>
-</context>
-<context>
- <name>KeyserverTab</name>
- <message>
- <location filename="../../src/ui/settings/SettingsKeyServer.cpp" line="32"/>
- <source>General</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/settings/SettingsKeyServer.cpp" line="53"/>
- <source>No.</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/settings/SettingsKeyServer.cpp" line="53"/>
- <source>Address</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/settings/SettingsKeyServer.cpp" line="53"/>
- <source>Available</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/settings/SettingsKeyServer.cpp" line="57"/>
- <source>Default Key Server for Import:</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/settings/SettingsKeyServer.cpp" line="67"/>
- <source>Add</source>
- <translation type="unfinished"></translation>
- </message>
-</context>
-<context>
- <name>MainWindow</name>
- <message>
- <location filename="../../src/MainWindow.cpp" line="35"/>
- <source>Loading Gnupg</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/MainWindow.cpp" line="62"/>
- <source>ENV Loading Failed</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/MainWindow.cpp" line="63"/>
- <source>Gnupg is not installed correctly, please follow the ReadME instructions to install gnupg and then open GPGFrontend.</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowFileSlotFunction.cpp" line="36"/>
- <location filename="../../src/ui/main_window/MainWindowFileSlotFunction.cpp" line="40"/>
- <location filename="../../src/ui/main_window/MainWindowFileSlotFunction.cpp" line="44"/>
- <location filename="../../src/ui/main_window/MainWindowFileSlotFunction.cpp" line="114"/>
- <location filename="../../src/ui/main_window/MainWindowFileSlotFunction.cpp" line="127"/>
- <location filename="../../src/ui/main_window/MainWindowFileSlotFunction.cpp" line="131"/>
- <location filename="../../src/ui/main_window/MainWindowFileSlotFunction.cpp" line="135"/>
- <location filename="../../src/ui/main_window/MainWindowFileSlotFunction.cpp" line="196"/>
- <location filename="../../src/ui/main_window/MainWindowFileSlotFunction.cpp" line="212"/>
- <location filename="../../src/ui/main_window/MainWindowFileSlotFunction.cpp" line="216"/>
- <location filename="../../src/ui/main_window/MainWindowFileSlotFunction.cpp" line="220"/>
- <location filename="../../src/ui/main_window/MainWindowFileSlotFunction.cpp" line="294"/>
- <location filename="../../src/ui/main_window/MainWindowFileSlotFunction.cpp" line="326"/>
- <location filename="../../src/ui/main_window/MainWindowFileSlotFunction.cpp" line="331"/>
- <location filename="../../src/ui/main_window/MainWindowFileSlotFunction.cpp" line="335"/>
- <location filename="../../src/ui/main_window/MainWindowFileSlotFunction.cpp" line="383"/>
- <location filename="../../src/ui/main_window/MainWindowFileSlotFunction.cpp" line="396"/>
- <location filename="../../src/ui/main_window/MainWindowFileSlotFunction.cpp" line="400"/>
- <location filename="../../src/ui/main_window/MainWindowFileSlotFunction.cpp" line="404"/>
- <location filename="../../src/ui/main_window/MainWindowFileSlotFunction.cpp" line="501"/>
- <location filename="../../src/ui/main_window/MainWindowFileSlotFunction.cpp" line="513"/>
- <location filename="../../src/ui/main_window/MainWindowFileSlotFunction.cpp" line="517"/>
- <location filename="../../src/ui/main_window/MainWindowFileSlotFunction.cpp" line="521"/>
- <location filename="../../src/ui/main_window/MainWindowFileSlotFunction.cpp" line="583"/>
- <location filename="../../src/ui/main_window/MainWindowServerSlotFunction.cpp" line="53"/>
- <location filename="../../src/ui/main_window/MainWindowServerSlotFunction.cpp" line="111"/>
- <location filename="../../src/ui/main_window/MainWindowServerSlotFunction.cpp" line="125"/>
- <location filename="../../src/ui/main_window/MainWindowServerSlotFunction.cpp" line="217"/>
- <location filename="../../src/ui/main_window/MainWindowServerSlotFunction.cpp" line="232"/>
- <location filename="../../src/ui/main_window/MainWindowSlotFunction.cpp" line="521"/>
- <location filename="../../src/ui/main_window/MainWindowSlotFunction.cpp" line="537"/>
- <source>Error</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowFileSlotFunction.cpp" line="36"/>
- <location filename="../../src/ui/main_window/MainWindowFileSlotFunction.cpp" line="127"/>
- <location filename="../../src/ui/main_window/MainWindowFileSlotFunction.cpp" line="212"/>
- <location filename="../../src/ui/main_window/MainWindowFileSlotFunction.cpp" line="396"/>
- <source>Select a file before doing it.</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowFileSlotFunction.cpp" line="40"/>
- <location filename="../../src/ui/main_window/MainWindowFileSlotFunction.cpp" line="131"/>
- <location filename="../../src/ui/main_window/MainWindowFileSlotFunction.cpp" line="216"/>
- <location filename="../../src/ui/main_window/MainWindowFileSlotFunction.cpp" line="400"/>
- <location filename="../../src/ui/main_window/MainWindowFileSlotFunction.cpp" line="517"/>
- <source>No permission to read this file.</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowFileSlotFunction.cpp" line="44"/>
- <location filename="../../src/ui/main_window/MainWindowFileSlotFunction.cpp" line="135"/>
- <location filename="../../src/ui/main_window/MainWindowFileSlotFunction.cpp" line="220"/>
- <location filename="../../src/ui/main_window/MainWindowFileSlotFunction.cpp" line="404"/>
- <location filename="../../src/ui/main_window/MainWindowFileSlotFunction.cpp" line="521"/>
- <source>No permission to create file.</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowFileSlotFunction.cpp" line="49"/>
- <location filename="../../src/ui/main_window/MainWindowFileSlotFunction.cpp" line="150"/>
- <location filename="../../src/ui/main_window/MainWindowFileSlotFunction.cpp" line="226"/>
- <location filename="../../src/ui/main_window/MainWindowFileSlotFunction.cpp" line="409"/>
- <source>Warning</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowFileSlotFunction.cpp" line="50"/>
- <location filename="../../src/ui/main_window/MainWindowFileSlotFunction.cpp" line="151"/>
- <location filename="../../src/ui/main_window/MainWindowFileSlotFunction.cpp" line="227"/>
- <location filename="../../src/ui/main_window/MainWindowFileSlotFunction.cpp" line="410"/>
- <source>The target file already exists, do you need to overwrite it?</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowFileSlotFunction.cpp" line="62"/>
- <location filename="../../src/ui/main_window/MainWindowFileSlotFunction.cpp" line="239"/>
- <location filename="../../src/ui/main_window/MainWindowFileSlotFunction.cpp" line="422"/>
- <location filename="../../src/ui/main_window/MainWindowSlotFunction.cpp" line="45"/>
- <location filename="../../src/ui/main_window/MainWindowSlotFunction.cpp" line="125"/>
- <location filename="../../src/ui/main_window/MainWindowSlotFunction.cpp" line="296"/>
- <source>No Key Selected</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowFileSlotFunction.cpp" line="69"/>
- <location filename="../../src/ui/main_window/MainWindowFileSlotFunction.cpp" line="246"/>
- <location filename="../../src/ui/main_window/MainWindowSlotFunction.cpp" line="52"/>
- <location filename="../../src/ui/main_window/MainWindowSlotFunction.cpp" line="132"/>
- <source>Invalid Operation</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowFileSlotFunction.cpp" line="70"/>
- <location filename="../../src/ui/main_window/MainWindowFileSlotFunction.cpp" line="247"/>
- <location filename="../../src/ui/main_window/MainWindowSlotFunction.cpp" line="53"/>
- <source>The selected key contains a key that does not actually have a encrypt usage.&lt;br/&gt;</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowFileSlotFunction.cpp" line="71"/>
- <location filename="../../src/ui/main_window/MainWindowFileSlotFunction.cpp" line="248"/>
- <location filename="../../src/ui/main_window/MainWindowFileSlotFunction.cpp" line="436"/>
- <location filename="../../src/ui/main_window/MainWindowSlotFunction.cpp" line="54"/>
- <location filename="../../src/ui/main_window/MainWindowSlotFunction.cpp" line="134"/>
- <location filename="../../src/ui/main_window/MainWindowSlotFunction.cpp" line="307"/>
- <source>&lt;br/&gt;For example the Following Key: &lt;br/&gt;</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowFileSlotFunction.cpp" line="91"/>
- <location filename="../../src/ui/main_window/MainWindowSlotFunction.cpp" line="72"/>
- <source>Encrypting</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowFileSlotFunction.cpp" line="114"/>
- <location filename="../../src/ui/main_window/MainWindowFileSlotFunction.cpp" line="196"/>
- <location filename="../../src/ui/main_window/MainWindowFileSlotFunction.cpp" line="294"/>
- <location filename="../../src/ui/main_window/MainWindowFileSlotFunction.cpp" line="383"/>
- <location filename="../../src/ui/main_window/MainWindowFileSlotFunction.cpp" line="501"/>
- <location filename="../../src/ui/main_window/MainWindowFileSlotFunction.cpp" line="583"/>
- <source>An error occurred during operation.</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowFileSlotFunction.cpp" line="268"/>
- <location filename="../../src/ui/main_window/MainWindowSlotFunction.cpp" line="150"/>
- <source>Signing</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowFileSlotFunction.cpp" line="327"/>
- <source>Please select the appropriate target file or signature file. Ensure that both are in this directory.</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowFileSlotFunction.cpp" line="331"/>
- <source>No permission to read target file.</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowFileSlotFunction.cpp" line="335"/>
- <source>No permission to read signature file.</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowFileSlotFunction.cpp" line="353"/>
- <location filename="../../src/ui/main_window/MainWindowSlotFunction.cpp" line="258"/>
- <source>Verifying</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowFileSlotFunction.cpp" line="434"/>
- <location filename="../../src/ui/main_window/MainWindowSlotFunction.cpp" line="305"/>
- <source>Invalid KeyPair</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowFileSlotFunction.cpp" line="435"/>
- <source>The selected keypair cannot be used for signing and encryption at the same time.&lt;br/&gt;</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowFileSlotFunction.cpp" line="446"/>
- <location filename="../../src/ui/main_window/MainWindowFileSlotFunction.cpp" line="453"/>
- <source>Incomplete Operation</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowFileSlotFunction.cpp" line="447"/>
- <source>None of the selected key pairs can provide the encryption function.</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowFileSlotFunction.cpp" line="454"/>
- <source>None of the selected key pairs can provide the signature function.</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowFileSlotFunction.cpp" line="473"/>
- <location filename="../../src/ui/main_window/MainWindowSlotFunction.cpp" line="345"/>
- <source>Encrypting and Signing</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowFileSlotFunction.cpp" line="513"/>
- <source>Select a file(.gpg/.asc) before doing it.</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowFileSlotFunction.cpp" line="551"/>
- <location filename="../../src/ui/main_window/MainWindowSlotFunction.cpp" line="440"/>
- <source>Decrypting and Verifying</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowServerSlotFunction.cpp" line="43"/>
- <location filename="../../src/ui/main_window/MainWindowServerSlotFunction.cpp" line="154"/>
- <source>Invalid Own Key</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowServerSlotFunction.cpp" line="154"/>
- <source>Own Key can not be use to do any operation.</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowServerSlotFunction.cpp" line="54"/>
- <source>Please obtain a Service Token from the server in the settings.</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowServerSlotFunction.cpp" line="44"/>
- <source>Own Key can not be use to do any operation. Please go to the setting interface to select an OwnKey and get a ServiceToken.</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowServerSlotFunction.cpp" line="90"/>
- <source>Getting Cpt From Server</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowServerSlotFunction.cpp" line="112"/>
- <location filename="../../src/ui/main_window/MainWindowServerSlotFunction.cpp" line="218"/>
- <source>The communication content with the server does not meet the requirements</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowServerSlotFunction.cpp" line="125"/>
- <source>Invalid short ciphertext</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowServerSlotFunction.cpp" line="143"/>
- <source>Invalid Service Token</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowServerSlotFunction.cpp" line="144"/>
- <source>Please go to the setting interface to get a ServiceToken.</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowServerSlotFunction.cpp" line="202"/>
- <source>Getting Scpt From Server</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowServerSlotFunction.cpp" line="228"/>
- <source>Notice: Use Decrypt &amp; Verify operation to decrypt this short crypto text.</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowServerSlotFunction.cpp" line="232"/>
- <source>There is a problem with the communication with the server</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowSlotFunction.cpp" line="102"/>
- <location filename="../../src/ui/main_window/MainWindowSlotFunction.cpp" line="394"/>
- <source>Function Disabled</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowSlotFunction.cpp" line="103"/>
- <location filename="../../src/ui/main_window/MainWindowSlotFunction.cpp" line="395"/>
- <source>Please go to the settings interface to enable and configure this function.</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowSlotFunction.cpp" line="133"/>
- <source>The selected key contains a key that does not actually have a signature usage.&lt;br/&gt;</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowSlotFunction.cpp" line="185"/>
- <source>Notice</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowSlotFunction.cpp" line="185"/>
- <source>Short Crypto Text only supports Decrypt &amp; Verify.</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowSlotFunction.cpp" line="199"/>
- <source>Decrypting</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowSlotFunction.cpp" line="306"/>
- <source>The selected keypair cannot be used for encryption.&lt;br/&gt;</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowSlotFunction.cpp" line="355"/>
- <source>Automatic Key Exchange Warning</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowSlotFunction.cpp" line="356"/>
- <source>Part of the automatic key exchange failed, which may be related to your key.</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowSlotFunction.cpp" line="358"/>
- <source>If possible, try to use the RSA algorithm compatible with the server for signing.</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowSlotFunction.cpp" line="401"/>
- <source>Service Token Empty</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowSlotFunction.cpp" line="402"/>
- <source>Please go to the settings interface to set Own Key and get Service Token.</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowSlotFunction.cpp" line="521"/>
- <location filename="../../src/ui/main_window/MainWindowSlotFunction.cpp" line="537"/>
- <source>Key Not Found.</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowSlotFunction.cpp" line="568"/>
- <source>Outdated Version</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowSlotFunction.cpp" line="569"/>
- <source>This version(%1) is out of date, please update the latest version in time. </source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowSlotFunction.cpp" line="571"/>
- <location filename="../../src/ui/main_window/MainWindowSlotFunction.cpp" line="578"/>
- <source>You can download the latest version(%1) on Github Releases Page.&lt;br/&gt;</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowSlotFunction.cpp" line="575"/>
- <source>Unreleased Version</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowSlotFunction.cpp" line="576"/>
- <source>This version(%1) has not been officially released and is not recommended for use in a production environment. &lt;br/&gt;</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowSlotUI.cpp" line="58"/>
- <source>There is one unencrypted file in attachment folder</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowSlotUI.cpp" line="60"/>
- <source>There are </source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowSlotUI.cpp" line="60"/>
- <source> unencrypted files in attachment folder</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowUI.cpp" line="30"/>
- <source>&amp;New</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowUI.cpp" line="36"/>
- <source>Open a new file</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowUI.cpp" line="39"/>
- <source>&amp;Open...</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowUI.cpp" line="42"/>
- <source>Open an existing file</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowUI.cpp" line="45"/>
- <source>&amp;Browser</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowUI.cpp" line="47"/>
- <source>Open a file browser</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowUI.cpp" line="50"/>
- <source>&amp;Save</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowUI.cpp" line="53"/>
- <source>Save the current File</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowUI.cpp" line="56"/>
- <source>Save &amp;As</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowUI.cpp" line="59"/>
- <source>Save the current File as...</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowUI.cpp" line="62"/>
- <source>&amp;Print</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowUI.cpp" line="65"/>
- <source>Print Document</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowUI.cpp" line="68"/>
- <source>&amp;Close</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowUI.cpp" line="70"/>
- <source>Close file</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowUI.cpp" line="73"/>
- <source>&amp;Quit</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowUI.cpp" line="76"/>
- <source>Quit Program</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowUI.cpp" line="81"/>
- <source>&amp;Undo</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowUI.cpp" line="83"/>
- <source>Undo Last Edit Action</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowUI.cpp" line="86"/>
- <source>&amp;Redo</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowUI.cpp" line="88"/>
- <source>Redo Last Edit Action</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowUI.cpp" line="91"/>
- <source>Zoom In</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowUI.cpp" line="95"/>
- <source>Zoom Out</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowUI.cpp" line="99"/>
- <source>&amp;Paste</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowUI.cpp" line="102"/>
- <source>Paste Text From Clipboard</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowUI.cpp" line="105"/>
- <source>Cu&amp;t</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowUI.cpp" line="108"/>
- <source>Cut the current selection&apos;s contents to the clipboard</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowUI.cpp" line="112"/>
- <source>&amp;Copy</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowUI.cpp" line="115"/>
- <source>Copy the current selection&apos;s contents to the clipboard</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowUI.cpp" line="119"/>
- <source>&amp;Quote</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowUI.cpp" line="121"/>
- <source>Quote whole text</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowUI.cpp" line="124"/>
- <source>Select &amp;All</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowUI.cpp" line="127"/>
- <source>Select the whole text</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowUI.cpp" line="130"/>
- <source>&amp;Find</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowUI.cpp" line="132"/>
- <source>Find a word</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowUI.cpp" line="135"/>
- <source>Remove &amp;spacing</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowUI.cpp" line="138"/>
- <source>Remove double linebreaks, e.g. in pasted text from webmailer</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowUI.cpp" line="141"/>
- <source>Se&amp;ttings</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowUI.cpp" line="142"/>
- <source>Open settings dialog</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowUI.cpp" line="148"/>
- <source>&amp;Encrypt</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowUI.cpp" line="151"/>
- <source>Encrypt Message</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowUI.cpp" line="154"/>
- <source>&amp;Encrypt &amp;Sign</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowUI.cpp" line="157"/>
- <source>Encrypt and Sign Message</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowUI.cpp" line="160"/>
- <source>&amp;Decrypt</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowUI.cpp" line="163"/>
- <source>Decrypt Message</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowUI.cpp" line="166"/>
- <source>&amp;Decrypt &amp;Verify</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowUI.cpp" line="169"/>
- <source>Decrypt and Verify Message</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowUI.cpp" line="175"/>
- <source>&amp;Encrypt File</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowUI.cpp" line="176"/>
- <source>Encrypt File</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowUI.cpp" line="179"/>
- <source>&amp;Decrypt File</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowUI.cpp" line="180"/>
- <source>Decrypt File</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowUI.cpp" line="183"/>
- <source>&amp;Sign File</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowUI.cpp" line="184"/>
- <source>Sign File</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowUI.cpp" line="187"/>
- <source>&amp;Verify File</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowUI.cpp" line="188"/>
- <source>Verify File</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowUI.cpp" line="192"/>
- <source>&amp;Sign</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowUI.cpp" line="195"/>
- <source>Sign Message</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowUI.cpp" line="198"/>
- <source>&amp;Verify</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowUI.cpp" line="201"/>
- <source>Verify Message</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowUI.cpp" line="207"/>
- <source>&amp;Editor</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowUI.cpp" line="209"/>
- <source>Import New Key From Editor</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowUI.cpp" line="212"/>
- <source>Manage &amp;Keys</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowUI.cpp" line="214"/>
- <source>Open Keymanagement</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowUI.cpp" line="220"/>
- <source>&amp;About</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowUI.cpp" line="222"/>
- <source>Show the application&apos;s About box</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowUI.cpp" line="228"/>
- <source>&amp;Check for Updates</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowUI.cpp" line="230"/>
- <source>Check for updates</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowUI.cpp" line="233"/>
- <source>Open &amp;Wizard</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowUI.cpp" line="234"/>
- <source>Open the wizard</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowUI.cpp" line="239"/>
- <source>Append Selected Key(s) To Text</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowUI.cpp" line="240"/>
- <source>Append The Selected Keys To Text in Editor</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowUI.cpp" line="243"/>
- <source>Copy Email</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowUI.cpp" line="244"/>
- <source>Copy selected Email to clipboard</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowUI.cpp" line="248"/>
- <source>Show Key Details</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowUI.cpp" line="249"/>
- <source>Show Details for this Key</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowUI.cpp" line="252"/>
- <source>Refresh Key From Key Server</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowUI.cpp" line="253"/>
- <source>Refresh key from default key server</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowUI.cpp" line="256"/>
- <source>Upload Public Key(s) To Server</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowUI.cpp" line="257"/>
- <source>Upload The Selected Public Keys To Server</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowUI.cpp" line="272"/>
- <source>Remove PGP Header</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowUI.cpp" line="275"/>
- <source>Add PGP Header</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowUI.cpp" line="280"/>
- <source>&amp;File</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowUI.cpp" line="293"/>
- <source>&amp;Edit</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowUI.cpp" line="311"/>
- <source>&amp;File...</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowUI.cpp" line="317"/>
- <source>&amp;Crypt</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowUI.cpp" line="328"/>
- <source>&amp;Keys</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowUI.cpp" line="329"/>
- <source>&amp;Import Key</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowUI.cpp" line="338"/>
- <source>&amp;Steganography</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowUI.cpp" line="347"/>
- <source>&amp;View</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowUI.cpp" line="349"/>
- <source>&amp;Help</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowUI.cpp" line="358"/>
- <source>File</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowUI.cpp" line="366"/>
- <source>Crypt</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowUI.cpp" line="376"/>
- <source>Key</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowUI.cpp" line="381"/>
- <source>Edit</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowUI.cpp" line="388"/>
- <source>Special Edit</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowUI.cpp" line="400"/>
- <source>Import key from...</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowUI.cpp" line="401"/>
- <source>Import key</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowUI.cpp" line="409"/>
- <source>Browser to view and operate file</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowUI.cpp" line="410"/>
- <source>Browser</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowUI.cpp" line="428"/>
- <source>Ready</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowUI.cpp" line="435"/>
- <source>Key ToolBox</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowUI.cpp" line="443"/>
- <source>Information Board</source>
- <translation type="unfinished"></translation>
- </message>
-</context>
-<context>
- <name>PubkeyGetter</name>
- <message>
- <location filename="../../src/server/api/PubkeyGetter.cpp" line="66"/>
- <location filename="../../src/server/api/PubkeyGetter.cpp" line="90"/>
- <source>Error</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/server/api/PubkeyGetter.cpp" line="67"/>
- <location filename="../../src/server/api/PubkeyGetter.cpp" line="91"/>
- <source>The communication content with the server does not meet the requirements</source>
- <translation type="unfinished"></translation>
- </message>
-</context>
-<context>
- <name>PubkeyUploader</name>
- <message>
- <location filename="../../src/server/api/PubkeyUploader.cpp" line="95"/>
- <source>Error</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/server/api/PubkeyUploader.cpp" line="96"/>
- <source>The communication content with the server does not meet the requirements</source>
- <translation type="unfinished"></translation>
- </message>
-</context>
-<context>
- <name>QApplication</name>
- <message>
- <location filename="../../src/gpg/result_analyse/DecryptResultAnalyse.cpp" line="66"/>
- <source> {&gt;} Recipient: </source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/gpg/result_analyse/VerifyResultAnalyse.cpp" line="63"/>
- <source>One or More Bad Signatures.</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/gpg/result_analyse/VerifyResultAnalyse.cpp" line="68"/>
- <source>A </source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/gpg/result_analyse/VerifyResultAnalyse.cpp" line="70"/>
- <source>Good </source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/gpg/result_analyse/VerifyResultAnalyse.cpp" line="73"/>
- <source>Bad </source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/gpg/result_analyse/VerifyResultAnalyse.cpp" line="76"/>
- <source>Expired </source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/gpg/result_analyse/VerifyResultAnalyse.cpp" line="79"/>
- <source>Missing Key&apos;s </source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/gpg/result_analyse/VerifyResultAnalyse.cpp" line="82"/>
- <source>Revoked Key&apos;s </source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/gpg/result_analyse/VerifyResultAnalyse.cpp" line="85"/>
- <source>Expired Key&apos;s </source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/gpg/result_analyse/VerifyResultAnalyse.cpp" line="88"/>
- <source>Missing CRL&apos;s </source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/gpg/result_analyse/VerifyResultAnalyse.cpp" line="92"/>
- <source>Signature Fully Valid.</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/gpg/result_analyse/VerifyResultAnalyse.cpp" line="94"/>
- <source>Signature Not Fully Valid.</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/gpg/result_analyse/VerifyResultAnalyse.cpp" line="100"/>
- <source>Key is NOT present with ID 0x</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/gpg/result_analyse/VerifyResultAnalyse.cpp" line="107"/>
- <source>A signature could NOT be verified due to a Missing Key
-</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/gpg/result_analyse/VerifyResultAnalyse.cpp" line="111"/>
- <source>A signature is valid but the key used to verify the signature has been revoked
-</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/gpg/result_analyse/VerifyResultAnalyse.cpp" line="119"/>
- <source>A signature is valid but expired
-</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/gpg/result_analyse/VerifyResultAnalyse.cpp" line="126"/>
- <source>A signature is valid but the key used to verify the signature has expired.
-</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/gpg/result_analyse/VerifyResultAnalyse.cpp" line="133"/>
- <source>There was some other error which prevented the signature verification.
-</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/gpg/result_analyse/VerifyResultAnalyse.cpp" line="139"/>
- <source>Error for key with fingerprint </source>
- <translation type="unfinished"></translation>
- </message>
-</context>
-<context>
- <name>QuitDialog</name>
- <message>
- <location filename="../../src/ui/QuitDialog.cpp" line="29"/>
- <source>Unsaved Files</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/QuitDialog.cpp" line="77"/>
- <source>%1 files contain unsaved information.&lt;br/&gt;Save the changes before closing?</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/QuitDialog.cpp" line="88"/>
- <source>Check the files you want to save:</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/QuitDialog.cpp" line="89"/>
- <source>&lt;b&gt;Note:&lt;/b&gt; If you don&apos;t save these files, all changes are lost.&lt;br/&gt;</source>
- <translation type="unfinished"></translation>
- </message>
-</context>
-<context>
- <name>SendMailDialog</name>
- <message>
- <location filename="../../src/ui/SendMailDialog.cpp" line="35"/>
- <source>Incomplete configuration</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/SendMailDialog.cpp" line="36"/>
- <source>The SMTP address is empty, please go to the setting interface to complete the configuration.</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/SendMailDialog.cpp" line="86"/>
- <source> Recipient cannot be empty
-</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/SendMailDialog.cpp" line="91"/>
- <source> One or more Recipient&apos;s Email Address is invalid
-</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/SendMailDialog.cpp" line="97"/>
- <source> Sender cannot be empty
-</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/SendMailDialog.cpp" line="99"/>
- <source> Sender&apos;s Email Address is invalid
-</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/SendMailDialog.cpp" line="155"/>
- <location filename="../../src/ui/SendMailDialog.cpp" line="160"/>
- <location filename="../../src/ui/SendMailDialog.cpp" line="165"/>
- <source>Fail</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/SendMailDialog.cpp" line="155"/>
- <source>Fail to Connect SMTP Server</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/SendMailDialog.cpp" line="160"/>
- <source>Fail to Login into SMTP Server</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/SendMailDialog.cpp" line="165"/>
- <source>Fail to Send Mail to SMTP Server</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/SendMailDialog.cpp" line="171"/>
- <source>Success</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/SendMailDialog.cpp" line="171"/>
- <source>Succeed in Sending Mail to SMTP Server</source>
- <translation type="unfinished"></translation>
- </message>
-</context>
-<context>
- <name>SendMailTab</name>
- <message>
- <location filename="../../src/ui/settings/SettingsSendMail.cpp" line="33"/>
- <source>Enable</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/settings/SettingsSendMail.cpp" line="51"/>
- <source>Check Connection</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/settings/SettingsSendMail.cpp" line="53"/>
- <source>General</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/settings/SettingsSendMail.cpp" line="54"/>
- <source>Connection</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/settings/SettingsSendMail.cpp" line="55"/>
- <source>Preference</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/settings/SettingsSendMail.cpp" line="61"/>
- <source>SMTP Address</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/settings/SettingsSendMail.cpp" line="63"/>
- <source>Username</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/settings/SettingsSendMail.cpp" line="65"/>
- <source>Password</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/settings/SettingsSendMail.cpp" line="67"/>
- <source>Port</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/settings/SettingsSendMail.cpp" line="69"/>
- <source>Connection Security</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/settings/SettingsSendMail.cpp" line="75"/>
- <source>Default Sender</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/settings/SettingsSendMail.cpp" line="161"/>
- <location filename="../../src/ui/settings/SettingsSendMail.cpp" line="165"/>
- <source>Fail</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/settings/SettingsSendMail.cpp" line="161"/>
- <source>Fail to Connect SMTP Server</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/settings/SettingsSendMail.cpp" line="165"/>
- <source>Fail to Login</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/settings/SettingsSendMail.cpp" line="170"/>
- <source>Success</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/settings/SettingsSendMail.cpp" line="170"/>
- <source>Succeed in connecting and login</source>
- <translation type="unfinished"></translation>
- </message>
-</context>
-<context>
- <name>SettingsDialog</name>
- <message>
- <location filename="../../src/ui/settings/SettingsDialog.cpp" line="39"/>
- <source>General</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/settings/SettingsDialog.cpp" line="40"/>
- <source>Appearance</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/settings/SettingsDialog.cpp" line="41"/>
- <source>Send Mail</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/settings/SettingsDialog.cpp" line="42"/>
- <source>Key Server</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/settings/SettingsDialog.cpp" line="44"/>
- <source>Advanced</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/settings/SettingsDialog.cpp" line="59"/>
- <source>Settings</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/settings/SettingsDialog.cpp" line="105"/>
- <source>System Default</source>
- <translation type="unfinished"></translation>
- </message>
-</context>
-<context>
- <name>SignResultAnalyse</name>
- <message>
- <location filename="../../src/gpg/result_analyse/SignResultAnalyse.cpp" line="31"/>
- <source>[#] Sign Operation </source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/gpg/result_analyse/SignResultAnalyse.cpp" line="34"/>
- <source>[Success]</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/gpg/result_analyse/SignResultAnalyse.cpp" line="36"/>
- <source>[Failed] </source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/gpg/result_analyse/SignResultAnalyse.cpp" line="47"/>
- <source>[&gt;] New Signature: </source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/gpg/result_analyse/SignResultAnalyse.cpp" line="51"/>
- <source> Sign Mode: </source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/gpg/result_analyse/SignResultAnalyse.cpp" line="53"/>
- <source>Normal</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/gpg/result_analyse/SignResultAnalyse.cpp" line="55"/>
- <source>Clear</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/gpg/result_analyse/SignResultAnalyse.cpp" line="57"/>
- <source>Detach</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/gpg/result_analyse/SignResultAnalyse.cpp" line="63"/>
- <location filename="../../src/gpg/result_analyse/SignResultAnalyse.cpp" line="65"/>
- <source> Signer: </source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/gpg/result_analyse/SignResultAnalyse.cpp" line="65"/>
- <source>&lt;unknown&gt;</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/gpg/result_analyse/SignResultAnalyse.cpp" line="67"/>
- <source> Public Key Algo: </source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/gpg/result_analyse/SignResultAnalyse.cpp" line="68"/>
- <source> Hash Algo: </source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/gpg/result_analyse/SignResultAnalyse.cpp" line="69"/>
- <source> Date &amp; Time: </source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/gpg/result_analyse/SignResultAnalyse.cpp" line="81"/>
- <source>Invalid Signers: </source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/gpg/result_analyse/SignResultAnalyse.cpp" line="85"/>
- <source>[&gt;] Signer: </source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/gpg/result_analyse/SignResultAnalyse.cpp" line="86"/>
- <source> Fingerprint: </source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/gpg/result_analyse/SignResultAnalyse.cpp" line="87"/>
- <source> Reason: </source>
- <translation type="unfinished"></translation>
- </message>
-</context>
-<context>
- <name>SignersPicker</name>
- <message>
- <location filename="../../src/ui/widgets/SignersPicker.cpp" line="28"/>
- <source>Confirm</source>
- <translation type="unfinished"></translation>
- </message>
-</context>
-<context>
- <name>SubkeyGenerateDialog</name>
- <message>
- <location filename="../../src/ui/keygen/SubkeyGenerateDialog.cpp" line="47"/>
- <source>Generate New Subkey</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keygen/SubkeyGenerateDialog.cpp" line="62"/>
- <source>Encryption</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keygen/SubkeyGenerateDialog.cpp" line="65"/>
- <source>Signing</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keygen/SubkeyGenerateDialog.cpp" line="68"/>
- <source>Certification</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keygen/SubkeyGenerateDialog.cpp" line="71"/>
- <source>Authentication</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keygen/SubkeyGenerateDialog.cpp" line="115"/>
- <source>Expiration Date:</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keygen/SubkeyGenerateDialog.cpp" line="116"/>
- <source>Never Expire</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keygen/SubkeyGenerateDialog.cpp" line="117"/>
- <source>KeySize (in Bit):</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keygen/SubkeyGenerateDialog.cpp" line="118"/>
- <source>Key Type:</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keygen/SubkeyGenerateDialog.cpp" line="127"/>
- <source>Basic Information</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keygen/SubkeyGenerateDialog.cpp" line="215"/>
- <source> Expiration time no more than 2 years. </source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keygen/SubkeyGenerateDialog.cpp" line="244"/>
- <source>Success</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keygen/SubkeyGenerateDialog.cpp" line="244"/>
- <source>The new subkey has been generated.</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keygen/SubkeyGenerateDialog.cpp" line="247"/>
- <source>Failure</source>
- <translation type="unfinished"></translation>
- </message>
-</context>
-<context>
- <name>TextEdit</name>
- <message>
- <location filename="../../src/ui/widgets/TextEdit.cpp" line="53"/>
- <source>untitled</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/widgets/TextEdit.cpp" line="120"/>
- <location filename="../../src/ui/widgets/TextEdit.cpp" line="200"/>
- <source>Warning</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/widgets/TextEdit.cpp" line="121"/>
- <location filename="../../src/ui/widgets/TextEdit.cpp" line="201"/>
- <location filename="../../src/ui/widgets/TextEdit.cpp" line="482"/>
- <source>Cannot read file %1:
-%2.</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/widgets/TextEdit.cpp" line="175"/>
- <source>Open file</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/widgets/TextEdit.cpp" line="251"/>
- <source>File</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/widgets/TextEdit.cpp" line="252"/>
- <source>Cannot write file %1:
-%2.</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/widgets/TextEdit.cpp" line="270"/>
- <source>Save file</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/widgets/TextEdit.cpp" line="333"/>
- <source>Unsaved document</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/widgets/TextEdit.cpp" line="334"/>
- <source>The document &quot;%1&quot; has been modified. Do you want to save your changes?&lt;br/&gt;</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/widgets/TextEdit.cpp" line="337"/>
- <source>&lt;b&gt;Note:&lt;/b&gt; If you don&apos;t save these files, all changes are lost.&lt;br/&gt;</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/widgets/TextEdit.cpp" line="481"/>
- <source>Application</source>
- <translation type="unfinished"></translation>
- </message>
-</context>
-<context>
- <name>UpdateTab</name>
- <message>
- <location filename="../../src/ui/help/AboutDialog.cpp" line="129"/>
- <source>It is recommended that you always check the version of GpgFrontend and upgrade to the latest version.</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/help/AboutDialog.cpp" line="131"/>
- <source>New versions not only represent new features, but also often represent functional and security fixes.</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/help/AboutDialog.cpp" line="135"/>
- <source>Current Version: </source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/help/AboutDialog.cpp" line="143"/>
- <source>The current version is inconsistent with the latest version on github.</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/help/AboutDialog.cpp" line="145"/>
- <source>Please click &lt;a href=&quot;https://github.com/saturneric/GpgFrontend/releases&quot;&gt;here&lt;/a&gt; to download the latest version.</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/help/AboutDialog.cpp" line="199"/>
- <location filename="../../src/ui/help/AboutDialog.cpp" line="214"/>
- <source>Latest Version From Github: </source>
- <translation type="unfinished"></translation>
- </message>
-</context>
-<context>
- <name>VerifyDetailsDialog</name>
- <message>
- <location filename="../../src/ui/VerifyDetailsDialog.cpp" line="32"/>
- <source>Signature Details</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/VerifyDetailsDialog.cpp" line="53"/>
- <source>Status: </source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/VerifyDetailsDialog.cpp" line="56"/>
- <source>No valid input found</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/VerifyDetailsDialog.cpp" line="67"/>
- <source>Error Validating signature</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/VerifyDetailsDialog.cpp" line="70"/>
- <source>File was signed on %1 &lt;br/&gt; It Contains:&lt;br/&gt;&lt;br/&gt;</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/VerifyDetailsDialog.cpp" line="72"/>
- <source>Signed on %1 &lt;br/&gt; It Contains:&lt;br /&gt;&lt;br/&gt;</source>
- <translation type="unfinished"></translation>
- </message>
-</context>
-<context>
- <name>VerifyKeyDetailBox</name>
- <message>
- <location filename="../../src/ui/widgets/VerifyKeyDetailBox.cpp" line="36"/>
- <source>Import from keyserver</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/widgets/VerifyKeyDetailBox.cpp" line="39"/>
- <source>Key not present with id 0x</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/widgets/VerifyKeyDetailBox.cpp" line="43"/>
- <source>Status:</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/widgets/VerifyKeyDetailBox.cpp" line="45"/>
- <source>Key not present in keylist</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/widgets/VerifyKeyDetailBox.cpp" line="58"/>
- <location filename="../../src/ui/widgets/VerifyKeyDetailBox.cpp" line="72"/>
- <location filename="../../src/ui/widgets/VerifyKeyDetailBox.cpp" line="86"/>
- <location filename="../../src/ui/widgets/VerifyKeyDetailBox.cpp" line="101"/>
- <location filename="../../src/ui/widgets/VerifyKeyDetailBox.cpp" line="115"/>
- <location filename="../../src/ui/widgets/VerifyKeyDetailBox.cpp" line="129"/>
- <source>Key Information is NOT Available</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/widgets/VerifyKeyDetailBox.cpp" line="60"/>
- <location filename="../../src/ui/widgets/VerifyKeyDetailBox.cpp" line="74"/>
- <location filename="../../src/ui/widgets/VerifyKeyDetailBox.cpp" line="88"/>
- <location filename="../../src/ui/widgets/VerifyKeyDetailBox.cpp" line="103"/>
- <location filename="../../src/ui/widgets/VerifyKeyDetailBox.cpp" line="117"/>
- <location filename="../../src/ui/widgets/VerifyKeyDetailBox.cpp" line="131"/>
- <source>Fingerprint: </source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/widgets/VerifyKeyDetailBox.cpp" line="67"/>
- <source>Status: Cert Revoked</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/widgets/VerifyKeyDetailBox.cpp" line="81"/>
- <location filename="../../src/ui/widgets/VerifyKeyDetailBox.cpp" line="95"/>
- <source>Status: Signature Expired</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/widgets/VerifyKeyDetailBox.cpp" line="96"/>
- <source>Status: Key Expired</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/widgets/VerifyKeyDetailBox.cpp" line="110"/>
- <source>Status: General Error</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/widgets/VerifyKeyDetailBox.cpp" line="124"/>
- <source>Status: Unknown Error</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/widgets/VerifyKeyDetailBox.cpp" line="159"/>
- <source>Signer Name:</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/widgets/VerifyKeyDetailBox.cpp" line="160"/>
- <source>Signer Email:</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/widgets/VerifyKeyDetailBox.cpp" line="161"/>
- <source>Key&apos;s Fingerprint:</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/widgets/VerifyKeyDetailBox.cpp" line="162"/>
- <source>Valid:</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/widgets/VerifyKeyDetailBox.cpp" line="163"/>
- <source>Flags:</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/widgets/VerifyKeyDetailBox.cpp" line="171"/>
- <source>Fully Valid</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/widgets/VerifyKeyDetailBox.cpp" line="173"/>
- <source>NOT Fully Valid</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/widgets/VerifyKeyDetailBox.cpp" line="180"/>
- <source>Good </source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/widgets/VerifyKeyDetailBox.cpp" line="183"/>
- <source>Bad </source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/widgets/VerifyKeyDetailBox.cpp" line="186"/>
- <source>Expired </source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/widgets/VerifyKeyDetailBox.cpp" line="189"/>
- <source>Missing Key </source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/widgets/VerifyKeyDetailBox.cpp" line="192"/>
- <source>Revoked Key </source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/widgets/VerifyKeyDetailBox.cpp" line="195"/>
- <source>Expired Key </source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/widgets/VerifyKeyDetailBox.cpp" line="198"/>
- <source>Missing CRL </source>
- <translation type="unfinished"></translation>
- </message>
-</context>
-<context>
- <name>VerifyResultAnalyse</name>
- <message>
- <location filename="../../src/gpg/result_analyse/VerifyResultAnalyse.cpp" line="33"/>
- <source>[#] Verify Operation </source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/gpg/result_analyse/VerifyResultAnalyse.cpp" line="36"/>
- <source>[Success]</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/gpg/result_analyse/VerifyResultAnalyse.cpp" line="38"/>
- <source>[Failed] </source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/gpg/result_analyse/VerifyResultAnalyse.cpp" line="157"/>
- <location filename="../../src/gpg/result_analyse/VerifyResultAnalyse.cpp" line="161"/>
- <source> Signed By: </source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/gpg/result_analyse/VerifyResultAnalyse.cpp" line="157"/>
- <source>&lt;unknown&gt;</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/gpg/result_analyse/VerifyResultAnalyse.cpp" line="163"/>
- <source> Public Key Algo: </source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/gpg/result_analyse/VerifyResultAnalyse.cpp" line="164"/>
- <source> Hash Algo: </source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/gpg/result_analyse/VerifyResultAnalyse.cpp" line="165"/>
- <source> Date &amp; Time: </source>
- <translation type="unfinished"></translation>
- </message>
-</context>
-<context>
- <name>Wizard</name>
- <message>
- <location filename="../../src/ui/Wizard.cpp" line="40"/>
- <source>First Start Wizard</source>
- <translation type="unfinished"></translation>
- </message>
-</context>
-</TS>
diff --git a/resource/ts/gpgfrontend_fr.ts b/resource/ts/gpgfrontend_fr.ts
deleted file mode 100644
index 3b711b97..00000000
--- a/resource/ts/gpgfrontend_fr.ts
+++ /dev/null
@@ -1,3854 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!DOCTYPE TS>
-<TS version="2.1" language="fr_FR">
-<context>
- <name>AboutDialog</name>
- <message>
- <location filename="../../src/ui/help/AboutDialog.cpp" line="35"/>
- <source>About </source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/help/AboutDialog.cpp" line="42"/>
- <source>General</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/help/AboutDialog.cpp" line="43"/>
- <source>Translators</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/help/AboutDialog.cpp" line="44"/>
- <source>Update</source>
- <translation type="unfinished"></translation>
- </message>
-</context>
-<context>
- <name>AdvancedTab</name>
- <message>
- <location filename="../../src/ui/settings/SettingsAdvanced.cpp" line="34"/>
- <source>Show Steganography Options</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/settings/SettingsAdvanced.cpp" line="36"/>
- <source>Show Steganographic Options.</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/settings/SettingsAdvanced.cpp" line="40"/>
- <source>Pubkey Exchange</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/settings/SettingsAdvanced.cpp" line="42"/>
- <source>Auto Pubkey Exchange</source>
- <translation type="unfinished"></translation>
- </message>
-</context>
-<context>
- <name>AppearanceTab</name>
- <message>
- <location filename="../../src/ui/settings/SettingsAppearance.cpp" line="34"/>
- <source>Iconsize</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/settings/SettingsAppearance.cpp" line="36"/>
- <source>small</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/settings/SettingsAppearance.cpp" line="37"/>
- <source>medium</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/settings/SettingsAppearance.cpp" line="38"/>
- <source>large</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/settings/SettingsAppearance.cpp" line="54"/>
- <source>Iconstyle</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/settings/SettingsAppearance.cpp" line="56"/>
- <source>just text</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/settings/SettingsAppearance.cpp" line="57"/>
- <source>just icons</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/settings/SettingsAppearance.cpp" line="58"/>
- <source>text and icons</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/settings/SettingsAppearance.cpp" line="74"/>
- <source>Windowstate</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/settings/SettingsAppearance.cpp" line="77"/>
- <source>Save window size and position on exit.</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/settings/SettingsAppearance.cpp" line="85"/>
- <source>Information Board</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/settings/SettingsAppearance.cpp" line="91"/>
- <source> Front Size</source>
- <translation type="unfinished"></translation>
- </message>
-</context>
-<context>
- <name>ChoosePage</name>
- <message>
- <location filename="../../src/ui/Wizard.cpp" line="121"/>
- <source>Choose your action...</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/Wizard.cpp" line="122"/>
- <source>...by clicking on the appropriate link.</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/Wizard.cpp" line="124"/>
- <source>If you have never used GPGFrontend before and also don&apos;t own a gpg key yet you may possibly want to read how to</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/Wizard.cpp" line="127"/>
- <source>Generate Key</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/Wizard.cpp" line="134"/>
- <source>If you want to learn how to encrypt, decrypt, sign and verify text, you can read </source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/Wizard.cpp" line="136"/>
- <source>Encrypt &amp; Decrypt Text</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/Wizard.cpp" line="136"/>
- <location filename="../../src/ui/Wizard.cpp" line="149"/>
- <source>or</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/Wizard.cpp" line="138"/>
- <source>Sign &amp; Verify Text</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/Wizard.cpp" line="146"/>
- <source>If you want to operate file, you can read </source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/Wizard.cpp" line="149"/>
- <source>Encrypt &amp; Sign File</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/Wizard.cpp" line="152"/>
- <source>Sign &amp; Verify File</source>
- <translation type="unfinished"></translation>
- </message>
-</context>
-<context>
- <name>ComUtils</name>
- <message>
- <location filename="../../src/server/ComUtils.cpp" line="35"/>
- <location filename="../../src/server/ComUtils.cpp" line="55"/>
- <source>Error</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/server/ComUtils.cpp" line="35"/>
- <source>Nothing Reply. Please check the Internet connection.</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/server/ComUtils.cpp" line="55"/>
- <source>Unknown Error</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/server/ComUtils.cpp" line="75"/>
- <location filename="../../src/server/ComUtils.cpp" line="90"/>
- <source>Network Error</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/server/ComUtils.cpp" line="75"/>
- <source>Outdated Reply</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/server/ComUtils.cpp" line="87"/>
- <source>Unknown Reason</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/server/ComUtils.cpp" line="90"/>
- <source>Unknown Reply Format</source>
- <translation type="unfinished"></translation>
- </message>
-</context>
-<context>
- <name>ConclusionPage</name>
- <message>
- <location filename="../../src/ui/Wizard.cpp" line="224"/>
- <source>Ready.</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/Wizard.cpp" line="225"/>
- <source>Have fun with GPGFrontend!</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/Wizard.cpp" line="227"/>
- <source>You are ready to use GPGFrontend now.&lt;br&gt;&lt;br&gt;</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/Wizard.cpp" line="229"/>
- <source>The Online Document</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/Wizard.cpp" line="231"/>
- <source> will get you started with GPGFrontend. It will open in the main window.&lt;br&gt;</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/Wizard.cpp" line="238"/>
- <source>Open offline help.</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/Wizard.cpp" line="241"/>
- <source>Dont show the wizard again.</source>
- <translation type="unfinished"></translation>
- </message>
-</context>
-<context>
- <name>DecryptResultAnalyse</name>
- <message>
- <location filename="../../src/gpg/result_analyse/DecryptResultAnalyse.cpp" line="30"/>
- <source>[#] Decrypt Operation </source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/gpg/result_analyse/DecryptResultAnalyse.cpp" line="33"/>
- <source>[Success]</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/gpg/result_analyse/DecryptResultAnalyse.cpp" line="35"/>
- <source>[Failed] </source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/gpg/result_analyse/DecryptResultAnalyse.cpp" line="39"/>
- <source>Unsupported Algo: </source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/gpg/result_analyse/DecryptResultAnalyse.cpp" line="46"/>
- <source>File Name: </source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/gpg/result_analyse/DecryptResultAnalyse.cpp" line="52"/>
- <source>Recipient(s): </source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/gpg/result_analyse/DecryptResultAnalyse.cpp" line="82"/>
- <source> Keu ID: </source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/gpg/result_analyse/DecryptResultAnalyse.cpp" line="83"/>
- <source> Public Algo: </source>
- <translation type="unfinished"></translation>
- </message>
-</context>
-<context>
- <name>EncryptResultAnalyse</name>
- <message>
- <location filename="../../src/gpg/result_analyse/EncryptResultAnalyse.cpp" line="43"/>
- <source>Invalid Recipients: </source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/gpg/result_analyse/EncryptResultAnalyse.cpp" line="46"/>
- <source>Fingerprint: </source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/gpg/result_analyse/EncryptResultAnalyse.cpp" line="47"/>
- <source>Reason: </source>
- <translation type="unfinished"></translation>
- </message>
-</context>
-<context>
- <name>FileEncryptionDialog</name>
- <message>
- <location filename="../../src/ui/FileEncryptionDialog.cpp" line="32"/>
- <source>Decrypt File</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/FileEncryptionDialog.cpp" line="34"/>
- <source>Encrypt File</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/FileEncryptionDialog.cpp" line="36"/>
- <source>Sign File</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/FileEncryptionDialog.cpp" line="38"/>
- <source>Verify File</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/FileEncryptionDialog.cpp" line="47"/>
- <source>Input Parameters</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/FileEncryptionDialog.cpp" line="53"/>
- <source>Target File</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/FileEncryptionDialog.cpp" line="59"/>
- <source>Output File</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/FileEncryptionDialog.cpp" line="75"/>
- <source>Signature File(.sig) Path</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/FileEncryptionDialog.cpp" line="134"/>
- <location filename="../../src/ui/FileEncryptionDialog.cpp" line="177"/>
- <source>Open File</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/FileEncryptionDialog.cpp" line="165"/>
- <source>Save File</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/FileEncryptionDialog.cpp" line="194"/>
- <location filename="../../src/ui/FileEncryptionDialog.cpp" line="245"/>
- <source>Couldn&apos;t open file</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/FileEncryptionDialog.cpp" line="213"/>
- <location filename="../../src/ui/FileEncryptionDialog.cpp" line="224"/>
- <location filename="../../src/ui/FileEncryptionDialog.cpp" line="235"/>
- <source>Error</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/FileEncryptionDialog.cpp" line="214"/>
- <source>Error Occurred During Encryption</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/FileEncryptionDialog.cpp" line="225"/>
- <source>Error Occurred During Decryption</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/FileEncryptionDialog.cpp" line="236"/>
- <source>Error Occurred During Signature</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/FileEncryptionDialog.cpp" line="259"/>
- <location filename="../../src/ui/FileEncryptionDialog.cpp" line="268"/>
- <source>File</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/FileEncryptionDialog.cpp" line="260"/>
- <source>File exists! Do you want to overwrite it?</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/FileEncryptionDialog.cpp" line="269"/>
- <source>Cannot write file %1:
-%2.</source>
- <translation type="unfinished"></translation>
- </message>
-</context>
-<context>
- <name>FilePage</name>
- <message>
- <location filename="../../src/ui/widgets/FilePage.cpp" line="161"/>
- <source>Open</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/widgets/FilePage.cpp" line="163"/>
- <source>Delete</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/widgets/FilePage.cpp" line="165"/>
- <source>Encrypt and Sign</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/widgets/FilePage.cpp" line="167"/>
- <source>Decrypt and Verify</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/widgets/FilePage.cpp" line="169"/>
- <source>Only Sign</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/widgets/FilePage.cpp" line="171"/>
- <source>Only Verify</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/widgets/FilePage.cpp" line="222"/>
- <source>Warning</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/widgets/FilePage.cpp" line="223"/>
- <source>Are you sure you want to delete it?</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/widgets/FilePage.cpp" line="233"/>
- <source>Error</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/widgets/FilePage.cpp" line="234"/>
- <source>Unable to delete the file or folder.</source>
- <translation type="unfinished"></translation>
- </message>
-</context>
-<context>
- <name>FindWidget</name>
- <message>
- <location filename="../../src/ui/FindWidget.cpp" line="38"/>
- <source>Find:</source>
- <translation type="unfinished"></translation>
- </message>
-</context>
-<context>
- <name>GeneralTab</name>
- <message>
- <location filename="../../src/ui/settings/SettingsGeneral.cpp" line="40"/>
- <source>GpgFrontend Server</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/settings/SettingsGeneral.cpp" line="45"/>
- <source>Server that provides short key and key exchange services</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/settings/SettingsGeneral.cpp" line="52"/>
- <source>Save Checked Keys</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/settings/SettingsGeneral.cpp" line="55"/>
- <source>Save checked private keys on exit and restore them on next start.</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/settings/SettingsGeneral.cpp" line="64"/>
- <source>Confirm drag&apos;n&apos;drop key import</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/settings/SettingsGeneral.cpp" line="67"/>
- <source>Import files dropped on the keylist without confirmation.</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/settings/SettingsGeneral.cpp" line="74"/>
- <source>Language</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/settings/SettingsGeneral.cpp" line="83"/>
- <source>&lt;b&gt;NOTE: &lt;/b&gt; GpgFrontend will restart automatically if you change the language!</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/settings/SettingsGeneral.cpp" line="92"/>
- <source>Own key</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/settings/SettingsGeneral.cpp" line="96"/>
- <source>Get Service Token</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/settings/SettingsGeneral.cpp" line="97"/>
- <location filename="../../src/ui/settings/SettingsGeneral.cpp" line="235"/>
- <source>No Service Token Found</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/settings/SettingsGeneral.cpp" line="104"/>
- <source>&lt;none&gt;</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/settings/SettingsGeneral.cpp" line="121"/>
- <source>Key pair for synchronization and identity authentication</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/settings/SettingsGeneral.cpp" line="253"/>
- <source>Invalid Operation</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/settings/SettingsGeneral.cpp" line="254"/>
- <source>Own Key can not be None while getting service token.</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/settings/SettingsGeneral.cpp" line="266"/>
- <location filename="../../src/ui/settings/SettingsGeneral.cpp" line="337"/>
- <location filename="../../src/ui/settings/SettingsGeneral.cpp" line="354"/>
- <source>Error</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/settings/SettingsGeneral.cpp" line="267"/>
- <source>Key Not Exists</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/settings/SettingsGeneral.cpp" line="338"/>
- <source>The communication content with the server does not meet the requirements</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/settings/SettingsGeneral.cpp" line="351"/>
- <source>Notice</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/settings/SettingsGeneral.cpp" line="352"/>
- <source>Succeed in getting service token</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/settings/SettingsGeneral.cpp" line="354"/>
- <source>There is a problem with the communication with the server</source>
- <translation type="unfinished"></translation>
- </message>
-</context>
-<context>
- <name>GpgME::GpgContext</name>
- <message>
- <location filename="../../src/gpg/gpg_context/GpgContext.cpp" line="182"/>
- <source>Wrong password</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/gpg/gpg_context/GpgContext.cpp" line="190"/>
- <source>Enter Password for</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/gpg/gpg_context/GpgContext.cpp" line="194"/>
- <source>Enter Password</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/gpg/gpg_context/GpgContext.cpp" line="256"/>
- <source>Processing</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/gpg/gpg_context/GpgContextBasicOpera.cpp" line="169"/>
- <source>Key Selection</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/gpg/gpg_context/GpgContextBasicOpera.cpp" line="169"/>
- <source>No Private Key Selected</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/gpg/gpg_context/GpgContextBasicOpera.cpp" line="200"/>
- <source>Error in signing:</source>
- <translation type="unfinished"></translation>
- </message>
-</context>
-<context>
- <name>GpgPathsTab</name>
- <message>
- <location filename="../../src/ui/settings/SettingsDialog.cpp" line="139"/>
- <source>Relative path to keydb</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/settings/SettingsDialog.cpp" line="152"/>
- <source>Current keydb path: </source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/settings/SettingsDialog.cpp" line="157"/>
- <source>&lt;b&gt;NOTE: &lt;/b&gt; Gpg4usb will restart automatically if you change the keydb path!</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/settings/SettingsDialog.cpp" line="186"/>
- <source>Choose keydb directory</source>
- <translation type="unfinished"></translation>
- </message>
-</context>
-<context>
- <name>InfoBoardWidget</name>
- <message>
- <location filename="../../src/ui/widgets/InfoBoardWidget.cpp" line="40"/>
- <source>Import missing key from Keyserver</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/widgets/InfoBoardWidget.cpp" line="57"/>
- <source>Optional Actions</source>
- <translation type="unfinished"></translation>
- </message>
-</context>
-<context>
- <name>InfoTab</name>
- <message>
- <location filename="../../src/ui/help/AboutDialog.cpp" line="76"/>
- <source>&lt;br&gt;&lt;center&gt;GPGFrontend is an easy-to-use, compact, cross-platform, &lt;br&gt;and installation-free gpg front-end tool.&lt;br&gt;It visualizes most of the common operations of gpg commands.&lt;br&gt;It&apos;s licensed under the GPL v3&lt;br&gt;&lt;br&gt;&lt;b&gt;Developer:&lt;/b&gt;&lt;br&gt;Saturneric&lt;br&gt;&lt;br&gt;If you have any questions or suggestions, raise an issue&lt;br/&gt;at &lt;a href=&quot;https://github.com/saturneric/GpgFrontend&quot;&gt;GitHub&lt;/a&gt; or send a mail to my mailing list at &lt;a href=&quot;mailto:[email protected]&quot;&gt;[email protected]&lt;/a&gt;.</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/help/AboutDialog.cpp" line="84"/>
- <source>&lt;br&gt;&lt;br&gt; Built with Qt </source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/help/AboutDialog.cpp" line="85"/>
- <source> and GPGME </source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/help/AboutDialog.cpp" line="86"/>
- <source>&lt;br&gt;Built at </source>
- <translation type="unfinished"></translation>
- </message>
-</context>
-<context>
- <name>IntroPage</name>
- <message>
- <location filename="../../src/ui/Wizard.cpp" line="66"/>
- <source>Getting Started...</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/Wizard.cpp" line="67"/>
- <source>... with GPGFrontend</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/Wizard.cpp" line="69"/>
- <source>Welcome to use GPGFrontend for decrypting and signing text or file!</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/Wizard.cpp" line="71"/>
- <source>is a Powerful, Easy-to-Use, Compact, Cross-Platform, and Installation-Free OpenPGP Crypto Tool.</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/Wizard.cpp" line="72"/>
- <source>For brief information have a look at the</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/Wizard.cpp" line="74"/>
- <source>Overview</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/Wizard.cpp" line="75"/>
- <source>by clicking the link, the page will open in the web browser</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/Wizard.cpp" line="83"/>
- <source>Choose a Language</source>
- <translation type="unfinished"></translation>
- </message>
-</context>
-<context>
- <name>KeyDetailsDialog</name>
- <message>
- <location filename="../../src/ui/keypair_details/KeyDetailsDialog.cpp" line="31"/>
- <source>KeyPair</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keypair_details/KeyDetailsDialog.cpp" line="32"/>
- <source>UIDs</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keypair_details/KeyDetailsDialog.cpp" line="33"/>
- <source>Subkeys</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keypair_details/KeyDetailsDialog.cpp" line="40"/>
- <source>Key Details</source>
- <translation type="unfinished"></translation>
- </message>
-</context>
-<context>
- <name>KeyGenDialog</name>
- <message>
- <location filename="../../src/ui/keygen/KeygenDialog.cpp" line="33"/>
- <source>Generate Key</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keygen/KeygenDialog.cpp" line="69"/>
- <source> Name must contain at least five characters.
-</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keygen/KeygenDialog.cpp" line="71"/>
- <source> Please give a email address.
-</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keygen/KeygenDialog.cpp" line="78"/>
- <source> Expiration time no more than 2 years.
-</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keygen/KeygenDialog.cpp" line="112"/>
- <source>Success</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keygen/KeygenDialog.cpp" line="112"/>
- <source>The new key pair has been generated.</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keygen/KeygenDialog.cpp" line="116"/>
- <source>Failure</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keygen/KeygenDialog.cpp" line="145"/>
- <source>Key Usage</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keygen/KeygenDialog.cpp" line="147"/>
- <source>Encryption</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keygen/KeygenDialog.cpp" line="150"/>
- <source>Signing</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keygen/KeygenDialog.cpp" line="153"/>
- <source>Certification</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keygen/KeygenDialog.cpp" line="156"/>
- <source>Authentication</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keygen/KeygenDialog.cpp" line="338"/>
- <source>Name:</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keygen/KeygenDialog.cpp" line="339"/>
- <source>Email Address:</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keygen/KeygenDialog.cpp" line="340"/>
- <source>Comment:</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keygen/KeygenDialog.cpp" line="341"/>
- <source>Expiration Date:</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keygen/KeygenDialog.cpp" line="342"/>
- <source>Never Expire</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keygen/KeygenDialog.cpp" line="343"/>
- <source>KeySize (in Bit):</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keygen/KeygenDialog.cpp" line="344"/>
- <source>Key Type:</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keygen/KeygenDialog.cpp" line="345"/>
- <source>Non Pass Phrase</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keygen/KeygenDialog.cpp" line="358"/>
- <source>Basic Information</source>
- <translation type="unfinished"></translation>
- </message>
-</context>
-<context>
- <name>KeyGenPage</name>
- <message>
- <location filename="../../src/ui/Wizard.cpp" line="183"/>
- <source>Create a keypair...</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/Wizard.cpp" line="184"/>
- <source>...for decrypting and signing messages</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/Wizard.cpp" line="185"/>
- <source>You should create a new keypair.The pair consists of a public and a private key.&lt;br&gt;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.&lt;br&gt;For more information have a look at the offline tutorial (which then is shown in the main window):</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/Wizard.cpp" line="192"/>
- <source>Offline tutorial</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/Wizard.cpp" line="199"/>
- <source>Create New Key</source>
- <translation type="unfinished"></translation>
- </message>
-</context>
-<context>
- <name>KeyImportDetailDialog</name>
- <message>
- <location filename="../../src/ui/KeyImportDetailDialog.cpp" line="34"/>
- <location filename="../../src/ui/KeyImportDetailDialog.cpp" line="53"/>
- <source>Key Update Details</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/KeyImportDetailDialog.cpp" line="34"/>
- <source>No keys found</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/KeyImportDetailDialog.cpp" line="36"/>
- <location filename="../../src/ui/KeyImportDetailDialog.cpp" line="55"/>
- <source>Key Import Details</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/KeyImportDetailDialog.cpp" line="36"/>
- <source>No keys found to import</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/KeyImportDetailDialog.cpp" line="64"/>
- <source>General key info</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/KeyImportDetailDialog.cpp" line="67"/>
- <source>Considered:</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/KeyImportDetailDialog.cpp" line="71"/>
- <source>Public unchanged:</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/KeyImportDetailDialog.cpp" line="76"/>
- <source>Imported:</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/KeyImportDetailDialog.cpp" line="81"/>
- <source>Not imported:</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/KeyImportDetailDialog.cpp" line="86"/>
- <source>Private read:</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/KeyImportDetailDialog.cpp" line="91"/>
- <source>Private imported:</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/KeyImportDetailDialog.cpp" line="96"/>
- <source>Private unchanged:</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/KeyImportDetailDialog.cpp" line="111"/>
- <source>Name</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/KeyImportDetailDialog.cpp" line="111"/>
- <source>Email</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/KeyImportDetailDialog.cpp" line="111"/>
- <source>Status</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/KeyImportDetailDialog.cpp" line="111"/>
- <source>Fingerprint</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/KeyImportDetailDialog.cpp" line="135"/>
- <source>private</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/KeyImportDetailDialog.cpp" line="138"/>
- <source>public</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/KeyImportDetailDialog.cpp" line="141"/>
- <source>unchanged</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/KeyImportDetailDialog.cpp" line="144"/>
- <source>new key</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/KeyImportDetailDialog.cpp" line="147"/>
- <source>new subkey</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/KeyImportDetailDialog.cpp" line="151"/>
- <source>new signature</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/KeyImportDetailDialog.cpp" line="155"/>
- <source>new uid</source>
- <translation type="unfinished"></translation>
- </message>
-</context>
-<context>
- <name>KeyList</name>
- <message>
- <location filename="../../src/ui/widgets/KeyList.cpp" line="76"/>
- <source>Select</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/widgets/KeyList.cpp" line="76"/>
- <source>Type</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/widgets/KeyList.cpp" line="76"/>
- <source>Name</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/widgets/KeyList.cpp" line="76"/>
- <source>Email Address</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/widgets/KeyList.cpp" line="77"/>
- <source>Usage</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/widgets/KeyList.cpp" line="77"/>
- <source>Validity</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/widgets/KeyList.cpp" line="77"/>
- <source>Finger Print</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/widgets/KeyList.cpp" line="302"/>
- <source>Import Keys</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/widgets/KeyList.cpp" line="305"/>
- <source>You&apos;ve dropped something on the table.
- GpgFrontend will now try to import key(s).</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/widgets/KeyList.cpp" line="308"/>
- <source>Always import without bothering.</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/widgets/KeyList.cpp" line="341"/>
- <source>Couldn&apos;t Open File: </source>
- <translation type="unfinished"></translation>
- </message>
-</context>
-<context>
- <name>KeyMgmt</name>
- <message>
- <location filename="../../src/ui/KeyMgmt.cpp" line="82"/>
- <source>Key Pair Management</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/KeyMgmt.cpp" line="88"/>
- <source>&amp;Open</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/KeyMgmt.cpp" line="89"/>
- <source>Ctrl+O</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/KeyMgmt.cpp" line="90"/>
- <source>Open Key File</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/KeyMgmt.cpp" line="93"/>
- <source>&amp;Close</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/KeyMgmt.cpp" line="94"/>
- <source>Ctrl+Q</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/KeyMgmt.cpp" line="96"/>
- <source>Close</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/KeyMgmt.cpp" line="99"/>
- <source>New Keypair</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/KeyMgmt.cpp" line="100"/>
- <source>Ctrl+N</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/KeyMgmt.cpp" line="102"/>
- <source>Generate KeyPair</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/KeyMgmt.cpp" line="105"/>
- <source>New Subkey</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/KeyMgmt.cpp" line="106"/>
- <source>Ctrl+Shift+N</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/KeyMgmt.cpp" line="108"/>
- <source>Generate Subkey For Selected KeyPair</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/KeyMgmt.cpp" line="111"/>
- <location filename="../../src/ui/KeyMgmt.cpp" line="151"/>
- <source>&amp;File</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/KeyMgmt.cpp" line="113"/>
- <source>Import New Key From File</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/KeyMgmt.cpp" line="116"/>
- <source>&amp;Clipboard</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/KeyMgmt.cpp" line="118"/>
- <source>Import New Key From Clipboard</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/KeyMgmt.cpp" line="121"/>
- <source>&amp;Keyserver</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/KeyMgmt.cpp" line="123"/>
- <source>Import New Key From Keyserver</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/KeyMgmt.cpp" line="126"/>
- <source>Export To &amp;Clipboard</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/KeyMgmt.cpp" line="128"/>
- <source>Export Selected Key(s) To Clipboard</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/KeyMgmt.cpp" line="131"/>
- <source>Export To &amp;File</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/KeyMgmt.cpp" line="133"/>
- <source>Export Selected Key(s) To File</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/KeyMgmt.cpp" line="136"/>
- <source>Delete Selected Key(s)</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/KeyMgmt.cpp" line="137"/>
- <source>Delete the Selected keys</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/KeyMgmt.cpp" line="140"/>
- <source>Delete Checked Key(s)</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/KeyMgmt.cpp" line="141"/>
- <source>Delete the Checked keys</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/KeyMgmt.cpp" line="145"/>
- <source>Show Key Details</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/KeyMgmt.cpp" line="146"/>
- <source>Show Details for this Key</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/KeyMgmt.cpp" line="155"/>
- <source>&amp;Key</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/KeyMgmt.cpp" line="156"/>
- <source>&amp;Generate Key</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/KeyMgmt.cpp" line="160"/>
- <source>&amp;Import Key</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/KeyMgmt.cpp" line="171"/>
- <source>Key</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/KeyMgmt.cpp" line="179"/>
- <source>Generate</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/KeyMgmt.cpp" line="180"/>
- <source>Generate A New Keypair or Subkey</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/KeyMgmt.cpp" line="189"/>
- <source>Import key</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/KeyMgmt.cpp" line="190"/>
- <source>Import Key</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/KeyMgmt.cpp" line="209"/>
- <source>Open Key</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/KeyMgmt.cpp" line="210"/>
- <location filename="../../src/ui/KeyMgmt.cpp" line="302"/>
- <source>Key Files</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/KeyMgmt.cpp" line="210"/>
- <source>Keyring files</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/KeyMgmt.cpp" line="216"/>
- <source>Couldn&apos;t Open File: </source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/KeyMgmt.cpp" line="262"/>
- <source>Deleting Keys</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/KeyMgmt.cpp" line="263"/>
- <source>Are you sure that you want to delete the following keys?</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/KeyMgmt.cpp" line="265"/>
- <source>The action can not be undone.</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/KeyMgmt.cpp" line="281"/>
- <location filename="../../src/ui/KeyMgmt.cpp" line="296"/>
- <location filename="../../src/ui/KeyMgmt.cpp" line="344"/>
- <source>Error</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/KeyMgmt.cpp" line="281"/>
- <location filename="../../src/ui/KeyMgmt.cpp" line="296"/>
- <location filename="../../src/ui/KeyMgmt.cpp" line="344"/>
- <source>Key Not Found.</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/KeyMgmt.cpp" line="301"/>
- <source>Export Key To File</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/KeyMgmt.cpp" line="312"/>
- <source>key(s) exported</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/KeyMgmt.cpp" line="338"/>
- <location filename="../../src/ui/KeyMgmt.cpp" line="349"/>
- <source>Invalid Operation</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/KeyMgmt.cpp" line="339"/>
- <source>Please select one KeyPair before doing this operation.</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/KeyMgmt.cpp" line="350"/>
- <source>If a key pair does not have a private key then it will not be able to generate sub-keys.</source>
- <translation type="unfinished"></translation>
- </message>
-</context>
-<context>
- <name>KeyNewUIDDialog</name>
- <message>
- <location filename="../../src/ui/keypair_details/KeyNewUIDDialog.cpp" line="40"/>
- <source>Name</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keypair_details/KeyNewUIDDialog.cpp" line="41"/>
- <source>Email</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keypair_details/KeyNewUIDDialog.cpp" line="42"/>
- <source>Comment</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keypair_details/KeyNewUIDDialog.cpp" line="55"/>
- <source>Create New UID</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keypair_details/KeyNewUIDDialog.cpp" line="68"/>
- <source> Name must contain at least five characters.
-</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keypair_details/KeyNewUIDDialog.cpp" line="70"/>
- <source> Please give a email address.
-</source>
- <translation type="unfinished"></translation>
- </message>
-</context>
-<context>
- <name>KeyPairDetailTab</name>
- <message>
- <location filename="../../src/ui/keypair_details/KeyPairDetailTab.cpp" line="34"/>
- <source>Owner</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keypair_details/KeyPairDetailTab.cpp" line="35"/>
- <source>Master Key</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keypair_details/KeyPairDetailTab.cpp" line="36"/>
- <source>Fingerprint</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keypair_details/KeyPairDetailTab.cpp" line="37"/>
- <source>Additional UIDs</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keypair_details/KeyPairDetailTab.cpp" line="58"/>
- <source>Exists</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keypair_details/KeyPairDetailTab.cpp" line="58"/>
- <source>Not Exists</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keypair_details/KeyPairDetailTab.cpp" line="83"/>
- <source>Name:</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keypair_details/KeyPairDetailTab.cpp" line="84"/>
- <source>Email Address:</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keypair_details/KeyPairDetailTab.cpp" line="85"/>
- <source>Comment:</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keypair_details/KeyPairDetailTab.cpp" line="90"/>
- <source>Key ID: </source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keypair_details/KeyPairDetailTab.cpp" line="91"/>
- <source>Algorithm: </source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keypair_details/KeyPairDetailTab.cpp" line="92"/>
- <source>Key Size:</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keypair_details/KeyPairDetailTab.cpp" line="93"/>
- <source>Nominal Usage: </source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keypair_details/KeyPairDetailTab.cpp" line="94"/>
- <source>Actual Usage: </source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keypair_details/KeyPairDetailTab.cpp" line="95"/>
- <source>Expires on: </source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keypair_details/KeyPairDetailTab.cpp" line="96"/>
- <source>Last Update: </source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keypair_details/KeyPairDetailTab.cpp" line="97"/>
- <source>Secret Key Existence: </source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keypair_details/KeyPairDetailTab.cpp" line="121"/>
- <source>Copy</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keypair_details/KeyPairDetailTab.cpp" line="123"/>
- <source>copy fingerprint to clipboard</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keypair_details/KeyPairDetailTab.cpp" line="133"/>
- <source>Operations</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keypair_details/KeyPairDetailTab.cpp" line="136"/>
- <source>Export Private Key (Include Subkey)</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keypair_details/KeyPairDetailTab.cpp" line="141"/>
- <source>Modify Expiration Datetime (Master Key)</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keypair_details/KeyPairDetailTab.cpp" line="146"/>
- <source>Key Server Operation (Pubkey)</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keypair_details/KeyPairDetailTab.cpp" line="149"/>
- <source>Generate Revoke Certificate</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keypair_details/KeyPairDetailTab.cpp" line="174"/>
- <source>Warning: The Master Key has expired.</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keypair_details/KeyPairDetailTab.cpp" line="177"/>
- <source>Warning: The Master Key has been revoked</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keypair_details/KeyPairDetailTab.cpp" line="201"/>
- <source>Exporting private Key</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keypair_details/KeyPairDetailTab.cpp" line="202"/>
- <source>You are about to export your</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keypair_details/KeyPairDetailTab.cpp" line="203"/>
- <source>PRIVATE KEY</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keypair_details/KeyPairDetailTab.cpp" line="204"/>
- <source>This is NOT your Public Key, so DON&apos;T give it away.</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keypair_details/KeyPairDetailTab.cpp" line="205"/>
- <source>Do you REALLY want to export your PRIVATE KEY?</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keypair_details/KeyPairDetailTab.cpp" line="219"/>
- <source>Error</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keypair_details/KeyPairDetailTab.cpp" line="219"/>
- <source>Key Not Found.</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keypair_details/KeyPairDetailTab.cpp" line="224"/>
- <source>Export Key To File</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keypair_details/KeyPairDetailTab.cpp" line="225"/>
- <source>Key Files</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keypair_details/KeyPairDetailTab.cpp" line="228"/>
- <source>Export Error</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keypair_details/KeyPairDetailTab.cpp" line="228"/>
- <source>Couldn&apos;t open %1 for writing</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keypair_details/KeyPairDetailTab.cpp" line="298"/>
- <source>Never Expire</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keypair_details/KeyPairDetailTab.cpp" line="318"/>
- <source>Upload Key Pair to Key Server</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keypair_details/KeyPairDetailTab.cpp" line="320"/>
- <source>Update Key Pair</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keypair_details/KeyPairDetailTab.cpp" line="343"/>
- <source>Generate revocation certificate</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keypair_details/KeyPairDetailTab.cpp" line="346"/>
- <source>Revocation Certificates</source>
- <translation type="unfinished"></translation>
- </message>
-</context>
-<context>
- <name>KeyPairSubkeyTab</name>
- <message>
- <location filename="../../src/ui/keypair_details/KeyPairSubkeyTab.cpp" line="37"/>
- <source>Generate A New Subkey</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keypair_details/KeyPairSubkeyTab.cpp" line="54"/>
- <source>Key ID: </source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keypair_details/KeyPairSubkeyTab.cpp" line="55"/>
- <source>Algorithm: </source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keypair_details/KeyPairSubkeyTab.cpp" line="56"/>
- <source>Key Size:</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keypair_details/KeyPairSubkeyTab.cpp" line="57"/>
- <source>Usage: </source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keypair_details/KeyPairSubkeyTab.cpp" line="58"/>
- <source>Expires On </source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keypair_details/KeyPairSubkeyTab.cpp" line="59"/>
- <source>Last Update: </source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keypair_details/KeyPairSubkeyTab.cpp" line="60"/>
- <source>Existence: </source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keypair_details/KeyPairSubkeyTab.cpp" line="61"/>
- <source>Fingerprint: </source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keypair_details/KeyPairSubkeyTab.cpp" line="121"/>
- <source>Subkey ID</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keypair_details/KeyPairSubkeyTab.cpp" line="121"/>
- <source>Key Size</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keypair_details/KeyPairSubkeyTab.cpp" line="121"/>
- <source>Algo</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keypair_details/KeyPairSubkeyTab.cpp" line="121"/>
- <source>Create Date</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keypair_details/KeyPairSubkeyTab.cpp" line="121"/>
- <source>Expire Date</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keypair_details/KeyPairSubkeyTab.cpp" line="160"/>
- <source>Never Expire</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keypair_details/KeyPairSubkeyTab.cpp" line="184"/>
- <source>Never Expires</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keypair_details/KeyPairSubkeyTab.cpp" line="230"/>
- <source>Edit Expire Date</source>
- <translation type="unfinished"></translation>
- </message>
-</context>
-<context>
- <name>KeyPairUIDTab</name>
- <message>
- <location filename="../../src/ui/keypair_details/KeyPairUIDTab.cpp" line="39"/>
- <source>New UID</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keypair_details/KeyPairUIDTab.cpp" line="40"/>
- <source>UID Management</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keypair_details/KeyPairUIDTab.cpp" line="59"/>
- <source>UIDs</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keypair_details/KeyPairUIDTab.cpp" line="67"/>
- <source>Signature of Selected UID</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keypair_details/KeyPairUIDTab.cpp" line="103"/>
- <source>Select</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keypair_details/KeyPairUIDTab.cpp" line="103"/>
- <location filename="../../src/ui/keypair_details/KeyPairUIDTab.cpp" line="126"/>
- <source>Name</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keypair_details/KeyPairUIDTab.cpp" line="103"/>
- <location filename="../../src/ui/keypair_details/KeyPairUIDTab.cpp" line="126"/>
- <source>Email</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keypair_details/KeyPairUIDTab.cpp" line="103"/>
- <source>Comment</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keypair_details/KeyPairUIDTab.cpp" line="126"/>
- <source>Key ID</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keypair_details/KeyPairUIDTab.cpp" line="126"/>
- <source>Create Date</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keypair_details/KeyPairUIDTab.cpp" line="126"/>
- <source>Expired Date</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keypair_details/KeyPairUIDTab.cpp" line="219"/>
- <source>Never Expires</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keypair_details/KeyPairUIDTab.cpp" line="237"/>
- <location filename="../../src/ui/keypair_details/KeyPairUIDTab.cpp" line="300"/>
- <location filename="../../src/ui/keypair_details/KeyPairUIDTab.cpp" line="425"/>
- <location filename="../../src/ui/keypair_details/KeyPairUIDTab.cpp" line="440"/>
- <location filename="../../src/ui/keypair_details/KeyPairUIDTab.cpp" line="480"/>
- <location filename="../../src/ui/keypair_details/KeyPairUIDTab.cpp" line="487"/>
- <source>Invalid Operation</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keypair_details/KeyPairUIDTab.cpp" line="238"/>
- <location filename="../../src/ui/keypair_details/KeyPairUIDTab.cpp" line="301"/>
- <source>Please select one or more UIDs before doing this operation.</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keypair_details/KeyPairUIDTab.cpp" line="263"/>
- <source>Sign Selected UID(s)</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keypair_details/KeyPairUIDTab.cpp" line="265"/>
- <source>Delete Selected UID(s)</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keypair_details/KeyPairUIDTab.cpp" line="284"/>
- <source>Successful Operation</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keypair_details/KeyPairUIDTab.cpp" line="285"/>
- <source>Successfully added a new UID.</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keypair_details/KeyPairUIDTab.cpp" line="288"/>
- <location filename="../../src/ui/keypair_details/KeyPairUIDTab.cpp" line="330"/>
- <location filename="../../src/ui/keypair_details/KeyPairUIDTab.cpp" line="363"/>
- <location filename="../../src/ui/keypair_details/KeyPairUIDTab.cpp" line="460"/>
- <location filename="../../src/ui/keypair_details/KeyPairUIDTab.cpp" line="507"/>
- <source>Operation Failed</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keypair_details/KeyPairUIDTab.cpp" line="289"/>
- <location filename="../../src/ui/keypair_details/KeyPairUIDTab.cpp" line="331"/>
- <location filename="../../src/ui/keypair_details/KeyPairUIDTab.cpp" line="364"/>
- <location filename="../../src/ui/keypair_details/KeyPairUIDTab.cpp" line="461"/>
- <location filename="../../src/ui/keypair_details/KeyPairUIDTab.cpp" line="508"/>
- <source>An error occurred during the operation.</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keypair_details/KeyPairUIDTab.cpp" line="313"/>
- <source>Deleting UIDs</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keypair_details/KeyPairUIDTab.cpp" line="314"/>
- <source>Are you sure that you want to delete the following uids?</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keypair_details/KeyPairUIDTab.cpp" line="315"/>
- <location filename="../../src/ui/keypair_details/KeyPairUIDTab.cpp" line="357"/>
- <location filename="../../src/ui/keypair_details/KeyPairUIDTab.cpp" line="454"/>
- <location filename="../../src/ui/keypair_details/KeyPairUIDTab.cpp" line="501"/>
- <source>The action can not be undone.</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keypair_details/KeyPairUIDTab.cpp" line="355"/>
- <source>Set Primary UID</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keypair_details/KeyPairUIDTab.cpp" line="356"/>
- <source>Are you sure that you want to set the Primary UID to?</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keypair_details/KeyPairUIDTab.cpp" line="395"/>
- <source>Set As Primary</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keypair_details/KeyPairUIDTab.cpp" line="397"/>
- <source>Sign UID</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keypair_details/KeyPairUIDTab.cpp" line="399"/>
- <source>Delete UID</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keypair_details/KeyPairUIDTab.cpp" line="426"/>
- <location filename="../../src/ui/keypair_details/KeyPairUIDTab.cpp" line="441"/>
- <source>Please select one UID before doing this operation.</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keypair_details/KeyPairUIDTab.cpp" line="452"/>
- <source>Deleting UID</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keypair_details/KeyPairUIDTab.cpp" line="453"/>
- <source>Are you sure that you want to delete the following uid?</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keypair_details/KeyPairUIDTab.cpp" line="469"/>
- <source>Delete(Revoke) Key Signature</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keypair_details/KeyPairUIDTab.cpp" line="481"/>
- <source>Please select one Key Signature before doing this operation.</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keypair_details/KeyPairUIDTab.cpp" line="488"/>
- <source>To delete the signature, you need to have its corresponding public key in the local database.</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keypair_details/KeyPairUIDTab.cpp" line="499"/>
- <source>Deleting Key Signature</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keypair_details/KeyPairUIDTab.cpp" line="500"/>
- <source>Are you sure that you want to delete the following signature?</source>
- <translation type="unfinished"></translation>
- </message>
-</context>
-<context>
- <name>KeyServerImportDialog</name>
- <message>
- <location filename="../../src/ui/KeyServerImportDialog.cpp" line="40"/>
- <source>&amp;Close</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/KeyServerImportDialog.cpp" line="41"/>
- <source>&amp;Import ALL</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/KeyServerImportDialog.cpp" line="42"/>
- <source>&amp;Search</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/KeyServerImportDialog.cpp" line="45"/>
- <source>Search String:</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/KeyServerImportDialog.cpp" line="49"/>
- <source>Key Server:</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/KeyServerImportDialog.cpp" line="97"/>
- <source>Update Keys from Keyserver</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/KeyServerImportDialog.cpp" line="99"/>
- <source>Import Keys from Keyserver</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/KeyServerImportDialog.cpp" line="158"/>
- <source>UID</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/KeyServerImportDialog.cpp" line="158"/>
- <source>Creation date</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/KeyServerImportDialog.cpp" line="158"/>
- <source>KeyID</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/KeyServerImportDialog.cpp" line="158"/>
- <source>Tag</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/KeyServerImportDialog.cpp" line="179"/>
- <source>Text is empty.</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/KeyServerImportDialog.cpp" line="213"/>
- <source>Not Key Found</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/KeyServerImportDialog.cpp" line="216"/>
- <location filename="../../src/ui/KeyServerImportDialog.cpp" line="386"/>
- <source>Timeout</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/KeyServerImportDialog.cpp" line="219"/>
- <location filename="../../src/ui/KeyServerImportDialog.cpp" line="389"/>
- <source>Key Server Not Found</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/KeyServerImportDialog.cpp" line="222"/>
- <location filename="../../src/ui/KeyServerImportDialog.cpp" line="392"/>
- <source>Connection Error</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/KeyServerImportDialog.cpp" line="230"/>
- <source>Too many responses from keyserver!</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/KeyServerImportDialog.cpp" line="237"/>
- <source>No keys found, input may be kexId, retrying search with 0x.</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/KeyServerImportDialog.cpp" line="242"/>
- <source>No keys found containing the search string!</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/KeyServerImportDialog.cpp" line="246"/>
- <source>Insufficiently specific search string!</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/KeyServerImportDialog.cpp" line="274"/>
- <source>revoked</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/KeyServerImportDialog.cpp" line="277"/>
- <source>disabled</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/KeyServerImportDialog.cpp" line="317"/>
- <source>&lt;h4&gt;%1 keys found. Double click a key to import it.&lt;/h4&gt;</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/KeyServerImportDialog.cpp" line="383"/>
- <source>Key Not Found</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/KeyServerImportDialog.cpp" line="410"/>
- <source>&lt;h4&gt;Key Updated&lt;/h4&gt;</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/KeyServerImportDialog.cpp" line="412"/>
- <source>&lt;h4&gt;Key Imported&lt;/h4&gt;</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/KeyServerImportDialog.cpp" line="473"/>
- <source>Upload Keys from Keyserver</source>
- <translation type="unfinished"></translation>
- </message>
-</context>
-<context>
- <name>KeySetExpireDateDialog</name>
- <message>
- <location filename="../../src/ui/keypair_details/KeySetExpireDateDialog.cpp" line="36"/>
- <source>Confirm</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keypair_details/KeySetExpireDateDialog.cpp" line="41"/>
- <source>Never Expire</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keypair_details/KeySetExpireDateDialog.cpp" line="61"/>
- <source>Operation Failed</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keypair_details/KeySetExpireDateDialog.cpp" line="62"/>
- <source>An error occurred during the operation.</source>
- <translation type="unfinished"></translation>
- </message>
-</context>
-<context>
- <name>KeyUIDSignDialog</name>
- <message>
- <location filename="../../src/ui/keypair_details/KeyUIDSignDialog.cpp" line="72"/>
- <source>Expire Date</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keypair_details/KeyUIDSignDialog.cpp" line="81"/>
- <source>Sign For Key&apos;s UID(s)</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keypair_details/KeyUIDSignDialog.cpp" line="99"/>
- <source>Unsuccessful Operation</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keypair_details/KeyUIDSignDialog.cpp" line="100"/>
- <source>Signature operation failed for UID </source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keypair_details/KeyUIDSignDialog.cpp" line="107"/>
- <source>Operation Complete</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keypair_details/KeyUIDSignDialog.cpp" line="108"/>
- <source>The signature operation of the UID is complete</source>
- <translation type="unfinished"></translation>
- </message>
-</context>
-<context>
- <name>KeyUploadDialog</name>
- <message>
- <location filename="../../src/ui/KeyUploadDialog.cpp" line="47"/>
- <source>Uploading Public Key</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/KeyUploadDialog.cpp" line="110"/>
- <source>Key Not Found</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/KeyUploadDialog.cpp" line="113"/>
- <source>Timeout</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/KeyUploadDialog.cpp" line="116"/>
- <source>Key Server Not Found</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/KeyUploadDialog.cpp" line="119"/>
- <source>Connection Error</source>
- <translation type="unfinished"></translation>
- </message>
-</context>
-<context>
- <name>KeyserverTab</name>
- <message>
- <location filename="../../src/ui/settings/SettingsKeyServer.cpp" line="32"/>
- <source>General</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/settings/SettingsKeyServer.cpp" line="53"/>
- <source>No.</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/settings/SettingsKeyServer.cpp" line="53"/>
- <source>Address</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/settings/SettingsKeyServer.cpp" line="53"/>
- <source>Available</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/settings/SettingsKeyServer.cpp" line="57"/>
- <source>Default Key Server for Import:</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/settings/SettingsKeyServer.cpp" line="67"/>
- <source>Add</source>
- <translation type="unfinished"></translation>
- </message>
-</context>
-<context>
- <name>MainWindow</name>
- <message>
- <location filename="../../src/MainWindow.cpp" line="35"/>
- <source>Loading Gnupg</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/MainWindow.cpp" line="62"/>
- <source>ENV Loading Failed</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/MainWindow.cpp" line="63"/>
- <source>Gnupg is not installed correctly, please follow the ReadME instructions to install gnupg and then open GPGFrontend.</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowFileSlotFunction.cpp" line="36"/>
- <location filename="../../src/ui/main_window/MainWindowFileSlotFunction.cpp" line="40"/>
- <location filename="../../src/ui/main_window/MainWindowFileSlotFunction.cpp" line="44"/>
- <location filename="../../src/ui/main_window/MainWindowFileSlotFunction.cpp" line="114"/>
- <location filename="../../src/ui/main_window/MainWindowFileSlotFunction.cpp" line="127"/>
- <location filename="../../src/ui/main_window/MainWindowFileSlotFunction.cpp" line="131"/>
- <location filename="../../src/ui/main_window/MainWindowFileSlotFunction.cpp" line="135"/>
- <location filename="../../src/ui/main_window/MainWindowFileSlotFunction.cpp" line="196"/>
- <location filename="../../src/ui/main_window/MainWindowFileSlotFunction.cpp" line="212"/>
- <location filename="../../src/ui/main_window/MainWindowFileSlotFunction.cpp" line="216"/>
- <location filename="../../src/ui/main_window/MainWindowFileSlotFunction.cpp" line="220"/>
- <location filename="../../src/ui/main_window/MainWindowFileSlotFunction.cpp" line="294"/>
- <location filename="../../src/ui/main_window/MainWindowFileSlotFunction.cpp" line="326"/>
- <location filename="../../src/ui/main_window/MainWindowFileSlotFunction.cpp" line="331"/>
- <location filename="../../src/ui/main_window/MainWindowFileSlotFunction.cpp" line="335"/>
- <location filename="../../src/ui/main_window/MainWindowFileSlotFunction.cpp" line="383"/>
- <location filename="../../src/ui/main_window/MainWindowFileSlotFunction.cpp" line="396"/>
- <location filename="../../src/ui/main_window/MainWindowFileSlotFunction.cpp" line="400"/>
- <location filename="../../src/ui/main_window/MainWindowFileSlotFunction.cpp" line="404"/>
- <location filename="../../src/ui/main_window/MainWindowFileSlotFunction.cpp" line="501"/>
- <location filename="../../src/ui/main_window/MainWindowFileSlotFunction.cpp" line="513"/>
- <location filename="../../src/ui/main_window/MainWindowFileSlotFunction.cpp" line="517"/>
- <location filename="../../src/ui/main_window/MainWindowFileSlotFunction.cpp" line="521"/>
- <location filename="../../src/ui/main_window/MainWindowFileSlotFunction.cpp" line="583"/>
- <location filename="../../src/ui/main_window/MainWindowServerSlotFunction.cpp" line="53"/>
- <location filename="../../src/ui/main_window/MainWindowServerSlotFunction.cpp" line="111"/>
- <location filename="../../src/ui/main_window/MainWindowServerSlotFunction.cpp" line="125"/>
- <location filename="../../src/ui/main_window/MainWindowServerSlotFunction.cpp" line="217"/>
- <location filename="../../src/ui/main_window/MainWindowServerSlotFunction.cpp" line="232"/>
- <location filename="../../src/ui/main_window/MainWindowSlotFunction.cpp" line="521"/>
- <location filename="../../src/ui/main_window/MainWindowSlotFunction.cpp" line="537"/>
- <source>Error</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowFileSlotFunction.cpp" line="36"/>
- <location filename="../../src/ui/main_window/MainWindowFileSlotFunction.cpp" line="127"/>
- <location filename="../../src/ui/main_window/MainWindowFileSlotFunction.cpp" line="212"/>
- <location filename="../../src/ui/main_window/MainWindowFileSlotFunction.cpp" line="396"/>
- <source>Select a file before doing it.</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowFileSlotFunction.cpp" line="40"/>
- <location filename="../../src/ui/main_window/MainWindowFileSlotFunction.cpp" line="131"/>
- <location filename="../../src/ui/main_window/MainWindowFileSlotFunction.cpp" line="216"/>
- <location filename="../../src/ui/main_window/MainWindowFileSlotFunction.cpp" line="400"/>
- <location filename="../../src/ui/main_window/MainWindowFileSlotFunction.cpp" line="517"/>
- <source>No permission to read this file.</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowFileSlotFunction.cpp" line="44"/>
- <location filename="../../src/ui/main_window/MainWindowFileSlotFunction.cpp" line="135"/>
- <location filename="../../src/ui/main_window/MainWindowFileSlotFunction.cpp" line="220"/>
- <location filename="../../src/ui/main_window/MainWindowFileSlotFunction.cpp" line="404"/>
- <location filename="../../src/ui/main_window/MainWindowFileSlotFunction.cpp" line="521"/>
- <source>No permission to create file.</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowFileSlotFunction.cpp" line="49"/>
- <location filename="../../src/ui/main_window/MainWindowFileSlotFunction.cpp" line="150"/>
- <location filename="../../src/ui/main_window/MainWindowFileSlotFunction.cpp" line="226"/>
- <location filename="../../src/ui/main_window/MainWindowFileSlotFunction.cpp" line="409"/>
- <source>Warning</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowFileSlotFunction.cpp" line="50"/>
- <location filename="../../src/ui/main_window/MainWindowFileSlotFunction.cpp" line="151"/>
- <location filename="../../src/ui/main_window/MainWindowFileSlotFunction.cpp" line="227"/>
- <location filename="../../src/ui/main_window/MainWindowFileSlotFunction.cpp" line="410"/>
- <source>The target file already exists, do you need to overwrite it?</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowFileSlotFunction.cpp" line="62"/>
- <location filename="../../src/ui/main_window/MainWindowFileSlotFunction.cpp" line="239"/>
- <location filename="../../src/ui/main_window/MainWindowFileSlotFunction.cpp" line="422"/>
- <location filename="../../src/ui/main_window/MainWindowSlotFunction.cpp" line="45"/>
- <location filename="../../src/ui/main_window/MainWindowSlotFunction.cpp" line="125"/>
- <location filename="../../src/ui/main_window/MainWindowSlotFunction.cpp" line="296"/>
- <source>No Key Selected</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowFileSlotFunction.cpp" line="69"/>
- <location filename="../../src/ui/main_window/MainWindowFileSlotFunction.cpp" line="246"/>
- <location filename="../../src/ui/main_window/MainWindowSlotFunction.cpp" line="52"/>
- <location filename="../../src/ui/main_window/MainWindowSlotFunction.cpp" line="132"/>
- <source>Invalid Operation</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowFileSlotFunction.cpp" line="70"/>
- <location filename="../../src/ui/main_window/MainWindowFileSlotFunction.cpp" line="247"/>
- <location filename="../../src/ui/main_window/MainWindowSlotFunction.cpp" line="53"/>
- <source>The selected key contains a key that does not actually have a encrypt usage.&lt;br/&gt;</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowFileSlotFunction.cpp" line="71"/>
- <location filename="../../src/ui/main_window/MainWindowFileSlotFunction.cpp" line="248"/>
- <location filename="../../src/ui/main_window/MainWindowFileSlotFunction.cpp" line="436"/>
- <location filename="../../src/ui/main_window/MainWindowSlotFunction.cpp" line="54"/>
- <location filename="../../src/ui/main_window/MainWindowSlotFunction.cpp" line="134"/>
- <location filename="../../src/ui/main_window/MainWindowSlotFunction.cpp" line="307"/>
- <source>&lt;br/&gt;For example the Following Key: &lt;br/&gt;</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowFileSlotFunction.cpp" line="91"/>
- <location filename="../../src/ui/main_window/MainWindowSlotFunction.cpp" line="72"/>
- <source>Encrypting</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowFileSlotFunction.cpp" line="114"/>
- <location filename="../../src/ui/main_window/MainWindowFileSlotFunction.cpp" line="196"/>
- <location filename="../../src/ui/main_window/MainWindowFileSlotFunction.cpp" line="294"/>
- <location filename="../../src/ui/main_window/MainWindowFileSlotFunction.cpp" line="383"/>
- <location filename="../../src/ui/main_window/MainWindowFileSlotFunction.cpp" line="501"/>
- <location filename="../../src/ui/main_window/MainWindowFileSlotFunction.cpp" line="583"/>
- <source>An error occurred during operation.</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowFileSlotFunction.cpp" line="268"/>
- <location filename="../../src/ui/main_window/MainWindowSlotFunction.cpp" line="150"/>
- <source>Signing</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowFileSlotFunction.cpp" line="327"/>
- <source>Please select the appropriate target file or signature file. Ensure that both are in this directory.</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowFileSlotFunction.cpp" line="331"/>
- <source>No permission to read target file.</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowFileSlotFunction.cpp" line="335"/>
- <source>No permission to read signature file.</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowFileSlotFunction.cpp" line="353"/>
- <location filename="../../src/ui/main_window/MainWindowSlotFunction.cpp" line="258"/>
- <source>Verifying</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowFileSlotFunction.cpp" line="434"/>
- <location filename="../../src/ui/main_window/MainWindowSlotFunction.cpp" line="305"/>
- <source>Invalid KeyPair</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowFileSlotFunction.cpp" line="435"/>
- <source>The selected keypair cannot be used for signing and encryption at the same time.&lt;br/&gt;</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowFileSlotFunction.cpp" line="446"/>
- <location filename="../../src/ui/main_window/MainWindowFileSlotFunction.cpp" line="453"/>
- <source>Incomplete Operation</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowFileSlotFunction.cpp" line="447"/>
- <source>None of the selected key pairs can provide the encryption function.</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowFileSlotFunction.cpp" line="454"/>
- <source>None of the selected key pairs can provide the signature function.</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowFileSlotFunction.cpp" line="473"/>
- <location filename="../../src/ui/main_window/MainWindowSlotFunction.cpp" line="345"/>
- <source>Encrypting and Signing</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowFileSlotFunction.cpp" line="513"/>
- <source>Select a file(.gpg/.asc) before doing it.</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowFileSlotFunction.cpp" line="551"/>
- <location filename="../../src/ui/main_window/MainWindowSlotFunction.cpp" line="440"/>
- <source>Decrypting and Verifying</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowServerSlotFunction.cpp" line="43"/>
- <location filename="../../src/ui/main_window/MainWindowServerSlotFunction.cpp" line="154"/>
- <source>Invalid Own Key</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowServerSlotFunction.cpp" line="154"/>
- <source>Own Key can not be use to do any operation.</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowServerSlotFunction.cpp" line="54"/>
- <source>Please obtain a Service Token from the server in the settings.</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowServerSlotFunction.cpp" line="44"/>
- <source>Own Key can not be use to do any operation. Please go to the setting interface to select an OwnKey and get a ServiceToken.</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowServerSlotFunction.cpp" line="90"/>
- <source>Getting Cpt From Server</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowServerSlotFunction.cpp" line="112"/>
- <location filename="../../src/ui/main_window/MainWindowServerSlotFunction.cpp" line="218"/>
- <source>The communication content with the server does not meet the requirements</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowServerSlotFunction.cpp" line="125"/>
- <source>Invalid short ciphertext</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowServerSlotFunction.cpp" line="143"/>
- <source>Invalid Service Token</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowServerSlotFunction.cpp" line="144"/>
- <source>Please go to the setting interface to get a ServiceToken.</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowServerSlotFunction.cpp" line="202"/>
- <source>Getting Scpt From Server</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowServerSlotFunction.cpp" line="228"/>
- <source>Notice: Use Decrypt &amp; Verify operation to decrypt this short crypto text.</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowServerSlotFunction.cpp" line="232"/>
- <source>There is a problem with the communication with the server</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowSlotFunction.cpp" line="102"/>
- <location filename="../../src/ui/main_window/MainWindowSlotFunction.cpp" line="394"/>
- <source>Function Disabled</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowSlotFunction.cpp" line="103"/>
- <location filename="../../src/ui/main_window/MainWindowSlotFunction.cpp" line="395"/>
- <source>Please go to the settings interface to enable and configure this function.</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowSlotFunction.cpp" line="133"/>
- <source>The selected key contains a key that does not actually have a signature usage.&lt;br/&gt;</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowSlotFunction.cpp" line="185"/>
- <source>Notice</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowSlotFunction.cpp" line="185"/>
- <source>Short Crypto Text only supports Decrypt &amp; Verify.</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowSlotFunction.cpp" line="199"/>
- <source>Decrypting</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowSlotFunction.cpp" line="306"/>
- <source>The selected keypair cannot be used for encryption.&lt;br/&gt;</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowSlotFunction.cpp" line="355"/>
- <source>Automatic Key Exchange Warning</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowSlotFunction.cpp" line="356"/>
- <source>Part of the automatic key exchange failed, which may be related to your key.</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowSlotFunction.cpp" line="358"/>
- <source>If possible, try to use the RSA algorithm compatible with the server for signing.</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowSlotFunction.cpp" line="401"/>
- <source>Service Token Empty</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowSlotFunction.cpp" line="402"/>
- <source>Please go to the settings interface to set Own Key and get Service Token.</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowSlotFunction.cpp" line="521"/>
- <location filename="../../src/ui/main_window/MainWindowSlotFunction.cpp" line="537"/>
- <source>Key Not Found.</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowSlotFunction.cpp" line="568"/>
- <source>Outdated Version</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowSlotFunction.cpp" line="569"/>
- <source>This version(%1) is out of date, please update the latest version in time. </source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowSlotFunction.cpp" line="571"/>
- <location filename="../../src/ui/main_window/MainWindowSlotFunction.cpp" line="578"/>
- <source>You can download the latest version(%1) on Github Releases Page.&lt;br/&gt;</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowSlotFunction.cpp" line="575"/>
- <source>Unreleased Version</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowSlotFunction.cpp" line="576"/>
- <source>This version(%1) has not been officially released and is not recommended for use in a production environment. &lt;br/&gt;</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowSlotUI.cpp" line="58"/>
- <source>There is one unencrypted file in attachment folder</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowSlotUI.cpp" line="60"/>
- <source>There are </source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowSlotUI.cpp" line="60"/>
- <source> unencrypted files in attachment folder</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowUI.cpp" line="30"/>
- <source>&amp;New</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowUI.cpp" line="36"/>
- <source>Open a new file</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowUI.cpp" line="39"/>
- <source>&amp;Open...</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowUI.cpp" line="42"/>
- <source>Open an existing file</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowUI.cpp" line="45"/>
- <source>&amp;Browser</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowUI.cpp" line="47"/>
- <source>Open a file browser</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowUI.cpp" line="50"/>
- <source>&amp;Save</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowUI.cpp" line="53"/>
- <source>Save the current File</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowUI.cpp" line="56"/>
- <source>Save &amp;As</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowUI.cpp" line="59"/>
- <source>Save the current File as...</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowUI.cpp" line="62"/>
- <source>&amp;Print</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowUI.cpp" line="65"/>
- <source>Print Document</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowUI.cpp" line="68"/>
- <source>&amp;Close</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowUI.cpp" line="70"/>
- <source>Close file</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowUI.cpp" line="73"/>
- <source>&amp;Quit</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowUI.cpp" line="76"/>
- <source>Quit Program</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowUI.cpp" line="81"/>
- <source>&amp;Undo</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowUI.cpp" line="83"/>
- <source>Undo Last Edit Action</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowUI.cpp" line="86"/>
- <source>&amp;Redo</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowUI.cpp" line="88"/>
- <source>Redo Last Edit Action</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowUI.cpp" line="91"/>
- <source>Zoom In</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowUI.cpp" line="95"/>
- <source>Zoom Out</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowUI.cpp" line="99"/>
- <source>&amp;Paste</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowUI.cpp" line="102"/>
- <source>Paste Text From Clipboard</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowUI.cpp" line="105"/>
- <source>Cu&amp;t</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowUI.cpp" line="108"/>
- <source>Cut the current selection&apos;s contents to the clipboard</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowUI.cpp" line="112"/>
- <source>&amp;Copy</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowUI.cpp" line="115"/>
- <source>Copy the current selection&apos;s contents to the clipboard</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowUI.cpp" line="119"/>
- <source>&amp;Quote</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowUI.cpp" line="121"/>
- <source>Quote whole text</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowUI.cpp" line="124"/>
- <source>Select &amp;All</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowUI.cpp" line="127"/>
- <source>Select the whole text</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowUI.cpp" line="130"/>
- <source>&amp;Find</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowUI.cpp" line="132"/>
- <source>Find a word</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowUI.cpp" line="135"/>
- <source>Remove &amp;spacing</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowUI.cpp" line="138"/>
- <source>Remove double linebreaks, e.g. in pasted text from webmailer</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowUI.cpp" line="141"/>
- <source>Se&amp;ttings</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowUI.cpp" line="142"/>
- <source>Open settings dialog</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowUI.cpp" line="148"/>
- <source>&amp;Encrypt</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowUI.cpp" line="151"/>
- <source>Encrypt Message</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowUI.cpp" line="154"/>
- <source>&amp;Encrypt &amp;Sign</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowUI.cpp" line="157"/>
- <source>Encrypt and Sign Message</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowUI.cpp" line="160"/>
- <source>&amp;Decrypt</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowUI.cpp" line="163"/>
- <source>Decrypt Message</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowUI.cpp" line="166"/>
- <source>&amp;Decrypt &amp;Verify</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowUI.cpp" line="169"/>
- <source>Decrypt and Verify Message</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowUI.cpp" line="175"/>
- <source>&amp;Encrypt File</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowUI.cpp" line="176"/>
- <source>Encrypt File</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowUI.cpp" line="179"/>
- <source>&amp;Decrypt File</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowUI.cpp" line="180"/>
- <source>Decrypt File</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowUI.cpp" line="183"/>
- <source>&amp;Sign File</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowUI.cpp" line="184"/>
- <source>Sign File</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowUI.cpp" line="187"/>
- <source>&amp;Verify File</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowUI.cpp" line="188"/>
- <source>Verify File</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowUI.cpp" line="192"/>
- <source>&amp;Sign</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowUI.cpp" line="195"/>
- <source>Sign Message</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowUI.cpp" line="198"/>
- <source>&amp;Verify</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowUI.cpp" line="201"/>
- <source>Verify Message</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowUI.cpp" line="207"/>
- <source>&amp;Editor</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowUI.cpp" line="209"/>
- <source>Import New Key From Editor</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowUI.cpp" line="212"/>
- <source>Manage &amp;Keys</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowUI.cpp" line="214"/>
- <source>Open Keymanagement</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowUI.cpp" line="220"/>
- <source>&amp;About</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowUI.cpp" line="222"/>
- <source>Show the application&apos;s About box</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowUI.cpp" line="228"/>
- <source>&amp;Check for Updates</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowUI.cpp" line="230"/>
- <source>Check for updates</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowUI.cpp" line="233"/>
- <source>Open &amp;Wizard</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowUI.cpp" line="234"/>
- <source>Open the wizard</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowUI.cpp" line="239"/>
- <source>Append Selected Key(s) To Text</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowUI.cpp" line="240"/>
- <source>Append The Selected Keys To Text in Editor</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowUI.cpp" line="243"/>
- <source>Copy Email</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowUI.cpp" line="244"/>
- <source>Copy selected Email to clipboard</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowUI.cpp" line="248"/>
- <source>Show Key Details</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowUI.cpp" line="249"/>
- <source>Show Details for this Key</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowUI.cpp" line="252"/>
- <source>Refresh Key From Key Server</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowUI.cpp" line="253"/>
- <source>Refresh key from default key server</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowUI.cpp" line="256"/>
- <source>Upload Public Key(s) To Server</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowUI.cpp" line="257"/>
- <source>Upload The Selected Public Keys To Server</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowUI.cpp" line="272"/>
- <source>Remove PGP Header</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowUI.cpp" line="275"/>
- <source>Add PGP Header</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowUI.cpp" line="280"/>
- <source>&amp;File</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowUI.cpp" line="293"/>
- <source>&amp;Edit</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowUI.cpp" line="311"/>
- <source>&amp;File...</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowUI.cpp" line="317"/>
- <source>&amp;Crypt</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowUI.cpp" line="328"/>
- <source>&amp;Keys</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowUI.cpp" line="329"/>
- <source>&amp;Import Key</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowUI.cpp" line="338"/>
- <source>&amp;Steganography</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowUI.cpp" line="347"/>
- <source>&amp;View</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowUI.cpp" line="349"/>
- <source>&amp;Help</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowUI.cpp" line="358"/>
- <source>File</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowUI.cpp" line="366"/>
- <source>Crypt</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowUI.cpp" line="376"/>
- <source>Key</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowUI.cpp" line="381"/>
- <source>Edit</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowUI.cpp" line="388"/>
- <source>Special Edit</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowUI.cpp" line="400"/>
- <source>Import key from...</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowUI.cpp" line="401"/>
- <source>Import key</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowUI.cpp" line="409"/>
- <source>Browser to view and operate file</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowUI.cpp" line="410"/>
- <source>Browser</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowUI.cpp" line="428"/>
- <source>Ready</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowUI.cpp" line="435"/>
- <source>Key ToolBox</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowUI.cpp" line="443"/>
- <source>Information Board</source>
- <translation type="unfinished"></translation>
- </message>
-</context>
-<context>
- <name>PubkeyGetter</name>
- <message>
- <location filename="../../src/server/api/PubkeyGetter.cpp" line="66"/>
- <location filename="../../src/server/api/PubkeyGetter.cpp" line="90"/>
- <source>Error</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/server/api/PubkeyGetter.cpp" line="67"/>
- <location filename="../../src/server/api/PubkeyGetter.cpp" line="91"/>
- <source>The communication content with the server does not meet the requirements</source>
- <translation type="unfinished"></translation>
- </message>
-</context>
-<context>
- <name>PubkeyUploader</name>
- <message>
- <location filename="../../src/server/api/PubkeyUploader.cpp" line="95"/>
- <source>Error</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/server/api/PubkeyUploader.cpp" line="96"/>
- <source>The communication content with the server does not meet the requirements</source>
- <translation type="unfinished"></translation>
- </message>
-</context>
-<context>
- <name>QApplication</name>
- <message>
- <location filename="../../src/gpg/result_analyse/DecryptResultAnalyse.cpp" line="66"/>
- <source> {&gt;} Recipient: </source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/gpg/result_analyse/VerifyResultAnalyse.cpp" line="63"/>
- <source>One or More Bad Signatures.</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/gpg/result_analyse/VerifyResultAnalyse.cpp" line="68"/>
- <source>A </source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/gpg/result_analyse/VerifyResultAnalyse.cpp" line="70"/>
- <source>Good </source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/gpg/result_analyse/VerifyResultAnalyse.cpp" line="73"/>
- <source>Bad </source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/gpg/result_analyse/VerifyResultAnalyse.cpp" line="76"/>
- <source>Expired </source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/gpg/result_analyse/VerifyResultAnalyse.cpp" line="79"/>
- <source>Missing Key&apos;s </source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/gpg/result_analyse/VerifyResultAnalyse.cpp" line="82"/>
- <source>Revoked Key&apos;s </source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/gpg/result_analyse/VerifyResultAnalyse.cpp" line="85"/>
- <source>Expired Key&apos;s </source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/gpg/result_analyse/VerifyResultAnalyse.cpp" line="88"/>
- <source>Missing CRL&apos;s </source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/gpg/result_analyse/VerifyResultAnalyse.cpp" line="92"/>
- <source>Signature Fully Valid.</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/gpg/result_analyse/VerifyResultAnalyse.cpp" line="94"/>
- <source>Signature Not Fully Valid.</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/gpg/result_analyse/VerifyResultAnalyse.cpp" line="100"/>
- <source>Key is NOT present with ID 0x</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/gpg/result_analyse/VerifyResultAnalyse.cpp" line="107"/>
- <source>A signature could NOT be verified due to a Missing Key
-</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/gpg/result_analyse/VerifyResultAnalyse.cpp" line="111"/>
- <source>A signature is valid but the key used to verify the signature has been revoked
-</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/gpg/result_analyse/VerifyResultAnalyse.cpp" line="119"/>
- <source>A signature is valid but expired
-</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/gpg/result_analyse/VerifyResultAnalyse.cpp" line="126"/>
- <source>A signature is valid but the key used to verify the signature has expired.
-</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/gpg/result_analyse/VerifyResultAnalyse.cpp" line="133"/>
- <source>There was some other error which prevented the signature verification.
-</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/gpg/result_analyse/VerifyResultAnalyse.cpp" line="139"/>
- <source>Error for key with fingerprint </source>
- <translation type="unfinished"></translation>
- </message>
-</context>
-<context>
- <name>QuitDialog</name>
- <message>
- <location filename="../../src/ui/QuitDialog.cpp" line="29"/>
- <source>Unsaved Files</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/QuitDialog.cpp" line="77"/>
- <source>%1 files contain unsaved information.&lt;br/&gt;Save the changes before closing?</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/QuitDialog.cpp" line="88"/>
- <source>Check the files you want to save:</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/QuitDialog.cpp" line="89"/>
- <source>&lt;b&gt;Note:&lt;/b&gt; If you don&apos;t save these files, all changes are lost.&lt;br/&gt;</source>
- <translation type="unfinished"></translation>
- </message>
-</context>
-<context>
- <name>SendMailDialog</name>
- <message>
- <location filename="../../src/ui/SendMailDialog.cpp" line="35"/>
- <source>Incomplete configuration</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/SendMailDialog.cpp" line="36"/>
- <source>The SMTP address is empty, please go to the setting interface to complete the configuration.</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/SendMailDialog.cpp" line="86"/>
- <source> Recipient cannot be empty
-</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/SendMailDialog.cpp" line="91"/>
- <source> One or more Recipient&apos;s Email Address is invalid
-</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/SendMailDialog.cpp" line="97"/>
- <source> Sender cannot be empty
-</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/SendMailDialog.cpp" line="99"/>
- <source> Sender&apos;s Email Address is invalid
-</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/SendMailDialog.cpp" line="155"/>
- <location filename="../../src/ui/SendMailDialog.cpp" line="160"/>
- <location filename="../../src/ui/SendMailDialog.cpp" line="165"/>
- <source>Fail</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/SendMailDialog.cpp" line="155"/>
- <source>Fail to Connect SMTP Server</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/SendMailDialog.cpp" line="160"/>
- <source>Fail to Login into SMTP Server</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/SendMailDialog.cpp" line="165"/>
- <source>Fail to Send Mail to SMTP Server</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/SendMailDialog.cpp" line="171"/>
- <source>Success</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/SendMailDialog.cpp" line="171"/>
- <source>Succeed in Sending Mail to SMTP Server</source>
- <translation type="unfinished"></translation>
- </message>
-</context>
-<context>
- <name>SendMailTab</name>
- <message>
- <location filename="../../src/ui/settings/SettingsSendMail.cpp" line="33"/>
- <source>Enable</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/settings/SettingsSendMail.cpp" line="51"/>
- <source>Check Connection</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/settings/SettingsSendMail.cpp" line="53"/>
- <source>General</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/settings/SettingsSendMail.cpp" line="54"/>
- <source>Connection</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/settings/SettingsSendMail.cpp" line="55"/>
- <source>Preference</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/settings/SettingsSendMail.cpp" line="61"/>
- <source>SMTP Address</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/settings/SettingsSendMail.cpp" line="63"/>
- <source>Username</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/settings/SettingsSendMail.cpp" line="65"/>
- <source>Password</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/settings/SettingsSendMail.cpp" line="67"/>
- <source>Port</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/settings/SettingsSendMail.cpp" line="69"/>
- <source>Connection Security</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/settings/SettingsSendMail.cpp" line="75"/>
- <source>Default Sender</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/settings/SettingsSendMail.cpp" line="161"/>
- <location filename="../../src/ui/settings/SettingsSendMail.cpp" line="165"/>
- <source>Fail</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/settings/SettingsSendMail.cpp" line="161"/>
- <source>Fail to Connect SMTP Server</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/settings/SettingsSendMail.cpp" line="165"/>
- <source>Fail to Login</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/settings/SettingsSendMail.cpp" line="170"/>
- <source>Success</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/settings/SettingsSendMail.cpp" line="170"/>
- <source>Succeed in connecting and login</source>
- <translation type="unfinished"></translation>
- </message>
-</context>
-<context>
- <name>SettingsDialog</name>
- <message>
- <location filename="../../src/ui/settings/SettingsDialog.cpp" line="39"/>
- <source>General</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/settings/SettingsDialog.cpp" line="40"/>
- <source>Appearance</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/settings/SettingsDialog.cpp" line="41"/>
- <source>Send Mail</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/settings/SettingsDialog.cpp" line="42"/>
- <source>Key Server</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/settings/SettingsDialog.cpp" line="44"/>
- <source>Advanced</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/settings/SettingsDialog.cpp" line="59"/>
- <source>Settings</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/settings/SettingsDialog.cpp" line="105"/>
- <source>System Default</source>
- <translation type="unfinished"></translation>
- </message>
-</context>
-<context>
- <name>SignResultAnalyse</name>
- <message>
- <location filename="../../src/gpg/result_analyse/SignResultAnalyse.cpp" line="31"/>
- <source>[#] Sign Operation </source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/gpg/result_analyse/SignResultAnalyse.cpp" line="34"/>
- <source>[Success]</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/gpg/result_analyse/SignResultAnalyse.cpp" line="36"/>
- <source>[Failed] </source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/gpg/result_analyse/SignResultAnalyse.cpp" line="47"/>
- <source>[&gt;] New Signature: </source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/gpg/result_analyse/SignResultAnalyse.cpp" line="51"/>
- <source> Sign Mode: </source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/gpg/result_analyse/SignResultAnalyse.cpp" line="53"/>
- <source>Normal</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/gpg/result_analyse/SignResultAnalyse.cpp" line="55"/>
- <source>Clear</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/gpg/result_analyse/SignResultAnalyse.cpp" line="57"/>
- <source>Detach</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/gpg/result_analyse/SignResultAnalyse.cpp" line="63"/>
- <location filename="../../src/gpg/result_analyse/SignResultAnalyse.cpp" line="65"/>
- <source> Signer: </source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/gpg/result_analyse/SignResultAnalyse.cpp" line="65"/>
- <source>&lt;unknown&gt;</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/gpg/result_analyse/SignResultAnalyse.cpp" line="67"/>
- <source> Public Key Algo: </source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/gpg/result_analyse/SignResultAnalyse.cpp" line="68"/>
- <source> Hash Algo: </source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/gpg/result_analyse/SignResultAnalyse.cpp" line="69"/>
- <source> Date &amp; Time: </source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/gpg/result_analyse/SignResultAnalyse.cpp" line="81"/>
- <source>Invalid Signers: </source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/gpg/result_analyse/SignResultAnalyse.cpp" line="85"/>
- <source>[&gt;] Signer: </source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/gpg/result_analyse/SignResultAnalyse.cpp" line="86"/>
- <source> Fingerprint: </source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/gpg/result_analyse/SignResultAnalyse.cpp" line="87"/>
- <source> Reason: </source>
- <translation type="unfinished"></translation>
- </message>
-</context>
-<context>
- <name>SignersPicker</name>
- <message>
- <location filename="../../src/ui/widgets/SignersPicker.cpp" line="28"/>
- <source>Confirm</source>
- <translation type="unfinished"></translation>
- </message>
-</context>
-<context>
- <name>SubkeyGenerateDialog</name>
- <message>
- <location filename="../../src/ui/keygen/SubkeyGenerateDialog.cpp" line="47"/>
- <source>Generate New Subkey</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keygen/SubkeyGenerateDialog.cpp" line="62"/>
- <source>Encryption</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keygen/SubkeyGenerateDialog.cpp" line="65"/>
- <source>Signing</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keygen/SubkeyGenerateDialog.cpp" line="68"/>
- <source>Certification</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keygen/SubkeyGenerateDialog.cpp" line="71"/>
- <source>Authentication</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keygen/SubkeyGenerateDialog.cpp" line="115"/>
- <source>Expiration Date:</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keygen/SubkeyGenerateDialog.cpp" line="116"/>
- <source>Never Expire</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keygen/SubkeyGenerateDialog.cpp" line="117"/>
- <source>KeySize (in Bit):</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keygen/SubkeyGenerateDialog.cpp" line="118"/>
- <source>Key Type:</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keygen/SubkeyGenerateDialog.cpp" line="127"/>
- <source>Basic Information</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keygen/SubkeyGenerateDialog.cpp" line="215"/>
- <source> Expiration time no more than 2 years. </source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keygen/SubkeyGenerateDialog.cpp" line="244"/>
- <source>Success</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keygen/SubkeyGenerateDialog.cpp" line="244"/>
- <source>The new subkey has been generated.</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keygen/SubkeyGenerateDialog.cpp" line="247"/>
- <source>Failure</source>
- <translation type="unfinished"></translation>
- </message>
-</context>
-<context>
- <name>TextEdit</name>
- <message>
- <location filename="../../src/ui/widgets/TextEdit.cpp" line="53"/>
- <source>untitled</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/widgets/TextEdit.cpp" line="120"/>
- <location filename="../../src/ui/widgets/TextEdit.cpp" line="200"/>
- <source>Warning</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/widgets/TextEdit.cpp" line="121"/>
- <location filename="../../src/ui/widgets/TextEdit.cpp" line="201"/>
- <location filename="../../src/ui/widgets/TextEdit.cpp" line="482"/>
- <source>Cannot read file %1:
-%2.</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/widgets/TextEdit.cpp" line="175"/>
- <source>Open file</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/widgets/TextEdit.cpp" line="251"/>
- <source>File</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/widgets/TextEdit.cpp" line="252"/>
- <source>Cannot write file %1:
-%2.</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/widgets/TextEdit.cpp" line="270"/>
- <source>Save file</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/widgets/TextEdit.cpp" line="333"/>
- <source>Unsaved document</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/widgets/TextEdit.cpp" line="334"/>
- <source>The document &quot;%1&quot; has been modified. Do you want to save your changes?&lt;br/&gt;</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/widgets/TextEdit.cpp" line="337"/>
- <source>&lt;b&gt;Note:&lt;/b&gt; If you don&apos;t save these files, all changes are lost.&lt;br/&gt;</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/widgets/TextEdit.cpp" line="481"/>
- <source>Application</source>
- <translation type="unfinished"></translation>
- </message>
-</context>
-<context>
- <name>UpdateTab</name>
- <message>
- <location filename="../../src/ui/help/AboutDialog.cpp" line="129"/>
- <source>It is recommended that you always check the version of GpgFrontend and upgrade to the latest version.</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/help/AboutDialog.cpp" line="131"/>
- <source>New versions not only represent new features, but also often represent functional and security fixes.</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/help/AboutDialog.cpp" line="135"/>
- <source>Current Version: </source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/help/AboutDialog.cpp" line="143"/>
- <source>The current version is inconsistent with the latest version on github.</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/help/AboutDialog.cpp" line="145"/>
- <source>Please click &lt;a href=&quot;https://github.com/saturneric/GpgFrontend/releases&quot;&gt;here&lt;/a&gt; to download the latest version.</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/help/AboutDialog.cpp" line="199"/>
- <location filename="../../src/ui/help/AboutDialog.cpp" line="214"/>
- <source>Latest Version From Github: </source>
- <translation type="unfinished"></translation>
- </message>
-</context>
-<context>
- <name>VerifyDetailsDialog</name>
- <message>
- <location filename="../../src/ui/VerifyDetailsDialog.cpp" line="32"/>
- <source>Signature Details</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/VerifyDetailsDialog.cpp" line="53"/>
- <source>Status: </source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/VerifyDetailsDialog.cpp" line="56"/>
- <source>No valid input found</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/VerifyDetailsDialog.cpp" line="67"/>
- <source>Error Validating signature</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/VerifyDetailsDialog.cpp" line="70"/>
- <source>File was signed on %1 &lt;br/&gt; It Contains:&lt;br/&gt;&lt;br/&gt;</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/VerifyDetailsDialog.cpp" line="72"/>
- <source>Signed on %1 &lt;br/&gt; It Contains:&lt;br /&gt;&lt;br/&gt;</source>
- <translation type="unfinished"></translation>
- </message>
-</context>
-<context>
- <name>VerifyKeyDetailBox</name>
- <message>
- <location filename="../../src/ui/widgets/VerifyKeyDetailBox.cpp" line="36"/>
- <source>Import from keyserver</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/widgets/VerifyKeyDetailBox.cpp" line="39"/>
- <source>Key not present with id 0x</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/widgets/VerifyKeyDetailBox.cpp" line="43"/>
- <source>Status:</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/widgets/VerifyKeyDetailBox.cpp" line="45"/>
- <source>Key not present in keylist</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/widgets/VerifyKeyDetailBox.cpp" line="58"/>
- <location filename="../../src/ui/widgets/VerifyKeyDetailBox.cpp" line="72"/>
- <location filename="../../src/ui/widgets/VerifyKeyDetailBox.cpp" line="86"/>
- <location filename="../../src/ui/widgets/VerifyKeyDetailBox.cpp" line="101"/>
- <location filename="../../src/ui/widgets/VerifyKeyDetailBox.cpp" line="115"/>
- <location filename="../../src/ui/widgets/VerifyKeyDetailBox.cpp" line="129"/>
- <source>Key Information is NOT Available</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/widgets/VerifyKeyDetailBox.cpp" line="60"/>
- <location filename="../../src/ui/widgets/VerifyKeyDetailBox.cpp" line="74"/>
- <location filename="../../src/ui/widgets/VerifyKeyDetailBox.cpp" line="88"/>
- <location filename="../../src/ui/widgets/VerifyKeyDetailBox.cpp" line="103"/>
- <location filename="../../src/ui/widgets/VerifyKeyDetailBox.cpp" line="117"/>
- <location filename="../../src/ui/widgets/VerifyKeyDetailBox.cpp" line="131"/>
- <source>Fingerprint: </source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/widgets/VerifyKeyDetailBox.cpp" line="67"/>
- <source>Status: Cert Revoked</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/widgets/VerifyKeyDetailBox.cpp" line="81"/>
- <location filename="../../src/ui/widgets/VerifyKeyDetailBox.cpp" line="95"/>
- <source>Status: Signature Expired</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/widgets/VerifyKeyDetailBox.cpp" line="96"/>
- <source>Status: Key Expired</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/widgets/VerifyKeyDetailBox.cpp" line="110"/>
- <source>Status: General Error</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/widgets/VerifyKeyDetailBox.cpp" line="124"/>
- <source>Status: Unknown Error</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/widgets/VerifyKeyDetailBox.cpp" line="159"/>
- <source>Signer Name:</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/widgets/VerifyKeyDetailBox.cpp" line="160"/>
- <source>Signer Email:</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/widgets/VerifyKeyDetailBox.cpp" line="161"/>
- <source>Key&apos;s Fingerprint:</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/widgets/VerifyKeyDetailBox.cpp" line="162"/>
- <source>Valid:</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/widgets/VerifyKeyDetailBox.cpp" line="163"/>
- <source>Flags:</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/widgets/VerifyKeyDetailBox.cpp" line="171"/>
- <source>Fully Valid</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/widgets/VerifyKeyDetailBox.cpp" line="173"/>
- <source>NOT Fully Valid</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/widgets/VerifyKeyDetailBox.cpp" line="180"/>
- <source>Good </source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/widgets/VerifyKeyDetailBox.cpp" line="183"/>
- <source>Bad </source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/widgets/VerifyKeyDetailBox.cpp" line="186"/>
- <source>Expired </source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/widgets/VerifyKeyDetailBox.cpp" line="189"/>
- <source>Missing Key </source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/widgets/VerifyKeyDetailBox.cpp" line="192"/>
- <source>Revoked Key </source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/widgets/VerifyKeyDetailBox.cpp" line="195"/>
- <source>Expired Key </source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/widgets/VerifyKeyDetailBox.cpp" line="198"/>
- <source>Missing CRL </source>
- <translation type="unfinished"></translation>
- </message>
-</context>
-<context>
- <name>VerifyResultAnalyse</name>
- <message>
- <location filename="../../src/gpg/result_analyse/VerifyResultAnalyse.cpp" line="33"/>
- <source>[#] Verify Operation </source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/gpg/result_analyse/VerifyResultAnalyse.cpp" line="36"/>
- <source>[Success]</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/gpg/result_analyse/VerifyResultAnalyse.cpp" line="38"/>
- <source>[Failed] </source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/gpg/result_analyse/VerifyResultAnalyse.cpp" line="157"/>
- <location filename="../../src/gpg/result_analyse/VerifyResultAnalyse.cpp" line="161"/>
- <source> Signed By: </source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/gpg/result_analyse/VerifyResultAnalyse.cpp" line="157"/>
- <source>&lt;unknown&gt;</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/gpg/result_analyse/VerifyResultAnalyse.cpp" line="163"/>
- <source> Public Key Algo: </source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/gpg/result_analyse/VerifyResultAnalyse.cpp" line="164"/>
- <source> Hash Algo: </source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/gpg/result_analyse/VerifyResultAnalyse.cpp" line="165"/>
- <source> Date &amp; Time: </source>
- <translation type="unfinished"></translation>
- </message>
-</context>
-<context>
- <name>Wizard</name>
- <message>
- <location filename="../../src/ui/Wizard.cpp" line="40"/>
- <source>First Start Wizard</source>
- <translation type="unfinished"></translation>
- </message>
-</context>
-</TS>
diff --git a/resource/ts/gpgfrontend_ru.ts b/resource/ts/gpgfrontend_ru.ts
deleted file mode 100644
index f2eb5f87..00000000
--- a/resource/ts/gpgfrontend_ru.ts
+++ /dev/null
@@ -1,3854 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!DOCTYPE TS>
-<TS version="2.1" language="ru_RU">
-<context>
- <name>AboutDialog</name>
- <message>
- <location filename="../../src/ui/help/AboutDialog.cpp" line="35"/>
- <source>About </source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/help/AboutDialog.cpp" line="42"/>
- <source>General</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/help/AboutDialog.cpp" line="43"/>
- <source>Translators</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/help/AboutDialog.cpp" line="44"/>
- <source>Update</source>
- <translation type="unfinished"></translation>
- </message>
-</context>
-<context>
- <name>AdvancedTab</name>
- <message>
- <location filename="../../src/ui/settings/SettingsAdvanced.cpp" line="34"/>
- <source>Show Steganography Options</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/settings/SettingsAdvanced.cpp" line="36"/>
- <source>Show Steganographic Options.</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/settings/SettingsAdvanced.cpp" line="40"/>
- <source>Pubkey Exchange</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/settings/SettingsAdvanced.cpp" line="42"/>
- <source>Auto Pubkey Exchange</source>
- <translation type="unfinished"></translation>
- </message>
-</context>
-<context>
- <name>AppearanceTab</name>
- <message>
- <location filename="../../src/ui/settings/SettingsAppearance.cpp" line="34"/>
- <source>Iconsize</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/settings/SettingsAppearance.cpp" line="36"/>
- <source>small</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/settings/SettingsAppearance.cpp" line="37"/>
- <source>medium</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/settings/SettingsAppearance.cpp" line="38"/>
- <source>large</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/settings/SettingsAppearance.cpp" line="54"/>
- <source>Iconstyle</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/settings/SettingsAppearance.cpp" line="56"/>
- <source>just text</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/settings/SettingsAppearance.cpp" line="57"/>
- <source>just icons</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/settings/SettingsAppearance.cpp" line="58"/>
- <source>text and icons</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/settings/SettingsAppearance.cpp" line="74"/>
- <source>Windowstate</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/settings/SettingsAppearance.cpp" line="77"/>
- <source>Save window size and position on exit.</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/settings/SettingsAppearance.cpp" line="85"/>
- <source>Information Board</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/settings/SettingsAppearance.cpp" line="91"/>
- <source> Front Size</source>
- <translation type="unfinished"></translation>
- </message>
-</context>
-<context>
- <name>ChoosePage</name>
- <message>
- <location filename="../../src/ui/Wizard.cpp" line="121"/>
- <source>Choose your action...</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/Wizard.cpp" line="122"/>
- <source>...by clicking on the appropriate link.</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/Wizard.cpp" line="124"/>
- <source>If you have never used GPGFrontend before and also don&apos;t own a gpg key yet you may possibly want to read how to</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/Wizard.cpp" line="127"/>
- <source>Generate Key</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/Wizard.cpp" line="134"/>
- <source>If you want to learn how to encrypt, decrypt, sign and verify text, you can read </source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/Wizard.cpp" line="136"/>
- <source>Encrypt &amp; Decrypt Text</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/Wizard.cpp" line="136"/>
- <location filename="../../src/ui/Wizard.cpp" line="149"/>
- <source>or</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/Wizard.cpp" line="138"/>
- <source>Sign &amp; Verify Text</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/Wizard.cpp" line="146"/>
- <source>If you want to operate file, you can read </source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/Wizard.cpp" line="149"/>
- <source>Encrypt &amp; Sign File</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/Wizard.cpp" line="152"/>
- <source>Sign &amp; Verify File</source>
- <translation type="unfinished"></translation>
- </message>
-</context>
-<context>
- <name>ComUtils</name>
- <message>
- <location filename="../../src/server/ComUtils.cpp" line="35"/>
- <location filename="../../src/server/ComUtils.cpp" line="55"/>
- <source>Error</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/server/ComUtils.cpp" line="35"/>
- <source>Nothing Reply. Please check the Internet connection.</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/server/ComUtils.cpp" line="55"/>
- <source>Unknown Error</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/server/ComUtils.cpp" line="75"/>
- <location filename="../../src/server/ComUtils.cpp" line="90"/>
- <source>Network Error</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/server/ComUtils.cpp" line="75"/>
- <source>Outdated Reply</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/server/ComUtils.cpp" line="87"/>
- <source>Unknown Reason</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/server/ComUtils.cpp" line="90"/>
- <source>Unknown Reply Format</source>
- <translation type="unfinished"></translation>
- </message>
-</context>
-<context>
- <name>ConclusionPage</name>
- <message>
- <location filename="../../src/ui/Wizard.cpp" line="224"/>
- <source>Ready.</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/Wizard.cpp" line="225"/>
- <source>Have fun with GPGFrontend!</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/Wizard.cpp" line="227"/>
- <source>You are ready to use GPGFrontend now.&lt;br&gt;&lt;br&gt;</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/Wizard.cpp" line="229"/>
- <source>The Online Document</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/Wizard.cpp" line="231"/>
- <source> will get you started with GPGFrontend. It will open in the main window.&lt;br&gt;</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/Wizard.cpp" line="238"/>
- <source>Open offline help.</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/Wizard.cpp" line="241"/>
- <source>Dont show the wizard again.</source>
- <translation type="unfinished"></translation>
- </message>
-</context>
-<context>
- <name>DecryptResultAnalyse</name>
- <message>
- <location filename="../../src/gpg/result_analyse/DecryptResultAnalyse.cpp" line="30"/>
- <source>[#] Decrypt Operation </source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/gpg/result_analyse/DecryptResultAnalyse.cpp" line="33"/>
- <source>[Success]</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/gpg/result_analyse/DecryptResultAnalyse.cpp" line="35"/>
- <source>[Failed] </source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/gpg/result_analyse/DecryptResultAnalyse.cpp" line="39"/>
- <source>Unsupported Algo: </source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/gpg/result_analyse/DecryptResultAnalyse.cpp" line="46"/>
- <source>File Name: </source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/gpg/result_analyse/DecryptResultAnalyse.cpp" line="52"/>
- <source>Recipient(s): </source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/gpg/result_analyse/DecryptResultAnalyse.cpp" line="82"/>
- <source> Keu ID: </source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/gpg/result_analyse/DecryptResultAnalyse.cpp" line="83"/>
- <source> Public Algo: </source>
- <translation type="unfinished"></translation>
- </message>
-</context>
-<context>
- <name>EncryptResultAnalyse</name>
- <message>
- <location filename="../../src/gpg/result_analyse/EncryptResultAnalyse.cpp" line="43"/>
- <source>Invalid Recipients: </source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/gpg/result_analyse/EncryptResultAnalyse.cpp" line="46"/>
- <source>Fingerprint: </source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/gpg/result_analyse/EncryptResultAnalyse.cpp" line="47"/>
- <source>Reason: </source>
- <translation type="unfinished"></translation>
- </message>
-</context>
-<context>
- <name>FileEncryptionDialog</name>
- <message>
- <location filename="../../src/ui/FileEncryptionDialog.cpp" line="32"/>
- <source>Decrypt File</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/FileEncryptionDialog.cpp" line="34"/>
- <source>Encrypt File</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/FileEncryptionDialog.cpp" line="36"/>
- <source>Sign File</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/FileEncryptionDialog.cpp" line="38"/>
- <source>Verify File</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/FileEncryptionDialog.cpp" line="47"/>
- <source>Input Parameters</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/FileEncryptionDialog.cpp" line="53"/>
- <source>Target File</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/FileEncryptionDialog.cpp" line="59"/>
- <source>Output File</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/FileEncryptionDialog.cpp" line="75"/>
- <source>Signature File(.sig) Path</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/FileEncryptionDialog.cpp" line="134"/>
- <location filename="../../src/ui/FileEncryptionDialog.cpp" line="177"/>
- <source>Open File</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/FileEncryptionDialog.cpp" line="165"/>
- <source>Save File</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/FileEncryptionDialog.cpp" line="194"/>
- <location filename="../../src/ui/FileEncryptionDialog.cpp" line="245"/>
- <source>Couldn&apos;t open file</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/FileEncryptionDialog.cpp" line="213"/>
- <location filename="../../src/ui/FileEncryptionDialog.cpp" line="224"/>
- <location filename="../../src/ui/FileEncryptionDialog.cpp" line="235"/>
- <source>Error</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/FileEncryptionDialog.cpp" line="214"/>
- <source>Error Occurred During Encryption</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/FileEncryptionDialog.cpp" line="225"/>
- <source>Error Occurred During Decryption</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/FileEncryptionDialog.cpp" line="236"/>
- <source>Error Occurred During Signature</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/FileEncryptionDialog.cpp" line="259"/>
- <location filename="../../src/ui/FileEncryptionDialog.cpp" line="268"/>
- <source>File</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/FileEncryptionDialog.cpp" line="260"/>
- <source>File exists! Do you want to overwrite it?</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/FileEncryptionDialog.cpp" line="269"/>
- <source>Cannot write file %1:
-%2.</source>
- <translation type="unfinished"></translation>
- </message>
-</context>
-<context>
- <name>FilePage</name>
- <message>
- <location filename="../../src/ui/widgets/FilePage.cpp" line="161"/>
- <source>Open</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/widgets/FilePage.cpp" line="163"/>
- <source>Delete</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/widgets/FilePage.cpp" line="165"/>
- <source>Encrypt and Sign</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/widgets/FilePage.cpp" line="167"/>
- <source>Decrypt and Verify</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/widgets/FilePage.cpp" line="169"/>
- <source>Only Sign</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/widgets/FilePage.cpp" line="171"/>
- <source>Only Verify</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/widgets/FilePage.cpp" line="222"/>
- <source>Warning</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/widgets/FilePage.cpp" line="223"/>
- <source>Are you sure you want to delete it?</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/widgets/FilePage.cpp" line="233"/>
- <source>Error</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/widgets/FilePage.cpp" line="234"/>
- <source>Unable to delete the file or folder.</source>
- <translation type="unfinished"></translation>
- </message>
-</context>
-<context>
- <name>FindWidget</name>
- <message>
- <location filename="../../src/ui/FindWidget.cpp" line="38"/>
- <source>Find:</source>
- <translation type="unfinished"></translation>
- </message>
-</context>
-<context>
- <name>GeneralTab</name>
- <message>
- <location filename="../../src/ui/settings/SettingsGeneral.cpp" line="40"/>
- <source>GpgFrontend Server</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/settings/SettingsGeneral.cpp" line="45"/>
- <source>Server that provides short key and key exchange services</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/settings/SettingsGeneral.cpp" line="52"/>
- <source>Save Checked Keys</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/settings/SettingsGeneral.cpp" line="55"/>
- <source>Save checked private keys on exit and restore them on next start.</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/settings/SettingsGeneral.cpp" line="64"/>
- <source>Confirm drag&apos;n&apos;drop key import</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/settings/SettingsGeneral.cpp" line="67"/>
- <source>Import files dropped on the keylist without confirmation.</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/settings/SettingsGeneral.cpp" line="74"/>
- <source>Language</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/settings/SettingsGeneral.cpp" line="83"/>
- <source>&lt;b&gt;NOTE: &lt;/b&gt; GpgFrontend will restart automatically if you change the language!</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/settings/SettingsGeneral.cpp" line="92"/>
- <source>Own key</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/settings/SettingsGeneral.cpp" line="96"/>
- <source>Get Service Token</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/settings/SettingsGeneral.cpp" line="97"/>
- <location filename="../../src/ui/settings/SettingsGeneral.cpp" line="235"/>
- <source>No Service Token Found</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/settings/SettingsGeneral.cpp" line="104"/>
- <source>&lt;none&gt;</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/settings/SettingsGeneral.cpp" line="121"/>
- <source>Key pair for synchronization and identity authentication</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/settings/SettingsGeneral.cpp" line="253"/>
- <source>Invalid Operation</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/settings/SettingsGeneral.cpp" line="254"/>
- <source>Own Key can not be None while getting service token.</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/settings/SettingsGeneral.cpp" line="266"/>
- <location filename="../../src/ui/settings/SettingsGeneral.cpp" line="337"/>
- <location filename="../../src/ui/settings/SettingsGeneral.cpp" line="354"/>
- <source>Error</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/settings/SettingsGeneral.cpp" line="267"/>
- <source>Key Not Exists</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/settings/SettingsGeneral.cpp" line="338"/>
- <source>The communication content with the server does not meet the requirements</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/settings/SettingsGeneral.cpp" line="351"/>
- <source>Notice</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/settings/SettingsGeneral.cpp" line="352"/>
- <source>Succeed in getting service token</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/settings/SettingsGeneral.cpp" line="354"/>
- <source>There is a problem with the communication with the server</source>
- <translation type="unfinished"></translation>
- </message>
-</context>
-<context>
- <name>GpgME::GpgContext</name>
- <message>
- <location filename="../../src/gpg/gpg_context/GpgContext.cpp" line="182"/>
- <source>Wrong password</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/gpg/gpg_context/GpgContext.cpp" line="190"/>
- <source>Enter Password for</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/gpg/gpg_context/GpgContext.cpp" line="194"/>
- <source>Enter Password</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/gpg/gpg_context/GpgContext.cpp" line="256"/>
- <source>Processing</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/gpg/gpg_context/GpgContextBasicOpera.cpp" line="169"/>
- <source>Key Selection</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/gpg/gpg_context/GpgContextBasicOpera.cpp" line="169"/>
- <source>No Private Key Selected</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/gpg/gpg_context/GpgContextBasicOpera.cpp" line="200"/>
- <source>Error in signing:</source>
- <translation type="unfinished"></translation>
- </message>
-</context>
-<context>
- <name>GpgPathsTab</name>
- <message>
- <location filename="../../src/ui/settings/SettingsDialog.cpp" line="139"/>
- <source>Relative path to keydb</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/settings/SettingsDialog.cpp" line="152"/>
- <source>Current keydb path: </source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/settings/SettingsDialog.cpp" line="157"/>
- <source>&lt;b&gt;NOTE: &lt;/b&gt; Gpg4usb will restart automatically if you change the keydb path!</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/settings/SettingsDialog.cpp" line="186"/>
- <source>Choose keydb directory</source>
- <translation type="unfinished"></translation>
- </message>
-</context>
-<context>
- <name>InfoBoardWidget</name>
- <message>
- <location filename="../../src/ui/widgets/InfoBoardWidget.cpp" line="40"/>
- <source>Import missing key from Keyserver</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/widgets/InfoBoardWidget.cpp" line="57"/>
- <source>Optional Actions</source>
- <translation type="unfinished"></translation>
- </message>
-</context>
-<context>
- <name>InfoTab</name>
- <message>
- <location filename="../../src/ui/help/AboutDialog.cpp" line="76"/>
- <source>&lt;br&gt;&lt;center&gt;GPGFrontend is an easy-to-use, compact, cross-platform, &lt;br&gt;and installation-free gpg front-end tool.&lt;br&gt;It visualizes most of the common operations of gpg commands.&lt;br&gt;It&apos;s licensed under the GPL v3&lt;br&gt;&lt;br&gt;&lt;b&gt;Developer:&lt;/b&gt;&lt;br&gt;Saturneric&lt;br&gt;&lt;br&gt;If you have any questions or suggestions, raise an issue&lt;br/&gt;at &lt;a href=&quot;https://github.com/saturneric/GpgFrontend&quot;&gt;GitHub&lt;/a&gt; or send a mail to my mailing list at &lt;a href=&quot;mailto:[email protected]&quot;&gt;[email protected]&lt;/a&gt;.</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/help/AboutDialog.cpp" line="84"/>
- <source>&lt;br&gt;&lt;br&gt; Built with Qt </source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/help/AboutDialog.cpp" line="85"/>
- <source> and GPGME </source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/help/AboutDialog.cpp" line="86"/>
- <source>&lt;br&gt;Built at </source>
- <translation type="unfinished"></translation>
- </message>
-</context>
-<context>
- <name>IntroPage</name>
- <message>
- <location filename="../../src/ui/Wizard.cpp" line="66"/>
- <source>Getting Started...</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/Wizard.cpp" line="67"/>
- <source>... with GPGFrontend</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/Wizard.cpp" line="69"/>
- <source>Welcome to use GPGFrontend for decrypting and signing text or file!</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/Wizard.cpp" line="71"/>
- <source>is a Powerful, Easy-to-Use, Compact, Cross-Platform, and Installation-Free OpenPGP Crypto Tool.</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/Wizard.cpp" line="72"/>
- <source>For brief information have a look at the</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/Wizard.cpp" line="74"/>
- <source>Overview</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/Wizard.cpp" line="75"/>
- <source>by clicking the link, the page will open in the web browser</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/Wizard.cpp" line="83"/>
- <source>Choose a Language</source>
- <translation type="unfinished"></translation>
- </message>
-</context>
-<context>
- <name>KeyDetailsDialog</name>
- <message>
- <location filename="../../src/ui/keypair_details/KeyDetailsDialog.cpp" line="31"/>
- <source>KeyPair</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keypair_details/KeyDetailsDialog.cpp" line="32"/>
- <source>UIDs</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keypair_details/KeyDetailsDialog.cpp" line="33"/>
- <source>Subkeys</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keypair_details/KeyDetailsDialog.cpp" line="40"/>
- <source>Key Details</source>
- <translation type="unfinished"></translation>
- </message>
-</context>
-<context>
- <name>KeyGenDialog</name>
- <message>
- <location filename="../../src/ui/keygen/KeygenDialog.cpp" line="33"/>
- <source>Generate Key</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keygen/KeygenDialog.cpp" line="69"/>
- <source> Name must contain at least five characters.
-</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keygen/KeygenDialog.cpp" line="71"/>
- <source> Please give a email address.
-</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keygen/KeygenDialog.cpp" line="78"/>
- <source> Expiration time no more than 2 years.
-</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keygen/KeygenDialog.cpp" line="112"/>
- <source>Success</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keygen/KeygenDialog.cpp" line="112"/>
- <source>The new key pair has been generated.</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keygen/KeygenDialog.cpp" line="116"/>
- <source>Failure</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keygen/KeygenDialog.cpp" line="145"/>
- <source>Key Usage</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keygen/KeygenDialog.cpp" line="147"/>
- <source>Encryption</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keygen/KeygenDialog.cpp" line="150"/>
- <source>Signing</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keygen/KeygenDialog.cpp" line="153"/>
- <source>Certification</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keygen/KeygenDialog.cpp" line="156"/>
- <source>Authentication</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keygen/KeygenDialog.cpp" line="338"/>
- <source>Name:</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keygen/KeygenDialog.cpp" line="339"/>
- <source>Email Address:</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keygen/KeygenDialog.cpp" line="340"/>
- <source>Comment:</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keygen/KeygenDialog.cpp" line="341"/>
- <source>Expiration Date:</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keygen/KeygenDialog.cpp" line="342"/>
- <source>Never Expire</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keygen/KeygenDialog.cpp" line="343"/>
- <source>KeySize (in Bit):</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keygen/KeygenDialog.cpp" line="344"/>
- <source>Key Type:</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keygen/KeygenDialog.cpp" line="345"/>
- <source>Non Pass Phrase</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keygen/KeygenDialog.cpp" line="358"/>
- <source>Basic Information</source>
- <translation type="unfinished"></translation>
- </message>
-</context>
-<context>
- <name>KeyGenPage</name>
- <message>
- <location filename="../../src/ui/Wizard.cpp" line="183"/>
- <source>Create a keypair...</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/Wizard.cpp" line="184"/>
- <source>...for decrypting and signing messages</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/Wizard.cpp" line="185"/>
- <source>You should create a new keypair.The pair consists of a public and a private key.&lt;br&gt;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.&lt;br&gt;For more information have a look at the offline tutorial (which then is shown in the main window):</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/Wizard.cpp" line="192"/>
- <source>Offline tutorial</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/Wizard.cpp" line="199"/>
- <source>Create New Key</source>
- <translation type="unfinished"></translation>
- </message>
-</context>
-<context>
- <name>KeyImportDetailDialog</name>
- <message>
- <location filename="../../src/ui/KeyImportDetailDialog.cpp" line="34"/>
- <location filename="../../src/ui/KeyImportDetailDialog.cpp" line="53"/>
- <source>Key Update Details</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/KeyImportDetailDialog.cpp" line="34"/>
- <source>No keys found</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/KeyImportDetailDialog.cpp" line="36"/>
- <location filename="../../src/ui/KeyImportDetailDialog.cpp" line="55"/>
- <source>Key Import Details</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/KeyImportDetailDialog.cpp" line="36"/>
- <source>No keys found to import</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/KeyImportDetailDialog.cpp" line="64"/>
- <source>General key info</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/KeyImportDetailDialog.cpp" line="67"/>
- <source>Considered:</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/KeyImportDetailDialog.cpp" line="71"/>
- <source>Public unchanged:</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/KeyImportDetailDialog.cpp" line="76"/>
- <source>Imported:</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/KeyImportDetailDialog.cpp" line="81"/>
- <source>Not imported:</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/KeyImportDetailDialog.cpp" line="86"/>
- <source>Private read:</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/KeyImportDetailDialog.cpp" line="91"/>
- <source>Private imported:</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/KeyImportDetailDialog.cpp" line="96"/>
- <source>Private unchanged:</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/KeyImportDetailDialog.cpp" line="111"/>
- <source>Name</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/KeyImportDetailDialog.cpp" line="111"/>
- <source>Email</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/KeyImportDetailDialog.cpp" line="111"/>
- <source>Status</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/KeyImportDetailDialog.cpp" line="111"/>
- <source>Fingerprint</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/KeyImportDetailDialog.cpp" line="135"/>
- <source>private</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/KeyImportDetailDialog.cpp" line="138"/>
- <source>public</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/KeyImportDetailDialog.cpp" line="141"/>
- <source>unchanged</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/KeyImportDetailDialog.cpp" line="144"/>
- <source>new key</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/KeyImportDetailDialog.cpp" line="147"/>
- <source>new subkey</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/KeyImportDetailDialog.cpp" line="151"/>
- <source>new signature</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/KeyImportDetailDialog.cpp" line="155"/>
- <source>new uid</source>
- <translation type="unfinished"></translation>
- </message>
-</context>
-<context>
- <name>KeyList</name>
- <message>
- <location filename="../../src/ui/widgets/KeyList.cpp" line="76"/>
- <source>Select</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/widgets/KeyList.cpp" line="76"/>
- <source>Type</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/widgets/KeyList.cpp" line="76"/>
- <source>Name</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/widgets/KeyList.cpp" line="76"/>
- <source>Email Address</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/widgets/KeyList.cpp" line="77"/>
- <source>Usage</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/widgets/KeyList.cpp" line="77"/>
- <source>Validity</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/widgets/KeyList.cpp" line="77"/>
- <source>Finger Print</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/widgets/KeyList.cpp" line="302"/>
- <source>Import Keys</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/widgets/KeyList.cpp" line="305"/>
- <source>You&apos;ve dropped something on the table.
- GpgFrontend will now try to import key(s).</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/widgets/KeyList.cpp" line="308"/>
- <source>Always import without bothering.</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/widgets/KeyList.cpp" line="341"/>
- <source>Couldn&apos;t Open File: </source>
- <translation type="unfinished"></translation>
- </message>
-</context>
-<context>
- <name>KeyMgmt</name>
- <message>
- <location filename="../../src/ui/KeyMgmt.cpp" line="82"/>
- <source>Key Pair Management</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/KeyMgmt.cpp" line="88"/>
- <source>&amp;Open</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/KeyMgmt.cpp" line="89"/>
- <source>Ctrl+O</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/KeyMgmt.cpp" line="90"/>
- <source>Open Key File</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/KeyMgmt.cpp" line="93"/>
- <source>&amp;Close</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/KeyMgmt.cpp" line="94"/>
- <source>Ctrl+Q</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/KeyMgmt.cpp" line="96"/>
- <source>Close</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/KeyMgmt.cpp" line="99"/>
- <source>New Keypair</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/KeyMgmt.cpp" line="100"/>
- <source>Ctrl+N</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/KeyMgmt.cpp" line="102"/>
- <source>Generate KeyPair</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/KeyMgmt.cpp" line="105"/>
- <source>New Subkey</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/KeyMgmt.cpp" line="106"/>
- <source>Ctrl+Shift+N</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/KeyMgmt.cpp" line="108"/>
- <source>Generate Subkey For Selected KeyPair</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/KeyMgmt.cpp" line="111"/>
- <location filename="../../src/ui/KeyMgmt.cpp" line="151"/>
- <source>&amp;File</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/KeyMgmt.cpp" line="113"/>
- <source>Import New Key From File</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/KeyMgmt.cpp" line="116"/>
- <source>&amp;Clipboard</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/KeyMgmt.cpp" line="118"/>
- <source>Import New Key From Clipboard</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/KeyMgmt.cpp" line="121"/>
- <source>&amp;Keyserver</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/KeyMgmt.cpp" line="123"/>
- <source>Import New Key From Keyserver</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/KeyMgmt.cpp" line="126"/>
- <source>Export To &amp;Clipboard</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/KeyMgmt.cpp" line="128"/>
- <source>Export Selected Key(s) To Clipboard</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/KeyMgmt.cpp" line="131"/>
- <source>Export To &amp;File</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/KeyMgmt.cpp" line="133"/>
- <source>Export Selected Key(s) To File</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/KeyMgmt.cpp" line="136"/>
- <source>Delete Selected Key(s)</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/KeyMgmt.cpp" line="137"/>
- <source>Delete the Selected keys</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/KeyMgmt.cpp" line="140"/>
- <source>Delete Checked Key(s)</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/KeyMgmt.cpp" line="141"/>
- <source>Delete the Checked keys</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/KeyMgmt.cpp" line="145"/>
- <source>Show Key Details</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/KeyMgmt.cpp" line="146"/>
- <source>Show Details for this Key</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/KeyMgmt.cpp" line="155"/>
- <source>&amp;Key</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/KeyMgmt.cpp" line="156"/>
- <source>&amp;Generate Key</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/KeyMgmt.cpp" line="160"/>
- <source>&amp;Import Key</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/KeyMgmt.cpp" line="171"/>
- <source>Key</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/KeyMgmt.cpp" line="179"/>
- <source>Generate</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/KeyMgmt.cpp" line="180"/>
- <source>Generate A New Keypair or Subkey</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/KeyMgmt.cpp" line="189"/>
- <source>Import key</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/KeyMgmt.cpp" line="190"/>
- <source>Import Key</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/KeyMgmt.cpp" line="209"/>
- <source>Open Key</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/KeyMgmt.cpp" line="210"/>
- <location filename="../../src/ui/KeyMgmt.cpp" line="302"/>
- <source>Key Files</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/KeyMgmt.cpp" line="210"/>
- <source>Keyring files</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/KeyMgmt.cpp" line="216"/>
- <source>Couldn&apos;t Open File: </source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/KeyMgmt.cpp" line="262"/>
- <source>Deleting Keys</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/KeyMgmt.cpp" line="263"/>
- <source>Are you sure that you want to delete the following keys?</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/KeyMgmt.cpp" line="265"/>
- <source>The action can not be undone.</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/KeyMgmt.cpp" line="281"/>
- <location filename="../../src/ui/KeyMgmt.cpp" line="296"/>
- <location filename="../../src/ui/KeyMgmt.cpp" line="344"/>
- <source>Error</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/KeyMgmt.cpp" line="281"/>
- <location filename="../../src/ui/KeyMgmt.cpp" line="296"/>
- <location filename="../../src/ui/KeyMgmt.cpp" line="344"/>
- <source>Key Not Found.</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/KeyMgmt.cpp" line="301"/>
- <source>Export Key To File</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/KeyMgmt.cpp" line="312"/>
- <source>key(s) exported</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/KeyMgmt.cpp" line="338"/>
- <location filename="../../src/ui/KeyMgmt.cpp" line="349"/>
- <source>Invalid Operation</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/KeyMgmt.cpp" line="339"/>
- <source>Please select one KeyPair before doing this operation.</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/KeyMgmt.cpp" line="350"/>
- <source>If a key pair does not have a private key then it will not be able to generate sub-keys.</source>
- <translation type="unfinished"></translation>
- </message>
-</context>
-<context>
- <name>KeyNewUIDDialog</name>
- <message>
- <location filename="../../src/ui/keypair_details/KeyNewUIDDialog.cpp" line="40"/>
- <source>Name</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keypair_details/KeyNewUIDDialog.cpp" line="41"/>
- <source>Email</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keypair_details/KeyNewUIDDialog.cpp" line="42"/>
- <source>Comment</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keypair_details/KeyNewUIDDialog.cpp" line="55"/>
- <source>Create New UID</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keypair_details/KeyNewUIDDialog.cpp" line="68"/>
- <source> Name must contain at least five characters.
-</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keypair_details/KeyNewUIDDialog.cpp" line="70"/>
- <source> Please give a email address.
-</source>
- <translation type="unfinished"></translation>
- </message>
-</context>
-<context>
- <name>KeyPairDetailTab</name>
- <message>
- <location filename="../../src/ui/keypair_details/KeyPairDetailTab.cpp" line="34"/>
- <source>Owner</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keypair_details/KeyPairDetailTab.cpp" line="35"/>
- <source>Master Key</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keypair_details/KeyPairDetailTab.cpp" line="36"/>
- <source>Fingerprint</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keypair_details/KeyPairDetailTab.cpp" line="37"/>
- <source>Additional UIDs</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keypair_details/KeyPairDetailTab.cpp" line="58"/>
- <source>Exists</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keypair_details/KeyPairDetailTab.cpp" line="58"/>
- <source>Not Exists</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keypair_details/KeyPairDetailTab.cpp" line="83"/>
- <source>Name:</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keypair_details/KeyPairDetailTab.cpp" line="84"/>
- <source>Email Address:</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keypair_details/KeyPairDetailTab.cpp" line="85"/>
- <source>Comment:</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keypair_details/KeyPairDetailTab.cpp" line="90"/>
- <source>Key ID: </source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keypair_details/KeyPairDetailTab.cpp" line="91"/>
- <source>Algorithm: </source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keypair_details/KeyPairDetailTab.cpp" line="92"/>
- <source>Key Size:</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keypair_details/KeyPairDetailTab.cpp" line="93"/>
- <source>Nominal Usage: </source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keypair_details/KeyPairDetailTab.cpp" line="94"/>
- <source>Actual Usage: </source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keypair_details/KeyPairDetailTab.cpp" line="95"/>
- <source>Expires on: </source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keypair_details/KeyPairDetailTab.cpp" line="96"/>
- <source>Last Update: </source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keypair_details/KeyPairDetailTab.cpp" line="97"/>
- <source>Secret Key Existence: </source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keypair_details/KeyPairDetailTab.cpp" line="121"/>
- <source>Copy</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keypair_details/KeyPairDetailTab.cpp" line="123"/>
- <source>copy fingerprint to clipboard</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keypair_details/KeyPairDetailTab.cpp" line="133"/>
- <source>Operations</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keypair_details/KeyPairDetailTab.cpp" line="136"/>
- <source>Export Private Key (Include Subkey)</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keypair_details/KeyPairDetailTab.cpp" line="141"/>
- <source>Modify Expiration Datetime (Master Key)</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keypair_details/KeyPairDetailTab.cpp" line="146"/>
- <source>Key Server Operation (Pubkey)</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keypair_details/KeyPairDetailTab.cpp" line="149"/>
- <source>Generate Revoke Certificate</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keypair_details/KeyPairDetailTab.cpp" line="174"/>
- <source>Warning: The Master Key has expired.</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keypair_details/KeyPairDetailTab.cpp" line="177"/>
- <source>Warning: The Master Key has been revoked</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keypair_details/KeyPairDetailTab.cpp" line="201"/>
- <source>Exporting private Key</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keypair_details/KeyPairDetailTab.cpp" line="202"/>
- <source>You are about to export your</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keypair_details/KeyPairDetailTab.cpp" line="203"/>
- <source>PRIVATE KEY</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keypair_details/KeyPairDetailTab.cpp" line="204"/>
- <source>This is NOT your Public Key, so DON&apos;T give it away.</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keypair_details/KeyPairDetailTab.cpp" line="205"/>
- <source>Do you REALLY want to export your PRIVATE KEY?</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keypair_details/KeyPairDetailTab.cpp" line="219"/>
- <source>Error</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keypair_details/KeyPairDetailTab.cpp" line="219"/>
- <source>Key Not Found.</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keypair_details/KeyPairDetailTab.cpp" line="224"/>
- <source>Export Key To File</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keypair_details/KeyPairDetailTab.cpp" line="225"/>
- <source>Key Files</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keypair_details/KeyPairDetailTab.cpp" line="228"/>
- <source>Export Error</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keypair_details/KeyPairDetailTab.cpp" line="228"/>
- <source>Couldn&apos;t open %1 for writing</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keypair_details/KeyPairDetailTab.cpp" line="298"/>
- <source>Never Expire</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keypair_details/KeyPairDetailTab.cpp" line="318"/>
- <source>Upload Key Pair to Key Server</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keypair_details/KeyPairDetailTab.cpp" line="320"/>
- <source>Update Key Pair</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keypair_details/KeyPairDetailTab.cpp" line="343"/>
- <source>Generate revocation certificate</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keypair_details/KeyPairDetailTab.cpp" line="346"/>
- <source>Revocation Certificates</source>
- <translation type="unfinished"></translation>
- </message>
-</context>
-<context>
- <name>KeyPairSubkeyTab</name>
- <message>
- <location filename="../../src/ui/keypair_details/KeyPairSubkeyTab.cpp" line="37"/>
- <source>Generate A New Subkey</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keypair_details/KeyPairSubkeyTab.cpp" line="54"/>
- <source>Key ID: </source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keypair_details/KeyPairSubkeyTab.cpp" line="55"/>
- <source>Algorithm: </source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keypair_details/KeyPairSubkeyTab.cpp" line="56"/>
- <source>Key Size:</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keypair_details/KeyPairSubkeyTab.cpp" line="57"/>
- <source>Usage: </source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keypair_details/KeyPairSubkeyTab.cpp" line="58"/>
- <source>Expires On </source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keypair_details/KeyPairSubkeyTab.cpp" line="59"/>
- <source>Last Update: </source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keypair_details/KeyPairSubkeyTab.cpp" line="60"/>
- <source>Existence: </source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keypair_details/KeyPairSubkeyTab.cpp" line="61"/>
- <source>Fingerprint: </source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keypair_details/KeyPairSubkeyTab.cpp" line="121"/>
- <source>Subkey ID</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keypair_details/KeyPairSubkeyTab.cpp" line="121"/>
- <source>Key Size</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keypair_details/KeyPairSubkeyTab.cpp" line="121"/>
- <source>Algo</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keypair_details/KeyPairSubkeyTab.cpp" line="121"/>
- <source>Create Date</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keypair_details/KeyPairSubkeyTab.cpp" line="121"/>
- <source>Expire Date</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keypair_details/KeyPairSubkeyTab.cpp" line="160"/>
- <source>Never Expire</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keypair_details/KeyPairSubkeyTab.cpp" line="184"/>
- <source>Never Expires</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keypair_details/KeyPairSubkeyTab.cpp" line="230"/>
- <source>Edit Expire Date</source>
- <translation type="unfinished"></translation>
- </message>
-</context>
-<context>
- <name>KeyPairUIDTab</name>
- <message>
- <location filename="../../src/ui/keypair_details/KeyPairUIDTab.cpp" line="39"/>
- <source>New UID</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keypair_details/KeyPairUIDTab.cpp" line="40"/>
- <source>UID Management</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keypair_details/KeyPairUIDTab.cpp" line="59"/>
- <source>UIDs</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keypair_details/KeyPairUIDTab.cpp" line="67"/>
- <source>Signature of Selected UID</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keypair_details/KeyPairUIDTab.cpp" line="103"/>
- <source>Select</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keypair_details/KeyPairUIDTab.cpp" line="103"/>
- <location filename="../../src/ui/keypair_details/KeyPairUIDTab.cpp" line="126"/>
- <source>Name</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keypair_details/KeyPairUIDTab.cpp" line="103"/>
- <location filename="../../src/ui/keypair_details/KeyPairUIDTab.cpp" line="126"/>
- <source>Email</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keypair_details/KeyPairUIDTab.cpp" line="103"/>
- <source>Comment</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keypair_details/KeyPairUIDTab.cpp" line="126"/>
- <source>Key ID</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keypair_details/KeyPairUIDTab.cpp" line="126"/>
- <source>Create Date</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keypair_details/KeyPairUIDTab.cpp" line="126"/>
- <source>Expired Date</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keypair_details/KeyPairUIDTab.cpp" line="219"/>
- <source>Never Expires</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keypair_details/KeyPairUIDTab.cpp" line="237"/>
- <location filename="../../src/ui/keypair_details/KeyPairUIDTab.cpp" line="300"/>
- <location filename="../../src/ui/keypair_details/KeyPairUIDTab.cpp" line="425"/>
- <location filename="../../src/ui/keypair_details/KeyPairUIDTab.cpp" line="440"/>
- <location filename="../../src/ui/keypair_details/KeyPairUIDTab.cpp" line="480"/>
- <location filename="../../src/ui/keypair_details/KeyPairUIDTab.cpp" line="487"/>
- <source>Invalid Operation</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keypair_details/KeyPairUIDTab.cpp" line="238"/>
- <location filename="../../src/ui/keypair_details/KeyPairUIDTab.cpp" line="301"/>
- <source>Please select one or more UIDs before doing this operation.</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keypair_details/KeyPairUIDTab.cpp" line="263"/>
- <source>Sign Selected UID(s)</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keypair_details/KeyPairUIDTab.cpp" line="265"/>
- <source>Delete Selected UID(s)</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keypair_details/KeyPairUIDTab.cpp" line="284"/>
- <source>Successful Operation</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keypair_details/KeyPairUIDTab.cpp" line="285"/>
- <source>Successfully added a new UID.</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keypair_details/KeyPairUIDTab.cpp" line="288"/>
- <location filename="../../src/ui/keypair_details/KeyPairUIDTab.cpp" line="330"/>
- <location filename="../../src/ui/keypair_details/KeyPairUIDTab.cpp" line="363"/>
- <location filename="../../src/ui/keypair_details/KeyPairUIDTab.cpp" line="460"/>
- <location filename="../../src/ui/keypair_details/KeyPairUIDTab.cpp" line="507"/>
- <source>Operation Failed</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keypair_details/KeyPairUIDTab.cpp" line="289"/>
- <location filename="../../src/ui/keypair_details/KeyPairUIDTab.cpp" line="331"/>
- <location filename="../../src/ui/keypair_details/KeyPairUIDTab.cpp" line="364"/>
- <location filename="../../src/ui/keypair_details/KeyPairUIDTab.cpp" line="461"/>
- <location filename="../../src/ui/keypair_details/KeyPairUIDTab.cpp" line="508"/>
- <source>An error occurred during the operation.</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keypair_details/KeyPairUIDTab.cpp" line="313"/>
- <source>Deleting UIDs</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keypair_details/KeyPairUIDTab.cpp" line="314"/>
- <source>Are you sure that you want to delete the following uids?</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keypair_details/KeyPairUIDTab.cpp" line="315"/>
- <location filename="../../src/ui/keypair_details/KeyPairUIDTab.cpp" line="357"/>
- <location filename="../../src/ui/keypair_details/KeyPairUIDTab.cpp" line="454"/>
- <location filename="../../src/ui/keypair_details/KeyPairUIDTab.cpp" line="501"/>
- <source>The action can not be undone.</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keypair_details/KeyPairUIDTab.cpp" line="355"/>
- <source>Set Primary UID</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keypair_details/KeyPairUIDTab.cpp" line="356"/>
- <source>Are you sure that you want to set the Primary UID to?</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keypair_details/KeyPairUIDTab.cpp" line="395"/>
- <source>Set As Primary</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keypair_details/KeyPairUIDTab.cpp" line="397"/>
- <source>Sign UID</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keypair_details/KeyPairUIDTab.cpp" line="399"/>
- <source>Delete UID</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keypair_details/KeyPairUIDTab.cpp" line="426"/>
- <location filename="../../src/ui/keypair_details/KeyPairUIDTab.cpp" line="441"/>
- <source>Please select one UID before doing this operation.</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keypair_details/KeyPairUIDTab.cpp" line="452"/>
- <source>Deleting UID</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keypair_details/KeyPairUIDTab.cpp" line="453"/>
- <source>Are you sure that you want to delete the following uid?</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keypair_details/KeyPairUIDTab.cpp" line="469"/>
- <source>Delete(Revoke) Key Signature</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keypair_details/KeyPairUIDTab.cpp" line="481"/>
- <source>Please select one Key Signature before doing this operation.</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keypair_details/KeyPairUIDTab.cpp" line="488"/>
- <source>To delete the signature, you need to have its corresponding public key in the local database.</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keypair_details/KeyPairUIDTab.cpp" line="499"/>
- <source>Deleting Key Signature</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keypair_details/KeyPairUIDTab.cpp" line="500"/>
- <source>Are you sure that you want to delete the following signature?</source>
- <translation type="unfinished"></translation>
- </message>
-</context>
-<context>
- <name>KeyServerImportDialog</name>
- <message>
- <location filename="../../src/ui/KeyServerImportDialog.cpp" line="40"/>
- <source>&amp;Close</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/KeyServerImportDialog.cpp" line="41"/>
- <source>&amp;Import ALL</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/KeyServerImportDialog.cpp" line="42"/>
- <source>&amp;Search</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/KeyServerImportDialog.cpp" line="45"/>
- <source>Search String:</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/KeyServerImportDialog.cpp" line="49"/>
- <source>Key Server:</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/KeyServerImportDialog.cpp" line="97"/>
- <source>Update Keys from Keyserver</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/KeyServerImportDialog.cpp" line="99"/>
- <source>Import Keys from Keyserver</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/KeyServerImportDialog.cpp" line="158"/>
- <source>UID</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/KeyServerImportDialog.cpp" line="158"/>
- <source>Creation date</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/KeyServerImportDialog.cpp" line="158"/>
- <source>KeyID</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/KeyServerImportDialog.cpp" line="158"/>
- <source>Tag</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/KeyServerImportDialog.cpp" line="179"/>
- <source>Text is empty.</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/KeyServerImportDialog.cpp" line="213"/>
- <source>Not Key Found</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/KeyServerImportDialog.cpp" line="216"/>
- <location filename="../../src/ui/KeyServerImportDialog.cpp" line="386"/>
- <source>Timeout</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/KeyServerImportDialog.cpp" line="219"/>
- <location filename="../../src/ui/KeyServerImportDialog.cpp" line="389"/>
- <source>Key Server Not Found</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/KeyServerImportDialog.cpp" line="222"/>
- <location filename="../../src/ui/KeyServerImportDialog.cpp" line="392"/>
- <source>Connection Error</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/KeyServerImportDialog.cpp" line="230"/>
- <source>Too many responses from keyserver!</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/KeyServerImportDialog.cpp" line="237"/>
- <source>No keys found, input may be kexId, retrying search with 0x.</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/KeyServerImportDialog.cpp" line="242"/>
- <source>No keys found containing the search string!</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/KeyServerImportDialog.cpp" line="246"/>
- <source>Insufficiently specific search string!</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/KeyServerImportDialog.cpp" line="274"/>
- <source>revoked</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/KeyServerImportDialog.cpp" line="277"/>
- <source>disabled</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/KeyServerImportDialog.cpp" line="317"/>
- <source>&lt;h4&gt;%1 keys found. Double click a key to import it.&lt;/h4&gt;</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/KeyServerImportDialog.cpp" line="383"/>
- <source>Key Not Found</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/KeyServerImportDialog.cpp" line="410"/>
- <source>&lt;h4&gt;Key Updated&lt;/h4&gt;</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/KeyServerImportDialog.cpp" line="412"/>
- <source>&lt;h4&gt;Key Imported&lt;/h4&gt;</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/KeyServerImportDialog.cpp" line="473"/>
- <source>Upload Keys from Keyserver</source>
- <translation type="unfinished"></translation>
- </message>
-</context>
-<context>
- <name>KeySetExpireDateDialog</name>
- <message>
- <location filename="../../src/ui/keypair_details/KeySetExpireDateDialog.cpp" line="36"/>
- <source>Confirm</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keypair_details/KeySetExpireDateDialog.cpp" line="41"/>
- <source>Never Expire</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keypair_details/KeySetExpireDateDialog.cpp" line="61"/>
- <source>Operation Failed</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keypair_details/KeySetExpireDateDialog.cpp" line="62"/>
- <source>An error occurred during the operation.</source>
- <translation type="unfinished"></translation>
- </message>
-</context>
-<context>
- <name>KeyUIDSignDialog</name>
- <message>
- <location filename="../../src/ui/keypair_details/KeyUIDSignDialog.cpp" line="72"/>
- <source>Expire Date</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keypair_details/KeyUIDSignDialog.cpp" line="81"/>
- <source>Sign For Key&apos;s UID(s)</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keypair_details/KeyUIDSignDialog.cpp" line="99"/>
- <source>Unsuccessful Operation</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keypair_details/KeyUIDSignDialog.cpp" line="100"/>
- <source>Signature operation failed for UID </source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keypair_details/KeyUIDSignDialog.cpp" line="107"/>
- <source>Operation Complete</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keypair_details/KeyUIDSignDialog.cpp" line="108"/>
- <source>The signature operation of the UID is complete</source>
- <translation type="unfinished"></translation>
- </message>
-</context>
-<context>
- <name>KeyUploadDialog</name>
- <message>
- <location filename="../../src/ui/KeyUploadDialog.cpp" line="47"/>
- <source>Uploading Public Key</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/KeyUploadDialog.cpp" line="110"/>
- <source>Key Not Found</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/KeyUploadDialog.cpp" line="113"/>
- <source>Timeout</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/KeyUploadDialog.cpp" line="116"/>
- <source>Key Server Not Found</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/KeyUploadDialog.cpp" line="119"/>
- <source>Connection Error</source>
- <translation type="unfinished"></translation>
- </message>
-</context>
-<context>
- <name>KeyserverTab</name>
- <message>
- <location filename="../../src/ui/settings/SettingsKeyServer.cpp" line="32"/>
- <source>General</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/settings/SettingsKeyServer.cpp" line="53"/>
- <source>No.</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/settings/SettingsKeyServer.cpp" line="53"/>
- <source>Address</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/settings/SettingsKeyServer.cpp" line="53"/>
- <source>Available</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/settings/SettingsKeyServer.cpp" line="57"/>
- <source>Default Key Server for Import:</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/settings/SettingsKeyServer.cpp" line="67"/>
- <source>Add</source>
- <translation type="unfinished"></translation>
- </message>
-</context>
-<context>
- <name>MainWindow</name>
- <message>
- <location filename="../../src/MainWindow.cpp" line="35"/>
- <source>Loading Gnupg</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/MainWindow.cpp" line="62"/>
- <source>ENV Loading Failed</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/MainWindow.cpp" line="63"/>
- <source>Gnupg is not installed correctly, please follow the ReadME instructions to install gnupg and then open GPGFrontend.</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowFileSlotFunction.cpp" line="36"/>
- <location filename="../../src/ui/main_window/MainWindowFileSlotFunction.cpp" line="40"/>
- <location filename="../../src/ui/main_window/MainWindowFileSlotFunction.cpp" line="44"/>
- <location filename="../../src/ui/main_window/MainWindowFileSlotFunction.cpp" line="114"/>
- <location filename="../../src/ui/main_window/MainWindowFileSlotFunction.cpp" line="127"/>
- <location filename="../../src/ui/main_window/MainWindowFileSlotFunction.cpp" line="131"/>
- <location filename="../../src/ui/main_window/MainWindowFileSlotFunction.cpp" line="135"/>
- <location filename="../../src/ui/main_window/MainWindowFileSlotFunction.cpp" line="196"/>
- <location filename="../../src/ui/main_window/MainWindowFileSlotFunction.cpp" line="212"/>
- <location filename="../../src/ui/main_window/MainWindowFileSlotFunction.cpp" line="216"/>
- <location filename="../../src/ui/main_window/MainWindowFileSlotFunction.cpp" line="220"/>
- <location filename="../../src/ui/main_window/MainWindowFileSlotFunction.cpp" line="294"/>
- <location filename="../../src/ui/main_window/MainWindowFileSlotFunction.cpp" line="326"/>
- <location filename="../../src/ui/main_window/MainWindowFileSlotFunction.cpp" line="331"/>
- <location filename="../../src/ui/main_window/MainWindowFileSlotFunction.cpp" line="335"/>
- <location filename="../../src/ui/main_window/MainWindowFileSlotFunction.cpp" line="383"/>
- <location filename="../../src/ui/main_window/MainWindowFileSlotFunction.cpp" line="396"/>
- <location filename="../../src/ui/main_window/MainWindowFileSlotFunction.cpp" line="400"/>
- <location filename="../../src/ui/main_window/MainWindowFileSlotFunction.cpp" line="404"/>
- <location filename="../../src/ui/main_window/MainWindowFileSlotFunction.cpp" line="501"/>
- <location filename="../../src/ui/main_window/MainWindowFileSlotFunction.cpp" line="513"/>
- <location filename="../../src/ui/main_window/MainWindowFileSlotFunction.cpp" line="517"/>
- <location filename="../../src/ui/main_window/MainWindowFileSlotFunction.cpp" line="521"/>
- <location filename="../../src/ui/main_window/MainWindowFileSlotFunction.cpp" line="583"/>
- <location filename="../../src/ui/main_window/MainWindowServerSlotFunction.cpp" line="53"/>
- <location filename="../../src/ui/main_window/MainWindowServerSlotFunction.cpp" line="111"/>
- <location filename="../../src/ui/main_window/MainWindowServerSlotFunction.cpp" line="125"/>
- <location filename="../../src/ui/main_window/MainWindowServerSlotFunction.cpp" line="217"/>
- <location filename="../../src/ui/main_window/MainWindowServerSlotFunction.cpp" line="232"/>
- <location filename="../../src/ui/main_window/MainWindowSlotFunction.cpp" line="521"/>
- <location filename="../../src/ui/main_window/MainWindowSlotFunction.cpp" line="537"/>
- <source>Error</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowFileSlotFunction.cpp" line="36"/>
- <location filename="../../src/ui/main_window/MainWindowFileSlotFunction.cpp" line="127"/>
- <location filename="../../src/ui/main_window/MainWindowFileSlotFunction.cpp" line="212"/>
- <location filename="../../src/ui/main_window/MainWindowFileSlotFunction.cpp" line="396"/>
- <source>Select a file before doing it.</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowFileSlotFunction.cpp" line="40"/>
- <location filename="../../src/ui/main_window/MainWindowFileSlotFunction.cpp" line="131"/>
- <location filename="../../src/ui/main_window/MainWindowFileSlotFunction.cpp" line="216"/>
- <location filename="../../src/ui/main_window/MainWindowFileSlotFunction.cpp" line="400"/>
- <location filename="../../src/ui/main_window/MainWindowFileSlotFunction.cpp" line="517"/>
- <source>No permission to read this file.</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowFileSlotFunction.cpp" line="44"/>
- <location filename="../../src/ui/main_window/MainWindowFileSlotFunction.cpp" line="135"/>
- <location filename="../../src/ui/main_window/MainWindowFileSlotFunction.cpp" line="220"/>
- <location filename="../../src/ui/main_window/MainWindowFileSlotFunction.cpp" line="404"/>
- <location filename="../../src/ui/main_window/MainWindowFileSlotFunction.cpp" line="521"/>
- <source>No permission to create file.</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowFileSlotFunction.cpp" line="49"/>
- <location filename="../../src/ui/main_window/MainWindowFileSlotFunction.cpp" line="150"/>
- <location filename="../../src/ui/main_window/MainWindowFileSlotFunction.cpp" line="226"/>
- <location filename="../../src/ui/main_window/MainWindowFileSlotFunction.cpp" line="409"/>
- <source>Warning</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowFileSlotFunction.cpp" line="50"/>
- <location filename="../../src/ui/main_window/MainWindowFileSlotFunction.cpp" line="151"/>
- <location filename="../../src/ui/main_window/MainWindowFileSlotFunction.cpp" line="227"/>
- <location filename="../../src/ui/main_window/MainWindowFileSlotFunction.cpp" line="410"/>
- <source>The target file already exists, do you need to overwrite it?</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowFileSlotFunction.cpp" line="62"/>
- <location filename="../../src/ui/main_window/MainWindowFileSlotFunction.cpp" line="239"/>
- <location filename="../../src/ui/main_window/MainWindowFileSlotFunction.cpp" line="422"/>
- <location filename="../../src/ui/main_window/MainWindowSlotFunction.cpp" line="45"/>
- <location filename="../../src/ui/main_window/MainWindowSlotFunction.cpp" line="125"/>
- <location filename="../../src/ui/main_window/MainWindowSlotFunction.cpp" line="296"/>
- <source>No Key Selected</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowFileSlotFunction.cpp" line="69"/>
- <location filename="../../src/ui/main_window/MainWindowFileSlotFunction.cpp" line="246"/>
- <location filename="../../src/ui/main_window/MainWindowSlotFunction.cpp" line="52"/>
- <location filename="../../src/ui/main_window/MainWindowSlotFunction.cpp" line="132"/>
- <source>Invalid Operation</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowFileSlotFunction.cpp" line="70"/>
- <location filename="../../src/ui/main_window/MainWindowFileSlotFunction.cpp" line="247"/>
- <location filename="../../src/ui/main_window/MainWindowSlotFunction.cpp" line="53"/>
- <source>The selected key contains a key that does not actually have a encrypt usage.&lt;br/&gt;</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowFileSlotFunction.cpp" line="71"/>
- <location filename="../../src/ui/main_window/MainWindowFileSlotFunction.cpp" line="248"/>
- <location filename="../../src/ui/main_window/MainWindowFileSlotFunction.cpp" line="436"/>
- <location filename="../../src/ui/main_window/MainWindowSlotFunction.cpp" line="54"/>
- <location filename="../../src/ui/main_window/MainWindowSlotFunction.cpp" line="134"/>
- <location filename="../../src/ui/main_window/MainWindowSlotFunction.cpp" line="307"/>
- <source>&lt;br/&gt;For example the Following Key: &lt;br/&gt;</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowFileSlotFunction.cpp" line="91"/>
- <location filename="../../src/ui/main_window/MainWindowSlotFunction.cpp" line="72"/>
- <source>Encrypting</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowFileSlotFunction.cpp" line="114"/>
- <location filename="../../src/ui/main_window/MainWindowFileSlotFunction.cpp" line="196"/>
- <location filename="../../src/ui/main_window/MainWindowFileSlotFunction.cpp" line="294"/>
- <location filename="../../src/ui/main_window/MainWindowFileSlotFunction.cpp" line="383"/>
- <location filename="../../src/ui/main_window/MainWindowFileSlotFunction.cpp" line="501"/>
- <location filename="../../src/ui/main_window/MainWindowFileSlotFunction.cpp" line="583"/>
- <source>An error occurred during operation.</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowFileSlotFunction.cpp" line="268"/>
- <location filename="../../src/ui/main_window/MainWindowSlotFunction.cpp" line="150"/>
- <source>Signing</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowFileSlotFunction.cpp" line="327"/>
- <source>Please select the appropriate target file or signature file. Ensure that both are in this directory.</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowFileSlotFunction.cpp" line="331"/>
- <source>No permission to read target file.</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowFileSlotFunction.cpp" line="335"/>
- <source>No permission to read signature file.</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowFileSlotFunction.cpp" line="353"/>
- <location filename="../../src/ui/main_window/MainWindowSlotFunction.cpp" line="258"/>
- <source>Verifying</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowFileSlotFunction.cpp" line="434"/>
- <location filename="../../src/ui/main_window/MainWindowSlotFunction.cpp" line="305"/>
- <source>Invalid KeyPair</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowFileSlotFunction.cpp" line="435"/>
- <source>The selected keypair cannot be used for signing and encryption at the same time.&lt;br/&gt;</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowFileSlotFunction.cpp" line="446"/>
- <location filename="../../src/ui/main_window/MainWindowFileSlotFunction.cpp" line="453"/>
- <source>Incomplete Operation</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowFileSlotFunction.cpp" line="447"/>
- <source>None of the selected key pairs can provide the encryption function.</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowFileSlotFunction.cpp" line="454"/>
- <source>None of the selected key pairs can provide the signature function.</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowFileSlotFunction.cpp" line="473"/>
- <location filename="../../src/ui/main_window/MainWindowSlotFunction.cpp" line="345"/>
- <source>Encrypting and Signing</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowFileSlotFunction.cpp" line="513"/>
- <source>Select a file(.gpg/.asc) before doing it.</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowFileSlotFunction.cpp" line="551"/>
- <location filename="../../src/ui/main_window/MainWindowSlotFunction.cpp" line="440"/>
- <source>Decrypting and Verifying</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowServerSlotFunction.cpp" line="43"/>
- <location filename="../../src/ui/main_window/MainWindowServerSlotFunction.cpp" line="154"/>
- <source>Invalid Own Key</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowServerSlotFunction.cpp" line="154"/>
- <source>Own Key can not be use to do any operation.</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowServerSlotFunction.cpp" line="54"/>
- <source>Please obtain a Service Token from the server in the settings.</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowServerSlotFunction.cpp" line="44"/>
- <source>Own Key can not be use to do any operation. Please go to the setting interface to select an OwnKey and get a ServiceToken.</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowServerSlotFunction.cpp" line="90"/>
- <source>Getting Cpt From Server</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowServerSlotFunction.cpp" line="112"/>
- <location filename="../../src/ui/main_window/MainWindowServerSlotFunction.cpp" line="218"/>
- <source>The communication content with the server does not meet the requirements</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowServerSlotFunction.cpp" line="125"/>
- <source>Invalid short ciphertext</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowServerSlotFunction.cpp" line="143"/>
- <source>Invalid Service Token</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowServerSlotFunction.cpp" line="144"/>
- <source>Please go to the setting interface to get a ServiceToken.</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowServerSlotFunction.cpp" line="202"/>
- <source>Getting Scpt From Server</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowServerSlotFunction.cpp" line="228"/>
- <source>Notice: Use Decrypt &amp; Verify operation to decrypt this short crypto text.</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowServerSlotFunction.cpp" line="232"/>
- <source>There is a problem with the communication with the server</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowSlotFunction.cpp" line="102"/>
- <location filename="../../src/ui/main_window/MainWindowSlotFunction.cpp" line="394"/>
- <source>Function Disabled</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowSlotFunction.cpp" line="103"/>
- <location filename="../../src/ui/main_window/MainWindowSlotFunction.cpp" line="395"/>
- <source>Please go to the settings interface to enable and configure this function.</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowSlotFunction.cpp" line="133"/>
- <source>The selected key contains a key that does not actually have a signature usage.&lt;br/&gt;</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowSlotFunction.cpp" line="185"/>
- <source>Notice</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowSlotFunction.cpp" line="185"/>
- <source>Short Crypto Text only supports Decrypt &amp; Verify.</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowSlotFunction.cpp" line="199"/>
- <source>Decrypting</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowSlotFunction.cpp" line="306"/>
- <source>The selected keypair cannot be used for encryption.&lt;br/&gt;</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowSlotFunction.cpp" line="355"/>
- <source>Automatic Key Exchange Warning</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowSlotFunction.cpp" line="356"/>
- <source>Part of the automatic key exchange failed, which may be related to your key.</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowSlotFunction.cpp" line="358"/>
- <source>If possible, try to use the RSA algorithm compatible with the server for signing.</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowSlotFunction.cpp" line="401"/>
- <source>Service Token Empty</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowSlotFunction.cpp" line="402"/>
- <source>Please go to the settings interface to set Own Key and get Service Token.</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowSlotFunction.cpp" line="521"/>
- <location filename="../../src/ui/main_window/MainWindowSlotFunction.cpp" line="537"/>
- <source>Key Not Found.</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowSlotFunction.cpp" line="568"/>
- <source>Outdated Version</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowSlotFunction.cpp" line="569"/>
- <source>This version(%1) is out of date, please update the latest version in time. </source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowSlotFunction.cpp" line="571"/>
- <location filename="../../src/ui/main_window/MainWindowSlotFunction.cpp" line="578"/>
- <source>You can download the latest version(%1) on Github Releases Page.&lt;br/&gt;</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowSlotFunction.cpp" line="575"/>
- <source>Unreleased Version</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowSlotFunction.cpp" line="576"/>
- <source>This version(%1) has not been officially released and is not recommended for use in a production environment. &lt;br/&gt;</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowSlotUI.cpp" line="58"/>
- <source>There is one unencrypted file in attachment folder</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowSlotUI.cpp" line="60"/>
- <source>There are </source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowSlotUI.cpp" line="60"/>
- <source> unencrypted files in attachment folder</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowUI.cpp" line="30"/>
- <source>&amp;New</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowUI.cpp" line="36"/>
- <source>Open a new file</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowUI.cpp" line="39"/>
- <source>&amp;Open...</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowUI.cpp" line="42"/>
- <source>Open an existing file</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowUI.cpp" line="45"/>
- <source>&amp;Browser</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowUI.cpp" line="47"/>
- <source>Open a file browser</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowUI.cpp" line="50"/>
- <source>&amp;Save</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowUI.cpp" line="53"/>
- <source>Save the current File</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowUI.cpp" line="56"/>
- <source>Save &amp;As</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowUI.cpp" line="59"/>
- <source>Save the current File as...</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowUI.cpp" line="62"/>
- <source>&amp;Print</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowUI.cpp" line="65"/>
- <source>Print Document</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowUI.cpp" line="68"/>
- <source>&amp;Close</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowUI.cpp" line="70"/>
- <source>Close file</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowUI.cpp" line="73"/>
- <source>&amp;Quit</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowUI.cpp" line="76"/>
- <source>Quit Program</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowUI.cpp" line="81"/>
- <source>&amp;Undo</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowUI.cpp" line="83"/>
- <source>Undo Last Edit Action</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowUI.cpp" line="86"/>
- <source>&amp;Redo</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowUI.cpp" line="88"/>
- <source>Redo Last Edit Action</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowUI.cpp" line="91"/>
- <source>Zoom In</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowUI.cpp" line="95"/>
- <source>Zoom Out</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowUI.cpp" line="99"/>
- <source>&amp;Paste</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowUI.cpp" line="102"/>
- <source>Paste Text From Clipboard</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowUI.cpp" line="105"/>
- <source>Cu&amp;t</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowUI.cpp" line="108"/>
- <source>Cut the current selection&apos;s contents to the clipboard</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowUI.cpp" line="112"/>
- <source>&amp;Copy</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowUI.cpp" line="115"/>
- <source>Copy the current selection&apos;s contents to the clipboard</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowUI.cpp" line="119"/>
- <source>&amp;Quote</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowUI.cpp" line="121"/>
- <source>Quote whole text</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowUI.cpp" line="124"/>
- <source>Select &amp;All</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowUI.cpp" line="127"/>
- <source>Select the whole text</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowUI.cpp" line="130"/>
- <source>&amp;Find</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowUI.cpp" line="132"/>
- <source>Find a word</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowUI.cpp" line="135"/>
- <source>Remove &amp;spacing</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowUI.cpp" line="138"/>
- <source>Remove double linebreaks, e.g. in pasted text from webmailer</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowUI.cpp" line="141"/>
- <source>Se&amp;ttings</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowUI.cpp" line="142"/>
- <source>Open settings dialog</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowUI.cpp" line="148"/>
- <source>&amp;Encrypt</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowUI.cpp" line="151"/>
- <source>Encrypt Message</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowUI.cpp" line="154"/>
- <source>&amp;Encrypt &amp;Sign</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowUI.cpp" line="157"/>
- <source>Encrypt and Sign Message</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowUI.cpp" line="160"/>
- <source>&amp;Decrypt</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowUI.cpp" line="163"/>
- <source>Decrypt Message</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowUI.cpp" line="166"/>
- <source>&amp;Decrypt &amp;Verify</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowUI.cpp" line="169"/>
- <source>Decrypt and Verify Message</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowUI.cpp" line="175"/>
- <source>&amp;Encrypt File</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowUI.cpp" line="176"/>
- <source>Encrypt File</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowUI.cpp" line="179"/>
- <source>&amp;Decrypt File</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowUI.cpp" line="180"/>
- <source>Decrypt File</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowUI.cpp" line="183"/>
- <source>&amp;Sign File</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowUI.cpp" line="184"/>
- <source>Sign File</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowUI.cpp" line="187"/>
- <source>&amp;Verify File</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowUI.cpp" line="188"/>
- <source>Verify File</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowUI.cpp" line="192"/>
- <source>&amp;Sign</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowUI.cpp" line="195"/>
- <source>Sign Message</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowUI.cpp" line="198"/>
- <source>&amp;Verify</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowUI.cpp" line="201"/>
- <source>Verify Message</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowUI.cpp" line="207"/>
- <source>&amp;Editor</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowUI.cpp" line="209"/>
- <source>Import New Key From Editor</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowUI.cpp" line="212"/>
- <source>Manage &amp;Keys</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowUI.cpp" line="214"/>
- <source>Open Keymanagement</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowUI.cpp" line="220"/>
- <source>&amp;About</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowUI.cpp" line="222"/>
- <source>Show the application&apos;s About box</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowUI.cpp" line="228"/>
- <source>&amp;Check for Updates</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowUI.cpp" line="230"/>
- <source>Check for updates</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowUI.cpp" line="233"/>
- <source>Open &amp;Wizard</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowUI.cpp" line="234"/>
- <source>Open the wizard</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowUI.cpp" line="239"/>
- <source>Append Selected Key(s) To Text</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowUI.cpp" line="240"/>
- <source>Append The Selected Keys To Text in Editor</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowUI.cpp" line="243"/>
- <source>Copy Email</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowUI.cpp" line="244"/>
- <source>Copy selected Email to clipboard</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowUI.cpp" line="248"/>
- <source>Show Key Details</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowUI.cpp" line="249"/>
- <source>Show Details for this Key</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowUI.cpp" line="252"/>
- <source>Refresh Key From Key Server</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowUI.cpp" line="253"/>
- <source>Refresh key from default key server</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowUI.cpp" line="256"/>
- <source>Upload Public Key(s) To Server</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowUI.cpp" line="257"/>
- <source>Upload The Selected Public Keys To Server</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowUI.cpp" line="272"/>
- <source>Remove PGP Header</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowUI.cpp" line="275"/>
- <source>Add PGP Header</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowUI.cpp" line="280"/>
- <source>&amp;File</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowUI.cpp" line="293"/>
- <source>&amp;Edit</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowUI.cpp" line="311"/>
- <source>&amp;File...</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowUI.cpp" line="317"/>
- <source>&amp;Crypt</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowUI.cpp" line="328"/>
- <source>&amp;Keys</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowUI.cpp" line="329"/>
- <source>&amp;Import Key</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowUI.cpp" line="338"/>
- <source>&amp;Steganography</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowUI.cpp" line="347"/>
- <source>&amp;View</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowUI.cpp" line="349"/>
- <source>&amp;Help</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowUI.cpp" line="358"/>
- <source>File</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowUI.cpp" line="366"/>
- <source>Crypt</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowUI.cpp" line="376"/>
- <source>Key</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowUI.cpp" line="381"/>
- <source>Edit</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowUI.cpp" line="388"/>
- <source>Special Edit</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowUI.cpp" line="400"/>
- <source>Import key from...</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowUI.cpp" line="401"/>
- <source>Import key</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowUI.cpp" line="409"/>
- <source>Browser to view and operate file</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowUI.cpp" line="410"/>
- <source>Browser</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowUI.cpp" line="428"/>
- <source>Ready</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowUI.cpp" line="435"/>
- <source>Key ToolBox</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowUI.cpp" line="443"/>
- <source>Information Board</source>
- <translation type="unfinished"></translation>
- </message>
-</context>
-<context>
- <name>PubkeyGetter</name>
- <message>
- <location filename="../../src/server/api/PubkeyGetter.cpp" line="66"/>
- <location filename="../../src/server/api/PubkeyGetter.cpp" line="90"/>
- <source>Error</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/server/api/PubkeyGetter.cpp" line="67"/>
- <location filename="../../src/server/api/PubkeyGetter.cpp" line="91"/>
- <source>The communication content with the server does not meet the requirements</source>
- <translation type="unfinished"></translation>
- </message>
-</context>
-<context>
- <name>PubkeyUploader</name>
- <message>
- <location filename="../../src/server/api/PubkeyUploader.cpp" line="95"/>
- <source>Error</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/server/api/PubkeyUploader.cpp" line="96"/>
- <source>The communication content with the server does not meet the requirements</source>
- <translation type="unfinished"></translation>
- </message>
-</context>
-<context>
- <name>QApplication</name>
- <message>
- <location filename="../../src/gpg/result_analyse/DecryptResultAnalyse.cpp" line="66"/>
- <source> {&gt;} Recipient: </source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/gpg/result_analyse/VerifyResultAnalyse.cpp" line="63"/>
- <source>One or More Bad Signatures.</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/gpg/result_analyse/VerifyResultAnalyse.cpp" line="68"/>
- <source>A </source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/gpg/result_analyse/VerifyResultAnalyse.cpp" line="70"/>
- <source>Good </source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/gpg/result_analyse/VerifyResultAnalyse.cpp" line="73"/>
- <source>Bad </source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/gpg/result_analyse/VerifyResultAnalyse.cpp" line="76"/>
- <source>Expired </source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/gpg/result_analyse/VerifyResultAnalyse.cpp" line="79"/>
- <source>Missing Key&apos;s </source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/gpg/result_analyse/VerifyResultAnalyse.cpp" line="82"/>
- <source>Revoked Key&apos;s </source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/gpg/result_analyse/VerifyResultAnalyse.cpp" line="85"/>
- <source>Expired Key&apos;s </source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/gpg/result_analyse/VerifyResultAnalyse.cpp" line="88"/>
- <source>Missing CRL&apos;s </source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/gpg/result_analyse/VerifyResultAnalyse.cpp" line="92"/>
- <source>Signature Fully Valid.</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/gpg/result_analyse/VerifyResultAnalyse.cpp" line="94"/>
- <source>Signature Not Fully Valid.</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/gpg/result_analyse/VerifyResultAnalyse.cpp" line="100"/>
- <source>Key is NOT present with ID 0x</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/gpg/result_analyse/VerifyResultAnalyse.cpp" line="107"/>
- <source>A signature could NOT be verified due to a Missing Key
-</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/gpg/result_analyse/VerifyResultAnalyse.cpp" line="111"/>
- <source>A signature is valid but the key used to verify the signature has been revoked
-</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/gpg/result_analyse/VerifyResultAnalyse.cpp" line="119"/>
- <source>A signature is valid but expired
-</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/gpg/result_analyse/VerifyResultAnalyse.cpp" line="126"/>
- <source>A signature is valid but the key used to verify the signature has expired.
-</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/gpg/result_analyse/VerifyResultAnalyse.cpp" line="133"/>
- <source>There was some other error which prevented the signature verification.
-</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/gpg/result_analyse/VerifyResultAnalyse.cpp" line="139"/>
- <source>Error for key with fingerprint </source>
- <translation type="unfinished"></translation>
- </message>
-</context>
-<context>
- <name>QuitDialog</name>
- <message>
- <location filename="../../src/ui/QuitDialog.cpp" line="29"/>
- <source>Unsaved Files</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/QuitDialog.cpp" line="77"/>
- <source>%1 files contain unsaved information.&lt;br/&gt;Save the changes before closing?</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/QuitDialog.cpp" line="88"/>
- <source>Check the files you want to save:</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/QuitDialog.cpp" line="89"/>
- <source>&lt;b&gt;Note:&lt;/b&gt; If you don&apos;t save these files, all changes are lost.&lt;br/&gt;</source>
- <translation type="unfinished"></translation>
- </message>
-</context>
-<context>
- <name>SendMailDialog</name>
- <message>
- <location filename="../../src/ui/SendMailDialog.cpp" line="35"/>
- <source>Incomplete configuration</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/SendMailDialog.cpp" line="36"/>
- <source>The SMTP address is empty, please go to the setting interface to complete the configuration.</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/SendMailDialog.cpp" line="86"/>
- <source> Recipient cannot be empty
-</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/SendMailDialog.cpp" line="91"/>
- <source> One or more Recipient&apos;s Email Address is invalid
-</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/SendMailDialog.cpp" line="97"/>
- <source> Sender cannot be empty
-</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/SendMailDialog.cpp" line="99"/>
- <source> Sender&apos;s Email Address is invalid
-</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/SendMailDialog.cpp" line="155"/>
- <location filename="../../src/ui/SendMailDialog.cpp" line="160"/>
- <location filename="../../src/ui/SendMailDialog.cpp" line="165"/>
- <source>Fail</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/SendMailDialog.cpp" line="155"/>
- <source>Fail to Connect SMTP Server</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/SendMailDialog.cpp" line="160"/>
- <source>Fail to Login into SMTP Server</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/SendMailDialog.cpp" line="165"/>
- <source>Fail to Send Mail to SMTP Server</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/SendMailDialog.cpp" line="171"/>
- <source>Success</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/SendMailDialog.cpp" line="171"/>
- <source>Succeed in Sending Mail to SMTP Server</source>
- <translation type="unfinished"></translation>
- </message>
-</context>
-<context>
- <name>SendMailTab</name>
- <message>
- <location filename="../../src/ui/settings/SettingsSendMail.cpp" line="33"/>
- <source>Enable</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/settings/SettingsSendMail.cpp" line="51"/>
- <source>Check Connection</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/settings/SettingsSendMail.cpp" line="53"/>
- <source>General</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/settings/SettingsSendMail.cpp" line="54"/>
- <source>Connection</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/settings/SettingsSendMail.cpp" line="55"/>
- <source>Preference</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/settings/SettingsSendMail.cpp" line="61"/>
- <source>SMTP Address</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/settings/SettingsSendMail.cpp" line="63"/>
- <source>Username</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/settings/SettingsSendMail.cpp" line="65"/>
- <source>Password</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/settings/SettingsSendMail.cpp" line="67"/>
- <source>Port</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/settings/SettingsSendMail.cpp" line="69"/>
- <source>Connection Security</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/settings/SettingsSendMail.cpp" line="75"/>
- <source>Default Sender</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/settings/SettingsSendMail.cpp" line="161"/>
- <location filename="../../src/ui/settings/SettingsSendMail.cpp" line="165"/>
- <source>Fail</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/settings/SettingsSendMail.cpp" line="161"/>
- <source>Fail to Connect SMTP Server</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/settings/SettingsSendMail.cpp" line="165"/>
- <source>Fail to Login</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/settings/SettingsSendMail.cpp" line="170"/>
- <source>Success</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/settings/SettingsSendMail.cpp" line="170"/>
- <source>Succeed in connecting and login</source>
- <translation type="unfinished"></translation>
- </message>
-</context>
-<context>
- <name>SettingsDialog</name>
- <message>
- <location filename="../../src/ui/settings/SettingsDialog.cpp" line="39"/>
- <source>General</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/settings/SettingsDialog.cpp" line="40"/>
- <source>Appearance</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/settings/SettingsDialog.cpp" line="41"/>
- <source>Send Mail</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/settings/SettingsDialog.cpp" line="42"/>
- <source>Key Server</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/settings/SettingsDialog.cpp" line="44"/>
- <source>Advanced</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/settings/SettingsDialog.cpp" line="59"/>
- <source>Settings</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/settings/SettingsDialog.cpp" line="105"/>
- <source>System Default</source>
- <translation type="unfinished"></translation>
- </message>
-</context>
-<context>
- <name>SignResultAnalyse</name>
- <message>
- <location filename="../../src/gpg/result_analyse/SignResultAnalyse.cpp" line="31"/>
- <source>[#] Sign Operation </source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/gpg/result_analyse/SignResultAnalyse.cpp" line="34"/>
- <source>[Success]</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/gpg/result_analyse/SignResultAnalyse.cpp" line="36"/>
- <source>[Failed] </source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/gpg/result_analyse/SignResultAnalyse.cpp" line="47"/>
- <source>[&gt;] New Signature: </source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/gpg/result_analyse/SignResultAnalyse.cpp" line="51"/>
- <source> Sign Mode: </source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/gpg/result_analyse/SignResultAnalyse.cpp" line="53"/>
- <source>Normal</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/gpg/result_analyse/SignResultAnalyse.cpp" line="55"/>
- <source>Clear</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/gpg/result_analyse/SignResultAnalyse.cpp" line="57"/>
- <source>Detach</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/gpg/result_analyse/SignResultAnalyse.cpp" line="63"/>
- <location filename="../../src/gpg/result_analyse/SignResultAnalyse.cpp" line="65"/>
- <source> Signer: </source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/gpg/result_analyse/SignResultAnalyse.cpp" line="65"/>
- <source>&lt;unknown&gt;</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/gpg/result_analyse/SignResultAnalyse.cpp" line="67"/>
- <source> Public Key Algo: </source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/gpg/result_analyse/SignResultAnalyse.cpp" line="68"/>
- <source> Hash Algo: </source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/gpg/result_analyse/SignResultAnalyse.cpp" line="69"/>
- <source> Date &amp; Time: </source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/gpg/result_analyse/SignResultAnalyse.cpp" line="81"/>
- <source>Invalid Signers: </source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/gpg/result_analyse/SignResultAnalyse.cpp" line="85"/>
- <source>[&gt;] Signer: </source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/gpg/result_analyse/SignResultAnalyse.cpp" line="86"/>
- <source> Fingerprint: </source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/gpg/result_analyse/SignResultAnalyse.cpp" line="87"/>
- <source> Reason: </source>
- <translation type="unfinished"></translation>
- </message>
-</context>
-<context>
- <name>SignersPicker</name>
- <message>
- <location filename="../../src/ui/widgets/SignersPicker.cpp" line="28"/>
- <source>Confirm</source>
- <translation type="unfinished"></translation>
- </message>
-</context>
-<context>
- <name>SubkeyGenerateDialog</name>
- <message>
- <location filename="../../src/ui/keygen/SubkeyGenerateDialog.cpp" line="47"/>
- <source>Generate New Subkey</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keygen/SubkeyGenerateDialog.cpp" line="62"/>
- <source>Encryption</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keygen/SubkeyGenerateDialog.cpp" line="65"/>
- <source>Signing</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keygen/SubkeyGenerateDialog.cpp" line="68"/>
- <source>Certification</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keygen/SubkeyGenerateDialog.cpp" line="71"/>
- <source>Authentication</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keygen/SubkeyGenerateDialog.cpp" line="115"/>
- <source>Expiration Date:</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keygen/SubkeyGenerateDialog.cpp" line="116"/>
- <source>Never Expire</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keygen/SubkeyGenerateDialog.cpp" line="117"/>
- <source>KeySize (in Bit):</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keygen/SubkeyGenerateDialog.cpp" line="118"/>
- <source>Key Type:</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keygen/SubkeyGenerateDialog.cpp" line="127"/>
- <source>Basic Information</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keygen/SubkeyGenerateDialog.cpp" line="215"/>
- <source> Expiration time no more than 2 years. </source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keygen/SubkeyGenerateDialog.cpp" line="244"/>
- <source>Success</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keygen/SubkeyGenerateDialog.cpp" line="244"/>
- <source>The new subkey has been generated.</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keygen/SubkeyGenerateDialog.cpp" line="247"/>
- <source>Failure</source>
- <translation type="unfinished"></translation>
- </message>
-</context>
-<context>
- <name>TextEdit</name>
- <message>
- <location filename="../../src/ui/widgets/TextEdit.cpp" line="53"/>
- <source>untitled</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/widgets/TextEdit.cpp" line="120"/>
- <location filename="../../src/ui/widgets/TextEdit.cpp" line="200"/>
- <source>Warning</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/widgets/TextEdit.cpp" line="121"/>
- <location filename="../../src/ui/widgets/TextEdit.cpp" line="201"/>
- <location filename="../../src/ui/widgets/TextEdit.cpp" line="482"/>
- <source>Cannot read file %1:
-%2.</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/widgets/TextEdit.cpp" line="175"/>
- <source>Open file</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/widgets/TextEdit.cpp" line="251"/>
- <source>File</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/widgets/TextEdit.cpp" line="252"/>
- <source>Cannot write file %1:
-%2.</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/widgets/TextEdit.cpp" line="270"/>
- <source>Save file</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/widgets/TextEdit.cpp" line="333"/>
- <source>Unsaved document</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/widgets/TextEdit.cpp" line="334"/>
- <source>The document &quot;%1&quot; has been modified. Do you want to save your changes?&lt;br/&gt;</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/widgets/TextEdit.cpp" line="337"/>
- <source>&lt;b&gt;Note:&lt;/b&gt; If you don&apos;t save these files, all changes are lost.&lt;br/&gt;</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/widgets/TextEdit.cpp" line="481"/>
- <source>Application</source>
- <translation type="unfinished"></translation>
- </message>
-</context>
-<context>
- <name>UpdateTab</name>
- <message>
- <location filename="../../src/ui/help/AboutDialog.cpp" line="129"/>
- <source>It is recommended that you always check the version of GpgFrontend and upgrade to the latest version.</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/help/AboutDialog.cpp" line="131"/>
- <source>New versions not only represent new features, but also often represent functional and security fixes.</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/help/AboutDialog.cpp" line="135"/>
- <source>Current Version: </source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/help/AboutDialog.cpp" line="143"/>
- <source>The current version is inconsistent with the latest version on github.</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/help/AboutDialog.cpp" line="145"/>
- <source>Please click &lt;a href=&quot;https://github.com/saturneric/GpgFrontend/releases&quot;&gt;here&lt;/a&gt; to download the latest version.</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/help/AboutDialog.cpp" line="199"/>
- <location filename="../../src/ui/help/AboutDialog.cpp" line="214"/>
- <source>Latest Version From Github: </source>
- <translation type="unfinished"></translation>
- </message>
-</context>
-<context>
- <name>VerifyDetailsDialog</name>
- <message>
- <location filename="../../src/ui/VerifyDetailsDialog.cpp" line="32"/>
- <source>Signature Details</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/VerifyDetailsDialog.cpp" line="53"/>
- <source>Status: </source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/VerifyDetailsDialog.cpp" line="56"/>
- <source>No valid input found</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/VerifyDetailsDialog.cpp" line="67"/>
- <source>Error Validating signature</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/VerifyDetailsDialog.cpp" line="70"/>
- <source>File was signed on %1 &lt;br/&gt; It Contains:&lt;br/&gt;&lt;br/&gt;</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/VerifyDetailsDialog.cpp" line="72"/>
- <source>Signed on %1 &lt;br/&gt; It Contains:&lt;br /&gt;&lt;br/&gt;</source>
- <translation type="unfinished"></translation>
- </message>
-</context>
-<context>
- <name>VerifyKeyDetailBox</name>
- <message>
- <location filename="../../src/ui/widgets/VerifyKeyDetailBox.cpp" line="36"/>
- <source>Import from keyserver</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/widgets/VerifyKeyDetailBox.cpp" line="39"/>
- <source>Key not present with id 0x</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/widgets/VerifyKeyDetailBox.cpp" line="43"/>
- <source>Status:</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/widgets/VerifyKeyDetailBox.cpp" line="45"/>
- <source>Key not present in keylist</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/widgets/VerifyKeyDetailBox.cpp" line="58"/>
- <location filename="../../src/ui/widgets/VerifyKeyDetailBox.cpp" line="72"/>
- <location filename="../../src/ui/widgets/VerifyKeyDetailBox.cpp" line="86"/>
- <location filename="../../src/ui/widgets/VerifyKeyDetailBox.cpp" line="101"/>
- <location filename="../../src/ui/widgets/VerifyKeyDetailBox.cpp" line="115"/>
- <location filename="../../src/ui/widgets/VerifyKeyDetailBox.cpp" line="129"/>
- <source>Key Information is NOT Available</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/widgets/VerifyKeyDetailBox.cpp" line="60"/>
- <location filename="../../src/ui/widgets/VerifyKeyDetailBox.cpp" line="74"/>
- <location filename="../../src/ui/widgets/VerifyKeyDetailBox.cpp" line="88"/>
- <location filename="../../src/ui/widgets/VerifyKeyDetailBox.cpp" line="103"/>
- <location filename="../../src/ui/widgets/VerifyKeyDetailBox.cpp" line="117"/>
- <location filename="../../src/ui/widgets/VerifyKeyDetailBox.cpp" line="131"/>
- <source>Fingerprint: </source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/widgets/VerifyKeyDetailBox.cpp" line="67"/>
- <source>Status: Cert Revoked</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/widgets/VerifyKeyDetailBox.cpp" line="81"/>
- <location filename="../../src/ui/widgets/VerifyKeyDetailBox.cpp" line="95"/>
- <source>Status: Signature Expired</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/widgets/VerifyKeyDetailBox.cpp" line="96"/>
- <source>Status: Key Expired</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/widgets/VerifyKeyDetailBox.cpp" line="110"/>
- <source>Status: General Error</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/widgets/VerifyKeyDetailBox.cpp" line="124"/>
- <source>Status: Unknown Error</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/widgets/VerifyKeyDetailBox.cpp" line="159"/>
- <source>Signer Name:</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/widgets/VerifyKeyDetailBox.cpp" line="160"/>
- <source>Signer Email:</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/widgets/VerifyKeyDetailBox.cpp" line="161"/>
- <source>Key&apos;s Fingerprint:</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/widgets/VerifyKeyDetailBox.cpp" line="162"/>
- <source>Valid:</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/widgets/VerifyKeyDetailBox.cpp" line="163"/>
- <source>Flags:</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/widgets/VerifyKeyDetailBox.cpp" line="171"/>
- <source>Fully Valid</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/widgets/VerifyKeyDetailBox.cpp" line="173"/>
- <source>NOT Fully Valid</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/widgets/VerifyKeyDetailBox.cpp" line="180"/>
- <source>Good </source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/widgets/VerifyKeyDetailBox.cpp" line="183"/>
- <source>Bad </source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/widgets/VerifyKeyDetailBox.cpp" line="186"/>
- <source>Expired </source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/widgets/VerifyKeyDetailBox.cpp" line="189"/>
- <source>Missing Key </source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/widgets/VerifyKeyDetailBox.cpp" line="192"/>
- <source>Revoked Key </source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/widgets/VerifyKeyDetailBox.cpp" line="195"/>
- <source>Expired Key </source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/widgets/VerifyKeyDetailBox.cpp" line="198"/>
- <source>Missing CRL </source>
- <translation type="unfinished"></translation>
- </message>
-</context>
-<context>
- <name>VerifyResultAnalyse</name>
- <message>
- <location filename="../../src/gpg/result_analyse/VerifyResultAnalyse.cpp" line="33"/>
- <source>[#] Verify Operation </source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/gpg/result_analyse/VerifyResultAnalyse.cpp" line="36"/>
- <source>[Success]</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/gpg/result_analyse/VerifyResultAnalyse.cpp" line="38"/>
- <source>[Failed] </source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/gpg/result_analyse/VerifyResultAnalyse.cpp" line="157"/>
- <location filename="../../src/gpg/result_analyse/VerifyResultAnalyse.cpp" line="161"/>
- <source> Signed By: </source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/gpg/result_analyse/VerifyResultAnalyse.cpp" line="157"/>
- <source>&lt;unknown&gt;</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/gpg/result_analyse/VerifyResultAnalyse.cpp" line="163"/>
- <source> Public Key Algo: </source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/gpg/result_analyse/VerifyResultAnalyse.cpp" line="164"/>
- <source> Hash Algo: </source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/gpg/result_analyse/VerifyResultAnalyse.cpp" line="165"/>
- <source> Date &amp; Time: </source>
- <translation type="unfinished"></translation>
- </message>
-</context>
-<context>
- <name>Wizard</name>
- <message>
- <location filename="../../src/ui/Wizard.cpp" line="40"/>
- <source>First Start Wizard</source>
- <translation type="unfinished"></translation>
- </message>
-</context>
-</TS>
diff --git a/resource/ts/gpgfrontend_zh_cn.ts b/resource/ts/gpgfrontend_zh_cn.ts
deleted file mode 100644
index 79311e81..00000000
--- a/resource/ts/gpgfrontend_zh_cn.ts
+++ /dev/null
@@ -1,3854 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!DOCTYPE TS>
-<TS version="2.1" language="zh_CN">
-<context>
- <name>AboutDialog</name>
- <message>
- <location filename="../../src/ui/help/AboutDialog.cpp" line="35"/>
- <source>About </source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/help/AboutDialog.cpp" line="42"/>
- <source>General</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/help/AboutDialog.cpp" line="43"/>
- <source>Translators</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/help/AboutDialog.cpp" line="44"/>
- <source>Update</source>
- <translation type="unfinished"></translation>
- </message>
-</context>
-<context>
- <name>AdvancedTab</name>
- <message>
- <location filename="../../src/ui/settings/SettingsAdvanced.cpp" line="34"/>
- <source>Show Steganography Options</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/settings/SettingsAdvanced.cpp" line="36"/>
- <source>Show Steganographic Options.</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/settings/SettingsAdvanced.cpp" line="40"/>
- <source>Pubkey Exchange</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/settings/SettingsAdvanced.cpp" line="42"/>
- <source>Auto Pubkey Exchange</source>
- <translation type="unfinished"></translation>
- </message>
-</context>
-<context>
- <name>AppearanceTab</name>
- <message>
- <location filename="../../src/ui/settings/SettingsAppearance.cpp" line="34"/>
- <source>Iconsize</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/settings/SettingsAppearance.cpp" line="36"/>
- <source>small</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/settings/SettingsAppearance.cpp" line="37"/>
- <source>medium</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/settings/SettingsAppearance.cpp" line="38"/>
- <source>large</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/settings/SettingsAppearance.cpp" line="54"/>
- <source>Iconstyle</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/settings/SettingsAppearance.cpp" line="56"/>
- <source>just text</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/settings/SettingsAppearance.cpp" line="57"/>
- <source>just icons</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/settings/SettingsAppearance.cpp" line="58"/>
- <source>text and icons</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/settings/SettingsAppearance.cpp" line="74"/>
- <source>Windowstate</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/settings/SettingsAppearance.cpp" line="77"/>
- <source>Save window size and position on exit.</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/settings/SettingsAppearance.cpp" line="85"/>
- <source>Information Board</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/settings/SettingsAppearance.cpp" line="91"/>
- <source> Front Size</source>
- <translation type="unfinished"></translation>
- </message>
-</context>
-<context>
- <name>ChoosePage</name>
- <message>
- <location filename="../../src/ui/Wizard.cpp" line="121"/>
- <source>Choose your action...</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/Wizard.cpp" line="122"/>
- <source>...by clicking on the appropriate link.</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/Wizard.cpp" line="124"/>
- <source>If you have never used GPGFrontend before and also don&apos;t own a gpg key yet you may possibly want to read how to</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/Wizard.cpp" line="127"/>
- <source>Generate Key</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/Wizard.cpp" line="134"/>
- <source>If you want to learn how to encrypt, decrypt, sign and verify text, you can read </source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/Wizard.cpp" line="136"/>
- <source>Encrypt &amp; Decrypt Text</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/Wizard.cpp" line="136"/>
- <location filename="../../src/ui/Wizard.cpp" line="149"/>
- <source>or</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/Wizard.cpp" line="138"/>
- <source>Sign &amp; Verify Text</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/Wizard.cpp" line="146"/>
- <source>If you want to operate file, you can read </source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/Wizard.cpp" line="149"/>
- <source>Encrypt &amp; Sign File</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/Wizard.cpp" line="152"/>
- <source>Sign &amp; Verify File</source>
- <translation type="unfinished"></translation>
- </message>
-</context>
-<context>
- <name>ComUtils</name>
- <message>
- <location filename="../../src/server/ComUtils.cpp" line="35"/>
- <location filename="../../src/server/ComUtils.cpp" line="55"/>
- <source>Error</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/server/ComUtils.cpp" line="35"/>
- <source>Nothing Reply. Please check the Internet connection.</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/server/ComUtils.cpp" line="55"/>
- <source>Unknown Error</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/server/ComUtils.cpp" line="75"/>
- <location filename="../../src/server/ComUtils.cpp" line="90"/>
- <source>Network Error</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/server/ComUtils.cpp" line="75"/>
- <source>Outdated Reply</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/server/ComUtils.cpp" line="87"/>
- <source>Unknown Reason</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/server/ComUtils.cpp" line="90"/>
- <source>Unknown Reply Format</source>
- <translation type="unfinished"></translation>
- </message>
-</context>
-<context>
- <name>ConclusionPage</name>
- <message>
- <location filename="../../src/ui/Wizard.cpp" line="224"/>
- <source>Ready.</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/Wizard.cpp" line="225"/>
- <source>Have fun with GPGFrontend!</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/Wizard.cpp" line="227"/>
- <source>You are ready to use GPGFrontend now.&lt;br&gt;&lt;br&gt;</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/Wizard.cpp" line="229"/>
- <source>The Online Document</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/Wizard.cpp" line="231"/>
- <source> will get you started with GPGFrontend. It will open in the main window.&lt;br&gt;</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/Wizard.cpp" line="238"/>
- <source>Open offline help.</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/Wizard.cpp" line="241"/>
- <source>Dont show the wizard again.</source>
- <translation type="unfinished"></translation>
- </message>
-</context>
-<context>
- <name>DecryptResultAnalyse</name>
- <message>
- <location filename="../../src/gpg/result_analyse/DecryptResultAnalyse.cpp" line="30"/>
- <source>[#] Decrypt Operation </source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/gpg/result_analyse/DecryptResultAnalyse.cpp" line="33"/>
- <source>[Success]</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/gpg/result_analyse/DecryptResultAnalyse.cpp" line="35"/>
- <source>[Failed] </source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/gpg/result_analyse/DecryptResultAnalyse.cpp" line="39"/>
- <source>Unsupported Algo: </source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/gpg/result_analyse/DecryptResultAnalyse.cpp" line="46"/>
- <source>File Name: </source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/gpg/result_analyse/DecryptResultAnalyse.cpp" line="52"/>
- <source>Recipient(s): </source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/gpg/result_analyse/DecryptResultAnalyse.cpp" line="82"/>
- <source> Keu ID: </source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/gpg/result_analyse/DecryptResultAnalyse.cpp" line="83"/>
- <source> Public Algo: </source>
- <translation type="unfinished"></translation>
- </message>
-</context>
-<context>
- <name>EncryptResultAnalyse</name>
- <message>
- <location filename="../../src/gpg/result_analyse/EncryptResultAnalyse.cpp" line="43"/>
- <source>Invalid Recipients: </source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/gpg/result_analyse/EncryptResultAnalyse.cpp" line="46"/>
- <source>Fingerprint: </source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/gpg/result_analyse/EncryptResultAnalyse.cpp" line="47"/>
- <source>Reason: </source>
- <translation type="unfinished"></translation>
- </message>
-</context>
-<context>
- <name>FileEncryptionDialog</name>
- <message>
- <location filename="../../src/ui/FileEncryptionDialog.cpp" line="32"/>
- <source>Decrypt File</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/FileEncryptionDialog.cpp" line="34"/>
- <source>Encrypt File</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/FileEncryptionDialog.cpp" line="36"/>
- <source>Sign File</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/FileEncryptionDialog.cpp" line="38"/>
- <source>Verify File</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/FileEncryptionDialog.cpp" line="47"/>
- <source>Input Parameters</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/FileEncryptionDialog.cpp" line="53"/>
- <source>Target File</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/FileEncryptionDialog.cpp" line="59"/>
- <source>Output File</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/FileEncryptionDialog.cpp" line="75"/>
- <source>Signature File(.sig) Path</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/FileEncryptionDialog.cpp" line="134"/>
- <location filename="../../src/ui/FileEncryptionDialog.cpp" line="177"/>
- <source>Open File</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/FileEncryptionDialog.cpp" line="165"/>
- <source>Save File</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/FileEncryptionDialog.cpp" line="194"/>
- <location filename="../../src/ui/FileEncryptionDialog.cpp" line="245"/>
- <source>Couldn&apos;t open file</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/FileEncryptionDialog.cpp" line="213"/>
- <location filename="../../src/ui/FileEncryptionDialog.cpp" line="224"/>
- <location filename="../../src/ui/FileEncryptionDialog.cpp" line="235"/>
- <source>Error</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/FileEncryptionDialog.cpp" line="214"/>
- <source>Error Occurred During Encryption</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/FileEncryptionDialog.cpp" line="225"/>
- <source>Error Occurred During Decryption</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/FileEncryptionDialog.cpp" line="236"/>
- <source>Error Occurred During Signature</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/FileEncryptionDialog.cpp" line="259"/>
- <location filename="../../src/ui/FileEncryptionDialog.cpp" line="268"/>
- <source>File</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/FileEncryptionDialog.cpp" line="260"/>
- <source>File exists! Do you want to overwrite it?</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/FileEncryptionDialog.cpp" line="269"/>
- <source>Cannot write file %1:
-%2.</source>
- <translation type="unfinished"></translation>
- </message>
-</context>
-<context>
- <name>FilePage</name>
- <message>
- <location filename="../../src/ui/widgets/FilePage.cpp" line="161"/>
- <source>Open</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/widgets/FilePage.cpp" line="163"/>
- <source>Delete</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/widgets/FilePage.cpp" line="165"/>
- <source>Encrypt and Sign</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/widgets/FilePage.cpp" line="167"/>
- <source>Decrypt and Verify</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/widgets/FilePage.cpp" line="169"/>
- <source>Only Sign</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/widgets/FilePage.cpp" line="171"/>
- <source>Only Verify</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/widgets/FilePage.cpp" line="222"/>
- <source>Warning</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/widgets/FilePage.cpp" line="223"/>
- <source>Are you sure you want to delete it?</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/widgets/FilePage.cpp" line="233"/>
- <source>Error</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/widgets/FilePage.cpp" line="234"/>
- <source>Unable to delete the file or folder.</source>
- <translation type="unfinished"></translation>
- </message>
-</context>
-<context>
- <name>FindWidget</name>
- <message>
- <location filename="../../src/ui/FindWidget.cpp" line="38"/>
- <source>Find:</source>
- <translation type="unfinished"></translation>
- </message>
-</context>
-<context>
- <name>GeneralTab</name>
- <message>
- <location filename="../../src/ui/settings/SettingsGeneral.cpp" line="40"/>
- <source>GpgFrontend Server</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/settings/SettingsGeneral.cpp" line="45"/>
- <source>Server that provides short key and key exchange services</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/settings/SettingsGeneral.cpp" line="52"/>
- <source>Save Checked Keys</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/settings/SettingsGeneral.cpp" line="55"/>
- <source>Save checked private keys on exit and restore them on next start.</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/settings/SettingsGeneral.cpp" line="64"/>
- <source>Confirm drag&apos;n&apos;drop key import</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/settings/SettingsGeneral.cpp" line="67"/>
- <source>Import files dropped on the keylist without confirmation.</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/settings/SettingsGeneral.cpp" line="74"/>
- <source>Language</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/settings/SettingsGeneral.cpp" line="83"/>
- <source>&lt;b&gt;NOTE: &lt;/b&gt; GpgFrontend will restart automatically if you change the language!</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/settings/SettingsGeneral.cpp" line="92"/>
- <source>Own key</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/settings/SettingsGeneral.cpp" line="96"/>
- <source>Get Service Token</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/settings/SettingsGeneral.cpp" line="97"/>
- <location filename="../../src/ui/settings/SettingsGeneral.cpp" line="235"/>
- <source>No Service Token Found</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/settings/SettingsGeneral.cpp" line="104"/>
- <source>&lt;none&gt;</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/settings/SettingsGeneral.cpp" line="121"/>
- <source>Key pair for synchronization and identity authentication</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/settings/SettingsGeneral.cpp" line="253"/>
- <source>Invalid Operation</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/settings/SettingsGeneral.cpp" line="254"/>
- <source>Own Key can not be None while getting service token.</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/settings/SettingsGeneral.cpp" line="266"/>
- <location filename="../../src/ui/settings/SettingsGeneral.cpp" line="337"/>
- <location filename="../../src/ui/settings/SettingsGeneral.cpp" line="354"/>
- <source>Error</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/settings/SettingsGeneral.cpp" line="267"/>
- <source>Key Not Exists</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/settings/SettingsGeneral.cpp" line="338"/>
- <source>The communication content with the server does not meet the requirements</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/settings/SettingsGeneral.cpp" line="351"/>
- <source>Notice</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/settings/SettingsGeneral.cpp" line="352"/>
- <source>Succeed in getting service token</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/settings/SettingsGeneral.cpp" line="354"/>
- <source>There is a problem with the communication with the server</source>
- <translation type="unfinished"></translation>
- </message>
-</context>
-<context>
- <name>GpgME::GpgContext</name>
- <message>
- <location filename="../../src/gpg/gpg_context/GpgContext.cpp" line="182"/>
- <source>Wrong password</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/gpg/gpg_context/GpgContext.cpp" line="190"/>
- <source>Enter Password for</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/gpg/gpg_context/GpgContext.cpp" line="194"/>
- <source>Enter Password</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/gpg/gpg_context/GpgContext.cpp" line="256"/>
- <source>Processing</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/gpg/gpg_context/GpgContextBasicOpera.cpp" line="169"/>
- <source>Key Selection</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/gpg/gpg_context/GpgContextBasicOpera.cpp" line="169"/>
- <source>No Private Key Selected</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/gpg/gpg_context/GpgContextBasicOpera.cpp" line="200"/>
- <source>Error in signing:</source>
- <translation type="unfinished"></translation>
- </message>
-</context>
-<context>
- <name>GpgPathsTab</name>
- <message>
- <location filename="../../src/ui/settings/SettingsDialog.cpp" line="139"/>
- <source>Relative path to keydb</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/settings/SettingsDialog.cpp" line="152"/>
- <source>Current keydb path: </source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/settings/SettingsDialog.cpp" line="157"/>
- <source>&lt;b&gt;NOTE: &lt;/b&gt; Gpg4usb will restart automatically if you change the keydb path!</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/settings/SettingsDialog.cpp" line="186"/>
- <source>Choose keydb directory</source>
- <translation type="unfinished"></translation>
- </message>
-</context>
-<context>
- <name>InfoBoardWidget</name>
- <message>
- <location filename="../../src/ui/widgets/InfoBoardWidget.cpp" line="40"/>
- <source>Import missing key from Keyserver</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/widgets/InfoBoardWidget.cpp" line="57"/>
- <source>Optional Actions</source>
- <translation type="unfinished"></translation>
- </message>
-</context>
-<context>
- <name>InfoTab</name>
- <message>
- <location filename="../../src/ui/help/AboutDialog.cpp" line="76"/>
- <source>&lt;br&gt;&lt;center&gt;GPGFrontend is an easy-to-use, compact, cross-platform, &lt;br&gt;and installation-free gpg front-end tool.&lt;br&gt;It visualizes most of the common operations of gpg commands.&lt;br&gt;It&apos;s licensed under the GPL v3&lt;br&gt;&lt;br&gt;&lt;b&gt;Developer:&lt;/b&gt;&lt;br&gt;Saturneric&lt;br&gt;&lt;br&gt;If you have any questions or suggestions, raise an issue&lt;br/&gt;at &lt;a href=&quot;https://github.com/saturneric/GpgFrontend&quot;&gt;GitHub&lt;/a&gt; or send a mail to my mailing list at &lt;a href=&quot;mailto:[email protected]&quot;&gt;[email protected]&lt;/a&gt;.</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/help/AboutDialog.cpp" line="84"/>
- <source>&lt;br&gt;&lt;br&gt; Built with Qt </source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/help/AboutDialog.cpp" line="85"/>
- <source> and GPGME </source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/help/AboutDialog.cpp" line="86"/>
- <source>&lt;br&gt;Built at </source>
- <translation type="unfinished"></translation>
- </message>
-</context>
-<context>
- <name>IntroPage</name>
- <message>
- <location filename="../../src/ui/Wizard.cpp" line="66"/>
- <source>Getting Started...</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/Wizard.cpp" line="67"/>
- <source>... with GPGFrontend</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/Wizard.cpp" line="69"/>
- <source>Welcome to use GPGFrontend for decrypting and signing text or file!</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/Wizard.cpp" line="71"/>
- <source>is a Powerful, Easy-to-Use, Compact, Cross-Platform, and Installation-Free OpenPGP Crypto Tool.</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/Wizard.cpp" line="72"/>
- <source>For brief information have a look at the</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/Wizard.cpp" line="74"/>
- <source>Overview</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/Wizard.cpp" line="75"/>
- <source>by clicking the link, the page will open in the web browser</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/Wizard.cpp" line="83"/>
- <source>Choose a Language</source>
- <translation type="unfinished"></translation>
- </message>
-</context>
-<context>
- <name>KeyDetailsDialog</name>
- <message>
- <location filename="../../src/ui/keypair_details/KeyDetailsDialog.cpp" line="31"/>
- <source>KeyPair</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keypair_details/KeyDetailsDialog.cpp" line="32"/>
- <source>UIDs</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keypair_details/KeyDetailsDialog.cpp" line="33"/>
- <source>Subkeys</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keypair_details/KeyDetailsDialog.cpp" line="40"/>
- <source>Key Details</source>
- <translation type="unfinished"></translation>
- </message>
-</context>
-<context>
- <name>KeyGenDialog</name>
- <message>
- <location filename="../../src/ui/keygen/KeygenDialog.cpp" line="33"/>
- <source>Generate Key</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keygen/KeygenDialog.cpp" line="69"/>
- <source> Name must contain at least five characters.
-</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keygen/KeygenDialog.cpp" line="71"/>
- <source> Please give a email address.
-</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keygen/KeygenDialog.cpp" line="78"/>
- <source> Expiration time no more than 2 years.
-</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keygen/KeygenDialog.cpp" line="112"/>
- <source>Success</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keygen/KeygenDialog.cpp" line="112"/>
- <source>The new key pair has been generated.</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keygen/KeygenDialog.cpp" line="116"/>
- <source>Failure</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keygen/KeygenDialog.cpp" line="145"/>
- <source>Key Usage</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keygen/KeygenDialog.cpp" line="147"/>
- <source>Encryption</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keygen/KeygenDialog.cpp" line="150"/>
- <source>Signing</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keygen/KeygenDialog.cpp" line="153"/>
- <source>Certification</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keygen/KeygenDialog.cpp" line="156"/>
- <source>Authentication</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keygen/KeygenDialog.cpp" line="338"/>
- <source>Name:</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keygen/KeygenDialog.cpp" line="339"/>
- <source>Email Address:</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keygen/KeygenDialog.cpp" line="340"/>
- <source>Comment:</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keygen/KeygenDialog.cpp" line="341"/>
- <source>Expiration Date:</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keygen/KeygenDialog.cpp" line="342"/>
- <source>Never Expire</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keygen/KeygenDialog.cpp" line="343"/>
- <source>KeySize (in Bit):</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keygen/KeygenDialog.cpp" line="344"/>
- <source>Key Type:</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keygen/KeygenDialog.cpp" line="345"/>
- <source>Non Pass Phrase</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keygen/KeygenDialog.cpp" line="358"/>
- <source>Basic Information</source>
- <translation type="unfinished"></translation>
- </message>
-</context>
-<context>
- <name>KeyGenPage</name>
- <message>
- <location filename="../../src/ui/Wizard.cpp" line="183"/>
- <source>Create a keypair...</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/Wizard.cpp" line="184"/>
- <source>...for decrypting and signing messages</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/Wizard.cpp" line="185"/>
- <source>You should create a new keypair.The pair consists of a public and a private key.&lt;br&gt;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.&lt;br&gt;For more information have a look at the offline tutorial (which then is shown in the main window):</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/Wizard.cpp" line="192"/>
- <source>Offline tutorial</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/Wizard.cpp" line="199"/>
- <source>Create New Key</source>
- <translation type="unfinished"></translation>
- </message>
-</context>
-<context>
- <name>KeyImportDetailDialog</name>
- <message>
- <location filename="../../src/ui/KeyImportDetailDialog.cpp" line="34"/>
- <location filename="../../src/ui/KeyImportDetailDialog.cpp" line="53"/>
- <source>Key Update Details</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/KeyImportDetailDialog.cpp" line="34"/>
- <source>No keys found</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/KeyImportDetailDialog.cpp" line="36"/>
- <location filename="../../src/ui/KeyImportDetailDialog.cpp" line="55"/>
- <source>Key Import Details</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/KeyImportDetailDialog.cpp" line="36"/>
- <source>No keys found to import</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/KeyImportDetailDialog.cpp" line="64"/>
- <source>General key info</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/KeyImportDetailDialog.cpp" line="67"/>
- <source>Considered:</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/KeyImportDetailDialog.cpp" line="71"/>
- <source>Public unchanged:</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/KeyImportDetailDialog.cpp" line="76"/>
- <source>Imported:</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/KeyImportDetailDialog.cpp" line="81"/>
- <source>Not imported:</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/KeyImportDetailDialog.cpp" line="86"/>
- <source>Private read:</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/KeyImportDetailDialog.cpp" line="91"/>
- <source>Private imported:</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/KeyImportDetailDialog.cpp" line="96"/>
- <source>Private unchanged:</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/KeyImportDetailDialog.cpp" line="111"/>
- <source>Name</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/KeyImportDetailDialog.cpp" line="111"/>
- <source>Email</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/KeyImportDetailDialog.cpp" line="111"/>
- <source>Status</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/KeyImportDetailDialog.cpp" line="111"/>
- <source>Fingerprint</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/KeyImportDetailDialog.cpp" line="135"/>
- <source>private</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/KeyImportDetailDialog.cpp" line="138"/>
- <source>public</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/KeyImportDetailDialog.cpp" line="141"/>
- <source>unchanged</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/KeyImportDetailDialog.cpp" line="144"/>
- <source>new key</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/KeyImportDetailDialog.cpp" line="147"/>
- <source>new subkey</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/KeyImportDetailDialog.cpp" line="151"/>
- <source>new signature</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/KeyImportDetailDialog.cpp" line="155"/>
- <source>new uid</source>
- <translation type="unfinished"></translation>
- </message>
-</context>
-<context>
- <name>KeyList</name>
- <message>
- <location filename="../../src/ui/widgets/KeyList.cpp" line="76"/>
- <source>Select</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/widgets/KeyList.cpp" line="76"/>
- <source>Type</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/widgets/KeyList.cpp" line="76"/>
- <source>Name</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/widgets/KeyList.cpp" line="76"/>
- <source>Email Address</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/widgets/KeyList.cpp" line="77"/>
- <source>Usage</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/widgets/KeyList.cpp" line="77"/>
- <source>Validity</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/widgets/KeyList.cpp" line="77"/>
- <source>Finger Print</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/widgets/KeyList.cpp" line="302"/>
- <source>Import Keys</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/widgets/KeyList.cpp" line="305"/>
- <source>You&apos;ve dropped something on the table.
- GpgFrontend will now try to import key(s).</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/widgets/KeyList.cpp" line="308"/>
- <source>Always import without bothering.</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/widgets/KeyList.cpp" line="341"/>
- <source>Couldn&apos;t Open File: </source>
- <translation type="unfinished"></translation>
- </message>
-</context>
-<context>
- <name>KeyMgmt</name>
- <message>
- <location filename="../../src/ui/KeyMgmt.cpp" line="82"/>
- <source>Key Pair Management</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/KeyMgmt.cpp" line="88"/>
- <source>&amp;Open</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/KeyMgmt.cpp" line="89"/>
- <source>Ctrl+O</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/KeyMgmt.cpp" line="90"/>
- <source>Open Key File</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/KeyMgmt.cpp" line="93"/>
- <source>&amp;Close</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/KeyMgmt.cpp" line="94"/>
- <source>Ctrl+Q</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/KeyMgmt.cpp" line="96"/>
- <source>Close</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/KeyMgmt.cpp" line="99"/>
- <source>New Keypair</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/KeyMgmt.cpp" line="100"/>
- <source>Ctrl+N</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/KeyMgmt.cpp" line="102"/>
- <source>Generate KeyPair</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/KeyMgmt.cpp" line="105"/>
- <source>New Subkey</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/KeyMgmt.cpp" line="106"/>
- <source>Ctrl+Shift+N</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/KeyMgmt.cpp" line="108"/>
- <source>Generate Subkey For Selected KeyPair</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/KeyMgmt.cpp" line="111"/>
- <location filename="../../src/ui/KeyMgmt.cpp" line="151"/>
- <source>&amp;File</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/KeyMgmt.cpp" line="113"/>
- <source>Import New Key From File</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/KeyMgmt.cpp" line="116"/>
- <source>&amp;Clipboard</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/KeyMgmt.cpp" line="118"/>
- <source>Import New Key From Clipboard</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/KeyMgmt.cpp" line="121"/>
- <source>&amp;Keyserver</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/KeyMgmt.cpp" line="123"/>
- <source>Import New Key From Keyserver</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/KeyMgmt.cpp" line="126"/>
- <source>Export To &amp;Clipboard</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/KeyMgmt.cpp" line="128"/>
- <source>Export Selected Key(s) To Clipboard</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/KeyMgmt.cpp" line="131"/>
- <source>Export To &amp;File</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/KeyMgmt.cpp" line="133"/>
- <source>Export Selected Key(s) To File</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/KeyMgmt.cpp" line="136"/>
- <source>Delete Selected Key(s)</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/KeyMgmt.cpp" line="137"/>
- <source>Delete the Selected keys</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/KeyMgmt.cpp" line="140"/>
- <source>Delete Checked Key(s)</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/KeyMgmt.cpp" line="141"/>
- <source>Delete the Checked keys</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/KeyMgmt.cpp" line="145"/>
- <source>Show Key Details</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/KeyMgmt.cpp" line="146"/>
- <source>Show Details for this Key</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/KeyMgmt.cpp" line="155"/>
- <source>&amp;Key</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/KeyMgmt.cpp" line="156"/>
- <source>&amp;Generate Key</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/KeyMgmt.cpp" line="160"/>
- <source>&amp;Import Key</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/KeyMgmt.cpp" line="171"/>
- <source>Key</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/KeyMgmt.cpp" line="179"/>
- <source>Generate</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/KeyMgmt.cpp" line="180"/>
- <source>Generate A New Keypair or Subkey</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/KeyMgmt.cpp" line="189"/>
- <source>Import key</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/KeyMgmt.cpp" line="190"/>
- <source>Import Key</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/KeyMgmt.cpp" line="209"/>
- <source>Open Key</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/KeyMgmt.cpp" line="210"/>
- <location filename="../../src/ui/KeyMgmt.cpp" line="302"/>
- <source>Key Files</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/KeyMgmt.cpp" line="210"/>
- <source>Keyring files</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/KeyMgmt.cpp" line="216"/>
- <source>Couldn&apos;t Open File: </source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/KeyMgmt.cpp" line="262"/>
- <source>Deleting Keys</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/KeyMgmt.cpp" line="263"/>
- <source>Are you sure that you want to delete the following keys?</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/KeyMgmt.cpp" line="265"/>
- <source>The action can not be undone.</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/KeyMgmt.cpp" line="281"/>
- <location filename="../../src/ui/KeyMgmt.cpp" line="296"/>
- <location filename="../../src/ui/KeyMgmt.cpp" line="344"/>
- <source>Error</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/KeyMgmt.cpp" line="281"/>
- <location filename="../../src/ui/KeyMgmt.cpp" line="296"/>
- <location filename="../../src/ui/KeyMgmt.cpp" line="344"/>
- <source>Key Not Found.</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/KeyMgmt.cpp" line="301"/>
- <source>Export Key To File</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/KeyMgmt.cpp" line="312"/>
- <source>key(s) exported</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/KeyMgmt.cpp" line="338"/>
- <location filename="../../src/ui/KeyMgmt.cpp" line="349"/>
- <source>Invalid Operation</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/KeyMgmt.cpp" line="339"/>
- <source>Please select one KeyPair before doing this operation.</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/KeyMgmt.cpp" line="350"/>
- <source>If a key pair does not have a private key then it will not be able to generate sub-keys.</source>
- <translation type="unfinished"></translation>
- </message>
-</context>
-<context>
- <name>KeyNewUIDDialog</name>
- <message>
- <location filename="../../src/ui/keypair_details/KeyNewUIDDialog.cpp" line="40"/>
- <source>Name</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keypair_details/KeyNewUIDDialog.cpp" line="41"/>
- <source>Email</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keypair_details/KeyNewUIDDialog.cpp" line="42"/>
- <source>Comment</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keypair_details/KeyNewUIDDialog.cpp" line="55"/>
- <source>Create New UID</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keypair_details/KeyNewUIDDialog.cpp" line="68"/>
- <source> Name must contain at least five characters.
-</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keypair_details/KeyNewUIDDialog.cpp" line="70"/>
- <source> Please give a email address.
-</source>
- <translation type="unfinished"></translation>
- </message>
-</context>
-<context>
- <name>KeyPairDetailTab</name>
- <message>
- <location filename="../../src/ui/keypair_details/KeyPairDetailTab.cpp" line="34"/>
- <source>Owner</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keypair_details/KeyPairDetailTab.cpp" line="35"/>
- <source>Master Key</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keypair_details/KeyPairDetailTab.cpp" line="36"/>
- <source>Fingerprint</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keypair_details/KeyPairDetailTab.cpp" line="37"/>
- <source>Additional UIDs</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keypair_details/KeyPairDetailTab.cpp" line="58"/>
- <source>Exists</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keypair_details/KeyPairDetailTab.cpp" line="58"/>
- <source>Not Exists</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keypair_details/KeyPairDetailTab.cpp" line="83"/>
- <source>Name:</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keypair_details/KeyPairDetailTab.cpp" line="84"/>
- <source>Email Address:</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keypair_details/KeyPairDetailTab.cpp" line="85"/>
- <source>Comment:</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keypair_details/KeyPairDetailTab.cpp" line="90"/>
- <source>Key ID: </source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keypair_details/KeyPairDetailTab.cpp" line="91"/>
- <source>Algorithm: </source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keypair_details/KeyPairDetailTab.cpp" line="92"/>
- <source>Key Size:</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keypair_details/KeyPairDetailTab.cpp" line="93"/>
- <source>Nominal Usage: </source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keypair_details/KeyPairDetailTab.cpp" line="94"/>
- <source>Actual Usage: </source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keypair_details/KeyPairDetailTab.cpp" line="95"/>
- <source>Expires on: </source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keypair_details/KeyPairDetailTab.cpp" line="96"/>
- <source>Last Update: </source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keypair_details/KeyPairDetailTab.cpp" line="97"/>
- <source>Secret Key Existence: </source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keypair_details/KeyPairDetailTab.cpp" line="121"/>
- <source>Copy</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keypair_details/KeyPairDetailTab.cpp" line="123"/>
- <source>copy fingerprint to clipboard</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keypair_details/KeyPairDetailTab.cpp" line="133"/>
- <source>Operations</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keypair_details/KeyPairDetailTab.cpp" line="136"/>
- <source>Export Private Key (Include Subkey)</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keypair_details/KeyPairDetailTab.cpp" line="141"/>
- <source>Modify Expiration Datetime (Master Key)</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keypair_details/KeyPairDetailTab.cpp" line="146"/>
- <source>Key Server Operation (Pubkey)</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keypair_details/KeyPairDetailTab.cpp" line="149"/>
- <source>Generate Revoke Certificate</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keypair_details/KeyPairDetailTab.cpp" line="174"/>
- <source>Warning: The Master Key has expired.</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keypair_details/KeyPairDetailTab.cpp" line="177"/>
- <source>Warning: The Master Key has been revoked</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keypair_details/KeyPairDetailTab.cpp" line="201"/>
- <source>Exporting private Key</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keypair_details/KeyPairDetailTab.cpp" line="202"/>
- <source>You are about to export your</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keypair_details/KeyPairDetailTab.cpp" line="203"/>
- <source>PRIVATE KEY</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keypair_details/KeyPairDetailTab.cpp" line="204"/>
- <source>This is NOT your Public Key, so DON&apos;T give it away.</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keypair_details/KeyPairDetailTab.cpp" line="205"/>
- <source>Do you REALLY want to export your PRIVATE KEY?</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keypair_details/KeyPairDetailTab.cpp" line="219"/>
- <source>Error</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keypair_details/KeyPairDetailTab.cpp" line="219"/>
- <source>Key Not Found.</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keypair_details/KeyPairDetailTab.cpp" line="224"/>
- <source>Export Key To File</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keypair_details/KeyPairDetailTab.cpp" line="225"/>
- <source>Key Files</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keypair_details/KeyPairDetailTab.cpp" line="228"/>
- <source>Export Error</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keypair_details/KeyPairDetailTab.cpp" line="228"/>
- <source>Couldn&apos;t open %1 for writing</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keypair_details/KeyPairDetailTab.cpp" line="298"/>
- <source>Never Expire</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keypair_details/KeyPairDetailTab.cpp" line="318"/>
- <source>Upload Key Pair to Key Server</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keypair_details/KeyPairDetailTab.cpp" line="320"/>
- <source>Update Key Pair</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keypair_details/KeyPairDetailTab.cpp" line="343"/>
- <source>Generate revocation certificate</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keypair_details/KeyPairDetailTab.cpp" line="346"/>
- <source>Revocation Certificates</source>
- <translation type="unfinished"></translation>
- </message>
-</context>
-<context>
- <name>KeyPairSubkeyTab</name>
- <message>
- <location filename="../../src/ui/keypair_details/KeyPairSubkeyTab.cpp" line="37"/>
- <source>Generate A New Subkey</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keypair_details/KeyPairSubkeyTab.cpp" line="54"/>
- <source>Key ID: </source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keypair_details/KeyPairSubkeyTab.cpp" line="55"/>
- <source>Algorithm: </source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keypair_details/KeyPairSubkeyTab.cpp" line="56"/>
- <source>Key Size:</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keypair_details/KeyPairSubkeyTab.cpp" line="57"/>
- <source>Usage: </source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keypair_details/KeyPairSubkeyTab.cpp" line="58"/>
- <source>Expires On </source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keypair_details/KeyPairSubkeyTab.cpp" line="59"/>
- <source>Last Update: </source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keypair_details/KeyPairSubkeyTab.cpp" line="60"/>
- <source>Existence: </source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keypair_details/KeyPairSubkeyTab.cpp" line="61"/>
- <source>Fingerprint: </source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keypair_details/KeyPairSubkeyTab.cpp" line="121"/>
- <source>Subkey ID</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keypair_details/KeyPairSubkeyTab.cpp" line="121"/>
- <source>Key Size</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keypair_details/KeyPairSubkeyTab.cpp" line="121"/>
- <source>Algo</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keypair_details/KeyPairSubkeyTab.cpp" line="121"/>
- <source>Create Date</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keypair_details/KeyPairSubkeyTab.cpp" line="121"/>
- <source>Expire Date</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keypair_details/KeyPairSubkeyTab.cpp" line="160"/>
- <source>Never Expire</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keypair_details/KeyPairSubkeyTab.cpp" line="184"/>
- <source>Never Expires</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keypair_details/KeyPairSubkeyTab.cpp" line="230"/>
- <source>Edit Expire Date</source>
- <translation type="unfinished"></translation>
- </message>
-</context>
-<context>
- <name>KeyPairUIDTab</name>
- <message>
- <location filename="../../src/ui/keypair_details/KeyPairUIDTab.cpp" line="39"/>
- <source>New UID</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keypair_details/KeyPairUIDTab.cpp" line="40"/>
- <source>UID Management</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keypair_details/KeyPairUIDTab.cpp" line="59"/>
- <source>UIDs</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keypair_details/KeyPairUIDTab.cpp" line="67"/>
- <source>Signature of Selected UID</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keypair_details/KeyPairUIDTab.cpp" line="103"/>
- <source>Select</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keypair_details/KeyPairUIDTab.cpp" line="103"/>
- <location filename="../../src/ui/keypair_details/KeyPairUIDTab.cpp" line="126"/>
- <source>Name</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keypair_details/KeyPairUIDTab.cpp" line="103"/>
- <location filename="../../src/ui/keypair_details/KeyPairUIDTab.cpp" line="126"/>
- <source>Email</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keypair_details/KeyPairUIDTab.cpp" line="103"/>
- <source>Comment</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keypair_details/KeyPairUIDTab.cpp" line="126"/>
- <source>Key ID</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keypair_details/KeyPairUIDTab.cpp" line="126"/>
- <source>Create Date</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keypair_details/KeyPairUIDTab.cpp" line="126"/>
- <source>Expired Date</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keypair_details/KeyPairUIDTab.cpp" line="219"/>
- <source>Never Expires</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keypair_details/KeyPairUIDTab.cpp" line="237"/>
- <location filename="../../src/ui/keypair_details/KeyPairUIDTab.cpp" line="300"/>
- <location filename="../../src/ui/keypair_details/KeyPairUIDTab.cpp" line="425"/>
- <location filename="../../src/ui/keypair_details/KeyPairUIDTab.cpp" line="440"/>
- <location filename="../../src/ui/keypair_details/KeyPairUIDTab.cpp" line="480"/>
- <location filename="../../src/ui/keypair_details/KeyPairUIDTab.cpp" line="487"/>
- <source>Invalid Operation</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keypair_details/KeyPairUIDTab.cpp" line="238"/>
- <location filename="../../src/ui/keypair_details/KeyPairUIDTab.cpp" line="301"/>
- <source>Please select one or more UIDs before doing this operation.</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keypair_details/KeyPairUIDTab.cpp" line="263"/>
- <source>Sign Selected UID(s)</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keypair_details/KeyPairUIDTab.cpp" line="265"/>
- <source>Delete Selected UID(s)</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keypair_details/KeyPairUIDTab.cpp" line="284"/>
- <source>Successful Operation</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keypair_details/KeyPairUIDTab.cpp" line="285"/>
- <source>Successfully added a new UID.</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keypair_details/KeyPairUIDTab.cpp" line="288"/>
- <location filename="../../src/ui/keypair_details/KeyPairUIDTab.cpp" line="330"/>
- <location filename="../../src/ui/keypair_details/KeyPairUIDTab.cpp" line="363"/>
- <location filename="../../src/ui/keypair_details/KeyPairUIDTab.cpp" line="460"/>
- <location filename="../../src/ui/keypair_details/KeyPairUIDTab.cpp" line="507"/>
- <source>Operation Failed</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keypair_details/KeyPairUIDTab.cpp" line="289"/>
- <location filename="../../src/ui/keypair_details/KeyPairUIDTab.cpp" line="331"/>
- <location filename="../../src/ui/keypair_details/KeyPairUIDTab.cpp" line="364"/>
- <location filename="../../src/ui/keypair_details/KeyPairUIDTab.cpp" line="461"/>
- <location filename="../../src/ui/keypair_details/KeyPairUIDTab.cpp" line="508"/>
- <source>An error occurred during the operation.</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keypair_details/KeyPairUIDTab.cpp" line="313"/>
- <source>Deleting UIDs</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keypair_details/KeyPairUIDTab.cpp" line="314"/>
- <source>Are you sure that you want to delete the following uids?</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keypair_details/KeyPairUIDTab.cpp" line="315"/>
- <location filename="../../src/ui/keypair_details/KeyPairUIDTab.cpp" line="357"/>
- <location filename="../../src/ui/keypair_details/KeyPairUIDTab.cpp" line="454"/>
- <location filename="../../src/ui/keypair_details/KeyPairUIDTab.cpp" line="501"/>
- <source>The action can not be undone.</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keypair_details/KeyPairUIDTab.cpp" line="355"/>
- <source>Set Primary UID</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keypair_details/KeyPairUIDTab.cpp" line="356"/>
- <source>Are you sure that you want to set the Primary UID to?</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keypair_details/KeyPairUIDTab.cpp" line="395"/>
- <source>Set As Primary</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keypair_details/KeyPairUIDTab.cpp" line="397"/>
- <source>Sign UID</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keypair_details/KeyPairUIDTab.cpp" line="399"/>
- <source>Delete UID</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keypair_details/KeyPairUIDTab.cpp" line="426"/>
- <location filename="../../src/ui/keypair_details/KeyPairUIDTab.cpp" line="441"/>
- <source>Please select one UID before doing this operation.</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keypair_details/KeyPairUIDTab.cpp" line="452"/>
- <source>Deleting UID</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keypair_details/KeyPairUIDTab.cpp" line="453"/>
- <source>Are you sure that you want to delete the following uid?</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keypair_details/KeyPairUIDTab.cpp" line="469"/>
- <source>Delete(Revoke) Key Signature</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keypair_details/KeyPairUIDTab.cpp" line="481"/>
- <source>Please select one Key Signature before doing this operation.</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keypair_details/KeyPairUIDTab.cpp" line="488"/>
- <source>To delete the signature, you need to have its corresponding public key in the local database.</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keypair_details/KeyPairUIDTab.cpp" line="499"/>
- <source>Deleting Key Signature</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keypair_details/KeyPairUIDTab.cpp" line="500"/>
- <source>Are you sure that you want to delete the following signature?</source>
- <translation type="unfinished"></translation>
- </message>
-</context>
-<context>
- <name>KeyServerImportDialog</name>
- <message>
- <location filename="../../src/ui/KeyServerImportDialog.cpp" line="40"/>
- <source>&amp;Close</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/KeyServerImportDialog.cpp" line="41"/>
- <source>&amp;Import ALL</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/KeyServerImportDialog.cpp" line="42"/>
- <source>&amp;Search</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/KeyServerImportDialog.cpp" line="45"/>
- <source>Search String:</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/KeyServerImportDialog.cpp" line="49"/>
- <source>Key Server:</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/KeyServerImportDialog.cpp" line="97"/>
- <source>Update Keys from Keyserver</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/KeyServerImportDialog.cpp" line="99"/>
- <source>Import Keys from Keyserver</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/KeyServerImportDialog.cpp" line="158"/>
- <source>UID</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/KeyServerImportDialog.cpp" line="158"/>
- <source>Creation date</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/KeyServerImportDialog.cpp" line="158"/>
- <source>KeyID</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/KeyServerImportDialog.cpp" line="158"/>
- <source>Tag</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/KeyServerImportDialog.cpp" line="179"/>
- <source>Text is empty.</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/KeyServerImportDialog.cpp" line="213"/>
- <source>Not Key Found</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/KeyServerImportDialog.cpp" line="216"/>
- <location filename="../../src/ui/KeyServerImportDialog.cpp" line="386"/>
- <source>Timeout</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/KeyServerImportDialog.cpp" line="219"/>
- <location filename="../../src/ui/KeyServerImportDialog.cpp" line="389"/>
- <source>Key Server Not Found</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/KeyServerImportDialog.cpp" line="222"/>
- <location filename="../../src/ui/KeyServerImportDialog.cpp" line="392"/>
- <source>Connection Error</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/KeyServerImportDialog.cpp" line="230"/>
- <source>Too many responses from keyserver!</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/KeyServerImportDialog.cpp" line="237"/>
- <source>No keys found, input may be kexId, retrying search with 0x.</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/KeyServerImportDialog.cpp" line="242"/>
- <source>No keys found containing the search string!</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/KeyServerImportDialog.cpp" line="246"/>
- <source>Insufficiently specific search string!</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/KeyServerImportDialog.cpp" line="274"/>
- <source>revoked</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/KeyServerImportDialog.cpp" line="277"/>
- <source>disabled</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/KeyServerImportDialog.cpp" line="317"/>
- <source>&lt;h4&gt;%1 keys found. Double click a key to import it.&lt;/h4&gt;</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/KeyServerImportDialog.cpp" line="383"/>
- <source>Key Not Found</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/KeyServerImportDialog.cpp" line="410"/>
- <source>&lt;h4&gt;Key Updated&lt;/h4&gt;</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/KeyServerImportDialog.cpp" line="412"/>
- <source>&lt;h4&gt;Key Imported&lt;/h4&gt;</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/KeyServerImportDialog.cpp" line="473"/>
- <source>Upload Keys from Keyserver</source>
- <translation type="unfinished"></translation>
- </message>
-</context>
-<context>
- <name>KeySetExpireDateDialog</name>
- <message>
- <location filename="../../src/ui/keypair_details/KeySetExpireDateDialog.cpp" line="36"/>
- <source>Confirm</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keypair_details/KeySetExpireDateDialog.cpp" line="41"/>
- <source>Never Expire</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keypair_details/KeySetExpireDateDialog.cpp" line="61"/>
- <source>Operation Failed</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keypair_details/KeySetExpireDateDialog.cpp" line="62"/>
- <source>An error occurred during the operation.</source>
- <translation type="unfinished"></translation>
- </message>
-</context>
-<context>
- <name>KeyUIDSignDialog</name>
- <message>
- <location filename="../../src/ui/keypair_details/KeyUIDSignDialog.cpp" line="72"/>
- <source>Expire Date</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keypair_details/KeyUIDSignDialog.cpp" line="81"/>
- <source>Sign For Key&apos;s UID(s)</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keypair_details/KeyUIDSignDialog.cpp" line="99"/>
- <source>Unsuccessful Operation</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keypair_details/KeyUIDSignDialog.cpp" line="100"/>
- <source>Signature operation failed for UID </source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keypair_details/KeyUIDSignDialog.cpp" line="107"/>
- <source>Operation Complete</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keypair_details/KeyUIDSignDialog.cpp" line="108"/>
- <source>The signature operation of the UID is complete</source>
- <translation type="unfinished"></translation>
- </message>
-</context>
-<context>
- <name>KeyUploadDialog</name>
- <message>
- <location filename="../../src/ui/KeyUploadDialog.cpp" line="47"/>
- <source>Uploading Public Key</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/KeyUploadDialog.cpp" line="110"/>
- <source>Key Not Found</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/KeyUploadDialog.cpp" line="113"/>
- <source>Timeout</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/KeyUploadDialog.cpp" line="116"/>
- <source>Key Server Not Found</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/KeyUploadDialog.cpp" line="119"/>
- <source>Connection Error</source>
- <translation type="unfinished"></translation>
- </message>
-</context>
-<context>
- <name>KeyserverTab</name>
- <message>
- <location filename="../../src/ui/settings/SettingsKeyServer.cpp" line="32"/>
- <source>General</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/settings/SettingsKeyServer.cpp" line="53"/>
- <source>No.</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/settings/SettingsKeyServer.cpp" line="53"/>
- <source>Address</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/settings/SettingsKeyServer.cpp" line="53"/>
- <source>Available</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/settings/SettingsKeyServer.cpp" line="57"/>
- <source>Default Key Server for Import:</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/settings/SettingsKeyServer.cpp" line="67"/>
- <source>Add</source>
- <translation type="unfinished"></translation>
- </message>
-</context>
-<context>
- <name>MainWindow</name>
- <message>
- <location filename="../../src/MainWindow.cpp" line="35"/>
- <source>Loading Gnupg</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/MainWindow.cpp" line="62"/>
- <source>ENV Loading Failed</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/MainWindow.cpp" line="63"/>
- <source>Gnupg is not installed correctly, please follow the ReadME instructions to install gnupg and then open GPGFrontend.</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowFileSlotFunction.cpp" line="36"/>
- <location filename="../../src/ui/main_window/MainWindowFileSlotFunction.cpp" line="40"/>
- <location filename="../../src/ui/main_window/MainWindowFileSlotFunction.cpp" line="44"/>
- <location filename="../../src/ui/main_window/MainWindowFileSlotFunction.cpp" line="114"/>
- <location filename="../../src/ui/main_window/MainWindowFileSlotFunction.cpp" line="127"/>
- <location filename="../../src/ui/main_window/MainWindowFileSlotFunction.cpp" line="131"/>
- <location filename="../../src/ui/main_window/MainWindowFileSlotFunction.cpp" line="135"/>
- <location filename="../../src/ui/main_window/MainWindowFileSlotFunction.cpp" line="196"/>
- <location filename="../../src/ui/main_window/MainWindowFileSlotFunction.cpp" line="212"/>
- <location filename="../../src/ui/main_window/MainWindowFileSlotFunction.cpp" line="216"/>
- <location filename="../../src/ui/main_window/MainWindowFileSlotFunction.cpp" line="220"/>
- <location filename="../../src/ui/main_window/MainWindowFileSlotFunction.cpp" line="294"/>
- <location filename="../../src/ui/main_window/MainWindowFileSlotFunction.cpp" line="326"/>
- <location filename="../../src/ui/main_window/MainWindowFileSlotFunction.cpp" line="331"/>
- <location filename="../../src/ui/main_window/MainWindowFileSlotFunction.cpp" line="335"/>
- <location filename="../../src/ui/main_window/MainWindowFileSlotFunction.cpp" line="383"/>
- <location filename="../../src/ui/main_window/MainWindowFileSlotFunction.cpp" line="396"/>
- <location filename="../../src/ui/main_window/MainWindowFileSlotFunction.cpp" line="400"/>
- <location filename="../../src/ui/main_window/MainWindowFileSlotFunction.cpp" line="404"/>
- <location filename="../../src/ui/main_window/MainWindowFileSlotFunction.cpp" line="501"/>
- <location filename="../../src/ui/main_window/MainWindowFileSlotFunction.cpp" line="513"/>
- <location filename="../../src/ui/main_window/MainWindowFileSlotFunction.cpp" line="517"/>
- <location filename="../../src/ui/main_window/MainWindowFileSlotFunction.cpp" line="521"/>
- <location filename="../../src/ui/main_window/MainWindowFileSlotFunction.cpp" line="583"/>
- <location filename="../../src/ui/main_window/MainWindowServerSlotFunction.cpp" line="53"/>
- <location filename="../../src/ui/main_window/MainWindowServerSlotFunction.cpp" line="111"/>
- <location filename="../../src/ui/main_window/MainWindowServerSlotFunction.cpp" line="125"/>
- <location filename="../../src/ui/main_window/MainWindowServerSlotFunction.cpp" line="217"/>
- <location filename="../../src/ui/main_window/MainWindowServerSlotFunction.cpp" line="232"/>
- <location filename="../../src/ui/main_window/MainWindowSlotFunction.cpp" line="521"/>
- <location filename="../../src/ui/main_window/MainWindowSlotFunction.cpp" line="537"/>
- <source>Error</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowFileSlotFunction.cpp" line="36"/>
- <location filename="../../src/ui/main_window/MainWindowFileSlotFunction.cpp" line="127"/>
- <location filename="../../src/ui/main_window/MainWindowFileSlotFunction.cpp" line="212"/>
- <location filename="../../src/ui/main_window/MainWindowFileSlotFunction.cpp" line="396"/>
- <source>Select a file before doing it.</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowFileSlotFunction.cpp" line="40"/>
- <location filename="../../src/ui/main_window/MainWindowFileSlotFunction.cpp" line="131"/>
- <location filename="../../src/ui/main_window/MainWindowFileSlotFunction.cpp" line="216"/>
- <location filename="../../src/ui/main_window/MainWindowFileSlotFunction.cpp" line="400"/>
- <location filename="../../src/ui/main_window/MainWindowFileSlotFunction.cpp" line="517"/>
- <source>No permission to read this file.</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowFileSlotFunction.cpp" line="44"/>
- <location filename="../../src/ui/main_window/MainWindowFileSlotFunction.cpp" line="135"/>
- <location filename="../../src/ui/main_window/MainWindowFileSlotFunction.cpp" line="220"/>
- <location filename="../../src/ui/main_window/MainWindowFileSlotFunction.cpp" line="404"/>
- <location filename="../../src/ui/main_window/MainWindowFileSlotFunction.cpp" line="521"/>
- <source>No permission to create file.</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowFileSlotFunction.cpp" line="49"/>
- <location filename="../../src/ui/main_window/MainWindowFileSlotFunction.cpp" line="150"/>
- <location filename="../../src/ui/main_window/MainWindowFileSlotFunction.cpp" line="226"/>
- <location filename="../../src/ui/main_window/MainWindowFileSlotFunction.cpp" line="409"/>
- <source>Warning</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowFileSlotFunction.cpp" line="50"/>
- <location filename="../../src/ui/main_window/MainWindowFileSlotFunction.cpp" line="151"/>
- <location filename="../../src/ui/main_window/MainWindowFileSlotFunction.cpp" line="227"/>
- <location filename="../../src/ui/main_window/MainWindowFileSlotFunction.cpp" line="410"/>
- <source>The target file already exists, do you need to overwrite it?</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowFileSlotFunction.cpp" line="62"/>
- <location filename="../../src/ui/main_window/MainWindowFileSlotFunction.cpp" line="239"/>
- <location filename="../../src/ui/main_window/MainWindowFileSlotFunction.cpp" line="422"/>
- <location filename="../../src/ui/main_window/MainWindowSlotFunction.cpp" line="45"/>
- <location filename="../../src/ui/main_window/MainWindowSlotFunction.cpp" line="125"/>
- <location filename="../../src/ui/main_window/MainWindowSlotFunction.cpp" line="296"/>
- <source>No Key Selected</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowFileSlotFunction.cpp" line="69"/>
- <location filename="../../src/ui/main_window/MainWindowFileSlotFunction.cpp" line="246"/>
- <location filename="../../src/ui/main_window/MainWindowSlotFunction.cpp" line="52"/>
- <location filename="../../src/ui/main_window/MainWindowSlotFunction.cpp" line="132"/>
- <source>Invalid Operation</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowFileSlotFunction.cpp" line="70"/>
- <location filename="../../src/ui/main_window/MainWindowFileSlotFunction.cpp" line="247"/>
- <location filename="../../src/ui/main_window/MainWindowSlotFunction.cpp" line="53"/>
- <source>The selected key contains a key that does not actually have a encrypt usage.&lt;br/&gt;</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowFileSlotFunction.cpp" line="71"/>
- <location filename="../../src/ui/main_window/MainWindowFileSlotFunction.cpp" line="248"/>
- <location filename="../../src/ui/main_window/MainWindowFileSlotFunction.cpp" line="436"/>
- <location filename="../../src/ui/main_window/MainWindowSlotFunction.cpp" line="54"/>
- <location filename="../../src/ui/main_window/MainWindowSlotFunction.cpp" line="134"/>
- <location filename="../../src/ui/main_window/MainWindowSlotFunction.cpp" line="307"/>
- <source>&lt;br/&gt;For example the Following Key: &lt;br/&gt;</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowFileSlotFunction.cpp" line="91"/>
- <location filename="../../src/ui/main_window/MainWindowSlotFunction.cpp" line="72"/>
- <source>Encrypting</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowFileSlotFunction.cpp" line="114"/>
- <location filename="../../src/ui/main_window/MainWindowFileSlotFunction.cpp" line="196"/>
- <location filename="../../src/ui/main_window/MainWindowFileSlotFunction.cpp" line="294"/>
- <location filename="../../src/ui/main_window/MainWindowFileSlotFunction.cpp" line="383"/>
- <location filename="../../src/ui/main_window/MainWindowFileSlotFunction.cpp" line="501"/>
- <location filename="../../src/ui/main_window/MainWindowFileSlotFunction.cpp" line="583"/>
- <source>An error occurred during operation.</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowFileSlotFunction.cpp" line="268"/>
- <location filename="../../src/ui/main_window/MainWindowSlotFunction.cpp" line="150"/>
- <source>Signing</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowFileSlotFunction.cpp" line="327"/>
- <source>Please select the appropriate target file or signature file. Ensure that both are in this directory.</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowFileSlotFunction.cpp" line="331"/>
- <source>No permission to read target file.</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowFileSlotFunction.cpp" line="335"/>
- <source>No permission to read signature file.</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowFileSlotFunction.cpp" line="353"/>
- <location filename="../../src/ui/main_window/MainWindowSlotFunction.cpp" line="258"/>
- <source>Verifying</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowFileSlotFunction.cpp" line="434"/>
- <location filename="../../src/ui/main_window/MainWindowSlotFunction.cpp" line="305"/>
- <source>Invalid KeyPair</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowFileSlotFunction.cpp" line="435"/>
- <source>The selected keypair cannot be used for signing and encryption at the same time.&lt;br/&gt;</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowFileSlotFunction.cpp" line="446"/>
- <location filename="../../src/ui/main_window/MainWindowFileSlotFunction.cpp" line="453"/>
- <source>Incomplete Operation</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowFileSlotFunction.cpp" line="447"/>
- <source>None of the selected key pairs can provide the encryption function.</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowFileSlotFunction.cpp" line="454"/>
- <source>None of the selected key pairs can provide the signature function.</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowFileSlotFunction.cpp" line="473"/>
- <location filename="../../src/ui/main_window/MainWindowSlotFunction.cpp" line="345"/>
- <source>Encrypting and Signing</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowFileSlotFunction.cpp" line="513"/>
- <source>Select a file(.gpg/.asc) before doing it.</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowFileSlotFunction.cpp" line="551"/>
- <location filename="../../src/ui/main_window/MainWindowSlotFunction.cpp" line="440"/>
- <source>Decrypting and Verifying</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowServerSlotFunction.cpp" line="43"/>
- <location filename="../../src/ui/main_window/MainWindowServerSlotFunction.cpp" line="154"/>
- <source>Invalid Own Key</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowServerSlotFunction.cpp" line="154"/>
- <source>Own Key can not be use to do any operation.</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowServerSlotFunction.cpp" line="54"/>
- <source>Please obtain a Service Token from the server in the settings.</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowServerSlotFunction.cpp" line="44"/>
- <source>Own Key can not be use to do any operation. Please go to the setting interface to select an OwnKey and get a ServiceToken.</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowServerSlotFunction.cpp" line="90"/>
- <source>Getting Cpt From Server</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowServerSlotFunction.cpp" line="112"/>
- <location filename="../../src/ui/main_window/MainWindowServerSlotFunction.cpp" line="218"/>
- <source>The communication content with the server does not meet the requirements</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowServerSlotFunction.cpp" line="125"/>
- <source>Invalid short ciphertext</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowServerSlotFunction.cpp" line="143"/>
- <source>Invalid Service Token</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowServerSlotFunction.cpp" line="144"/>
- <source>Please go to the setting interface to get a ServiceToken.</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowServerSlotFunction.cpp" line="202"/>
- <source>Getting Scpt From Server</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowServerSlotFunction.cpp" line="228"/>
- <source>Notice: Use Decrypt &amp; Verify operation to decrypt this short crypto text.</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowServerSlotFunction.cpp" line="232"/>
- <source>There is a problem with the communication with the server</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowSlotFunction.cpp" line="102"/>
- <location filename="../../src/ui/main_window/MainWindowSlotFunction.cpp" line="394"/>
- <source>Function Disabled</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowSlotFunction.cpp" line="103"/>
- <location filename="../../src/ui/main_window/MainWindowSlotFunction.cpp" line="395"/>
- <source>Please go to the settings interface to enable and configure this function.</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowSlotFunction.cpp" line="133"/>
- <source>The selected key contains a key that does not actually have a signature usage.&lt;br/&gt;</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowSlotFunction.cpp" line="185"/>
- <source>Notice</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowSlotFunction.cpp" line="185"/>
- <source>Short Crypto Text only supports Decrypt &amp; Verify.</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowSlotFunction.cpp" line="199"/>
- <source>Decrypting</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowSlotFunction.cpp" line="306"/>
- <source>The selected keypair cannot be used for encryption.&lt;br/&gt;</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowSlotFunction.cpp" line="355"/>
- <source>Automatic Key Exchange Warning</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowSlotFunction.cpp" line="356"/>
- <source>Part of the automatic key exchange failed, which may be related to your key.</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowSlotFunction.cpp" line="358"/>
- <source>If possible, try to use the RSA algorithm compatible with the server for signing.</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowSlotFunction.cpp" line="401"/>
- <source>Service Token Empty</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowSlotFunction.cpp" line="402"/>
- <source>Please go to the settings interface to set Own Key and get Service Token.</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowSlotFunction.cpp" line="521"/>
- <location filename="../../src/ui/main_window/MainWindowSlotFunction.cpp" line="537"/>
- <source>Key Not Found.</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowSlotFunction.cpp" line="568"/>
- <source>Outdated Version</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowSlotFunction.cpp" line="569"/>
- <source>This version(%1) is out of date, please update the latest version in time. </source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowSlotFunction.cpp" line="571"/>
- <location filename="../../src/ui/main_window/MainWindowSlotFunction.cpp" line="578"/>
- <source>You can download the latest version(%1) on Github Releases Page.&lt;br/&gt;</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowSlotFunction.cpp" line="575"/>
- <source>Unreleased Version</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowSlotFunction.cpp" line="576"/>
- <source>This version(%1) has not been officially released and is not recommended for use in a production environment. &lt;br/&gt;</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowSlotUI.cpp" line="58"/>
- <source>There is one unencrypted file in attachment folder</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowSlotUI.cpp" line="60"/>
- <source>There are </source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowSlotUI.cpp" line="60"/>
- <source> unencrypted files in attachment folder</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowUI.cpp" line="30"/>
- <source>&amp;New</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowUI.cpp" line="36"/>
- <source>Open a new file</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowUI.cpp" line="39"/>
- <source>&amp;Open...</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowUI.cpp" line="42"/>
- <source>Open an existing file</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowUI.cpp" line="45"/>
- <source>&amp;Browser</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowUI.cpp" line="47"/>
- <source>Open a file browser</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowUI.cpp" line="50"/>
- <source>&amp;Save</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowUI.cpp" line="53"/>
- <source>Save the current File</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowUI.cpp" line="56"/>
- <source>Save &amp;As</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowUI.cpp" line="59"/>
- <source>Save the current File as...</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowUI.cpp" line="62"/>
- <source>&amp;Print</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowUI.cpp" line="65"/>
- <source>Print Document</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowUI.cpp" line="68"/>
- <source>&amp;Close</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowUI.cpp" line="70"/>
- <source>Close file</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowUI.cpp" line="73"/>
- <source>&amp;Quit</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowUI.cpp" line="76"/>
- <source>Quit Program</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowUI.cpp" line="81"/>
- <source>&amp;Undo</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowUI.cpp" line="83"/>
- <source>Undo Last Edit Action</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowUI.cpp" line="86"/>
- <source>&amp;Redo</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowUI.cpp" line="88"/>
- <source>Redo Last Edit Action</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowUI.cpp" line="91"/>
- <source>Zoom In</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowUI.cpp" line="95"/>
- <source>Zoom Out</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowUI.cpp" line="99"/>
- <source>&amp;Paste</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowUI.cpp" line="102"/>
- <source>Paste Text From Clipboard</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowUI.cpp" line="105"/>
- <source>Cu&amp;t</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowUI.cpp" line="108"/>
- <source>Cut the current selection&apos;s contents to the clipboard</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowUI.cpp" line="112"/>
- <source>&amp;Copy</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowUI.cpp" line="115"/>
- <source>Copy the current selection&apos;s contents to the clipboard</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowUI.cpp" line="119"/>
- <source>&amp;Quote</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowUI.cpp" line="121"/>
- <source>Quote whole text</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowUI.cpp" line="124"/>
- <source>Select &amp;All</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowUI.cpp" line="127"/>
- <source>Select the whole text</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowUI.cpp" line="130"/>
- <source>&amp;Find</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowUI.cpp" line="132"/>
- <source>Find a word</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowUI.cpp" line="135"/>
- <source>Remove &amp;spacing</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowUI.cpp" line="138"/>
- <source>Remove double linebreaks, e.g. in pasted text from webmailer</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowUI.cpp" line="141"/>
- <source>Se&amp;ttings</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowUI.cpp" line="142"/>
- <source>Open settings dialog</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowUI.cpp" line="148"/>
- <source>&amp;Encrypt</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowUI.cpp" line="151"/>
- <source>Encrypt Message</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowUI.cpp" line="154"/>
- <source>&amp;Encrypt &amp;Sign</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowUI.cpp" line="157"/>
- <source>Encrypt and Sign Message</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowUI.cpp" line="160"/>
- <source>&amp;Decrypt</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowUI.cpp" line="163"/>
- <source>Decrypt Message</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowUI.cpp" line="166"/>
- <source>&amp;Decrypt &amp;Verify</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowUI.cpp" line="169"/>
- <source>Decrypt and Verify Message</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowUI.cpp" line="175"/>
- <source>&amp;Encrypt File</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowUI.cpp" line="176"/>
- <source>Encrypt File</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowUI.cpp" line="179"/>
- <source>&amp;Decrypt File</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowUI.cpp" line="180"/>
- <source>Decrypt File</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowUI.cpp" line="183"/>
- <source>&amp;Sign File</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowUI.cpp" line="184"/>
- <source>Sign File</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowUI.cpp" line="187"/>
- <source>&amp;Verify File</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowUI.cpp" line="188"/>
- <source>Verify File</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowUI.cpp" line="192"/>
- <source>&amp;Sign</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowUI.cpp" line="195"/>
- <source>Sign Message</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowUI.cpp" line="198"/>
- <source>&amp;Verify</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowUI.cpp" line="201"/>
- <source>Verify Message</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowUI.cpp" line="207"/>
- <source>&amp;Editor</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowUI.cpp" line="209"/>
- <source>Import New Key From Editor</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowUI.cpp" line="212"/>
- <source>Manage &amp;Keys</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowUI.cpp" line="214"/>
- <source>Open Keymanagement</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowUI.cpp" line="220"/>
- <source>&amp;About</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowUI.cpp" line="222"/>
- <source>Show the application&apos;s About box</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowUI.cpp" line="228"/>
- <source>&amp;Check for Updates</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowUI.cpp" line="230"/>
- <source>Check for updates</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowUI.cpp" line="233"/>
- <source>Open &amp;Wizard</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowUI.cpp" line="234"/>
- <source>Open the wizard</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowUI.cpp" line="239"/>
- <source>Append Selected Key(s) To Text</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowUI.cpp" line="240"/>
- <source>Append The Selected Keys To Text in Editor</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowUI.cpp" line="243"/>
- <source>Copy Email</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowUI.cpp" line="244"/>
- <source>Copy selected Email to clipboard</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowUI.cpp" line="248"/>
- <source>Show Key Details</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowUI.cpp" line="249"/>
- <source>Show Details for this Key</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowUI.cpp" line="252"/>
- <source>Refresh Key From Key Server</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowUI.cpp" line="253"/>
- <source>Refresh key from default key server</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowUI.cpp" line="256"/>
- <source>Upload Public Key(s) To Server</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowUI.cpp" line="257"/>
- <source>Upload The Selected Public Keys To Server</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowUI.cpp" line="272"/>
- <source>Remove PGP Header</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowUI.cpp" line="275"/>
- <source>Add PGP Header</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowUI.cpp" line="280"/>
- <source>&amp;File</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowUI.cpp" line="293"/>
- <source>&amp;Edit</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowUI.cpp" line="311"/>
- <source>&amp;File...</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowUI.cpp" line="317"/>
- <source>&amp;Crypt</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowUI.cpp" line="328"/>
- <source>&amp;Keys</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowUI.cpp" line="329"/>
- <source>&amp;Import Key</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowUI.cpp" line="338"/>
- <source>&amp;Steganography</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowUI.cpp" line="347"/>
- <source>&amp;View</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowUI.cpp" line="349"/>
- <source>&amp;Help</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowUI.cpp" line="358"/>
- <source>File</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowUI.cpp" line="366"/>
- <source>Crypt</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowUI.cpp" line="376"/>
- <source>Key</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowUI.cpp" line="381"/>
- <source>Edit</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowUI.cpp" line="388"/>
- <source>Special Edit</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowUI.cpp" line="400"/>
- <source>Import key from...</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowUI.cpp" line="401"/>
- <source>Import key</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowUI.cpp" line="409"/>
- <source>Browser to view and operate file</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowUI.cpp" line="410"/>
- <source>Browser</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowUI.cpp" line="428"/>
- <source>Ready</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowUI.cpp" line="435"/>
- <source>Key ToolBox</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/main_window/MainWindowUI.cpp" line="443"/>
- <source>Information Board</source>
- <translation type="unfinished"></translation>
- </message>
-</context>
-<context>
- <name>PubkeyGetter</name>
- <message>
- <location filename="../../src/server/api/PubkeyGetter.cpp" line="66"/>
- <location filename="../../src/server/api/PubkeyGetter.cpp" line="90"/>
- <source>Error</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/server/api/PubkeyGetter.cpp" line="67"/>
- <location filename="../../src/server/api/PubkeyGetter.cpp" line="91"/>
- <source>The communication content with the server does not meet the requirements</source>
- <translation type="unfinished"></translation>
- </message>
-</context>
-<context>
- <name>PubkeyUploader</name>
- <message>
- <location filename="../../src/server/api/PubkeyUploader.cpp" line="95"/>
- <source>Error</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/server/api/PubkeyUploader.cpp" line="96"/>
- <source>The communication content with the server does not meet the requirements</source>
- <translation type="unfinished"></translation>
- </message>
-</context>
-<context>
- <name>QApplication</name>
- <message>
- <location filename="../../src/gpg/result_analyse/DecryptResultAnalyse.cpp" line="66"/>
- <source> {&gt;} Recipient: </source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/gpg/result_analyse/VerifyResultAnalyse.cpp" line="63"/>
- <source>One or More Bad Signatures.</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/gpg/result_analyse/VerifyResultAnalyse.cpp" line="68"/>
- <source>A </source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/gpg/result_analyse/VerifyResultAnalyse.cpp" line="70"/>
- <source>Good </source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/gpg/result_analyse/VerifyResultAnalyse.cpp" line="73"/>
- <source>Bad </source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/gpg/result_analyse/VerifyResultAnalyse.cpp" line="76"/>
- <source>Expired </source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/gpg/result_analyse/VerifyResultAnalyse.cpp" line="79"/>
- <source>Missing Key&apos;s </source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/gpg/result_analyse/VerifyResultAnalyse.cpp" line="82"/>
- <source>Revoked Key&apos;s </source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/gpg/result_analyse/VerifyResultAnalyse.cpp" line="85"/>
- <source>Expired Key&apos;s </source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/gpg/result_analyse/VerifyResultAnalyse.cpp" line="88"/>
- <source>Missing CRL&apos;s </source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/gpg/result_analyse/VerifyResultAnalyse.cpp" line="92"/>
- <source>Signature Fully Valid.</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/gpg/result_analyse/VerifyResultAnalyse.cpp" line="94"/>
- <source>Signature Not Fully Valid.</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/gpg/result_analyse/VerifyResultAnalyse.cpp" line="100"/>
- <source>Key is NOT present with ID 0x</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/gpg/result_analyse/VerifyResultAnalyse.cpp" line="107"/>
- <source>A signature could NOT be verified due to a Missing Key
-</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/gpg/result_analyse/VerifyResultAnalyse.cpp" line="111"/>
- <source>A signature is valid but the key used to verify the signature has been revoked
-</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/gpg/result_analyse/VerifyResultAnalyse.cpp" line="119"/>
- <source>A signature is valid but expired
-</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/gpg/result_analyse/VerifyResultAnalyse.cpp" line="126"/>
- <source>A signature is valid but the key used to verify the signature has expired.
-</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/gpg/result_analyse/VerifyResultAnalyse.cpp" line="133"/>
- <source>There was some other error which prevented the signature verification.
-</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/gpg/result_analyse/VerifyResultAnalyse.cpp" line="139"/>
- <source>Error for key with fingerprint </source>
- <translation type="unfinished"></translation>
- </message>
-</context>
-<context>
- <name>QuitDialog</name>
- <message>
- <location filename="../../src/ui/QuitDialog.cpp" line="29"/>
- <source>Unsaved Files</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/QuitDialog.cpp" line="77"/>
- <source>%1 files contain unsaved information.&lt;br/&gt;Save the changes before closing?</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/QuitDialog.cpp" line="88"/>
- <source>Check the files you want to save:</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/QuitDialog.cpp" line="89"/>
- <source>&lt;b&gt;Note:&lt;/b&gt; If you don&apos;t save these files, all changes are lost.&lt;br/&gt;</source>
- <translation type="unfinished"></translation>
- </message>
-</context>
-<context>
- <name>SendMailDialog</name>
- <message>
- <location filename="../../src/ui/SendMailDialog.cpp" line="35"/>
- <source>Incomplete configuration</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/SendMailDialog.cpp" line="36"/>
- <source>The SMTP address is empty, please go to the setting interface to complete the configuration.</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/SendMailDialog.cpp" line="86"/>
- <source> Recipient cannot be empty
-</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/SendMailDialog.cpp" line="91"/>
- <source> One or more Recipient&apos;s Email Address is invalid
-</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/SendMailDialog.cpp" line="97"/>
- <source> Sender cannot be empty
-</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/SendMailDialog.cpp" line="99"/>
- <source> Sender&apos;s Email Address is invalid
-</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/SendMailDialog.cpp" line="155"/>
- <location filename="../../src/ui/SendMailDialog.cpp" line="160"/>
- <location filename="../../src/ui/SendMailDialog.cpp" line="165"/>
- <source>Fail</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/SendMailDialog.cpp" line="155"/>
- <source>Fail to Connect SMTP Server</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/SendMailDialog.cpp" line="160"/>
- <source>Fail to Login into SMTP Server</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/SendMailDialog.cpp" line="165"/>
- <source>Fail to Send Mail to SMTP Server</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/SendMailDialog.cpp" line="171"/>
- <source>Success</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/SendMailDialog.cpp" line="171"/>
- <source>Succeed in Sending Mail to SMTP Server</source>
- <translation type="unfinished"></translation>
- </message>
-</context>
-<context>
- <name>SendMailTab</name>
- <message>
- <location filename="../../src/ui/settings/SettingsSendMail.cpp" line="33"/>
- <source>Enable</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/settings/SettingsSendMail.cpp" line="51"/>
- <source>Check Connection</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/settings/SettingsSendMail.cpp" line="53"/>
- <source>General</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/settings/SettingsSendMail.cpp" line="54"/>
- <source>Connection</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/settings/SettingsSendMail.cpp" line="55"/>
- <source>Preference</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/settings/SettingsSendMail.cpp" line="61"/>
- <source>SMTP Address</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/settings/SettingsSendMail.cpp" line="63"/>
- <source>Username</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/settings/SettingsSendMail.cpp" line="65"/>
- <source>Password</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/settings/SettingsSendMail.cpp" line="67"/>
- <source>Port</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/settings/SettingsSendMail.cpp" line="69"/>
- <source>Connection Security</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/settings/SettingsSendMail.cpp" line="75"/>
- <source>Default Sender</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/settings/SettingsSendMail.cpp" line="161"/>
- <location filename="../../src/ui/settings/SettingsSendMail.cpp" line="165"/>
- <source>Fail</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/settings/SettingsSendMail.cpp" line="161"/>
- <source>Fail to Connect SMTP Server</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/settings/SettingsSendMail.cpp" line="165"/>
- <source>Fail to Login</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/settings/SettingsSendMail.cpp" line="170"/>
- <source>Success</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/settings/SettingsSendMail.cpp" line="170"/>
- <source>Succeed in connecting and login</source>
- <translation type="unfinished"></translation>
- </message>
-</context>
-<context>
- <name>SettingsDialog</name>
- <message>
- <location filename="../../src/ui/settings/SettingsDialog.cpp" line="39"/>
- <source>General</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/settings/SettingsDialog.cpp" line="40"/>
- <source>Appearance</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/settings/SettingsDialog.cpp" line="41"/>
- <source>Send Mail</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/settings/SettingsDialog.cpp" line="42"/>
- <source>Key Server</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/settings/SettingsDialog.cpp" line="44"/>
- <source>Advanced</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/settings/SettingsDialog.cpp" line="59"/>
- <source>Settings</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/settings/SettingsDialog.cpp" line="105"/>
- <source>System Default</source>
- <translation type="unfinished"></translation>
- </message>
-</context>
-<context>
- <name>SignResultAnalyse</name>
- <message>
- <location filename="../../src/gpg/result_analyse/SignResultAnalyse.cpp" line="31"/>
- <source>[#] Sign Operation </source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/gpg/result_analyse/SignResultAnalyse.cpp" line="34"/>
- <source>[Success]</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/gpg/result_analyse/SignResultAnalyse.cpp" line="36"/>
- <source>[Failed] </source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/gpg/result_analyse/SignResultAnalyse.cpp" line="47"/>
- <source>[&gt;] New Signature: </source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/gpg/result_analyse/SignResultAnalyse.cpp" line="51"/>
- <source> Sign Mode: </source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/gpg/result_analyse/SignResultAnalyse.cpp" line="53"/>
- <source>Normal</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/gpg/result_analyse/SignResultAnalyse.cpp" line="55"/>
- <source>Clear</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/gpg/result_analyse/SignResultAnalyse.cpp" line="57"/>
- <source>Detach</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/gpg/result_analyse/SignResultAnalyse.cpp" line="63"/>
- <location filename="../../src/gpg/result_analyse/SignResultAnalyse.cpp" line="65"/>
- <source> Signer: </source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/gpg/result_analyse/SignResultAnalyse.cpp" line="65"/>
- <source>&lt;unknown&gt;</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/gpg/result_analyse/SignResultAnalyse.cpp" line="67"/>
- <source> Public Key Algo: </source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/gpg/result_analyse/SignResultAnalyse.cpp" line="68"/>
- <source> Hash Algo: </source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/gpg/result_analyse/SignResultAnalyse.cpp" line="69"/>
- <source> Date &amp; Time: </source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/gpg/result_analyse/SignResultAnalyse.cpp" line="81"/>
- <source>Invalid Signers: </source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/gpg/result_analyse/SignResultAnalyse.cpp" line="85"/>
- <source>[&gt;] Signer: </source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/gpg/result_analyse/SignResultAnalyse.cpp" line="86"/>
- <source> Fingerprint: </source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/gpg/result_analyse/SignResultAnalyse.cpp" line="87"/>
- <source> Reason: </source>
- <translation type="unfinished"></translation>
- </message>
-</context>
-<context>
- <name>SignersPicker</name>
- <message>
- <location filename="../../src/ui/widgets/SignersPicker.cpp" line="28"/>
- <source>Confirm</source>
- <translation type="unfinished"></translation>
- </message>
-</context>
-<context>
- <name>SubkeyGenerateDialog</name>
- <message>
- <location filename="../../src/ui/keygen/SubkeyGenerateDialog.cpp" line="47"/>
- <source>Generate New Subkey</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keygen/SubkeyGenerateDialog.cpp" line="62"/>
- <source>Encryption</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keygen/SubkeyGenerateDialog.cpp" line="65"/>
- <source>Signing</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keygen/SubkeyGenerateDialog.cpp" line="68"/>
- <source>Certification</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keygen/SubkeyGenerateDialog.cpp" line="71"/>
- <source>Authentication</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keygen/SubkeyGenerateDialog.cpp" line="115"/>
- <source>Expiration Date:</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keygen/SubkeyGenerateDialog.cpp" line="116"/>
- <source>Never Expire</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keygen/SubkeyGenerateDialog.cpp" line="117"/>
- <source>KeySize (in Bit):</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keygen/SubkeyGenerateDialog.cpp" line="118"/>
- <source>Key Type:</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keygen/SubkeyGenerateDialog.cpp" line="127"/>
- <source>Basic Information</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keygen/SubkeyGenerateDialog.cpp" line="215"/>
- <source> Expiration time no more than 2 years. </source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keygen/SubkeyGenerateDialog.cpp" line="244"/>
- <source>Success</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keygen/SubkeyGenerateDialog.cpp" line="244"/>
- <source>The new subkey has been generated.</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/keygen/SubkeyGenerateDialog.cpp" line="247"/>
- <source>Failure</source>
- <translation type="unfinished"></translation>
- </message>
-</context>
-<context>
- <name>TextEdit</name>
- <message>
- <location filename="../../src/ui/widgets/TextEdit.cpp" line="53"/>
- <source>untitled</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/widgets/TextEdit.cpp" line="120"/>
- <location filename="../../src/ui/widgets/TextEdit.cpp" line="200"/>
- <source>Warning</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/widgets/TextEdit.cpp" line="121"/>
- <location filename="../../src/ui/widgets/TextEdit.cpp" line="201"/>
- <location filename="../../src/ui/widgets/TextEdit.cpp" line="482"/>
- <source>Cannot read file %1:
-%2.</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/widgets/TextEdit.cpp" line="175"/>
- <source>Open file</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/widgets/TextEdit.cpp" line="251"/>
- <source>File</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/widgets/TextEdit.cpp" line="252"/>
- <source>Cannot write file %1:
-%2.</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/widgets/TextEdit.cpp" line="270"/>
- <source>Save file</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/widgets/TextEdit.cpp" line="333"/>
- <source>Unsaved document</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/widgets/TextEdit.cpp" line="334"/>
- <source>The document &quot;%1&quot; has been modified. Do you want to save your changes?&lt;br/&gt;</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/widgets/TextEdit.cpp" line="337"/>
- <source>&lt;b&gt;Note:&lt;/b&gt; If you don&apos;t save these files, all changes are lost.&lt;br/&gt;</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/widgets/TextEdit.cpp" line="481"/>
- <source>Application</source>
- <translation type="unfinished"></translation>
- </message>
-</context>
-<context>
- <name>UpdateTab</name>
- <message>
- <location filename="../../src/ui/help/AboutDialog.cpp" line="129"/>
- <source>It is recommended that you always check the version of GpgFrontend and upgrade to the latest version.</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/help/AboutDialog.cpp" line="131"/>
- <source>New versions not only represent new features, but also often represent functional and security fixes.</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/help/AboutDialog.cpp" line="135"/>
- <source>Current Version: </source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/help/AboutDialog.cpp" line="143"/>
- <source>The current version is inconsistent with the latest version on github.</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/help/AboutDialog.cpp" line="145"/>
- <source>Please click &lt;a href=&quot;https://github.com/saturneric/GpgFrontend/releases&quot;&gt;here&lt;/a&gt; to download the latest version.</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/help/AboutDialog.cpp" line="199"/>
- <location filename="../../src/ui/help/AboutDialog.cpp" line="214"/>
- <source>Latest Version From Github: </source>
- <translation type="unfinished"></translation>
- </message>
-</context>
-<context>
- <name>VerifyDetailsDialog</name>
- <message>
- <location filename="../../src/ui/VerifyDetailsDialog.cpp" line="32"/>
- <source>Signature Details</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/VerifyDetailsDialog.cpp" line="53"/>
- <source>Status: </source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/VerifyDetailsDialog.cpp" line="56"/>
- <source>No valid input found</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/VerifyDetailsDialog.cpp" line="67"/>
- <source>Error Validating signature</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/VerifyDetailsDialog.cpp" line="70"/>
- <source>File was signed on %1 &lt;br/&gt; It Contains:&lt;br/&gt;&lt;br/&gt;</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/VerifyDetailsDialog.cpp" line="72"/>
- <source>Signed on %1 &lt;br/&gt; It Contains:&lt;br /&gt;&lt;br/&gt;</source>
- <translation type="unfinished"></translation>
- </message>
-</context>
-<context>
- <name>VerifyKeyDetailBox</name>
- <message>
- <location filename="../../src/ui/widgets/VerifyKeyDetailBox.cpp" line="36"/>
- <source>Import from keyserver</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/widgets/VerifyKeyDetailBox.cpp" line="39"/>
- <source>Key not present with id 0x</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/widgets/VerifyKeyDetailBox.cpp" line="43"/>
- <source>Status:</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/widgets/VerifyKeyDetailBox.cpp" line="45"/>
- <source>Key not present in keylist</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/widgets/VerifyKeyDetailBox.cpp" line="58"/>
- <location filename="../../src/ui/widgets/VerifyKeyDetailBox.cpp" line="72"/>
- <location filename="../../src/ui/widgets/VerifyKeyDetailBox.cpp" line="86"/>
- <location filename="../../src/ui/widgets/VerifyKeyDetailBox.cpp" line="101"/>
- <location filename="../../src/ui/widgets/VerifyKeyDetailBox.cpp" line="115"/>
- <location filename="../../src/ui/widgets/VerifyKeyDetailBox.cpp" line="129"/>
- <source>Key Information is NOT Available</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/widgets/VerifyKeyDetailBox.cpp" line="60"/>
- <location filename="../../src/ui/widgets/VerifyKeyDetailBox.cpp" line="74"/>
- <location filename="../../src/ui/widgets/VerifyKeyDetailBox.cpp" line="88"/>
- <location filename="../../src/ui/widgets/VerifyKeyDetailBox.cpp" line="103"/>
- <location filename="../../src/ui/widgets/VerifyKeyDetailBox.cpp" line="117"/>
- <location filename="../../src/ui/widgets/VerifyKeyDetailBox.cpp" line="131"/>
- <source>Fingerprint: </source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/widgets/VerifyKeyDetailBox.cpp" line="67"/>
- <source>Status: Cert Revoked</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/widgets/VerifyKeyDetailBox.cpp" line="81"/>
- <location filename="../../src/ui/widgets/VerifyKeyDetailBox.cpp" line="95"/>
- <source>Status: Signature Expired</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/widgets/VerifyKeyDetailBox.cpp" line="96"/>
- <source>Status: Key Expired</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/widgets/VerifyKeyDetailBox.cpp" line="110"/>
- <source>Status: General Error</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/widgets/VerifyKeyDetailBox.cpp" line="124"/>
- <source>Status: Unknown Error</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/widgets/VerifyKeyDetailBox.cpp" line="159"/>
- <source>Signer Name:</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/widgets/VerifyKeyDetailBox.cpp" line="160"/>
- <source>Signer Email:</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/widgets/VerifyKeyDetailBox.cpp" line="161"/>
- <source>Key&apos;s Fingerprint:</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/widgets/VerifyKeyDetailBox.cpp" line="162"/>
- <source>Valid:</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/widgets/VerifyKeyDetailBox.cpp" line="163"/>
- <source>Flags:</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/widgets/VerifyKeyDetailBox.cpp" line="171"/>
- <source>Fully Valid</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/widgets/VerifyKeyDetailBox.cpp" line="173"/>
- <source>NOT Fully Valid</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/widgets/VerifyKeyDetailBox.cpp" line="180"/>
- <source>Good </source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/widgets/VerifyKeyDetailBox.cpp" line="183"/>
- <source>Bad </source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/widgets/VerifyKeyDetailBox.cpp" line="186"/>
- <source>Expired </source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/widgets/VerifyKeyDetailBox.cpp" line="189"/>
- <source>Missing Key </source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/widgets/VerifyKeyDetailBox.cpp" line="192"/>
- <source>Revoked Key </source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/widgets/VerifyKeyDetailBox.cpp" line="195"/>
- <source>Expired Key </source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/ui/widgets/VerifyKeyDetailBox.cpp" line="198"/>
- <source>Missing CRL </source>
- <translation type="unfinished"></translation>
- </message>
-</context>
-<context>
- <name>VerifyResultAnalyse</name>
- <message>
- <location filename="../../src/gpg/result_analyse/VerifyResultAnalyse.cpp" line="33"/>
- <source>[#] Verify Operation </source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/gpg/result_analyse/VerifyResultAnalyse.cpp" line="36"/>
- <source>[Success]</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/gpg/result_analyse/VerifyResultAnalyse.cpp" line="38"/>
- <source>[Failed] </source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/gpg/result_analyse/VerifyResultAnalyse.cpp" line="157"/>
- <location filename="../../src/gpg/result_analyse/VerifyResultAnalyse.cpp" line="161"/>
- <source> Signed By: </source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/gpg/result_analyse/VerifyResultAnalyse.cpp" line="157"/>
- <source>&lt;unknown&gt;</source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/gpg/result_analyse/VerifyResultAnalyse.cpp" line="163"/>
- <source> Public Key Algo: </source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/gpg/result_analyse/VerifyResultAnalyse.cpp" line="164"/>
- <source> Hash Algo: </source>
- <translation type="unfinished"></translation>
- </message>
- <message>
- <location filename="../../src/gpg/result_analyse/VerifyResultAnalyse.cpp" line="165"/>
- <source> Date &amp; Time: </source>
- <translation type="unfinished"></translation>
- </message>
-</context>
-<context>
- <name>Wizard</name>
- <message>
- <location filename="../../src/ui/Wizard.cpp" line="40"/>
- <source>First Start Wizard</source>
- <translation type="unfinished"></translation>
- </message>
-</context>
-</TS>
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index 200f5beb..d5a713b1 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -1,146 +1,234 @@
-add_subdirectory(gpg)
-add_subdirectory(ui)
-add_subdirectory(smtp)
-add_subdirectory(server)
-add_subdirectory(advance)
-
-aux_source_directory(. BASE_SOURCE)
-
-set(APP_ICON_RESOURCE_WINDOWS "${CMAKE_SOURCE_DIR}/gpgfrontend.rc")
-set_property(SOURCE gpgfrontend.rc APPEND PROPERTY OBJECT_DEPENDS ${CMAKE_SOURCE_DIR}/gpgfrontend.ico)
-
-
-file(GLOB_RECURSE GPGFRONTEND_HEADER_FILES RELACTIVE ${CMAKE_SOURCE_DIR}/include/*.h)
-qt5_wrap_cpp(QT5_MOCS ${GPGFRONTEND_HEADER_FILES} TARGET ${AppName})
-
-# Set Binary Output Path
-set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/release)
-message(STATUS "CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}")
-
-# Set Resource Output Path
-if(${CMAKE_BUILD_TYPE} STREQUAL "Release")
- if(APPLE)
- set(RESOURCE_OUTPUT_DIRECTORY ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/Resources)
- elseif(LINUX)
- file(COPY ${CMAKE_SOURCE_DIR}/resource/gpgfrontend DESTINATION ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/ FOLLOW_SYMLINK_CHAIN)
- set(RESOURCE_OUTPUT_DIRECTORY ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/gpgfrontend/usr/share)
- else()
+if (GPG_CORE)
+ message(STATUS "Build Gpg Core")
+ add_subdirectory(gpg)
+endif ()
+
+if (UI_CORE)
+ message(STATUS "Build UI Core")
+ add_subdirectory(ui)
+endif ()
+
+if (SMTP_SUPPORT)
+ message(STATUS "Build SMTP Support")
+ add_compile_definitions(SMTP_SUPPORT)
+ add_subdirectory(smtp)
+endif ()
+
+if (SERVER_SUPPORT)
+ message(STATUS "Build Server Support")
+ add_compile_definitions(SERVER_SUPPORT)
+ add_subdirectory(server)
+endif ()
+
+if (ADVANCE_SUPPORT)
+ message(STATUS "Build Advance Support")
+ add_compile_definitions(ADVANCE_SUPPORT)
+ add_subdirectory(advance)
+endif ()
+
+if (APPLICATION_BUILD)
+ aux_source_directory(. BASE_SOURCE)
+ set(APP_ICON_RESOURCE_WINDOWS "${CMAKE_SOURCE_DIR}/gpgfrontend.rc")
+ set_property(SOURCE gpgfrontend.rc APPEND PROPERTY OBJECT_DEPENDS ${CMAKE_SOURCE_DIR}/gpgfrontend.ico)
+
+ # Set Binary Output Path
+ set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/release)
+ message(STATUS "CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}")
+endif ()
+
+
+if (APPLICATION_BUILD)
+ # Set Resource Output Path
+ if (${CMAKE_BUILD_TYPE} STREQUAL "Release")
+ if (APPLE)
+ set(RESOURCE_OUTPUT_DIRECTORY ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/Resources)
+ elseif (LINUX)
+ file(COPY ${CMAKE_SOURCE_DIR}/resource/gpgfrontend DESTINATION ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/ FOLLOW_SYMLINK_CHAIN)
+ set(RESOURCE_OUTPUT_DIRECTORY ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/gpgfrontend/usr/share)
+ else ()
+ set(RESOURCE_OUTPUT_DIRECTORY ${CMAKE_RUNTIME_OUTPUT_DIRECTORY})
+ endif ()
+ else ()
set(RESOURCE_OUTPUT_DIRECTORY ${CMAKE_RUNTIME_OUTPUT_DIRECTORY})
- endif()
-else()
- set(RESOURCE_OUTPUT_DIRECTORY ${CMAKE_RUNTIME_OUTPUT_DIRECTORY})
-endif()
-message(STATUS "RESOURCE_OUTPUT_DIRECTORY ${RESOURCE_OUTPUT_DIRECTORY}")
+ endif ()
+ message(STATUS "RESOURCE_OUTPUT_DIRECTORY ${RESOURCE_OUTPUT_DIRECTORY}")
+endif ()
# Get ALL SOURCE FILES
file(GLOB_RECURSE ALL_SOURCE_FILES RELACTIVE ${CMAKE_SOURCE_DIR}/src/*.cpp)
-# Set Translation Files
-set(QT_TS_FILES
- gpgfrontend_en_us.ts gpgfrontend_zh_cn.ts
- gpgfrontend_fr.ts gpgfrontend_ru.ts gpgfrontend_es.ts)
-list(TRANSFORM QT_TS_FILES PREPEND ${CMAKE_SOURCE_DIR}/resource/ts/)
-message(STATUS "QT_TS_FILES ${QT_TS_FILES}")
-set(QT_QM_FILES_OUTPUT_DIR ${RESOURCE_OUTPUT_DIRECTORY}/ts)
-set_source_files_properties(${QT_TS_FILES} PROPERTIES OUTPUT_LOCATION ${QT_QM_FILES_OUTPUT_DIR})
-QT5_create_translation(QON_QM_FILES ${CMAKE_SOURCE_DIR} ${QT_TS_FILES})
-message(STATUS "QON_QM_FILES ${QON_QM_FILES}")
-add_custom_target(translations DEPENDS ${QON_QM_FILES})
-
-# Set Build Information
-configure_file(${CMAKE_SOURCE_DIR}/include/GpgFrontend.h.in ${CMAKE_SOURCE_DIR}/include/GpgFrontend.h @ONLY)
-configure_file(${CMAKE_SOURCE_DIR}/include/GpgFrontendBuildInfo.h.in ${CMAKE_SOURCE_DIR}/include/GpgFrontendBuildInfo.h @ONLY)
-
-# Copy Resource Files
-file(COPY ${CMAKE_SOURCE_DIR}/resource/css DESTINATION ${RESOURCE_OUTPUT_DIRECTORY}/ FOLLOW_SYMLINK_CHAIN)
-file(COPY ${CMAKE_SOURCE_DIR}/resource/icons DESTINATION ${RESOURCE_OUTPUT_DIRECTORY}/ FOLLOW_SYMLINK_CHAIN)
-file(COPY ${CMAKE_SOURCE_DIR}/resource/conf DESTINATION ${RESOURCE_OUTPUT_DIRECTORY}/ FOLLOW_SYMLINK_CHAIN)
-
-if(${CMAKE_BUILD_TYPE} STREQUAL "Release")
- if(APPLE)
- file(COPY ${CMAKE_SOURCE_DIR}/gpgfrontend.icns DESTINATION ${RESOURCE_OUTPUT_DIRECTORY}/ FOLLOW_SYMLINK_CHAIN)
- # Refresh App Bundle
- file(REMOVE ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/${AppName}.app)
- elseif(LINUX)
- file(REMOVE ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/gpgfrontend/usr/bin/${AppName})
- endif()
-endif()
-
-# Copy Utils Files
-if(MINGW)
- message(STATUS "Copying Dependent DLL For Windows Runtime Env")
- file(COPY ${CMAKE_SOURCE_DIR}/resource/utils/lib/ DESTINATION ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/ FOLLOW_SYMLINK_CHAIN)
- file(COPY ${CMAKE_SOURCE_DIR}/resource/utils/gpgme/ DESTINATION ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/ FOLLOW_SYMLINK_CHAIN)
- file(COPY ${CMAKE_SOURCE_DIR}/resource/utils/bearer DESTINATION ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/ FOLLOW_SYMLINK_CHAIN)
- file(COPY ${CMAKE_SOURCE_DIR}/resource/utils/iconengines DESTINATION ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/ FOLLOW_SYMLINK_CHAIN)
- file(COPY ${CMAKE_SOURCE_DIR}/resource/utils/imageformats DESTINATION ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/ FOLLOW_SYMLINK_CHAIN)
- file(COPY ${CMAKE_SOURCE_DIR}/resource/utils/printsupport DESTINATION ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/ FOLLOW_SYMLINK_CHAIN)
- file(COPY ${CMAKE_SOURCE_DIR}/resource/utils/platforms DESTINATION ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/ FOLLOW_SYMLINK_CHAIN)
- file(COPY ${CMAKE_SOURCE_DIR}/resource/utils/openssl/ DESTINATION ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/ FOLLOW_SYMLINK_CHAIN)
-endif()
-
-set(RESOURCE_FILES ${CMAKE_SOURCE_DIR}/gpgfrontend.qrc ${APP_ICON_RESOURCE_WINDOWS} ${QON_QM_FILES})
-add_custom_target(resources ALL DEPENDS ${RESOURCE_FILES})
-add_dependencies(resources translations)
-
-if(${CMAKE_BUILD_TYPE} STREQUAL "Release")
- if(MINGW)
- add_executable(${AppName} WIN32 ${BASE_SOURCE} ${RESOURCE_FILES} ${QT5_MOCS})
- elseif(APPLE)
- add_executable(${AppName} MACOSX_BUNDLE ${ICON_RESOURCE} ${BASE_SOURCE} ${RESOURCE_FILES} ${QT5_MOCS})
- set_target_properties(${AppName} PROPERTIES
- BUNDLE True
- MACOSX_BUNDLE_GUI_IDENTIFIER pub.gpgfrontend.gpgfrontend
- MACOSX_BUNDLE_BUNDLE_NAME ${AppName}
- MACOSX_BUNDLE_LONG_VERSION_STRING ${BUILD_VERSION}
- MACOSX_BUNDLE_SHORT_VERSION_STRING ${PROJECT_VERSION}
- MACOSX_BUNDLE_BUNDLE_VERSION ${BUILD_VERSION}
- MACOSX_BUNDLE_ICON_FILE "gpgfrontend.icns")
- add_custom_command(TARGET ${AppName} POST_BUILD
- COMMAND /bin/rm -rf ./${AppName}.app/Contents/Resources
- WORKING_DIRECTORY ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}
- COMMENT "Deleting Resources in App Bundle")
- add_custom_command(TARGET ${AppName} POST_BUILD
- COMMAND /bin/mv -n ./Resources ./${AppName}.app/Contents/
- WORKING_DIRECTORY ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}
- COMMENT "Copying Resources into App Bundle Resource")
- elseif(LINUX)
- add_executable(${AppName} ${BASE_SOURCE} ${RESOURCE_FILES} ${QT5_MOCS})
- add_custom_command(TARGET ${AppName} POST_BUILD
- COMMAND /bin/mkdir ./gpgfrontend/usr/bin && /bin/mv -f ./${AppName} ./gpgfrontend/usr/bin/
- WORKING_DIRECTORY ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}
- COMMENT "Copying Binary into App Image")
- add_custom_command(TARGET ${AppName} POST_BUILD
- COMMAND /bin/mkdir ./gpgfrontend/usr/lib
- WORKING_DIRECTORY ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}
- COMMENT "Complement to build the required architecture")
- else()
+# i18n
+if (MULTI_LANG_SUPPORT)
+ message(STATUS "Build Multiply Languages Support")
+ # Set Translation Files
+ find_package(Gettext REQUIRED)
+ FIND_PROGRAM(GETTEXT_MSGFMT_EXECUTABLE msgfmt)
+ FIND_PROGRAM(GETTEXT_XGETTEXT_EXECUTABLE xgettext)
+ if (NOT GETTEXT_MSGFMT_EXECUTABLE OR NOT GETTEXT_XGETTEXT_EXECUTABLE)
+ message(ERROR "msgfmt or xgettext not found. Translations will *not* be installed")
+ else (NOT GETTEXT_MSGFMT_EXECUTABLE)
+ message(STATUS "Setting target translations")
+ add_custom_target(translations)
+ set(OUTPUT_POT_PATH ${CMAKE_SOURCE_DIR}/resource/locale/template/${PROJECT_NAME}.pot)
+ add_custom_command(
+ TARGET translations
+ COMMAND find ${CMAKE_SOURCE_DIR}/src -iname \"*.cpp\" | xargs xgettext --package-name=${PROJECT_NAME} --copyright-holder=Saturneric --package-version=${PROJECT_VERSION} [email protected] --add-comments="/*" --c++ -k_ -o ${OUTPUT_POT_PATH}
+ )
+
+ file(GLOB ALL_PO_FILES ${CMAKE_SOURCE_DIR}/resource/locale/po/*.po)
+ SET(GMO_FILES)
+ message(STATUS "ALL_PO_FILES ${ALL_PO_FILES}")
+
+ foreach (_poFile ${ALL_PO_FILES})
+ GET_FILENAME_COMPONENT(_poFileName ${_poFile} NAME)
+ string(REGEX REPLACE "\\.[^.]*$" "" _langName ${_poFileName})
+ message(STATUS "_poFileName ${_langName}")
+ make_directory(${CMAKE_SOURCE_DIR}/resource/locale/out/${_langName}/LC_MESSAGES)
+ add_custom_command(
+ TARGET translations
+ COMMAND echo Processing po LANG ${_langName}
+ )
+ add_custom_command(
+ TARGET translations
+ COMMAND msgfmt --check --verbose --output-file ${CMAKE_SOURCE_DIR}/resource/locale/out/${_langName}/LC_MESSAGES/GpgFrontend.mo ${_poFile}
+ )
+ endforeach ()
+
+ endif ()
+endif ()
+
+if (BASIC_ENV_CONFIG)
+ # Set Build Information
+ configure_file(${CMAKE_SOURCE_DIR}/src/GpgFrontend.h.in ${CMAKE_SOURCE_DIR}/src/GpgFrontend.h @ONLY)
+ configure_file(${CMAKE_SOURCE_DIR}/src/GpgFrontendBuildInfo.h.in ${CMAKE_SOURCE_DIR}/src/GpgFrontendBuildInfo.h @ONLY)
+endif ()
+
+if (APPLICATION_BUILD)
+ # Copy Resource Files
+ file(COPY ${CMAKE_SOURCE_DIR}/resource/css DESTINATION ${RESOURCE_OUTPUT_DIRECTORY}/ FOLLOW_SYMLINK_CHAIN)
+ file(COPY ${CMAKE_SOURCE_DIR}/resource/icons DESTINATION ${RESOURCE_OUTPUT_DIRECTORY}/ FOLLOW_SYMLINK_CHAIN)
+ if (MULTI_LANG_SUPPORT)
+ make_directory(${RESOURCE_OUTPUT_DIRECTORY}/locales)
+ file(COPY ${CMAKE_SOURCE_DIR}/resource/locale/out/ DESTINATION ${RESOURCE_OUTPUT_DIRECTORY}/locales FOLLOW_SYMLINK_CHAIN)
+ endif ()
+endif ()
+
+if (APPLICATION_BUILD)
+ if (${CMAKE_BUILD_TYPE} STREQUAL "Release")
+ if (APPLE)
+ file(COPY ${CMAKE_SOURCE_DIR}/gpgfrontend.icns DESTINATION ${RESOURCE_OUTPUT_DIRECTORY}/ FOLLOW_SYMLINK_CHAIN)
+ # Refresh App Bundle
+ file(REMOVE ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/${AppName}.app)
+ elseif (LINUX)
+ file(REMOVE ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/gpgfrontend/usr/bin/${AppName})
+ endif ()
+ endif ()
+endif ()
+
+if (APPLICATION_BUILD)
+ # Copy Utils Files
+ if (MINGW)
+ message(STATUS "Copying Dependent DLL For Windows Runtime Env")
+ file(COPY ${CMAKE_SOURCE_DIR}/resource/utils/lib/ DESTINATION ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/ FOLLOW_SYMLINK_CHAIN)
+ file(COPY ${CMAKE_SOURCE_DIR}/resource/utils/gpgme/ DESTINATION ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/ FOLLOW_SYMLINK_CHAIN)
+ file(COPY ${CMAKE_SOURCE_DIR}/resource/utils/bearer DESTINATION ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/ FOLLOW_SYMLINK_CHAIN)
+ file(COPY ${CMAKE_SOURCE_DIR}/resource/utils/iconengines DESTINATION ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/ FOLLOW_SYMLINK_CHAIN)
+ file(COPY ${CMAKE_SOURCE_DIR}/resource/utils/imageformats DESTINATION ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/ FOLLOW_SYMLINK_CHAIN)
+ file(COPY ${CMAKE_SOURCE_DIR}/resource/utils/printsupport DESTINATION ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/ FOLLOW_SYMLINK_CHAIN)
+ file(COPY ${CMAKE_SOURCE_DIR}/resource/utils/platforms DESTINATION ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/ FOLLOW_SYMLINK_CHAIN)
+ file(COPY ${CMAKE_SOURCE_DIR}/resource/utils/openssl/ DESTINATION ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/ FOLLOW_SYMLINK_CHAIN)
+ endif ()
+endif ()
+
+if (APPLICATION_BUILD)
+ set(RESOURCE_FILES ${CMAKE_SOURCE_DIR}/gpgfrontend.qrc ${APP_ICON_RESOURCE_WINDOWS} ${QON_QM_FILES})
+ add_custom_target(resources ALL DEPENDS ${RESOURCE_FILES})
+ if (MULTI_LANG_SUPPORT)
+ add_dependencies(resources translations)
+ endif ()
+endif ()
+
+if (APPLICATION_BUILD)
+ if (${CMAKE_BUILD_TYPE} STREQUAL "Release")
+ if (MINGW)
+ add_executable(${AppName} WIN32 ${BASE_SOURCE} ${RESOURCE_FILES} ${QT5_MOCS})
+ elseif (APPLE)
+ add_executable(${AppName} MACOSX_BUNDLE ${ICON_RESOURCE} ${BASE_SOURCE} ${RESOURCE_FILES} ${QT5_MOCS})
+ set_target_properties(${AppName} PROPERTIES
+ BUNDLE True
+ MACOSX_BUNDLE_GUI_IDENTIFIER pub.gpgfrontend.gpgfrontend
+ MACOSX_BUNDLE_BUNDLE_NAME ${AppName}
+ MACOSX_BUNDLE_LONG_VERSION_STRING ${BUILD_VERSION}
+ MACOSX_BUNDLE_SHORT_VERSION_STRING ${PROJECT_VERSION}
+ MACOSX_BUNDLE_BUNDLE_VERSION ${BUILD_VERSION}
+ MACOSX_BUNDLE_ICON_FILE "gpgfrontend.icns")
+ add_custom_command(TARGET ${AppName} POST_BUILD
+ COMMAND /bin/rm -rf ./${AppName}.app/Contents/Resources
+ WORKING_DIRECTORY ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}
+ COMMENT "Deleting Resources in App Bundle")
+ add_custom_command(TARGET ${AppName} POST_BUILD
+ COMMAND /bin/mv -n ./Resources ./${AppName}.app/Contents/
+ WORKING_DIRECTORY ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}
+ COMMENT "Copying Resources into App Bundle Resource")
+ elseif (LINUX)
+ add_executable(${AppName} ${BASE_SOURCE} ${RESOURCE_FILES} ${QT5_MOCS})
+ add_custom_command(TARGET ${AppName} POST_BUILD
+ COMMAND /bin/mkdir -p ./gpgfrontend/usr/bin && /bin/mv -f ./${AppName} ./gpgfrontend/usr/bin/
+ WORKING_DIRECTORY ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}
+ COMMENT "Copying Binary into App Image")
+ add_custom_command(TARGET ${AppName} POST_BUILD
+ COMMAND /bin/mkdir -p ./gpgfrontend/usr/lib
+ WORKING_DIRECTORY ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}
+ COMMENT "Complement to build the required architecture")
+ else ()
+ add_executable(${AppName} ${BASE_SOURCE} ${RESOURCE_FILES} ${QT5_MOCS})
+ endif ()
+ else ()
add_executable(${AppName} ${BASE_SOURCE} ${RESOURCE_FILES} ${QT5_MOCS})
- endif()
-else()
- add_executable(${AppName} ${BASE_SOURCE} ${RESOURCE_FILES} ${QT5_MOCS})
-endif()
-
-set(GPGFRONTEND_LIBS smtp gpgfrontend-ui advance server gpg)
-set(QT_DEPENDENCY_LIBS Qt5::Network Qt5::PrintSupport Qt5::Widgets Qt5::Test Qt5::Core)
-
-IF (MINGW)
- message(STATUS "Link Application Static Library For MINGW")
- target_link_libraries(${AppName}
- ${GPGFRONTEND_LIBS}
- ${QT_DEPENDENCY_LIBS}
- crypto ssl)
-elseif(APPLE)
- message(STATUS "Link Application Static Library For macOS")
- target_link_libraries(${AppName}
- ${GPGFRONTEND_LIBS}
- ${QT_DEPENDENCY_LIBS}
- crypto ssl)
-else()
- message(STATUS "Link Application Static Library For UNIX")
- target_link_libraries(${AppName}
- ${GPGFRONTEND_LIBS}
- ${QT_DEPENDENCY_LIBS}
- crypto ssl pthread)
-endif()
+ endif ()
+
+ # Make app build with resources
+ add_dependencies(${AppName} resources)
+
+endif ()
+
+if (APPLICATION_BUILD)
+
+ if (ADVANCE_SUPPORT)
+ set(GPGFRONTEND_BEFORE_UI_LIBS ${GPGFRONTEND_BEFORE_UI_LIBS} advance)
+ endif ()
+ if (ADVANCE_SUPPORT)
+ set(GPGFRONTEND_BEFORE_UI_LIBS ${GPGFRONTEND_BEFORE_UI_LIBS} server)
+ endif ()
+ if (SMTP_SUPPORT)
+ set(GPGFRONTEND_AFTER_UI_LIBS ${GPGFRONTEND_AFTER_UI_LIBS} server)
+ endif ()
+
+ set(GPGFRONTEND_LIBS ${GPGFRONTEND_AFTER_UI_LIBS} gpgfrontend-ui ${GPGFRONTEND_BEFORE_UI_LIBS} gpg_core easy_logging_pp)
+ set(QT_DEPENDENCY_LIBS Qt5::Network Qt5::PrintSupport Qt5::Widgets Qt5::Test Qt5::Core)
+
+ IF (MINGW)
+ message(STATUS "Link Application Static Library For MINGW")
+ find_library(libconfig NAMES libconfig++.a)
+ find_library(libintl NAMES libintl.a)
+ find_library(libiconv NAMES libiconv.a)
+
+ target_link_libraries(${AppName}
+ ${GPGFRONTEND_LIBS}
+ ${QT_DEPENDENCY_LIBS}
+ ${libintl} ${libiconv} ${libconfig} crypto ssl)
+ elseif (APPLE)
+ message(STATUS "Link Application Static Library For macOS")
+ target_link_libraries(${AppName}
+ ${GPGFRONTEND_LIBS}
+ ${QT_DEPENDENCY_LIBS}
+ crypto ssl intl)
+ else ()
+ message(STATUS "Link Application Static Library For UNIX ")
+ target_link_libraries(${AppName}
+ ${GPGFRONTEND_LIBS}
+ ${QT_DEPENDENCY_LIBS}
+ crypto ssl pthread)
+ endif ()
+endif ()
diff --git a/src/GpgFrontend.h.in b/src/GpgFrontend.h.in
new file mode 100644
index 00000000..622c2b07
--- /dev/null
+++ b/src/GpgFrontend.h.in
@@ -0,0 +1,63 @@
+/**
+ * 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_H_IN
+#define GPGFRONTEND_H_IN
+
+// i18n
+#ifdef WINDOWS
+#include <winsock2.h>
+#include <windows.h>
+#endif
+
+#include <libintl.h>
+#define _(String) gettext (String)
+#define gettext_noop(String) String
+#define N_(String) gettext_noop (String)
+
+#ifdef WINDOWS
+#include <clocale>
+#undef vsnprintf
+#endif
+
+// logging
+#define ELPP_DEFAULT_LOGGING_FLAGS 8192
+#include <easyloggingpp/easylogging++.h>
+
+#define PROJECT_NAME "@CMAKE_PROJECT_NAME@"
+#define OS_PLATFORM @OS_PLATFORM@
+#define LOCALE_DIR "@LOCALE_DIR@"
+
+/**
+ * Resources File(s) Path Vars
+ */
+#if defined(MACOS) && defined(RELEASE)
+#define RESOURCE_DIR(appDir) (appDir + "/../Resources/")
+#elif defined(LINUX) && defined(RELEASE)
+#define RESOURCE_DIR(appDir) (appDir + "/../share/")
+#else
+#define RESOURCE_DIR(appDir) (appDir)
+#endif
+
+#endif // GPGFRONTEND_H_IN
diff --git a/include/GpgFrontendBuildInfo.h.in b/src/GpgFrontendBuildInfo.h.in
index bf1d3f8a..eaf0475b 100644
--- a/include/GpgFrontendBuildInfo.h.in
+++ b/src/GpgFrontendBuildInfo.h.in
@@ -1,7 +1,7 @@
/**
- * This file is part of GPGFrontend.
+ * This file is part of GpgFrontend.
*
- * GPGFrontend is free software: you can redistribute it and/or modify
+ * 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.
diff --git a/src/MainWindow.cpp b/src/MainWindow.cpp
deleted file mode 100644
index 73f55672..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 GpgME::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/advance/UnknownSignersChecker.cpp b/src/advance/UnknownSignersChecker.cpp
index 1b087b5c..fc70ee20 100644
--- a/src/advance/UnknownSignersChecker.cpp
+++ b/src/advance/UnknownSignersChecker.cpp
@@ -1,7 +1,7 @@
/**
- * This file is part of GPGFrontend.
+ * This file is part of GpgFrontend.
*
- * GPGFrontend is free software: you can redistribute it and/or modify
+ * 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.
@@ -24,58 +24,52 @@
#include "advance/UnknownSignersChecker.h"
-
-UnknownSignersChecker::UnknownSignersChecker(GpgME::GpgContext *ctx, gpgme_verify_result_t result) :
- appPath(qApp->applicationDirPath()), settings(RESOURCE_DIR(appPath) + "/conf/gpgfrontend.ini"), mCtx(ctx),
- mResult(result) {
-
-}
+UnknownSignersChecker::UnknownSignersChecker(GpgFrontend::GpgContext *ctx,
+ gpgme_verify_result_t result)
+ : appPath(qApp->applicationDirPath()),
+ settings(RESOURCE_DIR(appPath) + "/conf/gpgfrontend.ini"),
+ mCtx(ctx),
+ mResult(result) {}
void UnknownSignersChecker::start() {
+ auto sign = mResult->signatures;
+ bool canContinue = true;
- auto sign = mResult->signatures;
- bool canContinue = true;
-
- while (sign && canContinue) {
-
- switch (gpg_err_code(sign->status)) {
- case GPG_ERR_BAD_SIGNATURE:
- break;
- case GPG_ERR_NO_ERROR:
- if (!(sign->status & GPGME_SIGSUM_KEY_MISSING))
- check_signer(sign);
- break;
- case GPG_ERR_NO_PUBKEY:
+ while (sign && canContinue) {
+ switch (gpg_err_code(sign->status)) {
+ case GPG_ERR_BAD_SIGNATURE:
+ break;
+ case GPG_ERR_NO_ERROR:
+ if (!(sign->status & GPGME_SIGSUM_KEY_MISSING)) check_signer(sign);
+ break;
+ case GPG_ERR_NO_PUBKEY:
- case GPG_ERR_CERT_REVOKED:
- case GPG_ERR_SIG_EXPIRED:
- case GPG_ERR_KEY_EXPIRED:
- check_signer(sign);
- break;
- case GPG_ERR_GENERAL:
- canContinue = false;
- break;
- default:
- break;
- }
- sign = sign->next;
+ case GPG_ERR_CERT_REVOKED:
+ case GPG_ERR_SIG_EXPIRED:
+ case GPG_ERR_KEY_EXPIRED:
+ check_signer(sign);
+ break;
+ case GPG_ERR_GENERAL:
+ canContinue = false;
+ break;
+ default:
+ break;
}
+ sign = sign->next;
+ }
- if(!unknownFprs.isEmpty()) {
- PubkeyGetter pubkeyGetter(mCtx, unknownFprs);
- pubkeyGetter.start();
- if (!pubkeyGetter.result()) {
-
- }
+ if (!unknownFprs.isEmpty()) {
+ PubkeyGetter pubkeyGetter(mCtx, unknownFprs);
+ pubkeyGetter.start();
+ if (!pubkeyGetter.result()) {
}
+ }
}
void UnknownSignersChecker::check_signer(gpgme_signature_t sign) {
-
- auto key = mCtx->getKeyByFpr(sign->fpr);
- if (!key.good) {
- qDebug() << "Find Unknown FingerPrint " << sign->fpr;
- unknownFprs.append(sign->fpr);
- }
-
+ auto key = mCtx->getKeyRefByFpr(sign->fpr);
+ if (!key.good) {
+ qDebug() << "Find Unknown FingerPrint " << sign->fpr;
+ unknownFprs.append(sign->fpr);
+ }
}
diff --git a/include/advance/UnknownSignersChecker.h b/src/advance/UnknownSignersChecker.h
index 8f644de6..de07eaf8 100644
--- a/include/advance/UnknownSignersChecker.h
+++ b/src/advance/UnknownSignersChecker.h
@@ -1,7 +1,7 @@
/**
- * This file is part of GPGFrontend.
+ * This file is part of GpgFrontend.
*
- * GPGFrontend is free software: you can redistribute it and/or modify
+ * 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.
@@ -28,25 +28,22 @@
#include "server/api/PubkeyGetter.h"
class UnknownSignersChecker : public QObject {
-Q_OBJECT
-public:
+ Q_OBJECT
+ public:
+ UnknownSignersChecker(GpgFrontend::GpgContext *ctx,
+ gpgme_verify_result_t result);
- UnknownSignersChecker(GpgME::GpgContext *ctx, gpgme_verify_result_t result);
+ void start();
- void start();
+ private:
+ QString appPath;
+ QSettings settings;
+ GpgFrontend::GpgContext *mCtx;
+ gpgme_verify_result_t mResult;
-private:
-
- QString appPath;
- QSettings settings;
- GpgME::GpgContext *mCtx;
- gpgme_verify_result_t mResult;
-
- QVector<QString> unknownFprs;
-
- void check_signer(gpgme_signature_t sign);
+ QVector<QString> unknownFprs;
+ void check_signer(gpgme_signature_t sign);
};
-
-#endif //GPGFRONTEND_ZH_CN_TS_UNKNOWNSIGNERSCHECKER_H
+#endif // GPGFRONTEND_ZH_CN_TS_UNKNOWNSIGNERSCHECKER_H
diff --git a/src/gpg/CMakeLists.txt b/src/gpg/CMakeLists.txt
index 2bcacade..886f8fdc 100644
--- a/src/gpg/CMakeLists.txt
+++ b/src/gpg/CMakeLists.txt
@@ -1,28 +1,42 @@
aux_source_directory(./result_analyse GPG_SOURCE)
-aux_source_directory(./gpg_context GPG_SOURCE)
+aux_source_directory(./function GPG_SOURCE)
+aux_source_directory(./model GPG_SOURCE)
aux_source_directory(. GPG_SOURCE)
-add_library(gpg STATIC ${GPG_SOURCE})
+add_library(gpg_core STATIC ${GPG_SOURCE})
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 ()
+
+set(BOOST_LIBS Boost::date_time Boost::filesystem)
+
+message(STATUS "Third Party Libraries " ${THIRD_PARTY_LIBS})
+
if (MINGW)
message(STATUS "Link GPG Static Library For MINGW")
- target_link_libraries(gpg
- gpgme gpg-error assuan
- Qt5::Network Qt5::PrintSupport Qt5::Widgets Qt5::Test Qt5::Core
- wsock32)
-elseif(APPLE)
+ target_link_libraries(gpg_core ${THIRD_PARTY_LIBS}
+ ${BOOST_LIBS}
+ gpgme gpg-error assuan wsock32)
+ target_compile_features(gpg_core PUBLIC cxx_std_17)
+elseif (APPLE)
+ find_library(libgpgme NAMES libgpgme.a)
+ find_library(libgpg-error NAMES libgpg-error.a)
+ find_library(libassuan NAMES libassuan.a)
message(STATUS "Link GPG Static Library For macOS")
- target_link_libraries(gpg
- /usr/local/lib/libgpgme.a /usr/local/lib/libgpg-error.a /usr/local/lib/libassuan.a
- Qt5::Network Qt5::PrintSupport Qt5::Widgets Qt5::Test Qt5::Core)
-else()
-
+ target_link_libraries(gpg_core ${THIRD_PARTY_LIBS}
+ ${BOOST_LIBS}
+ ${libgpgme} ${libgpg-error} ${libassuan}
+ dl)
+else ()
message(STATUS "Link GPG Static Library For Unix")
- target_link_libraries(gpg
- /usr/local/lib/libgpgme.a /usr/local/lib/libgpg-error.a /usr/local/lib/libassuan.a
- Qt5::Network Qt5::PrintSupport Qt5::Widgets Qt5::Test Qt5::Core)
-endif()
+ target_link_libraries(gpg_core ${THIRD_PARTY_LIBS}
+ libgpgme.a libgpg-error.a libassuan.a
+ ${BOOST_LIBS}
+ pthread dl)
+endif ()
diff --git a/src/gpg/GpgConstants.cpp b/src/gpg/GpgConstants.cpp
index 1d59dab5..5688287e 100644
--- a/src/gpg/GpgConstants.cpp
+++ b/src/gpg/GpgConstants.cpp
@@ -1,7 +1,7 @@
/**
- * This file is part of GPGFrontend.
+ * This file is part of GpgFrontend.
*
- * GPGFrontend is free software: you can redistribute it and/or modify
+ * 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.
@@ -24,11 +24,156 @@
#include "gpg/GpgConstants.h"
-const char *GpgConstants::PGP_CRYPT_BEGIN = "-----BEGIN PGP MESSAGE-----";
-const char *GpgConstants::PGP_CRYPT_END = "-----END PGP MESSAGE-----";
-const char *GpgConstants::PGP_SIGNED_BEGIN = "-----BEGIN PGP SIGNED MESSAGE-----";
-const char *GpgConstants::PGP_SIGNED_END = "-----END PGP SIGNATURE-----";
-const char *GpgConstants::PGP_SIGNATURE_BEGIN = "-----BEGIN PGP SIGNATURE-----";
-const char *GpgConstants::PGP_SIGNATURE_END = "-----END PGP SIGNATURE-----";
-const char *GpgConstants::GPG_FRONTEND_SHORT_CRYPTO_HEAD = "GpgF_Scpt://";
+#include <gpg-error.h>
+#include <boost/algorithm/string/predicate.hpp>
+#include <boost/filesystem.hpp>
+
+const char* GpgFrontend::GpgConstants::PGP_CRYPT_BEGIN =
+ "-----BEGIN PGP MESSAGE-----";
+const char* GpgFrontend::GpgConstants::PGP_CRYPT_END =
+ "-----END PGP MESSAGE-----";
+const char* GpgFrontend::GpgConstants::PGP_SIGNED_BEGIN =
+ "-----BEGIN PGP SIGNED MESSAGE-----";
+const char* GpgFrontend::GpgConstants::PGP_SIGNED_END =
+ "-----END PGP SIGNATURE-----";
+const char* GpgFrontend::GpgConstants::PGP_SIGNATURE_BEGIN =
+ "-----BEGIN PGP SIGNATURE-----";
+const char* GpgFrontend::GpgConstants::PGP_SIGNATURE_END =
+ "-----END PGP SIGNATURE-----";
+const char* GpgFrontend::GpgConstants::GPG_FRONTEND_SHORT_CRYPTO_HEAD =
+ "GpgF_Scpt://";
+
+gpgme_error_t GpgFrontend::check_gpg_error(gpgme_error_t err) {
+ if (gpg_err_code(err) != GPG_ERR_NO_ERROR) {
+ LOG(ERROR) << "[Error " << gpg_err_code(err)
+ << "] Source: " << gpgme_strsource(err)
+ << " Description: " << gpgme_strerror(err);
+ }
+ return err;
+}
+
+gpg_err_code_t GpgFrontend::check_gpg_error_2_err_code(gpgme_error_t err,
+ gpgme_error_t predict) {
+ auto err_code = gpg_err_code(err);
+ if (err_code != predict) {
+ LOG(ERROR) << "[Error " << gpg_err_code(err)
+ << "] Source: " << gpgme_strsource(err)
+ << " Description: " << gpgme_strerror(err);
+ }
+ return err_code;
+}
+
+// error-handling
+gpgme_error_t GpgFrontend::check_gpg_error(gpgme_error_t err,
+ const std::string& comment) {
+ if (gpg_err_code(err) != GPG_ERR_NO_ERROR) {
+ LOG(ERROR) << "[Error " << gpg_err_code(err)
+ << "] Source: " << gpgme_strsource(err)
+ << " Description: " << gpgme_strerror(err) << " " << comment;
+ }
+ return err;
+}
+
+std::string GpgFrontend::beautify_fingerprint(
+ GpgFrontend::BypeArrayConstRef fingerprint) {
+ auto _fingerprint = fingerprint;
+ unsigned len = fingerprint.size();
+ if ((len > 0) && (len % 4 == 0))
+ for (unsigned n = 0; 4 * (n + 1) < len; ++n)
+ _fingerprint.insert(static_cast<int>(5u * n + 4u), " ");
+ return fingerprint;
+}
+
+// trim from start (in place)
+static inline void ltrim(std::string& s) {
+ s.erase(s.begin(), std::find_if(s.begin(), s.end(), [](unsigned char ch) {
+ return !std::isspace(ch);
+ }));
+}
+
+// trim from end (in place)
+static inline void rtrim(std::string& s) {
+ s.erase(std::find_if(s.rbegin(), s.rend(),
+ [](unsigned char ch) { return !std::isspace(ch); })
+ .base(),
+ s.end());
+}
+
+// trim from both ends (in place)
+static inline std::string trim(std::string& s) {
+ ltrim(s);
+ rtrim(s);
+ return s;
+}
+
+std::string GpgFrontend::read_all_data_in_file(const std::string& path) {
+ using namespace boost::filesystem;
+ class path file_info(path.c_str());
+
+ if (!exists(file_info) || !is_regular_file(path))
+ throw std::runtime_error("no permission");
+
+ std::ifstream in_file;
+ in_file.open(path, std::ios::in);
+ if (!in_file.good()) throw std::runtime_error("cannot open file");
+ std::istreambuf_iterator<char> begin(in_file);
+ std::istreambuf_iterator<char> end;
+ std::string in_buffer(begin, end);
+ in_file.close();
+ return in_buffer;
+}
+
+bool GpgFrontend::write_buffer_to_file(const std::string& path,
+ const std::string& out_buffer) {
+ std::ofstream out_file(boost::filesystem::path(path).string(), std::ios::out);
+ if (!out_file.good()) 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) {
+ // Create a Path object from given string
+ boost::filesystem::path path_obj(path);
+ // Check if file name in the path object has extension
+ if (path_obj.has_extension()) {
+ // Fetch the extension from path object and return
+ return path_obj.extension().string();
+ }
+ // In case of no extension return empty string
+ return {};
+}
+
+std::string GpgFrontend::get_only_file_name_with_path(const std::string& path) {
+ // Create a Path object from given string
+ boost::filesystem::path path_obj(path);
+ // Check if file name in the path object has extension
+ if (path_obj.has_filename()) {
+ // Fetch the extension from path object and return
+ return (path_obj.parent_path() / path_obj.stem()).string();
+ }
+ // In case of no extension return empty string
+ throw std::runtime_error("invalid file path");
+}
+
+/*
+ * isSigned returns:
+ * - 0, if text isn't signed at all
+ * - 1, if text is partially signed
+ * - 2, if text is completly signed
+ */
+int GpgFrontend::text_is_signed(GpgFrontend::BypeArrayRef text) {
+ using boost::algorithm::ends_with;
+ using boost::algorithm::starts_with;
+
+ auto trim_text = trim(text);
+ if (starts_with(trim_text, GpgConstants::PGP_SIGNED_BEGIN) &&
+ ends_with(trim_text, GpgConstants::PGP_SIGNED_END))
+ return 2;
+ else if (text.find(GpgConstants::PGP_SIGNED_BEGIN) != std::string::npos &&
+ text.find(GpgConstants::PGP_SIGNED_END) != std::string::npos)
+ return 1;
+ else
+ return 0;
+}
diff --git a/src/gpg/GpgConstants.h b/src/gpg/GpgConstants.h
new file mode 100644
index 00000000..1cd0f64d
--- /dev/null
+++ b/src/gpg/GpgConstants.h
@@ -0,0 +1,101 @@
+/**
+ * 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 GPG_CONSTANTS_H
+#define GPG_CONSTANTS_H
+
+#include "GpgFrontend.h"
+
+#include <gpg-error.h>
+#include <gpgme.h>
+
+#include <cassert>
+#include <functional>
+#include <memory>
+#include <string>
+
+const int RESTART_CODE = 1000;
+
+namespace GpgFrontend {
+
+using ByteArray = std::string;
+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>&;
+
+using GpgError = gpgme_error_t;
+
+// Result Deletor
+struct _result_ref_deletor {
+ void operator()(void* _result) {
+ // if (_result != nullptr)
+ // gpgme_result_unref(_result);
+ }
+};
+
+using GpgEncrResult =
+ std::unique_ptr<struct _gpgme_op_encrypt_result, _result_ref_deletor>;
+using GpgDecrResult =
+ std::unique_ptr<struct _gpgme_op_decrypt_result, _result_ref_deletor>;
+using GpgSignResult =
+ std::unique_ptr<struct _gpgme_op_sign_result, _result_ref_deletor>;
+using GpgVerifyResult =
+ std::unique_ptr<struct _gpgme_op_verify_result, _result_ref_deletor>;
+
+// Error Info Printer
+GpgError check_gpg_error(GpgError err);
+GpgError check_gpg_error(GpgError gpgmeError, const std::string& comment);
+gpg_err_code_t check_gpg_error_2_err_code(
+ gpgme_error_t err, gpgme_error_t predict = GPG_ERR_NO_ERROR);
+
+// Fingerprint
+std::string beautify_fingerprint(BypeArrayConstRef fingerprint);
+
+// File Operation
+std::string read_all_data_in_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_only_file_name_with_path(const std::string& path);
+
+// Check
+int text_is_signed(BypeArrayRef text);
+
+class GpgConstants {
+ public:
+ static const char* PGP_CRYPT_BEGIN;
+ static const char* PGP_CRYPT_END;
+ static const char* PGP_SIGNED_BEGIN;
+ static const char* PGP_SIGNED_END;
+ static const char* PGP_SIGNATURE_BEGIN;
+ static const char* PGP_SIGNATURE_END;
+ static const char* GPG_FRONTEND_SHORT_CRYPTO_HEAD;
+};
+} // namespace GpgFrontend
+
+#endif // GPG_CONSTANTS_H
diff --git a/src/gpg/GpgContext.cpp b/src/gpg/GpgContext.cpp
new file mode 100644
index 00000000..5d901c3f
--- /dev/null
+++ b/src/gpg/GpgContext.cpp
@@ -0,0 +1,127 @@
+/**
+ * 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 "gpg/GpgContext.h"
+
+#include <gpg-error.h>
+#include <gpgme.h>
+
+#include <functional>
+#include <string>
+
+#include "GpgConstants.h"
+
+#ifdef _WIN32
+#include <windows.h>
+#endif
+
+#define INT2VOIDP(i) (void*)(uintptr_t)(i)
+
+namespace GpgFrontend {
+
+/**
+ * Constructor
+ * Set up gpgme-context, set paths to app-run path
+ */
+GpgContext::GpgContext(bool independent_database, std::string db_path,
+ int channel)
+ : SingletonFunctionObject<GpgContext>(channel) {
+ static bool _first = true;
+
+ if (_first) {
+ /* Initialize the locale environment. */
+ setlocale(LC_ALL, "");
+ gpgme_check_version(nullptr);
+ gpgme_set_locale(nullptr, LC_CTYPE, setlocale(LC_CTYPE, nullptr));
+#ifdef LC_MESSAGES
+ gpgme_set_locale(nullptr, LC_MESSAGES, setlocale(LC_MESSAGES, nullptr));
+#endif
+ _first = false;
+ }
+
+ gpgme_ctx_t _p_ctx;
+ check_gpg_error(gpgme_new(&_p_ctx));
+ _ctx_ref = CtxRefHandler(_p_ctx);
+
+ auto engineInfo = gpgme_ctx_get_engine_info(*this);
+
+ // Check ENV before running
+ bool check_pass = false, find_openpgp = false, find_gpgconf = false,
+ find_assuan = false, find_cms = false;
+ while (engineInfo != nullptr) {
+ if (engineInfo->protocol == GPGME_PROTOCOL_GPGCONF &&
+ strcmp(engineInfo->version, "1.0.0") != 0)
+ find_gpgconf = true;
+ if (engineInfo->protocol == GPGME_PROTOCOL_OpenPGP &&
+ strcmp(engineInfo->version, "1.0.0") != 0)
+ find_openpgp = true, info.AppPath = engineInfo->file_name,
+ info.DatabasePath = "default";
+ if (engineInfo->protocol == GPGME_PROTOCOL_CMS &&
+ strcmp(engineInfo->version, "1.0.0") != 0)
+ find_cms = true;
+ if (engineInfo->protocol == GPGME_PROTOCOL_ASSUAN) find_assuan = true;
+ engineInfo = engineInfo->next;
+ }
+
+ if (find_gpgconf && find_openpgp && find_cms && find_assuan)
+ check_pass = true;
+
+ if (!check_pass) {
+ good_ = false;
+ return;
+ } else {
+ // Set Independent Database
+ if (independent_database) {
+ info.DatabasePath = db_path;
+ auto err = gpgme_ctx_set_engine_info(
+ _ctx_ref.get(), GPGME_PROTOCOL_OpenPGP, info.AppPath.c_str(),
+ info.DatabasePath.c_str());
+ assert(check_gpg_error_2_err_code(err) == GPG_ERR_NO_ERROR);
+ }
+
+ /** Setting the output type must be done at the beginning */
+ /** think this means ascii-armor --> ? */
+ gpgme_set_armor(*this, 1);
+ // Speed up loading process
+ gpgme_set_offline(*this, 1);
+
+ check_gpg_error(gpgme_set_keylist_mode(
+ *this, GPGME_KEYLIST_MODE_LOCAL | GPGME_KEYLIST_MODE_WITH_SECRET |
+ GPGME_KEYLIST_MODE_SIGS | GPGME_KEYLIST_MODE_SIG_NOTATIONS |
+ GPGME_KEYLIST_MODE_WITH_TOFU));
+ good_ = true;
+ }
+}
+
+bool GpgContext::good() const { return good_; }
+
+void GpgContext::SetPassphraseCb(decltype(test_passphrase_cb) cb) const {
+ gpgme_set_passphrase_cb(*this, cb, nullptr);
+}
+
+std::string GpgContext::getGpgmeVersion() {
+ return {gpgme_check_version(nullptr)};
+}
+
+} // namespace GpgFrontend \ No newline at end of file
diff --git a/src/gpg/GpgContext.h b/src/gpg/GpgContext.h
new file mode 100644
index 00000000..5812f49f
--- /dev/null
+++ b/src/gpg/GpgContext.h
@@ -0,0 +1,95 @@
+/**
+ * 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 __SGPGMEPP_CONTEXT_H__
+#define __SGPGMEPP_CONTEXT_H__
+
+#include "GpgConstants.h"
+#include "GpgFunctionObject.h"
+#include "GpgInfo.h"
+#include "GpgModel.h"
+
+namespace GpgFrontend {
+
+/**
+ * Custom Encapsulation of GpgME APIs
+ */
+class GpgContext : public SingletonFunctionObject<GpgContext> {
+ public:
+ explicit GpgContext(bool independent_database = false,
+ std::string path = std::string(), int channel = 0);
+
+ ~GpgContext() override = default;
+
+ [[nodiscard]] bool good() const;
+
+ [[nodiscard]] const GpgInfo& GetInfo() const { return info; }
+
+ static std::string getGpgmeVersion();
+
+ operator gpgme_ctx_t() const { return _ctx_ref.get(); }
+
+ private:
+ GpgInfo info;
+
+ struct _ctx_ref_deletor {
+ void operator()(gpgme_ctx_t _ctx) {
+ if (_ctx != nullptr) gpgme_release(_ctx);
+ }
+ };
+
+ using CtxRefHandler = std::unique_ptr<struct gpgme_context, _ctx_ref_deletor>;
+ CtxRefHandler _ctx_ref = nullptr;
+
+ bool good_ = true;
+
+ public:
+ static gpgme_error_t test_passphrase_cb(void* opaque, const char* uid_hint,
+ const char* passphrase_info,
+ int last_was_bad, int fd) {
+ LOG(INFO) << "test_passphrase_cb Called";
+ size_t res;
+ std::string pass = "abcdefg\n";
+ auto pass_len = pass.size();
+
+ size_t off = 0;
+
+ (void)opaque;
+ (void)uid_hint;
+ (void)passphrase_info;
+ (void)last_was_bad;
+
+ do {
+ res = gpgme_io_write(fd, &pass[off], pass_len - off);
+ if (res > 0) off += res;
+ } while (res > 0 && off != pass_len);
+
+ return off == pass_len ? 0 : gpgme_error_from_errno(errno);
+ }
+
+ void SetPassphraseCb(decltype(test_passphrase_cb) func) const;
+};
+} // namespace GpgFrontend
+
+#endif // __SGPGMEPP_CONTEXT_H__
diff --git a/src/gpg/GpgFileOpera.cpp b/src/gpg/GpgFileOpera.cpp
deleted file mode 100644
index af50c79a..00000000
--- a/src/gpg/GpgFileOpera.cpp
+++ /dev/null
@@ -1,249 +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 "gpg/GpgFileOpera.h"
-
-gpgme_error_t GpgFileOpera::encryptFile(GpgME::GpgContext *ctx, QVector<GpgKey> &keys, const QString &mPath,
- gpgme_encrypt_result_t *result) {
-
- QFileInfo fileInfo(mPath);
-
- if (!fileInfo.isFile() || !fileInfo.isReadable())
- throw std::runtime_error("no permission");
-
- QFile infile;
- infile.setFileName(mPath);
- if (!infile.open(QIODevice::ReadOnly))
- throw std::runtime_error("cannot open file");
-
- QByteArray inBuffer = infile.readAll();
- auto outBuffer = QByteArray();
- infile.close();
-
- auto error = ctx->encrypt(keys, inBuffer, &outBuffer, result);
-
- if (gpg_err_code(error) != GPG_ERR_NO_ERROR) return error;
-
- QFile outfile(mPath + ".asc");
-
- if (!outfile.open(QFile::WriteOnly))
- throw std::runtime_error("cannot open file");
-
- QDataStream out(&outfile);
- out.writeRawData(outBuffer.data(), outBuffer.length());
- outfile.close();
- return error;
-}
-
-gpgme_error_t GpgFileOpera::decryptFile(GpgME::GpgContext *ctx, const QString &mPath, gpgme_decrypt_result_t *result) {
-
- QFileInfo fileInfo(mPath);
-
- if (!fileInfo.isFile() || !fileInfo.isReadable())
- throw std::runtime_error("no permission");
-
- QFile infile;
- infile.setFileName(mPath);
- if (!infile.open(QIODevice::ReadOnly))
- throw std::runtime_error("cannot open file");
-
- QByteArray inBuffer = infile.readAll();
- auto outBuffer = QByteArray();
- infile.close();
-
- auto error = ctx->decrypt(inBuffer, &outBuffer, result);
-
- if (gpgme_err_code(error) != GPG_ERR_NO_ERROR) return error;
-
- QString outFileName, fileExtension = fileInfo.suffix();
-
- if (fileExtension == "asc" || fileExtension == "gpg") {
- int pos = mPath.lastIndexOf(QChar('.'));
- outFileName = mPath.left(pos);
- } else {
- outFileName = mPath + ".out";
- }
-
- QFile outfile(outFileName);
-
- if (!outfile.open(QFile::WriteOnly))
- throw std::runtime_error("cannot open file");
-
- QDataStream out(&outfile);
- out.writeRawData(outBuffer.data(), outBuffer.length());
- outfile.close();
-
- return error;
-}
-
-gpgme_error_t GpgFileOpera::signFile(GpgME::GpgContext *ctx, QVector<GpgKey> &keys, const QString &mPath,
- gpgme_sign_result_t *result) {
-
- QFileInfo fileInfo(mPath);
-
- if (!fileInfo.isFile() || !fileInfo.isReadable())
- throw std::runtime_error("no permission");
-
- QFile infile;
- infile.setFileName(mPath);
- if (!infile.open(QIODevice::ReadOnly))
- throw std::runtime_error("cannot open file");
-
-
- QByteArray inBuffer = infile.readAll();
- auto outBuffer = QByteArray();
- infile.close();
-
- auto error = ctx->sign(keys, inBuffer, &outBuffer, GPGME_SIG_MODE_DETACH, result);
-
- if (gpg_err_code(error) != GPG_ERR_NO_ERROR) return error;
-
- QFile outfile(mPath + ".sig");
-
- if (!outfile.open(QFile::WriteOnly))
- throw std::runtime_error("cannot open file");
-
- QDataStream out(&outfile);
- out.writeRawData(outBuffer.data(), outBuffer.length());
- outfile.close();
-
- return error;
-}
-
-gpgme_error_t GpgFileOpera::verifyFile(GpgME::GpgContext *ctx, const QString &mPath, gpgme_verify_result_t *result) {
-
- qDebug() << "Verify File Path" << mPath;
-
- QFileInfo fileInfo(mPath);
-
- if (!fileInfo.isFile() || !fileInfo.isReadable())
- throw std::runtime_error("no permission");
-
- QFile infile;
- infile.setFileName(mPath);
- if (!infile.open(QIODevice::ReadOnly))
- throw std::runtime_error("cannot open file");
-
- QByteArray inBuffer = infile.readAll();
-
- if(fileInfo.suffix() == "gpg") {
- auto error = ctx->verify(&inBuffer, nullptr, result);
- return error;
- }
- else {
- QFile signFile;
- signFile.setFileName(mPath + ".sig");
- if (!signFile.open(QIODevice::ReadOnly)) {
- throw std::runtime_error("cannot open file");
- }
-
- auto signBuffer = signFile.readAll();
- infile.close();
-
- auto error = ctx->verify(&inBuffer, &signBuffer, result);
- return error;
- }
-}
-
-gpg_error_t GpgFileOpera::encryptSignFile(GpgME::GpgContext *ctx, QVector<GpgKey> &keys, const QString &mPath,
- gpgme_encrypt_result_t *encr_res,
- gpgme_sign_result_t *sign_res) {
-
- qDebug() << "Encrypt Sign File Path" << mPath;
-
- QFileInfo fileInfo(mPath);
-
- if (!fileInfo.isFile() || !fileInfo.isReadable())
- throw std::runtime_error("no permission");
-
- QFile infile;
- infile.setFileName(mPath);
- if (!infile.open(QIODevice::ReadOnly))
- throw std::runtime_error("cannot open file");
-
- QByteArray inBuffer = infile.readAll();
- auto outBuffer = QByteArray();
- infile.close();
-
- QVector<GpgKey> signerKeys;
-
- // TODO dealing with signer keys
- auto error = ctx->encryptSign(keys, signerKeys, inBuffer, &outBuffer, encr_res, sign_res);
-
- if (gpg_err_code(error) != GPG_ERR_NO_ERROR)
- return error;
-
- QFile outfile(mPath + ".gpg");
-
- if (!outfile.open(QFile::WriteOnly))
- throw std::runtime_error("cannot open file");
-
- QDataStream out(&outfile);
- out.writeRawData(outBuffer.data(), outBuffer.length());
- outfile.close();
-
- return error;
-}
-
-gpg_error_t GpgFileOpera::decryptVerifyFile(GpgME::GpgContext *ctx, const QString &mPath, gpgme_decrypt_result_t *decr_res,
- gpgme_verify_result_t *verify_res) {
-
- qDebug() << "Decrypt Verify File Path" << mPath;
-
- QFileInfo fileInfo(mPath);
-
- if (!fileInfo.isFile() || !fileInfo.isReadable())
- throw std::runtime_error("no permission");
-
- QFile infile;
- infile.setFileName(mPath);
- if (!infile.open(QIODevice::ReadOnly))
- throw std::runtime_error("cannot open file");
-
- QByteArray inBuffer = infile.readAll();
- auto outBuffer = QByteArray();
- infile.close();
-
- auto error = ctx->decryptVerify(inBuffer, &outBuffer, decr_res, verify_res);
- if (gpg_err_code(error) != GPG_ERR_NO_ERROR) return error;
-
- QString outFileName, fileExtension = fileInfo.suffix();
-
- if (fileExtension == "asc" || fileExtension == "gpg") {
- int pos = mPath.lastIndexOf(QChar('.'));
- outFileName = mPath.left(pos);
- } else {
- outFileName = mPath + ".out";
- }
-
- QFile outfile(outFileName);
-
- if (!outfile.open(QFile::WriteOnly))
- throw std::runtime_error("cannot open file");
-
- QDataStream out(&outfile);
- out.writeRawData(outBuffer.data(), outBuffer.length());
- outfile.close();
-
- return error;
-}
diff --git a/src/gpg/GpgFunctionObject.h b/src/gpg/GpgFunctionObject.h
new file mode 100644
index 00000000..6f1d60af
--- /dev/null
+++ b/src/gpg/GpgFunctionObject.h
@@ -0,0 +1,138 @@
+/**
+ * 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_ZH_CN_TS_FUNCTIONOBJECT_H
+#define GPGFRONTEND_ZH_CN_TS_FUNCTIONOBJECT_H
+
+#include <easyloggingpp/easylogging++.h>
+
+#include <map>
+#include <memory>
+#include <mutex>
+#include <shared_mutex>
+#include <stdexcept>
+#include <string>
+
+namespace GpgFrontend {
+
+template <typename T>
+class SingletonFunctionObject {
+ public:
+ static T& GetInstance(int channel = 0) {
+ if (!channel) {
+ std::lock_guard<std::mutex> guard(_instance_mutex);
+ if (_instance == nullptr) _instance = std::make_unique<T>();
+ return *_instance;
+ } else {
+ // read _instances_map
+ decltype(_instances_map.end()) _it;
+ {
+ std::shared_lock lock(_instances_mutex);
+ _it = _instances_map.find(channel);
+ }
+ if (_it != _instances_map.end())
+ return *_it->second;
+ else
+ return CreateInstance(channel);
+ }
+ }
+
+ static T& CreateInstance(int channel, std::unique_ptr<T> p_obj = nullptr) {
+ if (!channel) return *_instance;
+
+ // read _instances_map
+ decltype(_instances_map.end()) _it;
+ {
+ std::shared_lock lock(_instances_mutex);
+ _it = _instances_map.find(channel);
+ }
+ if (_it == _instances_map.end()) {
+ {
+ std::lock_guard<std::mutex> guard(_default_channel_mutex);
+ int tmp = channel;
+ std::swap(_default_channel, tmp);
+ if (p_obj == nullptr) p_obj = std::make_unique<T>();
+ std::swap(_default_channel, tmp);
+ }
+ T* obj = p_obj.get();
+
+ // change _instances_map
+ {
+ std::unique_lock lock(_instances_mutex);
+ _instances_map.insert({channel, std::move(p_obj)});
+ }
+ return *obj;
+ } else {
+ return *_it->second;
+ }
+ }
+
+ static int GetDefaultChannel() { return _default_channel; }
+
+ int GetChannel() const { return channel_; }
+
+ SingletonFunctionObject(T&&) = delete;
+
+ SingletonFunctionObject(const T&) = delete;
+
+ void operator=(const T&) = delete;
+
+ protected:
+ SingletonFunctionObject() {}
+
+ SingletonFunctionObject(int channel) : channel_(channel) {}
+
+ virtual ~SingletonFunctionObject() = default;
+
+ private:
+ int channel_ = _default_channel;
+ static int _default_channel;
+ static std::mutex _default_channel_mutex;
+ static std::mutex _instance_mutex;
+ static std::shared_mutex _instances_mutex;
+ static std::unique_ptr<T> _instance;
+ static std::map<int, std::unique_ptr<T>> _instances_map;
+};
+
+template <typename T>
+int SingletonFunctionObject<T>::_default_channel = 0;
+
+template <typename T>
+std::mutex SingletonFunctionObject<T>::_default_channel_mutex;
+
+template <typename T>
+std::mutex SingletonFunctionObject<T>::_instance_mutex;
+
+template <typename T>
+std::shared_mutex SingletonFunctionObject<T>::_instances_mutex;
+
+template <typename T>
+std::unique_ptr<T> SingletonFunctionObject<T>::_instance = nullptr;
+
+template <typename T>
+std::map<int, std::unique_ptr<T>> SingletonFunctionObject<T>::_instances_map;
+
+} // namespace GpgFrontend
+
+#endif // GPGFRONTEND_ZH_CN_TS_FUNCTIONOBJECT_H
diff --git a/src/gpg/GpgGenKeyInfo.cpp b/src/gpg/GpgGenKeyInfo.cpp
index 69da27e3..07708433 100644
--- a/src/gpg/GpgGenKeyInfo.cpp
+++ b/src/gpg/GpgGenKeyInfo.cpp
@@ -1,7 +1,7 @@
/**
- * This file is part of GPGFrontend.
+ * This file is part of GpgFrontend.
*
- * GPGFrontend is free software: you can redistribute it and/or modify
+ * 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.
@@ -24,149 +24,149 @@
#include "gpg/GpgGenKeyInfo.h"
-const QVector<QString> GenKeyInfo::SupportedKeyAlgo = {
- "RSA",
- "DSA",
- "ED25519"
-};
-
-const QVector<QString> GenKeyInfo::SupportedSubkeyAlgo = {
- "RSA",
- "DSA",
- "ED25519",
- "ELG"
-};
-
-void GenKeyInfo::setAlgo(const QString &m_algo) {
-
- qDebug() << "set algo " << m_algo;
-
- reset_options();
-
- if (!this->subKey) {
- this->setAllowCertification(true);
- } else {
- this->setAllowCertification(false);
- }
-
- this->allowChangeCertification = false;
-
- auto lower_algo = m_algo.toLower();
-
- if(lower_algo == "rsa") {
- /**
- * RSA is the world’s premier asymmetric cryptographic algorithm,
- * and is built on the difficulty of factoring extremely large composites.
- * GnuPG supports RSA with key sizes of between 1024 and 4096 bits.
- */
- suggestMinKeySize = 1024;
- suggestMaxKeySize = 4096;
- suggestSizeAdditionStep = 1024;
- setKeySize(2048);
-
- } else if (lower_algo == "dsa") {
- /**
- * Algorithm (DSA) as a government standard for digital signatures.
- * Originally, it supported key lengths between 512 and 1024 bits.
- * Recently, NIST has declared 512-bit keys obsolete:
- * now, DSA is available in 1024, 2048 and 3072-bit lengths.
- */
- setAllowEncryption(false);
- allowChangeEncryption = false;
-
- suggestMinKeySize = 1024;
- suggestMaxKeySize = 3072;
- suggestSizeAdditionStep = 1024;
- setKeySize(2048);
-
- } else if (lower_algo == "ed25519") {
- /**
- * GnuPG supports the Elgamal asymmetric encryption algorithm in key lengths ranging from 1024 to 4096 bits.
- */
-
- setAllowEncryption(false);
- allowChangeEncryption = false;
-
- suggestMinKeySize = -1;
- suggestMaxKeySize = -1;
- suggestSizeAdditionStep = -1;
- setKeySize(-1);
- } else if (lower_algo == "elg") {
- /**
- * GnuPG supports the Elgamal asymmetric encryption algorithm in key lengths ranging from 1024 to 4096 bits.
- */
-
- setAllowAuthentication(false);
- allowChangeAuthentication = false;
-
- setAllowSigning(false);
- allowChangeSigning = false;
-
- suggestMinKeySize = 1024;
- suggestMaxKeySize = 4096;
- suggestSizeAdditionStep = 1024;
- setKeySize(2048);
- }
- GenKeyInfo::algo = lower_algo;
+#include <easyloggingpp/easylogging++.h>
+
+#include <boost/date_time/gregorian/greg_date.hpp>
+#include <boost/date_time/gregorian/greg_duration.hpp>
+#include <boost/date_time/gregorian/gregorian_types.hpp>
+#include <string>
+#include <vector>
+
+const std::vector<std::string> GpgFrontend::GenKeyInfo::SupportedKeyAlgo = {
+ "RSA", "DSA", "ED25519"};
+
+const std::vector<std::string> GpgFrontend::GenKeyInfo::SupportedSubkeyAlgo = {
+ "RSA", "DSA", "ED25519", "ELG"};
+
+void GpgFrontend::GenKeyInfo::setAlgo(const std::string &m_algo) {
+ LOG(INFO) << "GpgFrontend::GenKeyInfo::setAlgo m_algo" << m_algo;
+
+ reset_options();
+
+ if (!this->subKey) {
+ this->setAllowCertification(true);
+ } else {
+ this->setAllowCertification(false);
+ }
+
+ this->allowChangeCertification = false;
+
+ std::string lower_algo = std::string(m_algo);
+ boost::algorithm::to_lower(lower_algo);
+
+ LOG(INFO) << "GpgFrontend::GenKeyInfo::setAlgo lower_algo" << lower_algo;
+
+ if (lower_algo == "rsa") {
+ /**
+ * RSA is the world’s premier asymmetric cryptographic algorithm,
+ * and is built on the difficulty of factoring extremely large composites.
+ * GnuPG supports RSA with key sizes of between 1024 and 4096 bits.
+ */
+ suggestMinKeySize = 1024;
+ suggestMaxKeySize = 4096;
+ suggestSizeAdditionStep = 1024;
+ setKeySize(2048);
+
+ } else if (lower_algo == "dsa") {
+ /**
+ * Algorithm (DSA) as a government standard for digital signatures.
+ * Originally, it supported key lengths between 512 and 1024 bits.
+ * Recently, NIST has declared 512-bit keys obsolete:
+ * now, DSA is available in 1024, 2048 and 3072-bit lengths.
+ */
+ setAllowEncryption(false);
+ allowChangeEncryption = false;
+
+ suggestMinKeySize = 1024;
+ suggestMaxKeySize = 3072;
+ suggestSizeAdditionStep = 1024;
+ setKeySize(2048);
+
+ } else if (lower_algo == "ed25519") {
+ /**
+ * GnuPG supports the Elgamal asymmetric encryption algorithm in key lengths
+ * ranging from 1024 to 4096 bits.
+ */
+
+ setAllowEncryption(false);
+ allowChangeEncryption = false;
+
+ suggestMinKeySize = -1;
+ suggestMaxKeySize = -1;
+ suggestSizeAdditionStep = -1;
+ setKeySize(-1);
+ } else if (lower_algo == "elg") {
+ /**
+ * GnuPG supports the Elgamal asymmetric encryption algorithm in key lengths
+ * ranging from 1024 to 4096 bits.
+ */
+
+ setAllowAuthentication(false);
+ allowChangeAuthentication = false;
+
+ setAllowSigning(false);
+ allowChangeSigning = false;
+
+ suggestMinKeySize = 1024;
+ suggestMaxKeySize = 4096;
+ suggestSizeAdditionStep = 1024;
+ setKeySize(2048);
+ }
+ this->algo = lower_algo;
}
-void GenKeyInfo::reset_options() {
+void GpgFrontend::GenKeyInfo::reset_options() {
+ allowChangeEncryption = true;
+ setAllowEncryption(true);
- allowChangeEncryption = true;
- setAllowEncryption(true);
+ allowChangeCertification = true;
+ setAllowCertification(true);
- allowChangeCertification = true;
- setAllowCertification(true);
+ allowChangeSigning = true;
+ setAllowSigning(true);
- allowChangeSigning = true;
- setAllowSigning(true);
-
- allowChangeAuthentication = true;
- setAllowAuthentication(true);
-
-
- passPhrase.clear();
+ allowChangeAuthentication = true;
+ setAllowAuthentication(true);
+ passPhrase.clear();
}
-QString GenKeyInfo::getKeySizeStr() const {
- if(keySize > 0) {
- return QString::number(keySize);
- }
- else {
- return QString();
- }
-
+std::string GpgFrontend::GenKeyInfo::getKeySizeStr() const {
+ if (keySize > 0) {
+ return std::to_string(keySize);
+ } else {
+ return {};
+ }
}
-void GenKeyInfo::setKeySize(int m_key_size) {
- if (m_key_size < suggestMinKeySize || m_key_size > suggestMaxKeySize) {
- return;
- }
- GenKeyInfo::keySize = m_key_size;
+void GpgFrontend::GenKeyInfo::setKeySize(int m_key_size) {
+ if (m_key_size < suggestMinKeySize || m_key_size > suggestMaxKeySize) {
+ return;
+ }
+ GenKeyInfo::keySize = m_key_size;
}
-void GenKeyInfo::setExpired(const QDateTime &m_expired) {
- auto current = QDateTime::currentDateTime();
- if (isNonExpired() && m_expired < current.addYears(2)) {
- GenKeyInfo::expired = m_expired;
- }
+void GpgFrontend::GenKeyInfo::setExpired(
+ const boost::gregorian::date &m_expired) {
+ using namespace boost::gregorian;
+ auto current = day_clock::local_day();
+ if (isNonExpired() && m_expired < current + years(2)) {
+ GenKeyInfo::expired = m_expired;
+ }
}
-void GenKeyInfo::setNonExpired(bool m_non_expired) {
- if (!m_non_expired) {
- this->expired = QDateTime(QDateTime::fromTime_t(0));
- }
- GenKeyInfo::nonExpired = m_non_expired;
+void GpgFrontend::GenKeyInfo::setNonExpired(bool m_non_expired) {
+ using namespace boost::posix_time;
+ if (!m_non_expired) this->expired = from_time_t(0).date();
+ GenKeyInfo::nonExpired = m_non_expired;
}
-void GenKeyInfo::setAllowEncryption(bool m_allow_encryption) {
- if(allowChangeEncryption)
- GenKeyInfo::allowEncryption = m_allow_encryption;
+void GpgFrontend::GenKeyInfo::setAllowEncryption(bool m_allow_encryption) {
+ if (allowChangeEncryption) GenKeyInfo::allowEncryption = m_allow_encryption;
}
-void GenKeyInfo::setAllowCertification(bool m_allow_certification) {
- if(allowChangeCertification)
- GenKeyInfo::allowCertification = m_allow_certification;
+void GpgFrontend::GenKeyInfo::setAllowCertification(
+ bool m_allow_certification) {
+ if (allowChangeCertification)
+ GenKeyInfo::allowCertification = m_allow_certification;
}
-
diff --git a/src/gpg/GpgGenKeyInfo.h b/src/gpg/GpgGenKeyInfo.h
new file mode 100644
index 00000000..53b0c9f1
--- /dev/null
+++ b/src/gpg/GpgGenKeyInfo.h
@@ -0,0 +1,167 @@
+/**
+ * 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_GPGGENKEYINFO_H
+#define GPGFRONTEND_GPGGENKEYINFO_H
+
+#include <boost/date_time.hpp>
+#include <boost/date_time/gregorian/greg_duration_types.hpp>
+#include <string>
+#include <vector>
+
+namespace GpgFrontend {
+
+class GenKeyInfo {
+ bool subKey = true;
+ std::string userid;
+ std::string algo;
+ int keySize = 2048;
+ boost::gregorian::date expired =
+ boost::gregorian::day_clock::local_day() + boost::gregorian::years(2);
+ bool nonExpired = false;
+
+ bool noPassPhrase = false;
+ bool allowNoPassPhrase = true;
+
+ int suggestMaxKeySize = 4096;
+ int suggestSizeAdditionStep = 1024;
+ int suggestMinKeySize = 1024;
+
+ std::string passPhrase;
+
+ public:
+ static const std::vector<std::string> SupportedKeyAlgo;
+
+ static const std::vector<std::string> SupportedSubkeyAlgo;
+
+ [[nodiscard]] bool isSubKey() const { return subKey; }
+
+ void setIsSubKey(bool m_sub_key) { GenKeyInfo::subKey = m_sub_key; }
+
+ [[nodiscard]] const std::string &getUserid() const { return userid; }
+
+ void setUserid(const std::string &m_userid) { GenKeyInfo::userid = m_userid; }
+
+ [[nodiscard]] const std::string &getAlgo() const { return algo; }
+
+ void setAlgo(const std::string &m_algo);
+
+ [[nodiscard]] std::string getKeySizeStr() const;
+
+ [[nodiscard]] int getKeySize() const { return keySize; }
+
+ void setKeySize(int m_key_size);
+
+ [[nodiscard]] const boost::gregorian::date &getExpired() const {
+ return expired;
+ }
+
+ void setExpired(const boost::gregorian::date &m_expired);
+
+ [[nodiscard]] bool isNonExpired() const { return nonExpired; }
+
+ void setNonExpired(bool m_non_expired);
+
+ [[nodiscard]] bool isNoPassPhrase() const { return this->noPassPhrase; }
+
+ void setNonPassPhrase(bool m_non_pass_phrase) {
+ GenKeyInfo::noPassPhrase = m_non_pass_phrase;
+ }
+
+ [[nodiscard]] bool isAllowSigning() const { return allowSigning; }
+
+ [[nodiscard]] bool isAllowNoPassPhrase() const { return allowNoPassPhrase; }
+
+ void setAllowSigning(bool m_allow_signing) {
+ if (allowChangeSigning) GenKeyInfo::allowSigning = m_allow_signing;
+ }
+
+ [[nodiscard]] bool isAllowEncryption() const { return allowEncryption; }
+
+ void setAllowEncryption(bool m_allow_encryption);
+
+ [[nodiscard]] bool isAllowCertification() const { return allowCertification; }
+
+ void setAllowCertification(bool m_allow_certification);
+
+ [[nodiscard]] bool isAllowAuthentication() const {
+ return allowAuthentication;
+ }
+
+ void setAllowAuthentication(bool m_allow_authentication) {
+ if (allowChangeAuthentication)
+ GenKeyInfo::allowAuthentication = m_allow_authentication;
+ }
+
+ [[nodiscard]] const std::string &getPassPhrase() const { return passPhrase; }
+
+ void setPassPhrase(const std::string &m_pass_phrase) {
+ GenKeyInfo::passPhrase = m_pass_phrase;
+ }
+
+ [[nodiscard]] bool isAllowChangeSigning() const { return allowChangeSigning; }
+ [[nodiscard]] bool isAllowChangeEncryption() const {
+ return allowChangeEncryption;
+ }
+
+ [[nodiscard]] bool isAllowChangeCertification() const {
+ return allowChangeCertification;
+ }
+
+ [[nodiscard]] bool isAllowChangeAuthentication() const {
+ return allowChangeAuthentication;
+ }
+
+ [[nodiscard]] int getSuggestMaxKeySize() const { return suggestMaxKeySize; }
+
+ [[nodiscard]] int getSuggestMinKeySize() const { return suggestMinKeySize; }
+
+ [[nodiscard]] int getSizeChangeStep() const {
+ return suggestSizeAdditionStep;
+ }
+
+ private:
+ bool allowEncryption = true;
+ bool allowChangeEncryption = true;
+
+ bool allowCertification = true;
+ bool allowChangeCertification = true;
+
+ bool allowAuthentication = true;
+ bool allowChangeAuthentication = true;
+
+ bool allowSigning = true;
+ bool allowChangeSigning = true;
+
+ void reset_options();
+
+ public:
+ explicit GenKeyInfo(bool m_is_sub_key = false) : subKey(m_is_sub_key) {
+ setAlgo("rsa");
+ }
+};
+
+} // namespace GpgFrontend
+
+#endif // GPGFRONTEND_GPGGENKEYINFO_H
diff --git a/src/gpg/GpgInfo.cpp b/src/gpg/GpgInfo.cpp
index 00a15ef9..392dcf08 100644
--- a/src/gpg/GpgInfo.cpp
+++ b/src/gpg/GpgInfo.cpp
@@ -1,7 +1,7 @@
/**
- * This file is part of GPGFrontend.
+ * This file is part of GpgFrontend.
*
- * GPGFrontend is free software: you can redistribute it and/or modify
+ * 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.
diff --git a/include/gpg/GpgInfo.h b/src/gpg/GpgInfo.h
index 914491dd..27e13112 100644
--- a/include/gpg/GpgInfo.h
+++ b/src/gpg/GpgInfo.h
@@ -1,7 +1,7 @@
/**
- * This file is part of GPGFrontend.
+ * This file is part of GpgFrontend.
*
- * GPGFrontend is free software: you can redistribute it and/or modify
+ * 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.
@@ -20,24 +20,24 @@
* The source code version of this software was modified and released
* by Saturneric<[email protected]> starting on May 12, 2021.
*
-*/
+ */
#ifndef GPGFRONTEND_ZH_CN_TS_GPGINFO_H
#define GPGFRONTEND_ZH_CN_TS_GPGINFO_H
-#include "GpgFrontend.h"
+#include <string>
/**
* Use to record some info about gnupg
*/
class GpgInfo {
-public:
+ public:
+ /**
+ * executable binary path of gnupg
+ */
+ std::string AppPath;
- /**
- * executable binary path of gnupg
- */
- QString appPath;
+ std::string DatabasePath;
};
-
-#endif //GPGFRONTEND_ZH_CN_TS_GPGINFO_H
+#endif // GPGFRONTEND_ZH_CN_TS_GPGINFO_H
diff --git a/src/gpg/GpgKey.cpp b/src/gpg/GpgKey.cpp
deleted file mode 100644
index cd62fc5d..00000000
--- a/src/gpg/GpgKey.cpp
+++ /dev/null
@@ -1,274 +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 "gpg/GpgKey.h"
-
-void GpgKey::parse(gpgme_key_t key) {
-
- if(key == nullptr) return;
-
- good = true;
- key_refer = key;
- gpgme_key_ref(key_refer);
-
- is_private_key = key->secret;
- fpr = key->fpr;
- protocol = key->protocol;
- expired = (key->expired != 0u);
- revoked = (key->revoked != 0u);
-
- disabled = key->disabled;
-
- can_authenticate = key->can_authenticate;
- can_certify = key->can_certify;
- can_encrypt = key->can_encrypt;
- can_sign = key->can_sign;
-
- last_update = QDateTime(QDateTime::fromTime_t(key->last_update));
-
- switch (key->owner_trust) {
- case GPGME_VALIDITY_UNKNOWN:
- owner_trust = "Unknown";
- break;
- case GPGME_VALIDITY_UNDEFINED:
- owner_trust = "Undefined";
- break;
- case GPGME_VALIDITY_NEVER:
- owner_trust = "Never";
- break;
- case GPGME_VALIDITY_MARGINAL:
- owner_trust = "Marginal";
- break;
- case GPGME_VALIDITY_FULL:
- owner_trust = "FULL";
- break;
- case GPGME_VALIDITY_ULTIMATE:
- owner_trust = "Ultimate";
- break;
- }
-
- uids.clear();
- auto uid = key->uids;
-
- while (uid != nullptr) {
- uids.push_back(GpgUID(uid));
- uid = uid->next;
- }
-
- if (!uids.isEmpty()) {
- name = uids.first().name;
- email = uids.first().email;
- comment = uids.first().comment;
- }
-
- subKeys.clear();
- auto next = key->subkeys;
-
- while (next != nullptr) {
- subKeys.push_back(GpgSubKey(next));
- next = next->next;
- }
-
- if (!subKeys.isEmpty()) {
- id = subKeys.first().id;
- expires = subKeys.first().expires;
- pubkey_algo = subKeys.first().pubkey_algo;
- create_time = subKeys.first().timestamp;
- length = subKeys.first().length;
- has_master_key = subKeys.first().secret;
- } else {
- id = "";
- }
-
-}
-
-GpgKey::GpgKey(GpgKey &&k) noexcept {
-
- id = std::move(k.id);
- name = std::move(k.name);
- email = std::move(k.email);
- comment = std::move(k.comment);
- fpr = std::move(k.fpr);
- protocol = std::move(k.protocol);
- owner_trust = std::move(k.owner_trust);
- pubkey_algo = std::move(k.pubkey_algo);
- last_update = std::move(k.last_update);
- expires = std::move(k.expires);
- create_time = std::move(k.create_time);
-
- length = k.length;
- k.length = 0;
-
- can_encrypt = k.can_encrypt;
- can_sign = k.can_sign;
- can_certify = k.can_certify;
- can_authenticate = k.can_authenticate;
-
-
- is_private_key = k.is_private_key;
- expired = k.expired;
- revoked = k.revoked;
- disabled = k.disabled;
- k.has_master_key = k.has_master_key;
-
- good = k.good;
- k.good = false;
-
- subKeys = std::move(k.subKeys);
- uids = std::move(k.uids);
-
- key_refer = k.key_refer;
- k.key_refer = nullptr;
-
-}
-
-GpgKey &GpgKey::operator=(const GpgKey &k) {
-
- id = k.id;
- name = k.name;
- email = k.email;
- comment = k.comment;
- fpr = k.fpr;
- protocol = k.protocol;
- owner_trust = k.owner_trust;
- pubkey_algo = k.pubkey_algo;
- last_update = k.last_update;
- expires = k.expires;
- create_time = k.create_time;
-
- length = k.length;
-
- can_encrypt = k.can_encrypt;
- can_sign = k.can_sign;
- can_certify = k.can_certify;
- can_authenticate = k.can_authenticate;
-
- is_private_key = k.is_private_key;
- expired = k.expired;
- revoked = k.revoked;
- disabled = k.disabled;
-
- has_master_key = k.has_master_key;
-
- good = k.good;
-
- subKeys = k.subKeys;
- uids = k.uids;
-
- key_refer = k.key_refer;
- gpgme_key_ref(key_refer);
-
- return *this;
-}
-
-GpgKey::GpgKey(const GpgKey &k) :
- id(k.id), name(k.name), email(k.email), comment(k.comment),
- fpr(k.fpr), protocol(k.protocol), owner_trust(k.owner_trust),
- pubkey_algo(k.pubkey_algo), last_update(k.last_update),
- expires(k.expires), create_time(k.create_time){
-
- length = k.length;
-
- can_encrypt = k.can_encrypt;
- can_sign = k.can_sign;
- can_certify = k.can_certify;
- can_authenticate = k.can_authenticate;
-
- is_private_key = k.is_private_key;
- expired = k.expired;
- revoked = k.revoked;
- disabled = k.disabled;
-
- has_master_key = k.has_master_key;
-
- good = k.good;
-
- subKeys = k.subKeys;
- uids = k.uids;
-
- key_refer = k.key_refer;
- gpgme_key_ref(key_refer);
-
-}
-
-GpgKey &GpgKey::operator=(GpgKey &&k) noexcept {
-
- id = std::move(k.id);
- name = std::move(k.name);
- email = std::move(k.email);
- comment = std::move(k.comment);
- fpr = std::move(k.fpr);
- protocol = std::move(k.protocol);
- owner_trust = std::move(k.owner_trust);
- pubkey_algo = std::move(k.pubkey_algo);
- last_update = std::move(k.last_update);
- expires = std::move(k.expires);
- create_time = std::move(k.create_time);
-
- length = k.length;
- k.length = 0;
-
- can_encrypt = k.can_encrypt;
- can_sign = k.can_sign;
- can_certify = k.can_certify;
- can_authenticate = k.can_authenticate;
-
-
- is_private_key = k.is_private_key;
- expired = k.expired;
- revoked = k.revoked;
- disabled = k.disabled;
-
- has_master_key = k.has_master_key;
-
- good = k.good;
- k.good = false;
-
- subKeys = std::move(k.subKeys);
- uids = std::move(k.uids);
-
- key_refer = k.key_refer;
- k.key_refer = nullptr;
-
- return *this;
-}
-
-GpgKey::~GpgKey() {
- if(key_refer != nullptr && good) {
- gpgme_key_unref(key_refer);
- }
-}
-
-GpgKey::GpgKey(gpgme_key_t key) {
- parse(key);
-}
-
-void GpgKey::swapKeyRefer(gpgme_key_t key) {
-
- if(key == nullptr) return;
-
- gpgme_key_unref(key_refer);
- key_refer = nullptr;
- parse(key);
-}
diff --git a/src/gpg/GpgKeySignature.cpp b/src/gpg/GpgKeySignature.cpp
deleted file mode 100644
index 142d1550..00000000
--- a/src/gpg/GpgKeySignature.cpp
+++ /dev/null
@@ -1,34 +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 "gpg/GpgKeySignature.h"
-
-GpgKeySignature::GpgKeySignature(gpgme_key_sig_t key_sig) :
- revoked(key_sig->revoked), expired(key_sig->expired), invalid(key_sig->invalid),
- exportable(key_sig->exportable), status(key_sig->status),
- keyid(key_sig->keyid), pubkey_algo(gpgme_pubkey_algo_name(key_sig->pubkey_algo)),
- uid(key_sig->uid), name(key_sig->name), email(key_sig->email), comment(key_sig->comment),
- create_time(QDateTime::fromTime_t(key_sig->timestamp)), expire_time(QDateTime::fromTime_t(key_sig->expires)){
-
-}
diff --git a/src/gpg/GpgModel.h b/src/gpg/GpgModel.h
new file mode 100644
index 00000000..3e07427c
--- /dev/null
+++ b/src/gpg/GpgModel.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_ZH_CN_TS_GPGMODEL_H
+#define GPGFRONTEND_ZH_CN_TS_GPGMODEL_H
+
+#include "GpgConstants.h"
+
+#include <list>
+#include <utility>
+
+#include "gpg/model/GpgData.h"
+#include "gpg/model/GpgKey.h"
+
+namespace GpgFrontend {
+
+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 = std::vector<GpgKey>;
+
+using KeyListPtr = std::unique_ptr<KeyArgsList>;
+
+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/GpgSubKey.cpp b/src/gpg/GpgSubKey.cpp
deleted file mode 100644
index 4adda132..00000000
--- a/src/gpg/GpgSubKey.cpp
+++ /dev/null
@@ -1,51 +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 "gpg/GpgSubKey.h"
-
-GpgSubKey::GpgSubKey(gpgme_subkey_t key) {
-
- if (key == nullptr) return;
-
- id = key->keyid;
- pubkey_algo = gpgme_pubkey_algo_name(key->pubkey_algo);
- fpr = key->fpr;
-
- expired = key->expired;
- revoked = key->revoked;
- secret = key->secret;
-
- disabled = key->disabled;
-
- length = key->length;
-
- can_authenticate = key->can_authenticate;
- can_certify = key->can_certify;
- can_encrypt = key->can_encrypt;
- can_sign = key->can_sign;
- is_cardkey = key->is_cardkey;
- is_private_key = key->secret;
-
- timestamp = QDateTime::fromTime_t(key->timestamp);
- expires = QDateTime::fromTime_t(key->expires);
-}
diff --git a/src/gpg/GpgUID.cpp b/src/gpg/GpgUID.cpp
deleted file mode 100644
index 0dc6abfd..00000000
--- a/src/gpg/GpgUID.cpp
+++ /dev/null
@@ -1,38 +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 "gpg/GpgUID.h"
-
-GpgUID::GpgUID(gpgme_user_id_t user_id) :
- uid(user_id->uid), name(user_id->name), email(user_id->email), comment(user_id->comment),
- revoked(user_id->revoked), invalid(user_id->invalid) {
-
- auto sig = user_id->signatures;
-
- while (sig != nullptr) {
- signatures.push_back(GpgKeySignature(sig));
- sig = sig->next;
- }
-
-} \ No newline at end of file
diff --git a/src/gpg/function/BasicOperator.cpp b/src/gpg/function/BasicOperator.cpp
new file mode 100644
index 00000000..912119e2
--- /dev/null
+++ b/src/gpg/function/BasicOperator.cpp
@@ -0,0 +1,206 @@
+/**
+ * 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 "gpg/function/BasicOperator.h"
+
+#include <vector>
+
+#include "gpg/function/GpgKeyGetter.h"
+
+GpgFrontend::GpgError GpgFrontend::BasicOperator::Encrypt(
+ KeyListPtr keys, GpgFrontend::BypeArrayRef in_buffer,
+ GpgFrontend::ByteArrayPtr& out_buffer, GpgFrontend::GpgEncrResult& result) {
+ // gpgme_encrypt_result_t e_result;
+ gpgme_key_t recipients[keys->size() + 1];
+
+ int index = 0;
+ for (const auto& key : *keys) recipients[index++] = gpgme_key_t(key);
+
+ // Last entry data_in array has to be nullptr
+ recipients[keys->size()] = nullptr;
+
+ GpgData data_in(in_buffer.data(), in_buffer.size()), data_out;
+
+ gpgme_error_t err = check_gpg_error(gpgme_op_encrypt(
+ ctx, recipients, GPGME_ENCRYPT_ALWAYS_TRUST, data_in, data_out));
+
+ auto temp_data_out = data_out.Read2Buffer();
+ std::swap(temp_data_out, out_buffer);
+
+ auto temp_result = GpgEncrResult(gpgme_op_encrypt_result(ctx));
+ std::swap(result, temp_result);
+
+ return err;
+}
+
+GpgFrontend::GpgError GpgFrontend::BasicOperator::Decrypt(
+ BypeArrayRef in_buffer, GpgFrontend::ByteArrayPtr& out_buffer,
+ GpgFrontend::GpgDecrResult& result) {
+ gpgme_error_t err;
+
+ GpgData data_in(in_buffer.data(), in_buffer.size()), data_out;
+ err = check_gpg_error(gpgme_op_decrypt(ctx, data_in, data_out));
+
+ auto temp_data_out = data_out.Read2Buffer();
+ std::swap(temp_data_out, out_buffer);
+
+ auto temp_result = GpgDecrResult(gpgme_op_decrypt_result(ctx));
+ std::swap(result, temp_result);
+
+ return err;
+}
+
+GpgFrontend::GpgError GpgFrontend::BasicOperator::Verify(
+ BypeArrayRef& in_buffer, ByteArrayPtr& sig_buffer,
+ GpgVerifyResult& result) const {
+ gpgme_error_t err;
+
+ GpgData data_in(in_buffer.data(), in_buffer.size());
+
+ if (sig_buffer != nullptr) {
+ GpgData sig_data(sig_buffer->data(), sig_buffer->size());
+ err = check_gpg_error(gpgme_op_verify(ctx, sig_data, data_in, nullptr));
+ } else
+ err = check_gpg_error(gpgme_op_verify(ctx, data_in, nullptr, data_in));
+
+ auto temp_result = GpgVerifyResult(gpgme_op_verify_result(ctx));
+ std::swap(result, temp_result);
+
+ return err;
+}
+
+GpgFrontend::GpgError GpgFrontend::BasicOperator::Sign(KeyListPtr keys,
+ BypeArrayRef in_buffer,
+ ByteArrayPtr& out_buffer,
+ gpgme_sig_mode_t mode,
+ GpgSignResult& result) {
+ gpgme_error_t err;
+
+ // Set Singers of this opera
+ SetSigners(*keys);
+
+ GpgData data_in(in_buffer.data(), in_buffer.size()), data_out;
+
+ /**
+ `GPGME_SIG_MODE_NORMAL'
+ A normal signature is made, the output includes the plaintext
+ and the signature.
+
+ `GPGME_SIG_MODE_DETACH'
+ A detached signature is made.
+
+ `GPGME_SIG_MODE_CLEAR'
+ A clear text signature is made. The ASCII armor and text
+ mode settings of the context are ignored.
+ */
+
+ err = check_gpg_error(gpgme_op_sign(ctx, data_in, data_out, mode));
+
+ auto temp_data_out = data_out.Read2Buffer();
+ std::swap(temp_data_out, out_buffer);
+
+ auto temp_result = GpgSignResult(gpgme_op_sign_result(ctx));
+
+ std::swap(result, temp_result);
+
+ return err;
+}
+
+gpgme_error_t GpgFrontend::BasicOperator::DecryptVerify(
+ BypeArrayRef in_buffer, ByteArrayPtr& out_buffer,
+ GpgDecrResult& decrypt_result, GpgVerifyResult& verify_result) {
+ gpgme_error_t err;
+
+ GpgData data_in(in_buffer.data(), in_buffer.size()), data_out;
+
+ err = check_gpg_error(gpgme_op_decrypt_verify(ctx, data_in, data_out));
+
+ auto temp_data_out = data_out.Read2Buffer();
+ std::swap(temp_data_out, out_buffer);
+
+ auto temp_decr_result = GpgDecrResult(gpgme_op_decrypt_result(ctx));
+ std::swap(decrypt_result, temp_decr_result);
+
+ auto temp_verify_result = GpgVerifyResult(gpgme_op_verify_result(ctx));
+ std::swap(verify_result, temp_verify_result);
+
+ return err;
+}
+
+gpgme_error_t GpgFrontend::BasicOperator::EncryptSign(
+ KeyListPtr keys, KeyListPtr signers, BypeArrayRef in_buffer,
+ ByteArrayPtr& out_buffer, GpgEncrResult& encr_result,
+ GpgSignResult& sign_result) {
+ gpgme_error_t err;
+ SetSigners(*signers);
+
+ // gpgme_encrypt_result_t e_result;
+ gpgme_key_t recipients[keys->size() + 1];
+
+ // set key for user
+ int index = 0;
+ for (const auto& key : *keys) recipients[index++] = gpgme_key_t(key);
+
+ // Last entry dataIn array has to be nullptr
+ recipients[keys->size()] = nullptr;
+
+ GpgData data_in(in_buffer.data(), in_buffer.size()), data_out;
+
+ // If the last parameter isnt 0, a private copy of data is made
+ err = check_gpg_error(gpgme_op_encrypt_sign(
+ ctx, recipients, GPGME_ENCRYPT_ALWAYS_TRUST, data_in, data_out));
+
+ auto temp_data_out = data_out.Read2Buffer();
+ std::swap(temp_data_out, out_buffer);
+
+ auto temp_encr_result = GpgEncrResult(gpgme_op_encrypt_result(ctx));
+ swap(encr_result, temp_encr_result);
+ auto temp_sign_result = GpgSignResult(gpgme_op_sign_result(ctx));
+ swap(sign_result, temp_sign_result);
+
+ return err;
+}
+
+void GpgFrontend::BasicOperator::SetSigners(KeyArgsList& keys) {
+ gpgme_signers_clear(ctx);
+ for (const GpgKey& key : keys) {
+ if (key.CanSignActual()) {
+ auto gpgmeError = gpgme_signers_add(ctx, gpgme_key_t(key));
+ check_gpg_error(gpgmeError);
+ }
+ }
+ if (keys.size() != gpgme_signers_count(ctx))
+ DLOG(INFO) << "No All Signers Added";
+}
+
+std::unique_ptr<GpgFrontend::KeyArgsList>
+GpgFrontend::BasicOperator::GetSigners() {
+ auto count = gpgme_signers_count(ctx);
+ auto signers = std::make_unique<std::vector<GpgKey>>();
+ for (auto i = 0u; i < count; i++) {
+ auto key = GpgKey(gpgme_signers_enum(ctx, i));
+ signers->push_back(GpgKey(std::move(key)));
+ }
+ return signers;
+}
diff --git a/src/gpg/function/BasicOperator.h b/src/gpg/function/BasicOperator.h
new file mode 100644
index 00000000..39f93668
--- /dev/null
+++ b/src/gpg/function/BasicOperator.h
@@ -0,0 +1,69 @@
+/**
+ * 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_ZH_CN_TS_BASICOPERATOR_H
+#define GPGFRONTEND_ZH_CN_TS_BASICOPERATOR_H
+
+#include "gpg/GpgConstants.h"
+#include "gpg/GpgContext.h"
+#include "gpg/GpgFunctionObject.h"
+#include "gpg/GpgModel.h"
+
+namespace GpgFrontend {
+
+class BasicOperator : public SingletonFunctionObject<BasicOperator> {
+ public:
+ gpg_error_t Encrypt(KeyListPtr keys, BypeArrayRef in_buffer,
+ ByteArrayPtr& out_buffer, GpgEncrResult& result);
+
+ gpgme_error_t EncryptSign(KeyListPtr keys, KeyListPtr signers,
+ BypeArrayRef in_buffer, ByteArrayPtr& out_buffer,
+ GpgEncrResult& encr_result,
+ GpgSignResult& sign_result);
+
+ gpgme_error_t Decrypt(BypeArrayRef in_buffer, ByteArrayPtr& out_buffer,
+ GpgDecrResult& result);
+
+ gpgme_error_t DecryptVerify(BypeArrayRef in_buffer, ByteArrayPtr& out_buffer,
+ GpgDecrResult& decrypt_result,
+ GpgVerifyResult& verify_result);
+
+ gpgme_error_t Verify(BypeArrayRef in_buffer, ByteArrayPtr& sig_buffer,
+ GpgVerifyResult& result) const;
+
+ gpg_error_t Sign(KeyListPtr keys, BypeArrayRef in_buffer,
+ ByteArrayPtr& out_buffer, gpgme_sig_mode_t mode,
+ GpgSignResult& result);
+
+ void SetSigners(KeyArgsList& keys);
+
+ std::unique_ptr<KeyArgsList> GetSigners();
+
+ private:
+ GpgContext& ctx =
+ GpgContext::GetInstance(SingletonFunctionObject::GetDefaultChannel());
+};
+} // namespace GpgFrontend
+
+#endif // GPGFRONTEND_ZH_CN_TS_BASICOPERATOR_H
diff --git a/src/gpg/function/GpgCommandExecutor.cpp b/src/gpg/function/GpgCommandExecutor.cpp
new file mode 100644
index 00000000..9b99b400
--- /dev/null
+++ b/src/gpg/function/GpgCommandExecutor.cpp
@@ -0,0 +1,59 @@
+/**
+ * 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 "gpg/function/GpgCommandExecutor.h"
+#ifndef WINDOWS
+#include <boost/asio.hpp>
+#endif
+
+#ifndef WINDOWS
+
+using boost::process::async_pipe;
+
+void GpgFrontend::GpgCommandExecutor::Execute(
+ StringArgsRef arguments,
+ const std::function<void(async_pipe& in, async_pipe& out)>& interact_func) {
+ using namespace boost::process;
+
+ boost::asio::io_service ios;
+
+ std::vector<char> buf;
+
+ async_pipe in_pipe_stream(ios);
+ async_pipe out_pipe_stream(ios);
+
+ child child_process(ctx.GetInfo().AppPath.c_str(), arguments,
+ std_out > in_pipe_stream, std_in < out_pipe_stream);
+
+ boost::asio::async_read(
+ in_pipe_stream, boost::asio::buffer(buf),
+ [&](const boost::system::error_code& ec, std::size_t size) {
+ interact_func(in_pipe_stream, out_pipe_stream);
+ });
+
+ ios.run();
+ child_process.wait();
+ child_process.exit_code();
+}
+
+#endif
diff --git a/src/gpg/function/GpgCommandExecutor.h b/src/gpg/function/GpgCommandExecutor.h
new file mode 100644
index 00000000..f28caca8
--- /dev/null
+++ b/src/gpg/function/GpgCommandExecutor.h
@@ -0,0 +1,52 @@
+/**
+ * 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_ZH_CN_TS_GPGCOMMANDEXECUTOR_H
+#define GPGFRONTEND_ZH_CN_TS_GPGCOMMANDEXECUTOR_H
+
+#ifndef WINDOWS
+#include <boost/process.hpp>
+#endif
+
+#include "gpg/GpgContext.h"
+#include "gpg/GpgFunctionObject.h"
+
+namespace GpgFrontend {
+class GpgCommandExecutor : public SingletonFunctionObject<GpgCommandExecutor> {
+ public:
+
+#ifndef WINDOWS
+ void Execute(StringArgsRef arguments,
+ const std::function<void(boost::process::async_pipe &in,
+ boost::process::async_pipe &out)>
+ &interact_func);
+#endif
+
+ private:
+ GpgContext &ctx = GpgContext::GetInstance();
+};
+
+} // namespace GpgFrontend
+
+#endif // GPGFRONTEND_ZH_CN_TS_GPGCOMMANDEXECUTOR_H
diff --git a/src/gpg/function/GpgFileOpera.cpp b/src/gpg/function/GpgFileOpera.cpp
new file mode 100644
index 00000000..c3f75cf8
--- /dev/null
+++ b/src/gpg/function/GpgFileOpera.cpp
@@ -0,0 +1,162 @@
+/**
+ * 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 "gpg/function/GpgFileOpera.h"
+
+#include <memory>
+#include <string>
+
+#include "GpgConstants.h"
+#include "gpg/function/BasicOperator.h"
+
+GpgFrontend::GpgError GpgFrontend::GpgFileOpera::EncryptFile(
+ KeyListPtr keys, const std::string& path, GpgEncrResult& result) {
+ std::string in_buffer = read_all_data_in_file(path);
+ std::unique_ptr<std::string> out_buffer;
+
+ auto err = BasicOperator::GetInstance().Encrypt(std::move(keys), in_buffer,
+ out_buffer, result);
+
+ if (check_gpg_error_2_err_code(err) == GPG_ERR_NO_ERROR)
+ if (!write_buffer_to_file(path + ".asc", *out_buffer)) {
+ throw std::runtime_error("write_buffer_to_file error");
+ };
+
+ return err;
+}
+
+GpgFrontend::GpgError GpgFrontend::GpgFileOpera::DecryptFile(
+ const std::string& path, GpgDecrResult& result) {
+ std::string in_buffer = read_all_data_in_file(path);
+ std::unique_ptr<std::string> out_buffer;
+
+ auto err =
+ BasicOperator::GetInstance().Decrypt(in_buffer, out_buffer, result);
+
+ assert(check_gpg_error_2_err_code(err) == GPG_ERR_NO_ERROR);
+
+ std::string out_file_name = get_only_file_name_with_path(path),
+ file_extension = get_file_extension(path);
+
+ if (!(file_extension == ".asc" || file_extension == ".gpg"))
+ out_file_name += ".out";
+
+ if (check_gpg_error_2_err_code(err) == GPG_ERR_NO_ERROR)
+ if (!write_buffer_to_file(out_file_name, *out_buffer)) {
+ throw std::runtime_error("write_buffer_to_file error");
+ };
+
+ return err;
+}
+
+gpgme_error_t GpgFrontend::GpgFileOpera::SignFile(KeyListPtr keys,
+ const std::string& path,
+ GpgSignResult& result) {
+ auto in_buffer = read_all_data_in_file(path);
+ std::unique_ptr<std::string> out_buffer;
+
+ auto err = BasicOperator::GetInstance().Sign(
+ std::move(keys), in_buffer, out_buffer, GPGME_SIG_MODE_DETACH, result);
+
+ if (check_gpg_error_2_err_code(err) == GPG_ERR_NO_ERROR)
+ if (!write_buffer_to_file(path + ".sig", *out_buffer)) {
+ throw std::runtime_error("write_buffer_to_file error");
+ };
+
+ return err;
+}
+
+gpgme_error_t GpgFrontend::GpgFileOpera::VerifyFile(const std::string& path,
+ GpgVerifyResult& result) {
+ auto in_buffer = read_all_data_in_file(path);
+ std::unique_ptr<std::string> sign_buffer = nullptr;
+
+ if (get_file_extension(path) == ".gpg") {
+ auto err =
+ BasicOperator::GetInstance().Verify(in_buffer, sign_buffer, result);
+ assert(check_gpg_error_2_err_code(err) == GPG_ERR_NO_ERROR);
+ return err;
+ } else {
+ sign_buffer =
+ std::make_unique<std::string>(read_all_data_in_file(path + ".sig"));
+
+ auto err =
+ BasicOperator::GetInstance().Verify(in_buffer, sign_buffer, result);
+ return err;
+ }
+}
+
+// TODO
+
+gpg_error_t GpgFrontend::GpgFileOpera::EncryptSignFile(
+ KeyListPtr keys, KeyListPtr signer_keys, const std::string& path,
+ GpgEncrResult& encr_res, GpgSignResult& sign_res) {
+ auto in_buffer = read_all_data_in_file(path);
+ std::unique_ptr<std::string> out_buffer = nullptr;
+
+ // TODO dealing with signer keys
+ auto err = BasicOperator::GetInstance().EncryptSign(
+ std::move(keys), std::move(signer_keys), in_buffer, out_buffer, encr_res,
+ sign_res);
+
+ auto out_path = path + ".gpg";
+ LOG(INFO) << "EncryptSignFile out_path" << out_path;
+ LOG(INFO) << "EncryptSignFile out_buffer size" << out_buffer->size();
+
+ if (check_gpg_error_2_err_code(err) == GPG_ERR_NO_ERROR)
+ if (!write_buffer_to_file(out_path, *out_buffer)) {
+ throw std::runtime_error("write_buffer_to_file error");
+ };
+
+ return err;
+}
+
+gpg_error_t GpgFrontend::GpgFileOpera::DecryptVerifyFile(
+ const std::string& path, GpgDecrResult& decr_res,
+ GpgVerifyResult& verify_res) {
+ LOG(INFO) << "GpgFrontend::GpgFileOpera::DecryptVerifyFile Called";
+
+ auto in_buffer = read_all_data_in_file(path);
+
+ LOG(INFO) << "GpgFrontend::GpgFileOpera::DecryptVerifyFile in_buffer"
+ << in_buffer.size();
+ std::unique_ptr<std::string> out_buffer = nullptr;
+
+ auto err = BasicOperator::GetInstance().DecryptVerify(in_buffer, out_buffer,
+ decr_res, verify_res);
+
+ std::string out_file_name = get_only_file_name_with_path(path),
+ file_extension = get_file_extension(path);
+
+ if (!(file_extension == ".asc" || file_extension == ".gpg"))
+ out_file_name = path + ".out";
+ LOG(INFO) << "GpgFrontend::GpgFileOpera::DecryptVerifyFile out_file_name"
+ << out_file_name;
+
+ if (check_gpg_error_2_err_code(err) == GPG_ERR_NO_ERROR)
+ if (!write_buffer_to_file(out_file_name, *out_buffer)) {
+ throw std::runtime_error("write_buffer_to_file error");
+ };
+
+ return err;
+}
diff --git a/src/gpg/function/GpgFileOpera.h b/src/gpg/function/GpgFileOpera.h
new file mode 100644
index 00000000..4aaf09f1
--- /dev/null
+++ b/src/gpg/function/GpgFileOpera.h
@@ -0,0 +1,58 @@
+/**
+ * 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_GPGFILEOPERA_H
+#define GPGFRONTEND_GPGFILEOPERA_H
+
+#include "gpg/GpgConstants.h"
+#include "gpg/GpgContext.h"
+#include "gpg/GpgModel.h"
+
+namespace GpgFrontend {
+
+class GpgFileOpera : public SingletonFunctionObject<GpgFileOpera> {
+ public:
+ static GpgError EncryptFile(KeyListPtr keys, const std::string& path,
+ GpgEncrResult& result);
+
+ static GpgError DecryptFile(const std::string& path, GpgDecrResult& result);
+
+ static GpgError SignFile(KeyListPtr keys, const std::string& path,
+ GpgSignResult& result);
+
+ static GpgError VerifyFile(const std::string& path, GpgVerifyResult& result);
+
+ static GpgError EncryptSignFile(KeyListPtr keys, KeyListPtr signer_keys,
+ const std::string& path,
+ GpgEncrResult& encr_res,
+ GpgSignResult& sign_res);
+
+ static GpgError DecryptVerifyFile(const std::string& path,
+ GpgDecrResult& decr_res,
+ GpgVerifyResult& verify_res);
+};
+
+} // namespace GpgFrontend
+
+#endif // GPGFRONTEND_GPGFILEOPERA_H
diff --git a/src/gpg/function/GpgKeyGetter.cpp b/src/gpg/function/GpgKeyGetter.cpp
new file mode 100644
index 00000000..be27d69e
--- /dev/null
+++ b/src/gpg/function/GpgKeyGetter.cpp
@@ -0,0 +1,75 @@
+/**
+ * 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 "gpg/function/GpgKeyGetter.h"
+
+#include <gpg-error.h>
+
+#include "GpgConstants.h"
+
+GpgFrontend::GpgKey GpgFrontend::GpgKeyGetter::GetKey(const std::string& fpr) {
+ gpgme_key_t _p_key;
+ gpgme_get_key(ctx, fpr.c_str(), &_p_key, 1);
+ if (_p_key == nullptr) {
+ DLOG(WARNING) << "GpgKeyGetter GetKey Private _p_key Null fpr" << fpr;
+ return GetPubkey(fpr);
+ } else {
+ return GpgKey(std::move(_p_key));
+ }
+}
+
+GpgFrontend::GpgKey GpgFrontend::GpgKeyGetter::GetPubkey(
+ const std::string& fpr) {
+ gpgme_key_t _p_key;
+ gpgme_get_key(ctx, fpr.c_str(), &_p_key, 0);
+ if (_p_key == nullptr)
+ DLOG(WARNING) << "GpgKeyGetter GetKey _p_key Null" << fpr;
+ return GpgKey(std::move(_p_key));
+}
+
+GpgFrontend::KeyLinkListPtr GpgFrontend::GpgKeyGetter::FetchKey() {
+ gpgme_error_t err;
+
+ 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);
+
+ gpgme_key_t key;
+ while ((err = gpgme_op_keylist_next(ctx, &key)) == GPG_ERR_NO_ERROR) {
+ keys_list->push_back(GpgKey(std::move(key)));
+ }
+
+ assert(check_gpg_error_2_err_code(err, GPG_ERR_EOF) == GPG_ERR_EOF);
+
+ err = gpgme_op_keylist_end(ctx);
+
+ 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
new file mode 100644
index 00000000..c8f5d73a
--- /dev/null
+++ b/src/gpg/function/GpgKeyGetter.h
@@ -0,0 +1,52 @@
+/**
+ * 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_ZH_CN_TS_GPGKEYGETTER_H
+#define GPGFRONTEND_ZH_CN_TS_GPGKEYGETTER_H
+
+#include "gpg/GpgContext.h"
+#include "gpg/GpgFunctionObject.h"
+#include "gpg/GpgModel.h"
+
+namespace GpgFrontend {
+
+class GpgKeyGetter : public SingletonFunctionObject<GpgKeyGetter> {
+ public:
+ GpgKeyGetter() = default;
+
+ GpgKey GetKey(const std::string& fpr);
+
+ KeyListPtr GetKeys(const KeyIdArgsListPtr& ids);
+
+ GpgKey GetPubkey(const std::string& fpr);
+
+ KeyLinkListPtr FetchKey();
+
+ private:
+ GpgContext& ctx =
+ GpgContext::GetInstance(SingletonFunctionObject::GetDefaultChannel());
+};
+} // namespace GpgFrontend
+
+#endif // GPGFRONTEND_ZH_CN_TS_GPGKEYGETTER_H
diff --git a/src/gpg/function/GpgKeyImportExportor.cpp b/src/gpg/function/GpgKeyImportExportor.cpp
new file mode 100644
index 00000000..f4b88c60
--- /dev/null
+++ b/src/gpg/function/GpgKeyImportExportor.cpp
@@ -0,0 +1,117 @@
+/**
+ * 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 "gpg/function/GpgKeyImportExportor.h"
+
+#include "GpgConstants.h"
+
+/**
+ * Import key pair
+ * @param inBuffer input byte array
+ * @return Import information
+ */
+GpgFrontend::GpgImportInformation GpgFrontend::GpgKeyImportExportor::ImportKey(
+ StdBypeArrayPtr in_buffer) {
+ if (in_buffer->empty()) return GpgImportInformation();
+
+ GpgData data_in(in_buffer->data(), in_buffer->size());
+ auto err = check_gpg_error(gpgme_op_import(ctx, data_in));
+ assert(gpgme_err_code(err) == GPG_ERR_NO_ERROR);
+ gpgme_import_result_t result;
+ result = gpgme_op_import_result(ctx);
+ gpgme_import_status_t status = result->imports;
+ auto import_info = std::make_unique<GpgImportInformation>(result);
+ while (status != nullptr) {
+ GpgImportedKey key;
+ key.import_status = static_cast<int>(status->status);
+ key.fpr = status->fpr;
+ import_info->importedKeys.emplace_back(key);
+ status = status->next;
+ }
+ return *import_info;
+}
+
+/**
+ * Export Key
+ * @param uid_list key ids
+ * @param out_buffer output byte array
+ * @return if success
+ */
+bool GpgFrontend::GpgKeyImportExportor::ExportKeys(
+ KeyIdArgsListPtr& uid_list, ByteArrayPtr& out_buffer) const {
+ if (uid_list->empty()) return false;
+
+ // Alleviate another crash problem caused by an unknown array out-of-bounds
+ // access
+ for (size_t i = 0; i < uid_list->size(); i++) {
+ GpgData data_out;
+ auto err = gpgme_op_export(ctx, (*uid_list)[i].c_str(), 0, data_out);
+ assert(gpgme_err_code(err) == GPG_ERR_NO_ERROR);
+
+ DLOG(INFO) << "exportKeys read_bytes"
+ << gpgme_data_seek(data_out, 0, SEEK_END);
+
+ auto temp_out_buffer = data_out.Read2Buffer();
+ std::swap(out_buffer, temp_out_buffer);
+ }
+
+ return true;
+}
+
+/**
+ * Export keys
+ * @param keys keys used
+ * @param outBuffer output byte array
+ * @return if success
+ */
+bool GpgFrontend::GpgKeyImportExportor::ExportKeys(
+ 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());
+ return ExportKeys(key_ids, out_buffer);
+}
+
+/**
+ * Export the secret key of a key pair(including subkeys)
+ * @param key target key pair
+ * @param outBuffer output byte array
+ * @return if successful
+ */
+bool GpgFrontend::GpgKeyImportExportor::ExportSecretKey(
+ const GpgKey& key, ByteArrayPtr& out_buffer) const {
+ DLOG(INFO) << "Export Secret Key" << key.id().c_str();
+
+ gpgme_key_t target_key[2] = {gpgme_key_t(key), nullptr};
+
+ GpgData data_out;
+
+ // export private key to outBuffer
+ gpgme_error_t err =
+ gpgme_op_export_keys(ctx, target_key, GPGME_EXPORT_MODE_SECRET, data_out);
+
+ auto temp_out_buffer = data_out.Read2Buffer();
+ std::swap(out_buffer, temp_out_buffer);
+
+ return check_gpg_error_2_err_code(err) == GPG_ERR_NO_ERROR;
+}
diff --git a/src/gpg/function/GpgKeyImportExportor.h b/src/gpg/function/GpgKeyImportExportor.h
new file mode 100644
index 00000000..bceb87ef
--- /dev/null
+++ b/src/gpg/function/GpgKeyImportExportor.h
@@ -0,0 +1,100 @@
+/**
+ * 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 _GPGKEYIMPORTEXPORTOR_H
+#define _GPGKEYIMPORTEXPORTOR_H
+
+#include <string>
+
+#include "gpg/GpgConstants.h"
+#include "gpg/GpgContext.h"
+#include "gpg/GpgFunctionObject.h"
+#include "gpg/GpgModel.h"
+
+namespace GpgFrontend {
+
+class GpgImportedKey {
+ public:
+ std::string fpr;
+ int import_status;
+};
+
+typedef std::list<GpgImportedKey> GpgImportedKeyList;
+
+class GpgImportInformation {
+ public:
+ GpgImportInformation() = default;
+
+ explicit GpgImportInformation(gpgme_import_result_t result) {
+ if (result->unchanged) unchanged = result->unchanged;
+ if (result->considered) considered = result->considered;
+ if (result->no_user_id) no_user_id = result->no_user_id;
+ if (result->imported) imported = result->imported;
+ if (result->imported_rsa) imported_rsa = result->imported_rsa;
+ if (result->unchanged) unchanged = result->unchanged;
+ if (result->new_user_ids) new_user_ids = result->new_user_ids;
+ if (result->new_sub_keys) new_sub_keys = result->new_sub_keys;
+ if (result->new_signatures) new_signatures = result->new_signatures;
+ if (result->new_revocations) new_revocations = result->new_revocations;
+ if (result->secret_read) secret_read = result->secret_read;
+ if (result->secret_imported) secret_imported = result->secret_imported;
+ if (result->secret_unchanged) secret_unchanged = result->secret_unchanged;
+ if (result->not_imported) not_imported = result->not_imported;
+ }
+
+ int considered = 0;
+ int no_user_id = 0;
+ int imported = 0;
+ int imported_rsa = 0;
+ int unchanged = 0;
+ int new_user_ids = 0;
+ int new_sub_keys = 0;
+ int new_signatures = 0;
+ int new_revocations = 0;
+ int secret_read = 0;
+ int secret_imported = 0;
+ int secret_unchanged = 0;
+ int not_imported = 0;
+ GpgImportedKeyList importedKeys;
+};
+
+class GpgKeyImportExportor
+ : public SingletonFunctionObject<GpgKeyImportExportor> {
+ public:
+ GpgImportInformation ImportKey(StdBypeArrayPtr inBuffer);
+
+ bool ExportKeys(KeyIdArgsListPtr& uid_list, ByteArrayPtr& out_buffer) const;
+
+ bool ExportKeys(const KeyArgsList& keys, ByteArrayPtr& outBuffer) const;
+
+ bool ExportSecretKey(const GpgKey& key, ByteArrayPtr& outBuffer) const;
+
+ private:
+ GpgContext& ctx =
+ GpgContext::GetInstance(SingletonFunctionObject::GetDefaultChannel());
+};
+
+} // namespace GpgFrontend
+
+#endif // _GPGKEYIMPORTEXPORTOR_H \ No newline at end of file
diff --git a/src/gpg/function/GpgKeyManager.cpp b/src/gpg/function/GpgKeyManager.cpp
new file mode 100644
index 00000000..9e24b3d6
--- /dev/null
+++ b/src/gpg/function/GpgKeyManager.cpp
@@ -0,0 +1,88 @@
+/**
+ * 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 "gpg/function/GpgKeyManager.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,
+ const std::unique_ptr<boost::gregorian::date>& expires) {
+ using namespace boost::posix_time;
+
+ BasicOperator::GetInstance().SetSigners(keys);
+
+ unsigned int flags = 0;
+ unsigned int expires_time_t = 0;
+
+ if (expires == nullptr)
+ flags |= GPGME_KEYSIGN_NOEXPIRE;
+ else
+ expires_time_t = to_time_t(ptime(*expires));
+
+ auto err = check_gpg_error(gpgme_op_keysign(
+ ctx, gpgme_key_t(target), uid.c_str(), expires_time_t, flags));
+
+ return check_gpg_error_2_err_code(err) == GPG_ERR_NO_ERROR;
+}
+
+bool GpgFrontend::GpgKeyManager::revSign(
+ 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) {
+ using namespace boost::posix_time;
+
+ unsigned long expires_time = 0;
+
+ if (expires != nullptr) expires_time = to_time_t(ptime(*expires));
+
+ const char* sub_fprs = nullptr;
+
+ if (subkey != nullptr) sub_fprs = subkey->fpr().c_str();
+
+ auto err = check_gpg_error(
+ gpgme_op_setexpire(ctx, gpgme_key_t(key), expires_time, sub_fprs, 0));
+
+ return check_gpg_error_2_err_code(err) == GPG_ERR_NO_ERROR;
+}
diff --git a/src/gpg/function/GpgKeyManager.h b/src/gpg/function/GpgKeyManager.h
new file mode 100644
index 00000000..2b07425c
--- /dev/null
+++ b/src/gpg/function/GpgKeyManager.h
@@ -0,0 +1,58 @@
+/**
+ * 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_ZH_CN_TS_GPGKEYMANAGER_H
+#define GPGFRONTEND_ZH_CN_TS_GPGKEYMANAGER_H
+
+#include "gpg/GpgContext.h"
+#include "gpg/GpgFunctionObject.h"
+#include "gpg/GpgModel.h"
+
+namespace GpgFrontend {
+
+class GpgKeyManager : public SingletonFunctionObject<GpgKeyManager> {
+ public:
+ /**
+ * Sign a key pair(actually a certain uid)
+ * @param target target key pair
+ * @param uid target
+ * @param expires expire date and time of the signature
+ * @return if successful
+ */
+ bool signKey(const GpgKey& target, KeyArgsList& keys, const std::string& uid,
+ const std::unique_ptr<boost::gregorian::date>& expires);
+
+ 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);
+
+ private:
+ GpgContext& ctx = GpgContext::GetInstance();
+};
+
+} // namespace GpgFrontend
+
+#endif // GPGFRONTEND_ZH_CN_TS_GPGKEYMANAGER_H
diff --git a/src/gpg/function/GpgKeyOpera.cpp b/src/gpg/function/GpgKeyOpera.cpp
new file mode 100644
index 00000000..c60f9157
--- /dev/null
+++ b/src/gpg/function/GpgKeyOpera.cpp
@@ -0,0 +1,217 @@
+/**
+ * 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 "gpg/function/GpgKeyOpera.h"
+
+#include <boost/asio.hpp>
+#include <boost/date_time/posix_time/conversion.hpp>
+#include <boost/process/async_pipe.hpp>
+#include <memory>
+#include <string>
+#include <vector>
+
+#include "gpg/GpgConstants.h"
+#include "gpg/GpgGenKeyInfo.h"
+#include "gpg/function/GpgCommandExecutor.h"
+#include "gpg/function/GpgKeyGetter.h"
+
+/**
+ * Delete keys
+ * @param uidList key ids
+ */
+void GpgFrontend::GpgKeyOpera::DeleteKeys(
+ GpgFrontend::KeyIdArgsListPtr key_ids) {
+ GpgError err;
+ for (const auto& tmp : *key_ids) {
+ auto key = GpgKeyGetter::GetInstance().GetKey(tmp);
+ if (key.good()) {
+ LOG(INFO) << "GpgKeyOpera DeleteKeys Get Key Good";
+ err = check_gpg_error(gpgme_op_delete(ctx, gpgme_key_t(key), 1));
+ assert(gpg_err_code(err) == GPG_ERR_NO_ERROR);
+ } else
+ LOG(WARNING) << "GpgKeyOpera DeleteKeys Get Key Bad";
+ }
+}
+
+/**
+ * Set the expire date and time of a key pair(actually the master key) or subkey
+ * @param key target key pair
+ * @param subkey null if master key
+ * @param expires date and time
+ * @return if successful
+ */
+GpgFrontend::GpgError GpgFrontend::GpgKeyOpera::SetExpire(
+ const GpgKey& key, const SubkeyId& subkey_fpr,
+ std::unique_ptr<boost::gregorian::date>& expires) {
+ unsigned long expires_time = 0;
+ if (expires != nullptr) {
+ using namespace boost::posix_time;
+ using namespace std::chrono;
+ expires_time = to_time_t(ptime(*expires)) -
+ system_clock::to_time_t(system_clock::now());
+ }
+
+ LOG(INFO) << "GpgFrontend::GpgKeyOpera::SetExpire" << key.id() << subkey_fpr
+ << expires_time;
+
+ GpgError err;
+ if (subkey_fpr.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_fpr.c_str(), 0);
+
+ return err;
+}
+
+/**
+ * Generate revoke cert of a key pair
+ * @param key target key pair
+ * @param outputFileName out file name(path)
+ * @return the process doing this job
+ */
+void GpgFrontend::GpgKeyOpera::GenerateRevokeCert(
+ const GpgKey& key, const std::string& output_file_name) {
+ auto args = std::vector<std::string>{
+ "--no-tty", "--command-fd", "0", "--status-fd", "1", "-o",
+ output_file_name, "--gen-revoke", key.fpr()};
+
+ using boost::asio::async_write;
+ using boost::process::async_pipe;
+#ifndef WINDOWS
+ GpgCommandExecutor::GetInstance().Execute(
+ args, [](async_pipe& in, async_pipe& out) -> void {
+ // boost::asio::streambuf buff;
+ // boost::asio::read_until(in, buff, '\n');
+ //
+ // std::istream is(&buff);
+ //
+ // while (!is.eof()) {
+ // std::string line;
+ // is >> line;
+ // LOG(INFO) << "line" << line;
+ // boost::algorithm::trim(line);
+ // if (line == std::string("[GNUPG:] GET_BOOL
+ // gen_revoke.okay")) {
+ //
+ // } else if (line ==
+ // std::string(
+ // "[GNUPG:] GET_LINE
+ // ask_revocation_reason.code")) {
+ //
+ // } else if (line ==
+ // std::string(
+ // "[GNUPG:] GET_LINE
+ // ask_revocation_reason.text")) {
+ //
+ // } else if (line ==
+ // std::string("[GNUPG:] GET_BOOL
+ // openfile.overwrite.okay")) {
+ //
+ // } else if (line ==
+ // std::string(
+ // "[GNUPG:] GET_BOOL
+ // ask_revocation_reason.okay")) {
+ //
+ // }
+ // }
+ });
+#endif
+}
+
+/**
+ * Generate a new key pair
+ * @param params key generation args
+ * @return error information
+ */
+GpgFrontend::GpgError GpgFrontend::GpgKeyOpera::GenerateKey(
+ const std::unique_ptr<GenKeyInfo>& params) {
+ auto userid_utf8 = params->getUserid();
+ const char* userid = userid_utf8.c_str();
+ auto algo_utf8 = params->getAlgo() + params->getKeySizeStr();
+
+ LOG(INFO) << "GpgFrontend::GpgKeyOpera::GenerateKey Params"
+ << params->getAlgo() << params->getKeySizeStr();
+
+ const char* algo = algo_utf8.c_str();
+ unsigned long expires = 0;
+ {
+ using namespace boost::posix_time;
+ using namespace std::chrono;
+ expires = to_time_t(ptime(params->getExpired())) -
+ system_clock::to_time_t(system_clock::now());
+ }
+
+ unsigned int flags = 0;
+
+ if (!params->isSubKey()) flags |= GPGME_CREATE_CERT;
+ if (params->isAllowEncryption()) flags |= GPGME_CREATE_ENCR;
+ if (params->isAllowSigning()) flags |= GPGME_CREATE_SIGN;
+ if (params->isAllowAuthentication()) flags |= GPGME_CREATE_AUTH;
+ if (params->isNonExpired()) flags |= GPGME_CREATE_NOEXPIRE;
+ if (params->isNoPassPhrase()) flags |= GPGME_CREATE_NOPASSWD;
+
+ LOG(INFO) << "GpgFrontend::GpgKeyOpera::GenerateKey Args: " << userid << algo
+ << expires << flags;
+
+ auto err = gpgme_op_createkey(ctx, userid, algo, 0, expires, nullptr, flags);
+ return check_gpg_error(err);
+}
+
+/**
+ * Generate a new subkey of a certain key pair
+ * @param key target key pair
+ * @param params opera args
+ * @return error info
+ */
+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();
+ unsigned long expires = 0;
+ {
+ using namespace boost::posix_time;
+ using namespace std::chrono;
+ expires = to_time_t(ptime(params->getExpired())) -
+ system_clock::to_time_t(system_clock::now());
+ }
+ unsigned int flags = 0;
+
+ if (!params->isSubKey()) flags |= GPGME_CREATE_CERT;
+ if (params->isAllowEncryption()) flags |= GPGME_CREATE_ENCR;
+ if (params->isAllowSigning()) flags |= GPGME_CREATE_SIGN;
+ if (params->isAllowAuthentication()) flags |= GPGME_CREATE_AUTH;
+ if (params->isNonExpired()) flags |= GPGME_CREATE_NOEXPIRE;
+
+ flags |= GPGME_CREATE_NOPASSWD;
+
+ LOG(INFO) << "GpgFrontend::GpgKeyOpera::GenerateSubkey Args: " << key.id()
+ << algo << expires << flags;
+
+ auto err =
+ gpgme_op_createsubkey(ctx, gpgme_key_t(key), algo, 0, expires, flags);
+ return check_gpg_error(err);
+} \ No newline at end of file
diff --git a/src/gpg/function/GpgKeyOpera.h b/src/gpg/function/GpgKeyOpera.h
new file mode 100644
index 00000000..71e2de8b
--- /dev/null
+++ b/src/gpg/function/GpgKeyOpera.h
@@ -0,0 +1,54 @@
+/**
+ * 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 _GPGKEYOPERA_H
+#define _GPGKEYOPERA_H
+
+#include "gpg/GpgConstants.h"
+#include "gpg/GpgContext.h"
+#include "gpg/GpgModel.h"
+
+namespace GpgFrontend {
+class GenKeyInfo;
+class GpgKeyOpera : public SingletonFunctionObject<GpgKeyOpera> {
+ public:
+ void DeleteKeys(KeyIdArgsListPtr key_ids);
+
+ GpgError SetExpire(const GpgKey& key, const SubkeyId& subkey_fpr,
+ std::unique_ptr<boost::gregorian::date>& expires);
+
+ static void GenerateRevokeCert(const GpgKey& key,
+ const std::string& output_file_name);
+
+ GpgFrontend::GpgError GenerateKey(const std::unique_ptr<GenKeyInfo>& params);
+
+ GpgFrontend::GpgError GenerateSubkey(
+ const GpgKey& key, const std::unique_ptr<GenKeyInfo>& params);
+
+ private:
+ GpgContext& ctx = GpgContext::GetInstance();
+};
+} // namespace GpgFrontend
+
+#endif // _GPGKEYOPERA_H \ No newline at end of file
diff --git a/src/gpg/function/UidOperator.cpp b/src/gpg/function/UidOperator.cpp
new file mode 100644
index 00000000..d7acc3b1
--- /dev/null
+++ b/src/gpg/function/UidOperator.cpp
@@ -0,0 +1,64 @@
+/**
+ * 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 "gpg/function/UidOperator.h"
+
+#include "boost/format.hpp"
+
+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 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 std::string& uid) {
+ auto err = check_gpg_error(gpgme_op_set_uid_flag(
+ 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) {
+ LOG(INFO) << "GpgFrontend::UidOperator::addUID" << name << comment << 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
new file mode 100644
index 00000000..7d5df254
--- /dev/null
+++ b/src/gpg/function/UidOperator.h
@@ -0,0 +1,76 @@
+/**
+ * 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_ZH_CN_TS_UIDOPERATOR_H
+#define GPGFRONTEND_ZH_CN_TS_UIDOPERATOR_H
+
+#include "gpg/GpgContext.h"
+#include "gpg/GpgModel.h"
+
+namespace GpgFrontend {
+
+class UidOperator : public SingletonFunctionObject<UidOperator> {
+ public:
+ /**
+ * create a new uid in certain key pair
+ * @param key target key pair
+ * @param uid uid args(combine name&comment&email)
+ * @return if successful
+ */
+ 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
+ * @param key target key pair
+ * @param uid target uid
+ * @return if successful
+ */
+ bool revUID(const GpgKey& key, const std::string& uid);
+
+ /**
+ * Set one of a uid of a key pair as primary
+ * @param key target key pair
+ * @param uid target uid
+ * @return if successful
+ */
+ bool setPrimaryUID(const GpgKey& key, const std::string& uid);
+
+ private:
+ GpgContext& ctx = GpgContext::GetInstance();
+};
+
+} // namespace GpgFrontend
+
+#endif // GPGFRONTEND_ZH_CN_TS_UIDOPERATOR_H
diff --git a/src/gpg/gpg_context/GpgContext.cpp b/src/gpg/gpg_context/GpgContext.cpp
deleted file mode 100644
index 14b54b32..00000000
--- a/src/gpg/gpg_context/GpgContext.cpp
+++ /dev/null
@@ -1,410 +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 "gpg/GpgContext.h"
-#include "ui/WaitingDialog.h"
-
-#include <functional>
-#include <unistd.h> /* contains read/write */
-
-#ifdef _WIN32
-
-#include <windows.h>
-
-#endif
-
-#define INT2VOIDP(i) (void*)(uintptr_t)(i)
-
-namespace GpgME {
-
- /** Constructor
- * Set up gpgme-context, set paths to app-run path
- */
- GpgContext::GpgContext() {
-
- /** 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
-
- err = gpgme_new(&mCtx);
- checkErr(err);
-
- gpgme_engine_info_t engineInfo;
- engineInfo = gpgme_ctx_get_engine_info(mCtx);
-
-// Check ENV before running
- bool check_pass = false, find_openpgp = false, find_gpgconf = false, find_assuan = false, find_cms = false;
- while (engineInfo != nullptr) {
- qDebug() << gpgme_get_protocol_name(engineInfo->protocol) << engineInfo->file_name << engineInfo->protocol
- << engineInfo->home_dir << engineInfo->version;
- if (engineInfo->protocol == GPGME_PROTOCOL_GPGCONF && strcmp(engineInfo->version, "1.0.0") != 0)
- find_gpgconf = true;
- if (engineInfo->protocol == GPGME_PROTOCOL_OpenPGP && strcmp(engineInfo->version, "1.0.0") != 0)
- find_openpgp = true, info.appPath = engineInfo->file_name;
- if (engineInfo->protocol == GPGME_PROTOCOL_CMS && strcmp(engineInfo->version, "1.0.0") != 0)
- find_cms = true;
- if (engineInfo->protocol == GPGME_PROTOCOL_ASSUAN)
- find_assuan = true;
-
- engineInfo = engineInfo->next;
- }
-
- if (find_gpgconf && find_openpgp && find_cms && find_assuan)
- check_pass = true;
-
- if (!check_pass) {
- good = false;
- return;
- } else good = true;
-
-
-/** Setting the output type must be done at the beginning */
-/** think this means ascii-armor --> ? */
- gpgme_set_armor(mCtx, 1);
-/** passphrase-callback */
- gpgme_set_passphrase_cb(mCtx, passphraseCb, this);
-
-/** check if app is called with -d from command line */
- if (qApp->arguments().contains("-d")) {
- qDebug() << "gpgme_data_t debug on";
- debug = true;
- } else {
- debug = false;
- }
-
- connect(this, SIGNAL(signalKeyDBChanged()),
- this, SLOT(slotRefreshKeyList()), Qt::DirectConnection);
- connect(this, SIGNAL(signalKeyUpdated(QString)),
- this, SLOT(slotUpdateKeyList(QString)), Qt::DirectConnection);
- slotRefreshKeyList();
- }
-
- /** Destructor
- * Release gpgme-context
- */
- GpgContext::~GpgContext() {
- if (mCtx) gpgme_release(mCtx);
- mCtx = nullptr;
- }
-
- bool GpgContext::isGood() const {
- return good;
- }
-
- /** Read gpgme-Data to QByteArray
- * mainly from http://basket.kde.org/ (kgpgme.cpp)
- */
-#define BUF_SIZE (32 * 1024)
-
- gpgme_error_t GpgContext::readToBuffer(gpgme_data_t dataIn, QByteArray *outBuffer) {
- gpgme_off_t ret;
- gpgme_error_t gpgErrNoError = GPG_ERR_NO_ERROR;
-
- ret = gpgme_data_seek(dataIn, 0, SEEK_SET);
- if (ret) {
- gpgErrNoError = gpgme_err_code_from_errno(errno);
- checkErr(gpgErrNoError, "failed dataseek dataIn readToBuffer");
- } else {
- char buf[BUF_SIZE + 2];
-
- while ((ret = gpgme_data_read(dataIn, buf, BUF_SIZE)) > 0) {
- const size_t size = outBuffer->size();
- outBuffer->resize(static_cast<int>(size + ret));
- memcpy(outBuffer->data() + size, buf, ret);
- }
- if (ret < 0) {
- gpgErrNoError = gpgme_err_code_from_errno(errno);
- checkErr(gpgErrNoError, "failed data_read dataIn readToBuffer");
- }
- }
- return gpgErrNoError;
- }
-
- /**
- * The Passphrase window, if not provided by env-Var GPG_AGENT_INFO
- * originally copied from http://basket.kde.org/ (kgpgme.cpp), but modified
- */
- gpgme_error_t GpgContext::passphraseCb(void *hook, const char *uid_hint,
- const char *passphrase_info,
- int last_was_bad, int fd) {
- auto *gpg = static_cast<GpgContext *>(hook);
- return gpg->passphrase(uid_hint, passphrase_info, last_was_bad, fd);
- }
-
- gpgme_error_t GpgContext::passphrase(const char *uid_hint,
- const char * /*passphrase_info*/,
- int last_was_bad, int fd) {
-
- gpgme_error_t returnValue = GPG_ERR_CANCELED;
- QString passwordDialogMessage;
- QString gpgHint = QString::fromUtf8(uid_hint);
- bool result;
-
-#ifdef _WIN32
- DWORD written;
- auto hd = INT2VOIDP(fd);
-#endif
-
- if (last_was_bad) {
- passwordDialogMessage += "<i>" + tr("Wrong password") + ".</i><br><br>\n\n";
- clearPasswordCache();
- }
-
- /** if uid provided */
- if (!gpgHint.isEmpty()) {
- // remove UID, leave only username & email
- gpgHint.remove(0, gpgHint.indexOf(" "));
- passwordDialogMessage += "<b>" + tr("Enter Password for") + "</b><br>" + gpgHint + "<br>";
- }
-
- if (mPasswordCache.isEmpty()) {
- QString password = QInputDialog::getText(QApplication::activeWindow(), tr("Enter Password"),
- passwordDialogMessage, QLineEdit::Password,
- "", &result);
-
- if (result) mPasswordCache = password.toUtf8();
- } else result = true;
-
- if (result) {
-
-#ifndef _WIN32
- if (write(fd, mPasswordCache.data(), mPasswordCache.length()) == -1) qDebug() << "something is terribly broken";
-#else
- WriteFile(hd, mPasswordCache.data(), mPasswordCache.length(), &written, 0);
-#endif
- returnValue = GPG_ERR_NO_ERROR;
- }
-
-#ifndef _WIN32
- if (write(fd, "\n", 1) == -1) qDebug() << "something is terribly broken";
-#else
- WriteFile(hd, "\n", 1, &written, 0);
-
- /* program will hang on cancel if hd not closed */
- if (!result) CloseHandle(hd);
-#endif
-
- return returnValue;
- }
-
- /** also from kgpgme.cpp, seems to clear password from mem */
- void GpgContext::clearPasswordCache() {
- if (mPasswordCache.size() > 0) {
- mPasswordCache.fill('\0');
- mPasswordCache.truncate(0);
- }
- }
-
- // error-handling
- void GpgContext::checkErr(gpgme_error_t gpgmeError, const QString &comment) {
- //if (gpgmeError != GPG_ERR_NO_ERROR && gpgmeError != GPG_ERR_CANCELED) {
- if (gpgmeError != GPG_ERR_NO_ERROR) {
- qDebug() << "[Error " << gpg_err_code(gpgmeError)
- << "] Source: " << gpgme_strsource(gpgmeError) << " Description: " << gpgErrString(gpgmeError);
- }
- }
-
- void GpgContext::checkErr(gpgme_error_t gpgmeError) {
- //if (gpgmeError != GPG_ERR_NO_ERROR && gpgmeError != GPG_ERR_CANCELED) {
- if (gpg_err_code(gpgmeError) != GPG_ERR_NO_ERROR) {
- qDebug() << "[Error " << gpg_err_code(gpgmeError)
- << "] Source: " << gpgme_strsource(gpgmeError) << " Description: " << gpgErrString(gpgmeError);
- }
- }
-
- QString GpgContext::gpgErrString(gpgme_error_t err) {
- return QString::fromUtf8(gpgme_strerror(err));
- }
-
- /** return type should be gpgme_error_t*/
- void
- GpgContext::executeGpgCommand(const QStringList &arguments, const std::function<void(QProcess *)> &interactFunc) {
- QEventLoop looper;
- auto dialog = new WaitingDialog(tr("Processing"), nullptr);
- dialog->show();
- auto *gpgProcess = new QProcess(&looper);
- gpgProcess->setProcessChannelMode(QProcess::MergedChannels);
- connect(gpgProcess, qOverload<int, QProcess::ExitStatus>(&QProcess::finished), &looper, &QEventLoop::quit);
- connect(gpgProcess, qOverload<int, QProcess::ExitStatus>(&QProcess::finished), dialog,
- &WaitingDialog::deleteLater);
- connect(gpgProcess, &QProcess::errorOccurred, []() -> void { qDebug("Error in Process"); });
- connect(gpgProcess, &QProcess::errorOccurred, &looper, &QEventLoop::quit);
- connect(gpgProcess, &QProcess::started, []() -> void { qDebug() << "Gpg Process Started Success"; });
- connect(gpgProcess, &QProcess::readyReadStandardOutput, [interactFunc, gpgProcess]() {
- qDebug() << "Function Called";
- interactFunc(gpgProcess);
- });
- gpgProcess->setProgram(info.appPath);
- gpgProcess->setArguments(arguments);
- gpgProcess->start();
- looper.exec();
- dialog->close();
-
- }
-
-
- /*
- * if there is no '\n' before the PGP-Begin-Block, but for example a whitespace,
- * GPGME doesn't recognise the Message as encrypted. This function adds '\n'
- * before the PGP-Begin-Block, if missing.
- */
- void GpgContext::preventNoDataErr(QByteArray *in) {
- int block_start = in->indexOf(GpgConstants::PGP_CRYPT_BEGIN);
- if (block_start > 0 && in->at(block_start - 1) != '\n') {
- in->insert(block_start, '\n');
- }
- block_start = in->indexOf(GpgConstants::PGP_SIGNED_BEGIN);
- if (block_start > 0 && in->at(block_start - 1) != '\n') {
- in->insert(block_start, '\n');
- }
- }
-
- /*
- * isSigned returns:
- * - 0, if text isn't signed at all
- * - 1, if text is partially signed
- * - 2, if text is completly signed
- */
- int GpgContext::textIsSigned(const QByteArray &text) {
- if (text.trimmed().startsWith(GpgConstants::PGP_SIGNED_BEGIN) &&
- text.trimmed().endsWith(GpgConstants::PGP_SIGNED_END))
- return 2;
- else if (text.contains(GpgConstants::PGP_SIGNED_BEGIN) && text.contains(GpgConstants::PGP_SIGNED_END))
- return 1;
-
- else return 0;
- }
-
- QString GpgContext::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;
- }
-
- void GpgContext::slotRefreshKeyList() {
- qDebug() << "Refreshing Keys";
- this->fetch_keys();
- emit signalKeyInfoChanged();
- }
-
- QString GpgContext::getGpgmeVersion() {
- return {gpgme_check_version(nullptr)};
- }
-
- const GpgKeyList &GpgContext::getKeys() const {
- return mKeyList;
- }
-
- void GpgContext::getSigners(QVector<GpgKey> &signer, gpgme_ctx_t ctx) {
- auto count = gpgme_signers_count(ctx);
- signer.clear();
- for (auto i = 0; i < count; i++) {
- auto key = gpgme_signers_enum(ctx, i);
- auto it = mKeyMap.find(key->subkeys->keyid);
- if (it == mKeyMap.end()) {
- qDebug() << "Inconsistent state";
- signer.push_back(GpgKey(key));
- } else {
- signer.push_back(*it.value());
- }
- }
- }
-
- void GpgContext::setSigners(const QVector<GpgKey> &keys, gpgme_ctx_t ctx) {
- gpgme_signers_clear(ctx);
- for (const auto &key : keys) {
- if (checkIfKeyCanSign(key)) {
- auto gpgmeError = gpgme_signers_add(ctx, key.key_refer);
- checkErr(gpgmeError);
- }
- }
- if (keys.length() != gpgme_signers_count(ctx)) {
- qDebug() << "No All Keys Added";
- }
- }
-
- void GpgContext::slotUpdateKeyList(const QString &key_id) {
- auto it = mKeyMap.find(key_id);
- if (it != mKeyMap.end()) {
- gpgme_key_t new_key_refer;
- auto gpgmeErr = gpgme_get_key(mCtx, key_id.toUtf8().constData(), &new_key_refer, 0);
-
- if (gpgme_err_code(gpgmeErr) == GPG_ERR_EOF) {
- gpgmeErr = gpgme_get_key(mCtx, key_id.toUtf8().constData(), &new_key_refer, 1);
-
- if (gpgme_err_code(gpgmeErr) == GPG_ERR_EOF) {
- throw std::runtime_error("key_id not found in key database");
- }
-
- }
-
- if (new_key_refer != nullptr) {
- it.value()->swapKeyRefer(new_key_refer);
- emit signalKeyInfoChanged();
- }
-
- }
- }
-
- bool GpgContext::revSign(const GpgKey &key, const GpgKeySignature &signature) {
-
- auto signing_key = getKeyById(signature.keyid);
-
- auto gpgmeError = gpgme_op_revsig(mCtx, key.key_refer,
- signing_key.key_refer,
- signature.uid.toUtf8().constData(), 0);
- if (gpg_err_code(gpgmeError) == GPG_ERR_NO_ERROR) {
- emit signalKeyUpdated(key.id);
- return true;
- } else {
- checkErr(gpgmeError);
- return false;
- }
- }
-
- gpgme_ctx_t GpgME::GpgContext::create_ctx() {
- gpgme_ctx_t ctx;
- err = gpgme_new(&ctx);
- checkErr(err);
-
- gpgme_set_armor(ctx, 1);
- gpgme_set_passphrase_cb(ctx, passphraseCb, this);
- return ctx;
- }
-
-
-}
diff --git a/src/gpg/gpg_context/GpgContextBasicOpera.cpp b/src/gpg/gpg_context/GpgContextBasicOpera.cpp
deleted file mode 100644
index d9bf0bdb..00000000
--- a/src/gpg/gpg_context/GpgContextBasicOpera.cpp
+++ /dev/null
@@ -1,315 +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 "gpg/GpgContext.h"
-
-/**
- * Encrypt data
- * @param keys keys used
- * @param inBuffer input byte array
- * @param outBuffer output byte array
- * @param result opera result
- * @return error information
- */
-gpg_error_t GpgME::GpgContext::encrypt(QVector<GpgKey> &keys, const QByteArray &inBuffer, QByteArray *outBuffer,
- gpgme_encrypt_result_t *result) {
-
- gpgme_data_t dataIn = nullptr, dataOut = nullptr;
- outBuffer->resize(0);
-
- // gpgme_encrypt_result_t e_result;
- gpgme_key_t recipients[keys.count() + 1];
-
- int index = 0;
- for (const auto &key : keys) recipients[index++] = key.key_refer;
-
- // Last entry dataIn array has to be nullptr
- recipients[keys.count()] = nullptr;
-
- // If the last parameter isnt 0, a private copy of data is made
- if (mCtx) {
- err = gpgme_data_new_from_mem(&dataIn, inBuffer.data(), inBuffer.size(), 1);
- checkErr(err);
- if (!err) {
- err = gpgme_data_new(&dataOut);
- checkErr(err);
- if (!err) {
- err = gpgme_op_encrypt(mCtx, recipients, GPGME_ENCRYPT_ALWAYS_TRUST, dataIn, dataOut);
- checkErr(err);
- if (!err) {
- err = readToBuffer(dataOut, outBuffer);
- checkErr(err);
- }
- }
- }
- }
- if (dataIn) gpgme_data_release(dataIn);
- if (dataOut) gpgme_data_release(dataOut);
-
- if (result != nullptr) *result = gpgme_op_encrypt_result(mCtx);
- return err;
-}
-
-/**
- * Decrypt data
- * @param keys keys used
- * @param inBuffer input byte array
- * @param outBuffer output byte array
- * @param result opera result
- * @return error information
- */
-gpgme_error_t GpgME::GpgContext::decrypt(const QByteArray &inBuffer, QByteArray *outBuffer,
- gpgme_decrypt_result_t *result) {
- gpgme_data_t dataIn = nullptr, dataOut = nullptr;
- gpgme_decrypt_result_t m_result = nullptr;
-
- outBuffer->resize(0);
- if (mCtx != nullptr) {
- err = gpgme_data_new_from_mem(&dataIn, inBuffer.data(), inBuffer.size(), 1);
- if (gpgme_err_code(err) == GPG_ERR_NO_ERROR) {
- err = gpgme_data_new(&dataOut);
- if (gpgme_err_code(err) == GPG_ERR_NO_ERROR) {
- err = gpgme_op_decrypt(mCtx, dataIn, dataOut);
- m_result = gpgme_op_decrypt_result(mCtx);
- if (gpgme_err_code(err) == GPG_ERR_NO_ERROR) err = readToBuffer(dataOut, outBuffer);
- }
- }
- }
-
- if (!settings.value("general/rememberPassword").toBool()) clearPasswordCache();
-
- if (dataIn) gpgme_data_release(dataIn);
- if (dataOut) gpgme_data_release(dataOut);
-
- if (result != nullptr) *result = m_result;
-
- return err;
-}
-
-/**
- * Verify data
- * @param keys keys used
- * @param inBuffer input byte array
- * @param sigBuffer signature byte array (detected by format)
- * @param result opera result
- * @return error information
- */
-gpgme_error_t GpgME::GpgContext::verify(QByteArray *inBuffer, QByteArray *sigBuffer, gpgme_verify_result_t *result) {
-
- gpgme_data_t dataIn;
- gpgme_error_t gpgmeError;
- gpgme_verify_result_t m_result;
-
- gpgmeError = gpgme_data_new_from_mem(&dataIn, inBuffer->data(), inBuffer->size(), 1);
- checkErr(gpgmeError);
-
- if (sigBuffer != nullptr) {
- gpgme_data_t sigdata;
- gpgmeError = gpgme_data_new_from_mem(&sigdata, sigBuffer->data(), sigBuffer->size(), 1);
- checkErr(gpgmeError);
- gpgmeError = gpgme_op_verify(mCtx, sigdata, dataIn, nullptr);
- } else {
- gpgmeError = gpgme_op_verify(mCtx, dataIn, nullptr, dataIn);
- }
-
- checkErr(gpgmeError);
-
- m_result = gpgme_op_verify_result(mCtx);
-
- if (result != nullptr) {
- *result = m_result;
- }
-
- return gpgmeError;
-}
-
-/**
- * Sign data
- * @param keys keys used
- * @param inBuffer input byte array
- * @param outBuffer output byte array
- * @param mode sign mode
- * @param result opera result
- * @return
- */
-gpg_error_t GpgME::GpgContext::sign(const QVector<GpgKey> &keys, const QByteArray &inBuffer, QByteArray *outBuffer,
- gpgme_sig_mode_t mode, gpgme_sign_result_t *result, bool default_ctx) {
-
- gpgme_error_t gpgmeError;
- gpgme_data_t dataIn, dataOut;
- gpgme_sign_result_t m_result;
-
- auto _ctx = mCtx;
-
- if(!default_ctx)
- _ctx = create_ctx();
-
- if (keys.isEmpty()) {
- QMessageBox::critical(nullptr, tr("Key Selection"), tr("No Private Key Selected"));
- return false;
- }
-
- // Set Singers of this opera
- setSigners(keys, _ctx);
-
- gpgmeError = gpgme_data_new_from_mem(&dataIn, inBuffer.data(), inBuffer.size(), 1);
- checkErr(gpgmeError);
- gpgmeError = gpgme_data_new(&dataOut);
- checkErr(gpgmeError);
-
- /**
- `GPGME_SIG_MODE_NORMAL'
- A normal signature is made, the output includes the plaintext
- and the signature.
-
- `GPGME_SIG_MODE_DETACH'
- A detached signature is made.
-
- `GPGME_SIG_MODE_CLEAR'
- A clear text signature is made. The ASCII armor and text
- mode settings of the context are ignored.
- */
-
- gpgmeError = gpgme_op_sign(_ctx, dataIn, dataOut, mode);
- checkErr(gpgmeError);
-
- if (gpgmeError == GPG_ERR_CANCELED) return false;
-
- if (gpgmeError != GPG_ERR_NO_ERROR) {
- QMessageBox::critical(nullptr, tr("Error in signing:"), QString::fromUtf8(gpgme_strerror(gpgmeError)));
- return false;
- }
-
- if(default_ctx)
- m_result = gpgme_op_sign_result(_ctx);
- else m_result = nullptr;
-
- if (result != nullptr) *result = m_result;
-
- if(!default_ctx) gpgme_release(_ctx);
-
- gpgmeError = readToBuffer(dataOut, outBuffer);
- checkErr(gpgmeError);
-
- gpgme_data_release(dataIn);
- gpgme_data_release(dataOut);
-
- // Of no use yet
- if (!settings.value("general/rememberPassword").toBool()) clearPasswordCache();
-
- return gpgmeError;
-}
-
-/**
- * Encrypt and sign data
- * @param keys keys used
- * @param inBuffer input byte array
- * @param outBuffer output byte array
- * @param encr_result encrypt opera result
- * @param sign_result sign opera result
- * @return
- */
-gpgme_error_t
-GpgME::GpgContext::encryptSign(QVector<GpgKey> &keys, QVector<GpgKey> &signers, const QByteArray &inBuffer,
- QByteArray *outBuffer, gpgme_encrypt_result_t *encr_result,
- gpgme_sign_result_t *sign_result) {
- gpgme_data_t data_in = nullptr, data_out = nullptr;
- outBuffer->resize(0);
-
- setSigners(signers, mCtx);
-
- //gpgme_encrypt_result_t e_result;
- gpgme_key_t recipients[keys.count() + 1];
-
- // set key for user
- int index = 0;
- for (const auto &key : keys) recipients[index++] = key.key_refer;
-
- // Last entry dataIn array has to be nullptr
- recipients[keys.count()] = nullptr;
-
- // If the last parameter isnt 0, a private copy of data is made
- if (mCtx != nullptr) {
- err = gpgme_data_new_from_mem(&data_in, inBuffer.data(), inBuffer.size(), 1);
- if (gpg_err_code(err) == GPG_ERR_NO_ERROR) {
- err = gpgme_data_new(&data_out);
- if (gpg_err_code(err) == GPG_ERR_NO_ERROR) {
- err = gpgme_op_encrypt_sign(mCtx, recipients, GPGME_ENCRYPT_ALWAYS_TRUST, data_in, data_out);
- if (encr_result != nullptr)
- *encr_result = gpgme_op_encrypt_result(mCtx);
- if (sign_result != nullptr)
- *sign_result = gpgme_op_sign_result(mCtx);
- if (gpg_err_code(err) == GPG_ERR_NO_ERROR) {
- err = readToBuffer(data_out, outBuffer);
- }
- }
- }
- }
-
- if (gpgme_err_code(err) != GPG_ERR_NO_ERROR) checkErr(err);
-
- if (data_in) gpgme_data_release(data_in);
- if (data_out) gpgme_data_release(data_out);
-
- return err;
-}
-
-/**
- * Decrypt and verify data
- * @param inBuffer input byte array
- * @param outBuffer output byte array
- * @param decrypt_result decrypt opera result
- * @param verify_result verify opera result
- * @return error info
- */
-gpgme_error_t GpgME::GpgContext::decryptVerify(const QByteArray &inBuffer, QByteArray *outBuffer,
- gpgme_decrypt_result_t *decrypt_result,
- gpgme_verify_result_t *verify_result) {
- gpgme_data_t data_in = nullptr, data_out = nullptr;
-
- outBuffer->resize(0);
- if (mCtx != nullptr) {
- err = gpgme_data_new_from_mem(&data_in, inBuffer.data(), inBuffer.size(), 1);
- if (gpgme_err_code(err) == GPG_ERR_NO_ERROR) {
- err = gpgme_data_new(&data_out);
- if (gpgme_err_code(err) == GPG_ERR_NO_ERROR) {
- err = gpgme_op_decrypt_verify(mCtx, data_in, data_out);
- if (decrypt_result != nullptr)
- *decrypt_result = gpgme_op_decrypt_result(mCtx);
- if (verify_result != nullptr)
- *verify_result = gpgme_op_verify_result(mCtx);
- if (gpgme_err_code(err) == GPG_ERR_NO_ERROR) {
- err = readToBuffer(data_out, outBuffer);
- }
- }
- }
- }
-
- if (!settings.value("general/rememberPassword").toBool()) clearPasswordCache();
-
- if (data_in) gpgme_data_release(data_in);
- if (data_out) gpgme_data_release(data_out);
-
- return err;
-}
diff --git a/src/gpg/gpg_context/GpgContextKeyInfo.cpp b/src/gpg/gpg_context/GpgContextKeyInfo.cpp
deleted file mode 100644
index f6942e4e..00000000
--- a/src/gpg/gpg_context/GpgContextKeyInfo.cpp
+++ /dev/null
@@ -1,110 +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 "gpg/GpgContext.h"
-
-/**
- * check if key can sign(actually)
- * @param key target key
- * @return if key sign
- */
-bool GpgME::GpgContext::checkIfKeyCanSign(const GpgKey &key) {
- if (std::any_of(key.subKeys.begin(), key.subKeys.end(), [](const GpgSubKey &subkey) -> bool {
- return subkey.secret && subkey.can_sign && !subkey.disabled && !subkey.revoked && !subkey.expired;
- }))
- return true;
- else return false;
-}
-
-/**
- * check if key can certify(actually)
- * @param key target key
- * @return if key certify
- */
-bool GpgME::GpgContext::checkIfKeyCanCert(const GpgKey &key) {
- return key.has_master_key && !key.expired && !key.revoked && !key.disabled;
-}
-
-/**
- * check if key can authenticate(actually)
- * @param key target key
- * @return if key authenticate
- */
-bool GpgME::GpgContext::checkIfKeyCanAuth(const GpgKey &key) {
- if (std::any_of(key.subKeys.begin(), key.subKeys.end(), [](const GpgSubKey &subkey) -> bool {
- return subkey.secret && subkey.can_authenticate && !subkey.disabled && !subkey.revoked && !subkey.expired;
- }))
- return true;
- else return false;
-}
-
-/**
- * check if key can encrypt(actually)
- * @param key target key
- * @return if key encrypt
- */
-bool GpgME::GpgContext::checkIfKeyCanEncr(const GpgKey &key) {
- if (std::any_of(key.subKeys.begin(), key.subKeys.end(), [](const GpgSubKey &subkey) -> bool {
- return subkey.can_encrypt && !subkey.disabled && !subkey.revoked && !subkey.expired;
- }))
- return true;
- else return false;
-}
-
-/**
- * Get target key
- * @param fpr master key's fingerprint
- * @return the key
- */
-GpgKey GpgME::GpgContext::getKeyByFpr(const QString &fpr) {
- for (const auto &key : mKeyList) {
- if (key.fpr == fpr) return key;
- else
- for (auto &subkey : key.subKeys) {
- if (subkey.fpr == fpr) return key;
- }
- }
- return GpgKey(nullptr);
-}
-
-
-/**
- * Get target key
- * @param id master key's id
- * @return the key
- */
-GpgKey GpgME::GpgContext::getKeyById(const QString &id) {
-
- for (const auto &key : mKeyList) {
- if (key.id == id) return key;
- else {
- auto sub_keys = key.subKeys;
- for (const auto &subkey : sub_keys) {
- if (subkey.id == id) return key;
- }
- }
- }
-
- return GpgKey(nullptr);
-}
diff --git a/src/gpg/gpg_context/GpgContextKeyOpera.cpp b/src/gpg/gpg_context/GpgContextKeyOpera.cpp
deleted file mode 100644
index a224231d..00000000
--- a/src/gpg/gpg_context/GpgContextKeyOpera.cpp
+++ /dev/null
@@ -1,410 +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 "gpg/GpgContext.h"
-
-/**
- * Import key pair
- * @param inBuffer input byte array
- * @return Import information
- */
-GpgImportInformation GpgME::GpgContext::importKey(QByteArray inBuffer) {
- auto *importInformation = new GpgImportInformation();
- err = gpgme_data_new_from_mem(&in, inBuffer.data(), inBuffer.size(), 1);
- checkErr(err);
- err = gpgme_op_import(mCtx, in);
- gpgme_import_result_t result;
-
- result = gpgme_op_import_result(mCtx);
-
- if (result->unchanged) importInformation->unchanged = result->unchanged;
- if (result->considered) importInformation->considered = result->considered;
- if (result->no_user_id) importInformation->no_user_id = result->no_user_id;
- if (result->imported) importInformation->imported = result->imported;
- if (result->imported_rsa) importInformation->imported_rsa = result->imported_rsa;
- if (result->unchanged) importInformation->unchanged = result->unchanged;
- if (result->new_user_ids) importInformation->new_user_ids = result->new_user_ids;
- if (result->new_sub_keys) importInformation->new_sub_keys = result->new_sub_keys;
- if (result->new_signatures) importInformation->new_signatures = result->new_signatures;
- if (result->new_revocations) importInformation->new_revocations = result->new_revocations;
- if (result->secret_read) importInformation->secret_read = result->secret_read;
- if (result->secret_imported) importInformation->secret_imported = result->secret_imported;
- if (result->secret_unchanged) importInformation->secret_unchanged = result->secret_unchanged;
- if (result->not_imported) importInformation->not_imported = result->not_imported;
-
- gpgme_import_status_t status = result->imports;
- while (status != nullptr) {
- GpgImportedKey key;
- key.importStatus = static_cast<int>(status->status);
- key.fpr = status->fpr;
- importInformation->importedKeys.emplace_back(key);
- status = status->next;
- }
- checkErr(err);
- emit signalKeyDBChanged();
- gpgme_data_release(in);
- return *importInformation;
-}
-
-/**
- * Generate a new key pair
- * @param params key generation args
- * @return error information
- */
-gpgme_error_t GpgME::GpgContext::generateKey(GenKeyInfo *params) {
-
- auto userid_utf8 = params->getUserid().toUtf8();
- const char *userid = userid_utf8.constData();
- auto algo_utf8 = (params->getAlgo() + params->getKeySizeStr()).toUtf8();
- const char *algo = algo_utf8.constData();
- unsigned long expires = QDateTime::currentDateTime().secsTo(params->getExpired());
- unsigned int flags = 0;
-
- if (!params->isSubKey()) flags |= GPGME_CREATE_CERT;
- if (params->isAllowEncryption()) flags |= GPGME_CREATE_ENCR;
- if (params->isAllowSigning()) flags |= GPGME_CREATE_SIGN;
- if (params->isAllowAuthentication()) flags |= GPGME_CREATE_AUTH;
- if (params->isNonExpired()) flags |= GPGME_CREATE_NOEXPIRE;
- if (params->isNoPassPhrase()) flags |= GPGME_CREATE_NOPASSWD;
-
- err = gpgme_op_createkey(mCtx, userid, algo, 0, expires, nullptr, flags);
-
- if (gpgme_err_code(err) != GPG_ERR_NO_ERROR) {
- checkErr(err);
- return err;
- } else {
- emit signalKeyDBChanged();
- return err;
- }
-}
-
-/**
- * Export Key
- * @param uidList key ids
- * @param outBuffer output byte array
- * @return if success
- */
-bool GpgME::GpgContext::exportKeys(QStringList *uidList, QByteArray *outBuffer) {
- gpgme_data_t dataOut = nullptr;
- outBuffer->resize(0);
-
- if (uidList->count() == 0) {
- QMessageBox::critical(nullptr, "Export Keys Error", "No Keys Selected");
- return false;
- }
-
- // Alleviate another crash problem caused by an unknown array out-of-bounds access
- gpgme_ctx_t ctx = create_ctx();
-
- for (int i = 0; i < uidList->count(); i++) {
- err = gpgme_data_new(&dataOut);
- checkErr(err);
-
- err = gpgme_op_export(ctx, uidList->at(i).toUtf8().constData(), 0, dataOut);
- checkErr(err);
-
- qDebug() << "exportKeys read_bytes" << gpgme_data_seek(dataOut, 0, SEEK_END);
-
- err = readToBuffer(dataOut, outBuffer);
- checkErr(err);
- gpgme_data_release(dataOut);
- }
-
- gpgme_release(ctx);
-
- return true;
-}
-
-/**
- * Get and store all key pairs info
- */
-void GpgME::GpgContext::fetch_keys() {
-
- gpgme_error_t gpgmeError;
-
- gpgme_key_t key;
-
- qDebug() << "Clear List and Map";
-
- mKeyList.clear();
- mKeyMap.clear();
-
- auto &keys = mKeyList;
- auto &keys_map = mKeyMap;
-
- qDebug() << "Set Key Listing Mode";
-
- gpgmeError = gpgme_set_keylist_mode(mCtx,
- GPGME_KEYLIST_MODE_LOCAL
- | GPGME_KEYLIST_MODE_WITH_SECRET
- | GPGME_KEYLIST_MODE_SIGS
- | GPGME_KEYLIST_MODE_SIG_NOTATIONS
- | GPGME_KEYLIST_MODE_WITH_TOFU);
- if (gpg_err_code(gpgmeError) != GPG_ERR_NO_ERROR) {
- checkErr(gpgmeError);
- return;
- }
-
- qDebug() << "Operate KeyList Start";
-
- gpgmeError = gpgme_op_keylist_start(mCtx, nullptr, 0);
- if (gpg_err_code(gpgmeError) != GPG_ERR_NO_ERROR) {
- checkErr(gpgmeError);
- return;
- }
-
- qDebug() << "Start Loop";
-
- while ((gpgmeError = gpgme_op_keylist_next(mCtx, &key)) == GPG_ERR_NO_ERROR) {
- if (!key->subkeys)
- continue;
-
- qDebug() << "Append Key" << key->subkeys->keyid;
-
- keys.emplace_back(key);
- keys_map.insert(keys.back().id, &keys.back());
- gpgme_key_unref(key);
- }
-
-
- if (gpg_err_code(gpgmeError) != GPG_ERR_EOF) {
- checkErr(gpgmeError);
- return;
- }
-
- gpgmeError = gpgme_op_keylist_end(mCtx);
- if (gpg_err_code(gpgmeError) != GPG_ERR_NO_ERROR) {
- checkErr(gpgmeError);
- return;
- }
-
- qDebug() << "Operate KeyList End";
-
- mKeyList = keys;
-}
-
-/**
- * Delete keys
- * @param uidList key ids
- */
-void GpgME::GpgContext::deleteKeys(QStringList *uidList) {
-
- gpgme_error_t error;
- gpgme_key_t key;
-
- for (const auto &tmp : *uidList) {
-
- error = gpgme_op_keylist_start(mCtx, tmp.toUtf8().constData(), 0);
- if (error != GPG_ERR_NO_ERROR) {
- checkErr(error);
- continue;
- }
-
- error = gpgme_op_keylist_next(mCtx, &key);
- if (error != GPG_ERR_NO_ERROR) {
- checkErr(error);
- continue;
- }
-
- error = gpgme_op_keylist_end(mCtx);
- if (error != GPG_ERR_NO_ERROR) {
- checkErr(error);
- continue;
- }
-
- error = gpgme_op_delete(mCtx, key, 1);
- if (error != GPG_ERR_NO_ERROR) {
- checkErr(error);
- continue;
- }
-
- }
- emit signalKeyDBChanged();
-}
-
-/**
- * Export keys
- * @param keys keys used
- * @param outBuffer output byte array
- * @return if success
- */
-bool GpgME::GpgContext::exportKeys(const QVector<GpgKey> &keys, QByteArray &outBuffer) {
- gpgme_data_t data_out = nullptr;
- outBuffer.resize(0);
-
- if (keys.empty()) {
- QMessageBox::critical(nullptr, "Export Keys Error", "No Keys Selected");
- return false;
- }
-
- for (const auto &key : keys) {
- err = gpgme_data_new(&data_out);
- checkErr(err);
-
- err = gpgme_op_export(mCtx, key.id.toUtf8().constData(), 0, data_out);
- checkErr(err);
-
- gpgme_data_seek(data_out, 0, SEEK_END);
-
- err = readToBuffer(data_out, &outBuffer);
- checkErr(err);
- gpgme_data_release(data_out);
- }
-
- return true;
-}
-
-/**
- * Set the expire date and time of a key pair(actually the master key) or subkey
- * @param key target key pair
- * @param subkey null if master key
- * @param expires date and time
- * @return if successful
- */
-bool GpgME::GpgContext::setExpire(const GpgKey &key, const GpgSubKey *subkey, QDateTime *expires) {
- unsigned long expires_time = 0;
- if (expires != nullptr) {
- qDebug() << "Expire Datetime" << expires->toString();
- expires_time = QDateTime::currentDateTime().secsTo(*expires);
- }
-
- const char *subfprs = nullptr;
-
- if (subkey != nullptr) subfprs = subkey->fpr.toUtf8().constData();
-
- auto gpgmeError = gpgme_op_setexpire(mCtx, key.key_refer,
- expires_time, subfprs, 0);
- if (gpgmeError == GPG_ERR_NO_ERROR) {
- emit signalKeyUpdated(key.id);
- return true;
- } else {
- checkErr(gpgmeError);
- return false;
- }
-}
-
-/**
- * Export the secret key of a key pair(including subkeys)
- * @param key target key pair
- * @param outBuffer output byte array
- * @return if successful
- */
-bool GpgME::GpgContext::exportSecretKey(const GpgKey &key, QByteArray *outBuffer) {
- qDebug() << "Export Secret Key" << key.id;
- gpgme_key_t target_key[2] = {
- key.key_refer,
- nullptr
- };
-
- gpgme_data_t dataOut;
- gpgme_data_new(&dataOut);
-
- // export private key to outBuffer
- gpgme_error_t error = gpgme_op_export_keys(mCtx, target_key, GPGME_EXPORT_MODE_SECRET, dataOut);
-
- if (gpgme_err_code(error) != GPG_ERR_NO_ERROR) {
- checkErr(error);
- gpgme_data_release(dataOut);
- return false;
- }
-
- readToBuffer(dataOut, outBuffer);
- gpgme_data_release(dataOut);
- return true;
-}
-
-/**
- * Sign a key pair(actually a certain uid)
- * @param target target key pair
- * @param uid target
- * @param expires expire date and time of the signature
- * @return if successful
- */
-bool GpgME::GpgContext::signKey(const GpgKey &target, const QVector<GpgKey> &keys, const QString &uid,
- const QDateTime *expires) {
-
- setSigners(keys, mCtx);
-
- unsigned int flags = 0;
-
- unsigned int expires_time_t = 0;
- if (expires == nullptr) flags |= GPGME_KEYSIGN_NOEXPIRE;
- else expires_time_t = QDateTime::currentDateTime().secsTo(*expires);
-
- auto gpgmeError =
- gpgme_op_keysign(mCtx, target.key_refer, uid.toUtf8().constData(), expires_time_t, flags);
-
- if (gpgmeError == GPG_ERR_NO_ERROR) {
- emit signalKeyUpdated(target.id);
- return true;
- } else {
- checkErr(gpgmeError);
- return false;
- }
-}
-
-/**
- * Generate revoke cert of a key pair
- * @param key target key pair
- * @param outputFileName out file name(path)
- * @return the process doing this job
- */
-void GpgME::GpgContext::generateRevokeCert(const GpgKey &key, const QString &outputFileName) {
- executeGpgCommand({
- "--command-fd",
- "0",
- "--status-fd",
- "1",
- //"--no-tty",
- "-o",
- outputFileName,
- "--gen-revoke",
- key.fpr
- },
- [](QProcess *proc) -> void {
- qDebug() << "Function Called" << proc;
- // Code From Gpg4Win
- while (proc->canReadLine()) {
- const QString line = QString::fromUtf8(proc->readLine()).trimmed();
- if (line == QLatin1String("[GNUPG:] GET_BOOL gen_revoke.okay")) {
- proc->write("y\n");
- } else if (line == QLatin1String(
- "[GNUPG:] GET_LINE ask_revocation_reason.code")) {
- proc->write("0\n");
- } else if (line == QLatin1String(
- "[GNUPG:] GET_LINE ask_revocation_reason.text")) {
- proc->write("\n");
- } else if (line == QLatin1String(
- "[GNUPG:] GET_BOOL openfile.overwrite.okay")) {
- // We asked before
- proc->write("y\n");
- } else if (line == QLatin1String(
- "[GNUPG:] GET_BOOL ask_revocation_reason.okay")) {
- proc->write("y\n");
- }
- }
- // Code From Gpg4Win
- }
- );
-}
diff --git a/src/gpg/gpg_context/GpgContextSubkeyOpera.cpp b/src/gpg/gpg_context/GpgContextSubkeyOpera.cpp
deleted file mode 100644
index 10243f5e..00000000
--- a/src/gpg/gpg_context/GpgContextSubkeyOpera.cpp
+++ /dev/null
@@ -1,61 +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 "gpg/GpgContext.h"
-
-/**
- * Generate a new subkey of a certain key pair
- * @param key target key pair
- * @param params opera args
- * @return error info
- */
-gpgme_error_t GpgME::GpgContext::generateSubkey(const GpgKey &key, GenKeyInfo *params) {
-
- if (!params->isSubKey()) return GPG_ERR_CANCELED;
-
- auto algo_utf8 = (params->getAlgo() + params->getKeySizeStr()).toUtf8();
- const char *algo = algo_utf8.constData();
- unsigned long expires = QDateTime::currentDateTime().secsTo(params->getExpired());
- unsigned int flags = 0;
-
- if (!params->isSubKey()) flags |= GPGME_CREATE_CERT;
- if (params->isAllowEncryption()) flags |= GPGME_CREATE_ENCR;
- if (params->isAllowSigning()) flags |= GPGME_CREATE_SIGN;
- if (params->isAllowAuthentication()) flags |= GPGME_CREATE_AUTH;
- if (params->isNonExpired()) flags |= GPGME_CREATE_NOEXPIRE;
-
- flags |= GPGME_CREATE_NOPASSWD;
-
-
- auto gpgmeError = gpgme_op_createsubkey(mCtx, key.key_refer,
- algo, 0, expires, flags);
- if (gpgme_err_code(gpgmeError) == GPG_ERR_NO_ERROR) {
- emit signalKeyUpdated(key.id);
- return gpgmeError;
- } else {
- checkErr(gpgmeError);
- return gpgmeError;
- }
-}
-
diff --git a/src/gpg/gpg_context/GpgContextUIDOpera.cpp b/src/gpg/gpg_context/GpgContextUIDOpera.cpp
deleted file mode 100644
index b96f5f8f..00000000
--- a/src/gpg/gpg_context/GpgContextUIDOpera.cpp
+++ /dev/null
@@ -1,80 +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 "gpg/GpgContext.h"
-
-/**
- * create a new uid in certain key pair
- * @param key target key pair
- * @param uid uid args
- * @return if successful
- */
-bool GpgME::GpgContext::addUID(const GpgKey &key, const GpgUID &uid) {
- QString userid = QString("%1 (%3) <%2>").arg(uid.name, uid.email, uid.comment);
- auto gpgmeError = gpgme_op_adduid(mCtx, key.key_refer, userid.toUtf8().constData(), 0);
- if (gpgmeError == GPG_ERR_NO_ERROR) {
- emit signalKeyUpdated(key.id);
- return true;
- } else {
- checkErr(gpgmeError);
- return false;
- }
-
-}
-
-/**
- * Revoke(Delete) UID from certain key pair
- * @param key target key pair
- * @param uid target uid
- * @return if successful
- */
-bool GpgME::GpgContext::revUID(const GpgKey &key, const GpgUID &uid) {
- auto gpgmeError = gpgme_op_revuid(mCtx, key.key_refer, uid.uid.toUtf8().constData(), 0);
- if (gpgmeError == GPG_ERR_NO_ERROR) {
- emit signalKeyUpdated(key.id);
- return true;
- } else {
- checkErr(gpgmeError);
- return false;
- }
-}
-
-/**
- * Set one of a uid of a key pair as primary
- * @param key target key pair
- * @param uid target uid
- * @return if successful
- */
-bool GpgME::GpgContext::setPrimaryUID(const GpgKey &key, const GpgUID &uid) {
- auto gpgmeError = gpgme_op_set_uid_flag(mCtx, key.key_refer,
- uid.uid.toUtf8().constData(), "primary", nullptr);
- if (gpgmeError == GPG_ERR_NO_ERROR) {
- emit signalKeyUpdated(key.id);
- return true;
- } else {
- checkErr(gpgmeError);
- return false;
- }
-}
-
diff --git a/src/gpg/model/GpgData.cpp b/src/gpg/model/GpgData.cpp
new file mode 100644
index 00000000..c6e9b2ce
--- /dev/null
+++ b/src/gpg/model/GpgData.cpp
@@ -0,0 +1,74 @@
+/**
+ * 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 "gpg/model/GpgData.h"
+
+GpgFrontend::GpgData::GpgData() {
+ gpgme_data_t 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) {
+ gpgme_data_t data;
+
+ auto err = gpgme_data_new_from_mem(&data, (const char*)buffer, size, copy);
+ assert(gpgme_err_code(err) == GPG_ERR_NO_ERROR);
+
+ data_ =
+ std::unique_ptr<struct gpgme_data, __data_ref_deletor>(std::move(data));
+}
+
+/**
+ * Read gpgme-Data to QByteArray
+ * mainly from http://basket.kde.org/ (kgpgme.cpp)
+ */
+#define BUF_SIZE (32 * 1024)
+
+GpgFrontend::ByteArrayPtr GpgFrontend::GpgData::Read2Buffer() {
+ gpgme_off_t ret = gpgme_data_seek(*this, 0, SEEK_SET);
+ ByteArrayPtr out_buffer = std::make_unique<std::string>();
+
+ if (ret) {
+ gpgme_error_t err = gpgme_err_code_from_errno(errno);
+ assert(gpgme_err_code(err) == GPG_ERR_NO_ERROR);
+ } else {
+ char buf[BUF_SIZE + 2];
+
+ while ((ret = gpgme_data_read(*this, buf, BUF_SIZE)) > 0) {
+ const size_t size = out_buffer->size();
+ out_buffer->resize(static_cast<int>(size + ret));
+ memcpy(out_buffer->data() + size, buf, ret);
+ }
+ if (ret < 0) {
+ gpgme_error_t err = gpgme_err_code_from_errno(errno);
+ assert(gpgme_err_code(err) == GPG_ERR_NO_ERROR);
+ }
+ }
+ return out_buffer;
+} \ No newline at end of file
diff --git a/src/gpg/model/GpgData.h b/src/gpg/model/GpgData.h
new file mode 100644
index 00000000..e3202af6
--- /dev/null
+++ b/src/gpg/model/GpgData.h
@@ -0,0 +1,54 @@
+/**
+ * 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 _GPGDATA_H
+#define _GPGDATA_H
+
+#include "gpg/GpgConstants.h"
+
+namespace GpgFrontend {
+
+class GpgData {
+ public:
+ GpgData();
+
+ GpgData(void* buffer, size_t size, bool copy = true);
+
+ operator gpgme_data_t() { return data_.get(); }
+
+ ByteArrayPtr Read2Buffer();
+
+ private:
+ struct __data_ref_deletor {
+ void operator()(gpgme_data_t _data) {
+ if (_data != nullptr) gpgme_data_release(_data);
+ }
+ };
+
+ std::unique_ptr<struct gpgme_data, __data_ref_deletor> data_ = nullptr;
+};
+
+} // namespace GpgFrontend
+
+#endif // _GPGDATA_H \ No newline at end of file
diff --git a/src/gpg/model/GpgKey.cpp b/src/gpg/model/GpgKey.cpp
new file mode 100644
index 00000000..c14edd2d
--- /dev/null
+++ b/src/gpg/model/GpgKey.cpp
@@ -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.
+ *
+ */
+
+#include "gpg/model/GpgKey.h"
+
+GpgFrontend::GpgKey::GpgKey(gpgme_key_t &&key) : _key_ref(std::move(key)) {}
+
+GpgFrontend::GpgKey::GpgKey(GpgKey &&k) noexcept { swap(_key_ref, k._key_ref); }
+
+GpgFrontend::GpgKey &GpgFrontend::GpgKey::operator=(GpgKey &&k) noexcept {
+ swap(_key_ref, k._key_ref);
+ return *this;
+}
+
+std::unique_ptr<std::vector<GpgFrontend::GpgSubKey>>
+GpgFrontend::GpgKey::subKeys() const {
+ auto p_keys = std::make_unique<std::vector<GpgSubKey>>();
+ auto next = _key_ref->subkeys;
+ while (next != nullptr) {
+ p_keys->push_back(GpgSubKey(next));
+ next = next->next;
+ }
+ return p_keys;
+}
+
+std::unique_ptr<std::vector<GpgFrontend::GpgUID>> GpgFrontend::GpgKey::uids()
+ const {
+ auto p_uids = std::make_unique<std::vector<GpgUID>>();
+ auto uid_next = _key_ref->uids;
+ while (uid_next != nullptr) {
+ p_uids->push_back(GpgUID(uid_next));
+ uid_next = uid_next->next;
+ }
+ return p_uids;
+}
+
+bool GpgFrontend::GpgKey::CanSignActual() const {
+ auto subkeys = subKeys();
+ if (std::any_of(subkeys->begin(), subkeys->end(),
+ [](const GpgSubKey &subkey) -> bool {
+ return subkey.secret() && subkey.can_sign() &&
+ !subkey.disabled() && !subkey.revoked() &&
+ !subkey.expired();
+ }))
+ return true;
+ else
+ return false;
+}
+
+bool GpgFrontend::GpgKey::CanAuthActual() const {
+ auto subkeys = subKeys();
+ if (std::any_of(subkeys->begin(), subkeys->end(),
+ [](const GpgSubKey &subkey) -> bool {
+ return subkey.secret() && subkey.can_authenticate() &&
+ !subkey.disabled() && !subkey.revoked() &&
+ !subkey.expired();
+ }))
+ return true;
+ else
+ return false;
+}
+
+/**
+ * check if key can certify(actually)
+ * @param key target key
+ * @return if key certify
+ */
+bool GpgFrontend::GpgKey::CanCertActual() const {
+ return has_master_key() && !expired() && !revoked() && !disabled();
+}
+
+/**
+ * check if key can encrypt(actually)
+ * @param key target key
+ * @return if key encrypt
+ */
+bool GpgFrontend::GpgKey::CanEncrActual() const {
+ auto subkeys = subKeys();
+ if (std::any_of(subkeys->begin(), subkeys->end(),
+ [](const GpgSubKey &subkey) -> bool {
+ return subkey.can_encrypt() && !subkey.disabled() &&
+ !subkey.revoked() && !subkey.expired();
+ }))
+ return true;
+ else
+ return false;
+}
diff --git a/src/gpg/model/GpgKey.h b/src/gpg/model/GpgKey.h
new file mode 100644
index 00000000..53c074e8
--- /dev/null
+++ b/src/gpg/model/GpgKey.h
@@ -0,0 +1,162 @@
+/**
+ * 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_GPGKEY_H
+#define GPGFRONTEND_GPGKEY_H
+
+#include <boost/date_time.hpp>
+#include <boost/date_time/posix_time/conversion.hpp>
+
+#include "GpgSubKey.h"
+#include "GpgUID.h"
+
+namespace GpgFrontend {
+
+class GpgKey {
+ public:
+ [[nodiscard]] bool good() const { return _key_ref != nullptr; }
+
+ [[nodiscard]] std::string id() const { return _key_ref->subkeys->keyid; }
+
+ [[nodiscard]] std::string name() const { return _key_ref->uids->name; };
+
+ [[nodiscard]] std::string email() const { return _key_ref->uids->email; }
+
+ [[nodiscard]] std::string comment() const { return _key_ref->uids->comment; }
+
+ [[nodiscard]] std::string fpr() const { return _key_ref->fpr; }
+
+ [[nodiscard]] std::string protocol() const {
+ return gpgme_get_protocol_name(_key_ref->protocol);
+ }
+
+ [[nodiscard]] std::string owner_trust() const {
+ switch (_key_ref->owner_trust) {
+ case GPGME_VALIDITY_UNKNOWN:
+ return "Unknown";
+ case GPGME_VALIDITY_UNDEFINED:
+ return "Undefined";
+ case GPGME_VALIDITY_NEVER:
+ return "Never";
+ case GPGME_VALIDITY_MARGINAL:
+ return "Marginal";
+ case GPGME_VALIDITY_FULL:
+ return "FULL";
+ case GPGME_VALIDITY_ULTIMATE:
+ return "Ultimate";
+ }
+ return "Invalid";
+ }
+
+ [[nodiscard]] std::string pubkey_algo() const {
+ return gpgme_pubkey_algo_name(_key_ref->subkeys->pubkey_algo);
+ }
+
+ [[nodiscard]] boost::gregorian::date last_update() const {
+ return boost::posix_time::from_time_t(
+ static_cast<time_t>(_key_ref->last_update))
+ .date();
+ }
+
+ [[nodiscard]] boost::gregorian::date expires() const {
+ return boost::posix_time::from_time_t(_key_ref->subkeys->expires).date();
+ };
+
+ [[nodiscard]] boost::gregorian::date create_time() const {
+ return boost::posix_time::from_time_t(_key_ref->subkeys->timestamp).date();
+ };
+
+ [[nodiscard]] unsigned int length() const {
+ return _key_ref->subkeys->length;
+ }
+
+ [[nodiscard]] bool can_encrypt() const { return _key_ref->can_encrypt; }
+
+ [[nodiscard]] bool CanEncrActual() const;
+
+ [[nodiscard]] bool can_sign() const { return _key_ref->can_sign; }
+
+ [[nodiscard]] bool CanSignActual() const;
+
+ [[nodiscard]] bool can_certify() const { return _key_ref->can_certify; }
+
+ [[nodiscard]] bool CanCertActual() const;
+
+ [[nodiscard]] bool can_authenticate() const {
+ return _key_ref->can_authenticate;
+ }
+
+ [[nodiscard]] bool CanAuthActual() const;
+
+ [[nodiscard]] bool is_private_key() const { return _key_ref->secret; }
+
+ [[nodiscard]] bool expired() const { return _key_ref->expired; }
+
+ [[nodiscard]] bool revoked() const { return _key_ref->revoked; }
+
+ [[nodiscard]] bool disabled() const { return _key_ref->disabled; }
+
+ [[nodiscard]] bool has_master_key() const {
+ return _key_ref->subkeys->secret;
+ }
+
+ [[nodiscard]] std::unique_ptr<std::vector<GpgSubKey>> subKeys() const;
+
+ [[nodiscard]] std::unique_ptr<std::vector<GpgUID>> uids() const;
+
+ GpgKey() = default;
+
+ explicit GpgKey(gpgme_key_t&& key);
+
+ ~GpgKey() = default;
+
+ GpgKey(const gpgme_key_t& key) = delete;
+
+ GpgKey(GpgKey&& k) noexcept;
+
+ GpgKey& operator=(GpgKey&& k) noexcept;
+
+ GpgKey& operator=(const gpgme_key_t& key) = delete;
+
+ bool operator==(const GpgKey& o) const { return o.id() == this->id(); }
+
+ bool operator<=(const GpgKey& o) const { return this->id() < o.id(); }
+
+ explicit operator gpgme_key_t() const { return _key_ref.get(); }
+
+ private:
+ struct _key_ref_deletor {
+ void operator()(gpgme_key_t _key) {
+ if (_key != nullptr) gpgme_key_unref(_key);
+ }
+ };
+
+ using KeyRefHandler = std::unique_ptr<struct _gpgme_key, _key_ref_deletor>;
+
+ KeyRefHandler _key_ref = nullptr;
+};
+
+} // namespace GpgFrontend
+
+#endif // GPGFRONTEND_GPGKEY_H
diff --git a/src/gpg/model/GpgKeySignature.cpp b/src/gpg/model/GpgKeySignature.cpp
new file mode 100644
index 00000000..8f937198
--- /dev/null
+++ b/src/gpg/model/GpgKeySignature.cpp
@@ -0,0 +1,28 @@
+/**
+ * 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 "gpg/model/GpgKeySignature.h"
+
+GpgFrontend::GpgKeySignature::GpgKeySignature(gpgme_key_sig_t sig)
+ : _signature_ref(sig, [&](gpgme_key_sig_t signature) {}) {}
diff --git a/src/gpg/model/GpgKeySignature.h b/src/gpg/model/GpgKeySignature.h
new file mode 100644
index 00000000..70eaeb1c
--- /dev/null
+++ b/src/gpg/model/GpgKeySignature.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_GPGKEYSIGNATURE_H
+#define GPGFRONTEND_GPGKEYSIGNATURE_H
+
+#include <boost/date_time.hpp>
+#include <string>
+
+#include "gpg/GpgConstants.h"
+
+namespace GpgFrontend {
+
+class GpgKeySignature {
+ public:
+ [[nodiscard]] bool revoked() const { return _signature_ref->revoked; }
+ [[nodiscard]] bool expired() const { return _signature_ref->expired; }
+ [[nodiscard]] bool invalid() const { return _signature_ref->invalid; }
+ [[nodiscard]] bool exportable() const { return _signature_ref->exportable; }
+
+ [[nodiscard]] gpgme_error_t status() const { return _signature_ref->status; }
+
+ [[nodiscard]] std::string keyid() const { return _signature_ref->keyid; }
+ [[nodiscard]] std::string pubkey_algo() const {
+ return gpgme_pubkey_algo_name(_signature_ref->pubkey_algo);
+ }
+
+ [[nodiscard]] boost::gregorian::date create_time() const {
+ return boost::posix_time::from_time_t(_signature_ref->timestamp).date();
+ }
+ [[nodiscard]] boost::gregorian::date expire_time() const {
+ return boost::posix_time::from_time_t(_signature_ref->expires).date();
+ }
+
+ [[nodiscard]] std::string uid() const { return _signature_ref->uid; }
+ [[nodiscard]] std::string name() const { return _signature_ref->name; }
+ [[nodiscard]] std::string email() const { return _signature_ref->email; }
+ [[nodiscard]] std::string comment() const { return _signature_ref->comment; }
+
+ GpgKeySignature() = default;
+
+ ~GpgKeySignature() = default;
+
+ explicit GpgKeySignature(gpgme_key_sig_t sig);
+
+ GpgKeySignature(GpgKeySignature &&) noexcept = default;
+
+ GpgKeySignature(const GpgKeySignature &) = delete;
+
+ GpgKeySignature &operator=(GpgKeySignature &&) noexcept = default;
+
+ GpgKeySignature &operator=(const GpgKeySignature &) = delete;
+
+ private:
+ using KeySignatrueRefHandler =
+ std::unique_ptr<struct _gpgme_key_sig,
+ std::function<void(gpgme_key_sig_t)>>;
+
+ KeySignatrueRefHandler _signature_ref = nullptr;
+};
+
+} // namespace GpgFrontend
+
+#endif // GPGFRONTEND_GPGKEYSIGNATURE_H
diff --git a/src/gpg/model/GpgSubKey.cpp b/src/gpg/model/GpgSubKey.cpp
new file mode 100644
index 00000000..83fbcaa2
--- /dev/null
+++ b/src/gpg/model/GpgSubKey.cpp
@@ -0,0 +1,27 @@
+/**
+ * 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 "gpg/model/GpgSubKey.h"
+
+GpgFrontend::GpgSubKey::GpgSubKey(gpgme_subkey_t subkey)
+ : _subkey_ref(subkey, [&](gpgme_subkey_t subkey) {}) {}
diff --git a/src/gpg/model/GpgSubKey.h b/src/gpg/model/GpgSubKey.h
new file mode 100644
index 00000000..5f65c507
--- /dev/null
+++ b/src/gpg/model/GpgSubKey.h
@@ -0,0 +1,102 @@
+/**
+ * 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_GPGSUBKEY_H
+#define GPGFRONTEND_GPGSUBKEY_H
+
+#include <boost/date_time.hpp>
+#include <string>
+
+#include "gpg/GpgConstants.h"
+
+namespace GpgFrontend {
+
+class GpgSubKey {
+ public:
+ [[nodiscard]] std::string id() const { return _subkey_ref->keyid; }
+
+ [[nodiscard]] std::string fpr() const { return _subkey_ref->fpr; }
+
+ [[nodiscard]] std::string pubkey_algo() const {
+ return gpgme_pubkey_algo_name(_subkey_ref->pubkey_algo);
+ }
+
+ [[nodiscard]] unsigned int length() const { return _subkey_ref->length; }
+
+ [[nodiscard]] bool can_encrypt() const { return _subkey_ref->can_encrypt; }
+
+ [[nodiscard]] bool can_sign() const { return _subkey_ref->can_sign; }
+
+ [[nodiscard]] bool can_certify() const { return _subkey_ref->can_certify; }
+
+ [[nodiscard]] bool can_authenticate() const {
+ return _subkey_ref->can_authenticate;
+ }
+
+ [[nodiscard]] bool is_private_key() const { return _subkey_ref->secret; }
+
+ [[nodiscard]] bool expired() const { return _subkey_ref->expired; }
+
+ [[nodiscard]] bool revoked() const { return _subkey_ref->revoked; }
+
+ [[nodiscard]] bool disabled() const { return _subkey_ref->disabled; }
+
+ [[nodiscard]] bool secret() const { return _subkey_ref->secret; }
+
+ [[nodiscard]] bool is_cardkey() const { return _subkey_ref->is_cardkey; }
+
+ [[nodiscard]] boost::gregorian::date timestamp() const {
+ return boost::posix_time::from_time_t(_subkey_ref->timestamp).date();
+ }
+
+ [[nodiscard]] boost::gregorian::date expires() const {
+ return boost::posix_time::from_time_t(_subkey_ref->expires).date();
+ }
+
+ GpgSubKey() = default;
+
+ explicit GpgSubKey(gpgme_subkey_t subkey);
+
+ GpgSubKey(GpgSubKey&& o) noexcept { swap(_subkey_ref, o._subkey_ref); }
+
+ GpgSubKey(const GpgSubKey&) = delete;
+
+ GpgSubKey& operator=(GpgSubKey&& o) noexcept {
+ swap(_subkey_ref, o._subkey_ref);
+ return *this;
+ };
+
+ GpgSubKey& operator=(const GpgSubKey&) = delete;
+
+ 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
+
+#endif // GPGFRONTEND_GPGSUBKEY_H
diff --git a/src/gpg/model/GpgUID.cpp b/src/gpg/model/GpgUID.cpp
new file mode 100644
index 00000000..c0a63bab
--- /dev/null
+++ b/src/gpg/model/GpgUID.cpp
@@ -0,0 +1,28 @@
+/**
+ * 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 "gpg/model/GpgUID.h"
+
+GpgFrontend::GpgUID::GpgUID(gpgme_user_id_t uid)
+ : _uid_ref(uid, [&](gpgme_user_id_t uid) {}) {} \ No newline at end of file
diff --git a/src/gpg/model/GpgUID.h b/src/gpg/model/GpgUID.h
new file mode 100644
index 00000000..66dba321
--- /dev/null
+++ b/src/gpg/model/GpgUID.h
@@ -0,0 +1,81 @@
+/**
+ * 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_GPGUID_H
+#define GPGFRONTEND_GPGUID_H
+
+#include "GpgKeySignature.h"
+
+namespace GpgFrontend {
+
+class GpgUID {
+ public:
+ [[nodiscard]] std::string name() const { return _uid_ref->name; }
+
+ [[nodiscard]] std::string email() const { return _uid_ref->email; }
+
+ [[nodiscard]] std::string comment() const { return _uid_ref->comment; }
+
+ [[nodiscard]] std::string uid() const { return _uid_ref->uid; }
+
+ [[nodiscard]] bool revoked() const { return _uid_ref->revoked; }
+
+ [[nodiscard]] bool invalid() const { return _uid_ref->invalid; }
+
+ [[nodiscard]] std::unique_ptr<std::vector<GpgKeySignature>> signatures()
+ const {
+ auto sigs = std::make_unique<std::vector<GpgKeySignature>>();
+ auto sig_next = _uid_ref->signatures;
+ while (sig_next != nullptr) {
+ sigs->push_back(GpgKeySignature(sig_next));
+ sig_next = sig_next->next;
+ }
+ return sigs;
+ }
+
+ GpgUID() = default;
+
+ explicit GpgUID(gpgme_user_id_t uid);
+
+ GpgUID(GpgUID &&o) noexcept { swap(_uid_ref, o._uid_ref); }
+
+ GpgUID(const GpgUID &) = delete;
+
+ GpgUID &operator=(GpgUID &&o) noexcept {
+ swap(_uid_ref, o._uid_ref);
+ return *this;
+ }
+
+ GpgUID &operator=(const GpgUID &) = delete;
+
+ private:
+ using UidRefHandler = std::unique_ptr<struct _gpgme_user_id,
+ std::function<void(gpgme_user_id_t)>>;
+
+ UidRefHandler _uid_ref = nullptr;
+};
+
+} // namespace GpgFrontend
+
+#endif // GPGFRONTEND_GPGUID_H \ No newline at end of file
diff --git a/src/gpg/result_analyse/DecryptResultAnalyse.cpp b/src/gpg/result_analyse/DecryptResultAnalyse.cpp
index b4d0b14f..4ff32c59 100644
--- a/src/gpg/result_analyse/DecryptResultAnalyse.cpp
+++ b/src/gpg/result_analyse/DecryptResultAnalyse.cpp
@@ -1,7 +1,7 @@
/**
- * This file is part of GPGFrontend.
+ * This file is part of GpgFrontend.
*
- * GPGFrontend is free software: you can redistribute it and/or modify
+ * 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.
@@ -24,63 +24,68 @@
#include "gpg/result_analyse/DecryptResultAnalyse.h"
-DecryptResultAnalyse::DecryptResultAnalyse(GpgME::GpgContext *ctx, gpgme_error_t error, gpgme_decrypt_result_t result)
- : mCtx(ctx) {
+#include "gpg/function/GpgKeyGetter.h"
- stream << tr("[#] Decrypt Operation ");
+GpgFrontend::DecryptResultAnalyse::DecryptResultAnalyse(GpgError error,
+ GpgDecrResult result)
+ : error(error), result(std::move(result)) {}
- if (gpgme_err_code(error) == GPG_ERR_NO_ERROR) {
- stream << tr("[Success]") << Qt::endl;
- } else {
- stream << tr("[Failed] ") << gpgme_strerror(error) << Qt::endl;
- setStatus(-1);
- if (result != nullptr && result->unsupported_algorithm != nullptr) {
- stream << "------------>" << Qt::endl;
- stream << tr("Unsupported Algo: ") << result->unsupported_algorithm << Qt::endl;
- }
- }
+void GpgFrontend::DecryptResultAnalyse::do_analyse() {
+ stream << "[#]" << _("Decrypt Operation");
- if (result != nullptr && result->recipients != nullptr) {
- stream << "------------>" << Qt::endl;
- if (result->file_name != nullptr) {
- stream << tr("File Name: ") << result->file_name << Qt::endl;
- stream << Qt::endl;
- }
+ if (gpgme_err_code(error) == GPG_ERR_NO_ERROR) {
+ stream << "[" << _("Success") << "]" << std::endl;
+ } else {
+ stream << "[" << _("Failed") << "] " << gpgme_strerror(error) << std::endl;
+ setStatus(-1);
+ if (result != nullptr && result->unsupported_algorithm != nullptr) {
+ stream << "------------>" << std::endl;
+ stream << _("Unsupported Algo") << ": " << result->unsupported_algorithm
+ << std::endl;
+ }
+ }
- auto reci = result->recipients;
- if (reci != nullptr)
- stream << tr("Recipient(s): ") << Qt::endl;
- while (reci != nullptr) {
- printReci(stream, reci);
- reci = reci->next;
- }
- stream << "<------------" << Qt::endl;
+ if (result != nullptr && result->recipients != nullptr) {
+ stream << "------------>" << std::endl;
+ if (result->file_name != nullptr) {
+ stream << _("File Name") << ": " << result->file_name << std::endl;
+ stream << std::endl;
}
- stream << Qt::endl;
+ auto reci = result->recipients;
+ if (reci != nullptr) stream << _("Recipient(s)") << ": " << std::endl;
+ while (reci != nullptr) {
+ print_reci(stream, reci);
+ reci = reci->next;
+ }
+ stream << "<------------" << std::endl;
+ }
+ stream << std::endl;
}
-bool DecryptResultAnalyse::printReci(QTextStream &stream, gpgme_recipient_t reci) {
- bool keyFound = true;
- stream << QApplication::tr(" {>} Recipient: ");
+bool GpgFrontend::DecryptResultAnalyse::print_reci(std::stringstream &stream,
+ gpgme_recipient_t reci) {
+ bool keyFound = true;
+ stream << " {>} " << _("Recipient") << ": ";
- auto key = mCtx->getKeyById(reci->keyid);
- if(key.good) {
- stream << key.name;
- if (!key.email.isEmpty()) {
- stream << "<" << key.email << ">";
- }
- } else {
- stream << "<Unknown>";
- setStatus(0);
- keyFound = false;
+ auto key = GpgFrontend::GpgKeyGetter::GetInstance().GetKey(reci->keyid);
+ if (key.good()) {
+ stream << key.name().c_str();
+ if (!key.email().empty()) {
+ stream << "<" << key.email().c_str() << ">";
}
+ } else {
+ stream << "<" << _("Unknown") << ">";
+ setStatus(0);
+ keyFound = false;
+ }
- stream << Qt::endl;
+ stream << std::endl;
- stream << tr(" Keu ID: ") << reci->keyid << Qt::endl;
- stream << tr(" Public Algo: ") << gpgme_pubkey_algo_name(reci->pubkey_algo) << Qt::endl;
+ stream << " " << _("Keu ID") << ": " << key.id().c_str() << std::endl;
+ stream << " " << _("Public Algo") << ": "
+ << gpgme_pubkey_algo_name(reci->pubkey_algo) << std::endl;
- return keyFound;
+ return keyFound;
}
diff --git a/include/gpg/result_analyse/DecryptResultAnalyse.h b/src/gpg/result_analyse/DecryptResultAnalyse.h
index b1d0c7b4..0864c23b 100644
--- a/include/gpg/result_analyse/DecryptResultAnalyse.h
+++ b/src/gpg/result_analyse/DecryptResultAnalyse.h
@@ -1,7 +1,7 @@
/**
- * This file is part of GPGFrontend.
+ * This file is part of GpgFrontend.
*
- * GPGFrontend is free software: you can redistribute it and/or modify
+ * 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.
@@ -25,20 +25,25 @@
#ifndef GPGFRONTEND_DECRYPTRESULTANALYSE_H
#define GPGFRONTEND_DECRYPTRESULTANALYSE_H
-#include "gpg/GpgContext.h"
#include "ResultAnalyse.h"
+#include "gpg/GpgConstants.h"
+
+namespace GpgFrontend {
class DecryptResultAnalyse : public ResultAnalyse {
-Q_OBJECT
-public:
- explicit DecryptResultAnalyse(GpgME::GpgContext *ctx, gpgme_error_t error, gpgme_decrypt_result_t result);
+ public:
+ explicit DecryptResultAnalyse(GpgError error, GpgDecrResult result);
-private:
+ protected:
+ void do_analyse() final;
- GpgME::GpgContext *mCtx;
+ private:
+ bool print_reci(std::stringstream &stream, gpgme_recipient_t reci);
- bool printReci(QTextStream &stream, gpgme_recipient_t reci);
+ GpgError error;
+ GpgDecrResult result;
};
+} // namespace GpgFrontend
-#endif //GPGFRONTEND_DECRYPTRESULTANALYSE_H
+#endif // GPGFRONTEND_DECRYPTRESULTANALYSE_H
diff --git a/src/gpg/result_analyse/EncryptResultAnalyse.cpp b/src/gpg/result_analyse/EncryptResultAnalyse.cpp
index 1ba685c9..df240a1d 100644
--- a/src/gpg/result_analyse/EncryptResultAnalyse.cpp
+++ b/src/gpg/result_analyse/EncryptResultAnalyse.cpp
@@ -1,7 +1,7 @@
/**
- * This file is part of GPGFrontend.
+ * This file is part of GpgFrontend.
*
- * GPGFrontend is free software: you can redistribute it and/or modify
+ * 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.
@@ -24,35 +24,38 @@
#include "gpg/result_analyse/EncryptResultAnalyse.h"
-EncryptResultAnalyse::EncryptResultAnalyse(gpgme_error_t error, gpgme_encrypt_result_t result) {
-
- qDebug() << "Start Encrypt Result Analyse";
-
- stream << "[#] Encrypt Operation ";
-
- if(gpgme_err_code(error) == GPG_ERR_NO_ERROR)
- stream << "[Success]" << Qt::endl;
- else {
- stream << "[Failed] " << gpgme_strerror(error) << Qt::endl;
- setStatus(-1);
+GpgFrontend::EncryptResultAnalyse::EncryptResultAnalyse(GpgError error,
+ GpgEncrResult result)
+ : error(error), result(std::move(result)) {}
+
+void GpgFrontend::EncryptResultAnalyse::do_analyse() {
+ LOG(INFO) << _("Start Encrypt Result Analyse");
+
+ stream << "[#] " << _("Encrypt Operation") << " ";
+
+ if (gpgme_err_code(error) == GPG_ERR_NO_ERROR)
+ stream << "[" << _("Success") << "]" << std::endl;
+ else {
+ stream << "[" << _("Failed") << "] " << gpgme_strerror(error) << std::endl;
+ setStatus(-1);
+ }
+
+ if (!~status) {
+ stream << "------------>" << std::endl;
+ if (result != nullptr) {
+ stream << _("Invalid Recipients") << ": " << std::endl;
+ auto inv_reci = result->invalid_recipients;
+ while (inv_reci != nullptr) {
+ stream << _("Fingerprint") << ": " << inv_reci->fpr << std::endl;
+ stream << _("Reason") << ": " << gpgme_strerror(inv_reci->reason)
+ << std::endl;
+ stream << std::endl;
+
+ inv_reci = inv_reci->next;
+ }
}
+ stream << "<------------" << std::endl;
+ }
- if(!~status) {
- stream << "------------>" << Qt::endl;
- if (result != nullptr) {
- stream << tr("Invalid Recipients: ") << Qt::endl;
- auto inv_reci = result->invalid_recipients;
- while (inv_reci != nullptr) {
- stream << tr("Fingerprint: ") << inv_reci->fpr << Qt::endl;
- stream << tr("Reason: ") << gpgme_strerror(inv_reci->reason) << Qt::endl;
- stream << Qt::endl;
-
- inv_reci = inv_reci->next;
- }
- }
- stream << "<------------" << Qt::endl;
- }
-
- stream << Qt::endl;
-
+ stream << std::endl;
}
diff --git a/include/gpg/result_analyse/EncryptResultAnalyse.h b/src/gpg/result_analyse/EncryptResultAnalyse.h
index 447555c5..e0a411d1 100644
--- a/include/gpg/result_analyse/EncryptResultAnalyse.h
+++ b/src/gpg/result_analyse/EncryptResultAnalyse.h
@@ -1,7 +1,7 @@
/**
- * This file is part of GPGFrontend.
+ * This file is part of GpgFrontend.
*
- * GPGFrontend is free software: you can redistribute it and/or modify
+ * 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.
@@ -26,13 +26,20 @@
#define GPGFRONTEND_ENCRYPTRESULTANALYSE_H
#include "ResultAnalyse.h"
+#include "gpg/GpgConstants.h"
+namespace GpgFrontend {
class EncryptResultAnalyse : public ResultAnalyse {
-Q_OBJECT
-public:
- explicit EncryptResultAnalyse(gpgme_error_t error, gpgme_encrypt_result_t result);
+ public:
+ explicit EncryptResultAnalyse(GpgError error, GpgEncrResult result);
-};
+ protected:
+ void do_analyse() final;
+ private:
+ GpgError error;
+ GpgEncrResult result;
+};
+} // namespace GpgFrontend
-#endif //GPGFRONTEND_ENCRYPTRESULTANALYSE_H
+#endif // GPGFRONTEND_ENCRYPTRESULTANALYSE_H
diff --git a/src/gpg/result_analyse/ResultAnalyse.cpp b/src/gpg/result_analyse/ResultAnalyse.cpp
index 7186d21a..821da2ee 100644
--- a/src/gpg/result_analyse/ResultAnalyse.cpp
+++ b/src/gpg/result_analyse/ResultAnalyse.cpp
@@ -1,7 +1,7 @@
/**
- * This file is part of GPGFrontend.
+ * This file is part of GpgFrontend.
*
- * GPGFrontend is free software: you can redistribute it and/or modify
+ * 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.
@@ -24,15 +24,19 @@
#include "gpg/result_analyse/ResultAnalyse.h"
-const QString &ResultAnalyse::getResultReport() const{
- return resultText;
+const std::string GpgFrontend::ResultAnalyse::getResultReport() const {
+ return stream.str();
}
-int ResultAnalyse::getStatus() const {
- return status;
+int GpgFrontend::ResultAnalyse::getStatus() const { return status; }
+
+void GpgFrontend::ResultAnalyse::setStatus(int mStatus) {
+ if (mStatus < status) status = mStatus;
}
-void ResultAnalyse::setStatus(int mStatus) {
- if(mStatus < status)
- status = mStatus;
+void GpgFrontend::ResultAnalyse::analyse() {
+ if (!analysed_) {
+ do_analyse();
+ analysed_ = true;
+ }
}
diff --git a/include/gpg/result_analyse/ResultAnalyse.h b/src/gpg/result_analyse/ResultAnalyse.h
index da2e5676..33341b44 100644
--- a/include/gpg/result_analyse/ResultAnalyse.h
+++ b/src/gpg/result_analyse/ResultAnalyse.h
@@ -1,7 +1,7 @@
/**
- * This file is part of GPGFrontend.
+ * This file is part of GpgFrontend.
*
- * GPGFrontend is free software: you can redistribute it and/or modify
+ * 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.
@@ -24,25 +24,34 @@
#ifndef GPGFRONTEND_RESULTANALYSE_H
#define GPGFRONTEND_RESULTANALYSE_H
-#include "GpgFrontend.h"
+#include <sstream>
+#include <string>
-class ResultAnalyse : public QObject {
-Q_OBJECT
-public:
- ResultAnalyse() = default;
+#include "gpg/GpgConstants.h"
+namespace GpgFrontend {
- [[nodiscard]] const QString &getResultReport() const;
+class ResultAnalyse {
+ public:
+ ResultAnalyse() = default;
- [[nodiscard]] int getStatus() const;
+ [[nodiscard]] const std::string getResultReport() const;
-protected:
- QString resultText;
- QTextStream stream{&resultText};
+ [[nodiscard]] int getStatus() const;
- int status = 1;
+ void analyse();
- void setStatus(int mStatus);
+ protected:
+ virtual void do_analyse() = 0;
+
+ std::stringstream stream;
+
+ int status = 1;
+
+ bool analysed_ = false;
+
+ void setStatus(int mStatus);
};
+} // namespace GpgFrontend
-#endif //GPGFRONTEND_RESULTANALYSE_H
+#endif // GPGFRONTEND_RESULTANALYSE_H
diff --git a/src/gpg/result_analyse/SignResultAnalyse.cpp b/src/gpg/result_analyse/SignResultAnalyse.cpp
index 10d76678..770594ca 100644
--- a/src/gpg/result_analyse/SignResultAnalyse.cpp
+++ b/src/gpg/result_analyse/SignResultAnalyse.cpp
@@ -1,7 +1,7 @@
/**
- * This file is part of GPGFrontend.
+ * This file is part of GpgFrontend.
*
- * GPGFrontend is free software: you can redistribute it and/or modify
+ * 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.
@@ -24,73 +24,86 @@
#include "gpg/result_analyse/SignResultAnalyse.h"
-SignResultAnalyse::SignResultAnalyse(GpgME::GpgContext *ctx, gpgme_error_t error, gpgme_sign_result_t result) {
-
- qDebug() << "Start Sign Result Analyse";
-
- stream << tr("[#] Sign Operation ");
-
- if (gpgme_err_code(error) == GPG_ERR_NO_ERROR)
- stream << tr("[Success]") << Qt::endl;
- else {
- stream << tr("[Failed] ") << gpgme_strerror(error) << Qt::endl;
- setStatus(-1);
+#include "gpg/function/GpgKeyGetter.h"
+
+GpgFrontend::SignResultAnalyse::SignResultAnalyse(GpgError error,
+ GpgSignResult result)
+ : error(error), result(std::move(result)) {}
+
+void GpgFrontend::SignResultAnalyse::do_analyse() {
+ LOG(INFO) << _("Start Sign Result Analyse");
+
+ stream << "[#] " << _("Sign Operation") << " ";
+
+ if (gpgme_err_code(error) == GPG_ERR_NO_ERROR)
+ stream << "[" << _("Success") << "]" << std::endl;
+ else {
+ stream << "[" << _("Failed") << "] " << gpgme_strerror(error) << std::endl;
+ setStatus(-1);
+ }
+
+ if (result != nullptr &&
+ (result->signatures != nullptr || result->invalid_signers != nullptr)) {
+ LOG(INFO) << _("Sign Result Analyse Getting Result");
+ stream << "------------>" << std::endl;
+ auto new_sign = result->signatures;
+
+ while (new_sign != nullptr) {
+ stream << "[>]" << _("New Signature") << ": " << std::endl;
+
+ LOG(INFO) << _("Signers Fingerprint") << ": " << new_sign->fpr;
+
+ stream << " " << _("Sign Mode") << ": ";
+ if (new_sign->type == GPGME_SIG_MODE_NORMAL)
+ stream << _("Normal");
+ else if (new_sign->type == GPGME_SIG_MODE_CLEAR)
+ stream << _("Clear");
+ else if (new_sign->type == GPGME_SIG_MODE_DETACH)
+ stream << _("Detach");
+
+ stream << std::endl;
+
+ auto singerKey =
+ GpgFrontend::GpgKeyGetter::GetInstance().GetKey(new_sign->fpr);
+ if (singerKey.good()) {
+ stream << " " << _("Signer") << ": "
+ << singerKey.uids()->front().uid() << std::endl;
+ } else {
+ stream << " " << _("Signer") << ": "
+ << "<unknown>" << std::endl;
+ }
+ stream << " " << _("Public Key Algo") << ": "
+ << gpgme_pubkey_algo_name(new_sign->pubkey_algo) << std::endl;
+ stream << " " << _("Hash Algo") << ": "
+ << gpgme_hash_algo_name(new_sign->hash_algo) << std::endl;
+ stream << " " << _("Date & Time") << ": "
+ << boost::posix_time::to_iso_string(
+ boost::posix_time::from_time_t(new_sign->timestamp))
+ << std::endl;
+
+ stream << std::endl;
+
+ new_sign = new_sign->next;
}
- if (result != nullptr && (result->signatures != nullptr || result->invalid_signers != nullptr)) {
-
- qDebug() << "Sign Result Analyse Getting Result";
- stream << "------------>" << Qt::endl;
- auto new_sign = result->signatures;
-
- while (new_sign != nullptr) {
- stream << tr("[>] New Signature: ") << Qt::endl;
-
- qDebug() << "Signers Fingerprint: " << new_sign->fpr;
-
- stream << tr(" Sign Mode: ");
- if (new_sign->type == GPGME_SIG_MODE_NORMAL)
- stream << tr("Normal");
- else if (new_sign->type == GPGME_SIG_MODE_CLEAR)
- stream << tr("Clear");
- else if (new_sign->type == GPGME_SIG_MODE_DETACH)
- stream << tr("Detach");
+ LOG(INFO) << _("Sign Result Analyse Getting Invalid Signer");
- stream << Qt::endl;
+ auto invalid_signer = result->invalid_signers;
- GpgKey singerKey = ctx->getKeyByFpr(new_sign->fpr);
- if(singerKey.good) {
- stream << tr(" Signer: ") << singerKey.uids.first().uid << Qt::endl;
- } else {
- stream << tr(" Signer: ") << tr("<unknown>") << Qt::endl;
- }
- stream << tr(" Public Key Algo: ") << gpgme_pubkey_algo_name(new_sign->pubkey_algo) << Qt::endl;
- stream << tr(" Hash Algo: ") << gpgme_hash_algo_name(new_sign->hash_algo) << Qt::endl;
- stream << tr(" Date & Time: ") << QDateTime::fromTime_t(new_sign->timestamp).toString() << Qt::endl;
+ if (invalid_signer != nullptr)
+ stream << _("Invalid Signers") << ": " << std::endl;
- stream << Qt::endl;
-
- new_sign = new_sign->next;
- }
-
- qDebug() << "Sign Result Analyse Getting Invalid Signer";
-
- auto invalid_signer = result->invalid_signers;
-
- if (invalid_signer != nullptr)
- stream << tr("Invalid Signers: ") << Qt::endl;
-
- while (invalid_signer != nullptr) {
- setStatus(0);
- stream << tr("[>] Signer: ") << Qt::endl;
- stream << tr(" Fingerprint: ") << invalid_signer->fpr << Qt::endl;
- stream << tr(" Reason: ") << gpgme_strerror(invalid_signer->reason) << Qt::endl;
- stream << Qt::endl;
-
- invalid_signer = invalid_signer->next;
- }
- stream << "<------------" << Qt::endl;
+ while (invalid_signer != nullptr) {
+ setStatus(0);
+ stream << "[>] " << _("Signer") << ": " << std::endl;
+ stream << " " << _("Fingerprint") << ": " << invalid_signer->fpr
+ << std::endl;
+ stream << " " << _("Reason") << ": "
+ << gpgme_strerror(invalid_signer->reason) << std::endl;
+ stream << std::endl;
+ invalid_signer = invalid_signer->next;
}
-
-}
+ stream << "<------------" << std::endl;
+ }
+} \ No newline at end of file
diff --git a/include/gpg/result_analyse/SignResultAnalyse.h b/src/gpg/result_analyse/SignResultAnalyse.h
index ebb15dfb..988ddf99 100644
--- a/include/gpg/result_analyse/SignResultAnalyse.h
+++ b/src/gpg/result_analyse/SignResultAnalyse.h
@@ -1,7 +1,7 @@
/**
- * This file is part of GPGFrontend.
+ * This file is part of GpgFrontend.
*
- * GPGFrontend is free software: you can redistribute it and/or modify
+ * 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.
@@ -25,20 +25,23 @@
#ifndef GPGFRONTEND_SIGNRESULTANALYSE_H
#define GPGFRONTEND_SIGNRESULTANALYSE_H
-#include "GpgFrontend.h"
-
#include "ResultAnalyse.h"
-#include "gpg/GpgContext.h"
-class SignResultAnalyse : public ResultAnalyse {
-Q_OBJECT
-public:
+namespace GpgFrontend {
- explicit SignResultAnalyse(GpgME::GpgContext *ctx, gpgme_error_t error, gpgme_sign_result_t result);
+class SignResultAnalyse : public ResultAnalyse {
+ public:
+ explicit SignResultAnalyse(GpgError error, GpgSignResult result);
+ protected:
+ void do_analyse();
-private:
+ private:
+ GpgError error;
+ GpgSignResult result;
};
-#endif //GPGFRONTEND_SIGNRESULTANALYSE_H
+} // namespace GpgFrontend
+
+#endif // GPGFRONTEND_SIGNRESULTANALYSE_H
diff --git a/src/gpg/result_analyse/VerifyResultAnalyse.cpp b/src/gpg/result_analyse/VerifyResultAnalyse.cpp
index 75e07d33..55e50f38 100644
--- a/src/gpg/result_analyse/VerifyResultAnalyse.cpp
+++ b/src/gpg/result_analyse/VerifyResultAnalyse.cpp
@@ -1,7 +1,7 @@
/**
- * This file is part of GPGFrontend.
+ * This file is part of GpgFrontend.
*
- * GPGFrontend is free software: you can redistribute it and/or modify
+ * 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.
@@ -22,147 +22,172 @@
*
*/
-#include "GpgFrontend.h"
#include "gpg/result_analyse/VerifyResultAnalyse.h"
-VerifyResultAnalyse::VerifyResultAnalyse(GpgME::GpgContext *ctx, gpgme_error_t error, gpgme_verify_result_t result)
- : mCtx(ctx) {
+#include "GpgFrontend.h"
+#include "gpg/GpgConstants.h"
+#include "gpg/function/GpgKeyGetter.h"
- qDebug() << "Verify Result Analyse Started";
+GpgFrontend::VerifyResultAnalyse::VerifyResultAnalyse(GpgError error,
+ GpgVerifyResult result)
+ : error(error), result(std::move(result)) {}
- stream << tr("[#] Verify Operation ");
+void GpgFrontend::VerifyResultAnalyse::do_analyse() {
+ LOG(INFO) << _("Verify Result Analyse Started");
- if (gpgme_err_code(error) == GPG_ERR_NO_ERROR)
- stream << tr("[Success]") << Qt::endl;
- else {
- stream << tr("[Failed] ") << gpgme_strerror(error) << Qt::endl;
- setStatus(-1);
- }
+ stream << "[#] " << _("Verify Operation") << " ";
+ if (gpgme_err_code(error) == GPG_ERR_NO_ERROR)
+ stream << "[" << _("Success") << "]" << std::endl;
+ else {
+ stream << "[" << _("Failed") << "] " << gpgme_strerror(error) << std::endl;
+ setStatus(-1);
+ }
- if (result != nullptr && result->signatures) {
- stream << "------------>" << Qt::endl;
- auto sign = result->signatures;
+ if (result != nullptr && result->signatures) {
+ stream << "------------>" << std::endl;
+ auto sign = result->signatures;
- if (sign == nullptr) {
- stream << "[>] Not Signature Found" << Qt::endl;
+ if (sign == nullptr) {
+ stream << "[>] " << _("Not Signature Found") << std::endl;
+ setStatus(0);
+ return;
+ }
+
+ stream << "[>] " << _("Signed On") << " "
+ << boost::posix_time::to_iso_string(
+ boost::posix_time::from_time_t(sign->timestamp))
+ << std::endl;
+
+ stream << std::endl << "[>] " << _("Signatures") << ":" << std::endl;
+
+ bool canContinue = true;
+
+ while (sign && canContinue) {
+ switch (gpg_err_code(sign->status)) {
+ case GPG_ERR_BAD_SIGNATURE:
+ stream << _("One or More Bad Signatures.") << std::endl;
+ canContinue = false;
+ setStatus(-1);
+ break;
+ case GPG_ERR_NO_ERROR:
+ stream << _("A") << " ";
+ if (sign->summary & GPGME_SIGSUM_GREEN) {
+ stream << _("Good") << " ";
+ }
+ if (sign->summary & GPGME_SIGSUM_RED) {
+ stream << _("Bad") << " ";
+ }
+ if (sign->summary & GPGME_SIGSUM_SIG_EXPIRED) {
+ stream << _("Expired") << " ";
+ }
+ if (sign->summary & GPGME_SIGSUM_KEY_MISSING) {
+ stream << _("Missing Key's") << " ";
+ }
+ if (sign->summary & GPGME_SIGSUM_KEY_REVOKED) {
+ stream << _("Revoked Key's") << " ";
+ }
+ if (sign->summary & GPGME_SIGSUM_KEY_EXPIRED) {
+ stream << _("Expired Key's") << " ";
+ }
+ if (sign->summary & GPGME_SIGSUM_CRL_MISSING) {
+ stream << _("Missing CRL's") << " ";
+ }
+
+ if (sign->summary & GPGME_SIGSUM_VALID) {
+ stream << _("Signature Fully Valid.") << std::endl;
+ } else {
+ stream << _("Signature Not Fully Valid.") << std::endl;
+ }
+
+ if (!(sign->status & GPGME_SIGSUM_KEY_MISSING)) {
+ if (!print_signer(stream, sign)) setStatus(0);
+ } else {
+ stream << _("Key is NOT present with ID 0x") << sign->fpr
+ << std::endl;
+ }
+
+ setStatus(1);
+
+ break;
+ case GPG_ERR_NO_PUBKEY:
+ stream << _("A signature could NOT be verified due to a Missing Key")
+ << std::endl;
+ setStatus(-2);
+ break;
+ case GPG_ERR_CERT_REVOKED:
+ stream << _("A signature is valid but the key used to verify the "
+ "signature has been revoked")
+ << std::endl;
+ if (!print_signer(stream, sign)) {
+ setStatus(0);
+ }
+ setStatus(-1);
+ break;
+ case GPG_ERR_SIG_EXPIRED:
+ stream << _("A signature is valid but expired") << std::endl;
+ if (!print_signer(stream, sign)) {
setStatus(0);
- return;
- }
-
- stream << "[>] Signed On " << QDateTime::fromTime_t(sign->timestamp).toString() << Qt::endl;
-
- stream << Qt::endl << "[>] Signatures:" << Qt::endl;
-
- bool canContinue = true;
-
- while (sign && canContinue) {
-
- switch (gpg_err_code(sign->status)) {
- case GPG_ERR_BAD_SIGNATURE:
- stream << QApplication::tr("One or More Bad Signatures.") << Qt::endl;
- canContinue = false;
- setStatus(-1);
- break;
- case GPG_ERR_NO_ERROR:
- stream << QApplication::tr("A ");
- if (sign->summary & GPGME_SIGSUM_GREEN) {
- stream << QApplication::tr("Good ");
- }
- if (sign->summary & GPGME_SIGSUM_RED) {
- stream << QApplication::tr("Bad ");
- }
- if (sign->summary & GPGME_SIGSUM_SIG_EXPIRED) {
- stream << QApplication::tr("Expired ");
- }
- if (sign->summary & GPGME_SIGSUM_KEY_MISSING) {
- stream << QApplication::tr("Missing Key's ");
- }
- if (sign->summary & GPGME_SIGSUM_KEY_REVOKED) {
- stream << QApplication::tr("Revoked Key's ");
- }
- if (sign->summary & GPGME_SIGSUM_KEY_EXPIRED) {
- stream << QApplication::tr("Expired Key's ");
- }
- if (sign->summary & GPGME_SIGSUM_CRL_MISSING) {
- stream << QApplication::tr("Missing CRL's ");
- }
-
- if (sign->summary & GPGME_SIGSUM_VALID) {
- stream << QApplication::tr("Signature Fully Valid.") << Qt::endl;
- } else {
- stream << QApplication::tr("Signature Not Fully Valid.") << Qt::endl;
- }
-
- if (!(sign->status & GPGME_SIGSUM_KEY_MISSING)) {
- if (!printSigner(stream, sign)) setStatus(0);
- } else {
- stream << QApplication::tr("Key is NOT present with ID 0x") << QString(sign->fpr) << Qt::endl;
- }
-
- setStatus(1);
-
- break;
- case GPG_ERR_NO_PUBKEY:
- stream << QApplication::tr("A signature could NOT be verified due to a Missing Key\n");
- setStatus(-1);
- break;
- case GPG_ERR_CERT_REVOKED:
- stream << QApplication::tr(
- "A signature is valid but the key used to verify the signature has been revoked\n");
- if (!printSigner(stream, sign)) {
- setStatus(0);
- }
- setStatus(-1);
- break;
- case GPG_ERR_SIG_EXPIRED:
- stream << QApplication::tr("A signature is valid but expired\n");
- if (!printSigner(stream, sign)) {
- setStatus(0);
- }
- setStatus(-1);
- break;
- case GPG_ERR_KEY_EXPIRED:
- stream << QApplication::tr(
- "A signature is valid but the key used to verify the signature has expired.\n");
- if (!printSigner(stream, sign)) {
- setStatus(0);
- }
- break;
- case GPG_ERR_GENERAL:
- stream << QApplication::tr(
- "There was some other error which prevented the signature verification.\n");
- status = -1;
- canContinue = false;
- break;
- default:
- stream << QApplication::tr("Error for key with fingerprint ") <<
- GpgME::GpgContext::beautifyFingerprint(QString(sign->fpr));
- setStatus(-1);
- }
- stream << Qt::endl;
- sign = sign->next;
- }
- stream << "<------------" << Qt::endl;
+ }
+ setStatus(-1);
+ break;
+ case GPG_ERR_KEY_EXPIRED:
+ stream << _("A signature is valid but the key used to "
+ "verify the signature has expired.")
+ << std::endl;
+ if (!print_signer(stream, sign)) {
+ setStatus(0);
+ }
+ break;
+ case GPG_ERR_GENERAL:
+ stream << _("There was some other error which prevented "
+ "the signature verification.")
+ << std::endl;
+ status = -1;
+ canContinue = false;
+ break;
+ default:
+ auto fpr = std::string(sign->fpr);
+ stream << _("Error for key with fingerprint") << " "
+ << GpgFrontend::beautify_fingerprint(fpr);
+ setStatus(-1);
+ }
+ stream << std::endl;
+ sign = sign->next;
}
+ stream << "<------------" << std::endl;
+ }
}
-bool VerifyResultAnalyse::printSigner(QTextStream &stream, gpgme_signature_t sign) {
- bool keyFound = true;
- auto key = mCtx->getKeyByFpr(sign->fpr);
-
- key = mCtx->getKeyByFpr(sign->fpr);
+bool GpgFrontend::VerifyResultAnalyse::print_signer(std::stringstream &stream,
+ gpgme_signature_t sign) {
+ bool keyFound = true;
+ auto key = GpgFrontend::GpgKeyGetter::GetInstance().GetKey(sign->fpr);
+
+ if (!key.good()) {
+ stream << " " << _("Signed By") << ": "
+ << "<" << _("Unknown") << ">" << std::endl;
+ setStatus(0);
+ keyFound = false;
+ } else {
+ stream << " " << _("Signed By") << ": " << key.uids()->front().uid()
+ << std::endl;
+ }
+ stream << " " << _("Public Key Algo") << ": "
+ << gpgme_pubkey_algo_name(sign->pubkey_algo) << std::endl;
+ stream << " " << _("Hash Algo") << ": "
+ << gpgme_hash_algo_name(sign->hash_algo) << std::endl;
+ stream << " " << _("Date & Time") << ": "
+ << boost::posix_time::to_iso_string(
+ boost::posix_time::from_time_t(sign->timestamp))
+ << std::endl;
+ stream << std::endl;
+ return keyFound;
+}
- if (!key.good) {
- stream << tr(" Signed By: ") << tr("<unknown>") << Qt::endl;
- setStatus(0);
- keyFound = false;
- } else {
- stream << tr(" Signed By: ") << key.uids.first().uid << Qt::endl;
- }
- stream << tr(" Public Key Algo: ") << gpgme_pubkey_algo_name(sign->pubkey_algo) << Qt::endl;
- stream << tr(" Hash Algo: ") << gpgme_hash_algo_name(sign->hash_algo) << Qt::endl;
- stream << tr(" Date & Time: ") << QDateTime::fromTime_t(sign->timestamp).toString() << Qt::endl;
- stream << Qt::endl;
- return keyFound;
-} \ No newline at end of file
+gpgme_signature_t GpgFrontend::VerifyResultAnalyse::GetSignatures() {
+ if (result)
+ return result->signatures;
+ else
+ return nullptr;
+}
diff --git a/include/gpg/result_analyse/VerifyResultAnalyse.h b/src/gpg/result_analyse/VerifyResultAnalyse.h
index c009741a..51ce17ac 100644
--- a/include/gpg/result_analyse/VerifyResultAnalyse.h
+++ b/src/gpg/result_analyse/VerifyResultAnalyse.h
@@ -1,7 +1,7 @@
/**
- * This file is part of GPGFrontend.
+ * This file is part of GpgFrontend.
*
- * GPGFrontend is free software: you can redistribute it and/or modify
+ * 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.
@@ -25,23 +25,27 @@
#ifndef GPGFRONTEND_VERIFYRESULTANALYSE_H
#define GPGFRONTEND_VERIFYRESULTANALYSE_H
-#include "gpg/GpgContext.h"
-#include "gpg/GpgKeySignature.h"
-
#include "ResultAnalyse.h"
+#include "gpg/model/GpgKeySignature.h"
-class VerifyResultAnalyse : public ResultAnalyse{
-public:
+namespace GpgFrontend {
- explicit VerifyResultAnalyse(GpgME::GpgContext *ctx, gpgme_error_t error, gpgme_verify_result_t result);
+class VerifyResultAnalyse : public ResultAnalyse {
+ public:
+ explicit VerifyResultAnalyse(GpgError error, GpgVerifyResult result);
-private:
+ gpgme_signature_t GetSignatures();
- GpgME::GpgContext *mCtx;
+ private:
+ void do_analyse();
- bool printSigner(QTextStream &stream, gpgme_signature_t sign);
+ private:
+ bool print_signer(std::stringstream &stream, gpgme_signature_t sign);
+ GpgError error;
+ GpgVerifyResult result;
};
+} // namespace GpgFrontend
-#endif //GPGFRONTEND_VERIFYRESULTANALYSE_H
+#endif // GPGFRONTEND_VERIFYRESULTANALYSE_H
diff --git a/src/main.cpp b/src/main.cpp
index 1ec264e7..ee542ff0 100644
--- a/src/main.cpp
+++ b/src/main.cpp
@@ -1,7 +1,7 @@
/**
- * This file is part of GPGFrontend.
+ * This file is part of GpgFrontend.
*
- * GPGFrontend is free software: you can redistribute it and/or modify
+ * 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.
@@ -22,77 +22,149 @@
*
*/
-#include "MainWindow.h"
#include "GpgFrontendBuildInfo.h"
+#include "ui/MainWindow.h"
+#include "ui/settings/GlobalSettingStation.h"
-int main(int argc, char *argv[]) {
+// Easy Logging Cpp
+INITIALIZE_EASYLOGGINGPP
- Q_INIT_RESOURCE(gpgfrontend);
+void init_logging();
+void init_locale();
- QApplication app(argc, argv);
+int main(int argc, char* argv[]) {
+ // Qt
+ Q_INIT_RESOURCE(gpgfrontend);
- // get application path
- QString appPath = qApp->applicationDirPath();
+ // Qt App
+ QApplication app(argc, argv);
- QApplication::setApplicationVersion(BUILD_VERSION);
- QApplication::setApplicationName(PROJECT_NAME);
+ // logging system
+ init_logging();
- // dont show icons in menus
- QApplication::setAttribute(Qt::AA_DontShowIconsInMenus);
+ // i18n
+ init_locale();
- // unicode in source
- QTextCodec::setCodecForLocale(QTextCodec::codecForName("utf-8"));
+ // App config
+ QApplication::setApplicationVersion(BUILD_VERSION);
+ QApplication::setApplicationName(PROJECT_NAME);
-#if OS_PLATFORM == WINDOWS
- // load css file
- QFile file(RESOURCE_DIR(qApp->applicationDirPath()) + "/css/default.qss");
- file.open(QFile::ReadOnly);
- QString styleSheet = QLatin1String(file.readAll());
- qApp->setStyleSheet(styleSheet);
- file.close();
+ // don't show icons in menus
+ QApplication::setAttribute(Qt::AA_DontShowIconsInMenus);
+
+ // 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();
#endif
+ /**
+ * internationalisation. loop to restart mainwindow
+ * with changed translation when settings change.
+ */
+ int return_from_event_loop_code;
+
+ do {
+ QApplication::setQuitOnLastWindowClosed(true);
+
/**
- * 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();
- }
- 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);
-
- MainWindow window;
- return_from_event_loop_code = QApplication::exec();
-
- } while (return_from_event_loop_code == RESTART_CODE);
-
- return return_from_event_loop_code;
+ * 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);
+
+ /** set locale, because tests do also */
+ gpgme_set_locale(nullptr, LC_CTYPE, setlocale(LC_CTYPE, nullptr));
+#ifndef _WIN32
+ gpgme_set_locale(nullptr, LC_MESSAGES, setlocale(LC_MESSAGES, nullptr));
+#endif
+
+ auto main_window = std::make_unique<GpgFrontend::UI::MainWindow>();
+ main_window->init();
+ main_window->show();
+ return_from_event_loop_code = QApplication::exec();
+
+ } while (return_from_event_loop_code == RESTART_CODE);
+
+ return return_from_event_loop_code;
}
+void init_logging() {
+ using namespace boost::posix_time;
+ using namespace boost::gregorian;
+ ptime now = second_clock::local_time();
+ el::Loggers::addFlag(el::LoggingFlag::AutoSpacing);
+ el::Configurations defaultConf;
+ defaultConf.setToDefault();
+ el::Loggers::reconfigureLogger("default", defaultConf);
+
+ defaultConf.setGlobally(el::ConfigurationType::Format,
+ "%datetime %level %func %msg");
+
+ auto logfile_path =
+ (GpgFrontend::UI::GlobalSettingStation::GetInstance().GetLogDir() /
+ to_iso_string(now));
+ logfile_path.replace_extension(".log");
+ defaultConf.setGlobally(el::ConfigurationType::Filename,
+ logfile_path.string());
+
+ el::Loggers::reconfigureLogger("default", defaultConf);
+
+ LOG(INFO) << _("Logfile Path") << logfile_path;
+}
+
+void init_locale() {
+ auto& settings =
+ GpgFrontend::UI::GlobalSettingStation::GetInstance().GetUISettings();
+
+ if (!settings.exists("general") ||
+ settings.lookup("general").getType() != libconfig::Setting::TypeGroup)
+ settings.add("general", libconfig::Setting::TypeGroup);
+
+ // set system default at first
+ auto& general = settings["general"];
+ if (!general.exists("lang"))
+ general.add("lang", libconfig::Setting::TypeString) = "";
+
+ GpgFrontend::UI::GlobalSettingStation::GetInstance().Sync();
+
+ auto* locale_name = setlocale(LC_ALL, nullptr);
+ LOG(INFO) << "current system locale" << locale_name;
+
+ // read from settings file
+ std::string lang;
+ if (!general.lookupValue("lang", lang)) {
+ LOG(ERROR) << _("Could not read properly from configure file");
+ };
+
+ LOG(INFO) << "lang" << lang;
+ LOG(INFO) << "PROJECT_NAME" << PROJECT_NAME;
+ LOG(INFO) << "locales path"
+ << GpgFrontend::UI::GlobalSettingStation::GetInstance()
+ .GetLocaleDir()
+ .c_str();
+
+ if (!lang.empty()) lang += ".UTF8";
+ // GNU gettext settings
+ locale_name = setlocale(LC_ALL, lang.c_str());
+ if (locale_name == nullptr) {
+ LOG(WARNING) << "set locale name failed";
+ } else {
+ LOG(INFO) << "locale name now" << locale_name;
+ }
+
+ bindtextdomain(PROJECT_NAME,
+ GpgFrontend::UI::GlobalSettingStation::GetInstance()
+ .GetLocaleDir()
+ .string()
+ .c_str());
+ textdomain(PROJECT_NAME);
+}
diff --git a/src/server/BaseAPI.cpp b/src/server/BaseAPI.cpp
index be388df9..aa4c3f98 100644
--- a/src/server/BaseAPI.cpp
+++ b/src/server/BaseAPI.cpp
@@ -1,7 +1,7 @@
/**
- * This file is part of GPGFrontend.
+ * This file is part of GpgFrontend.
*
- * GPGFrontend is free software: you can redistribute it and/or modify
+ * 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.
@@ -23,48 +23,47 @@
*/
#include "server/BaseAPI.h"
+
#include "rapidjson/writer.h"
-BaseAPI::BaseAPI(ComUtils::ServiceType serviceType) : utils(new ComUtils(nullptr)),
- reqUrl(utils->getUrl(serviceType)), request(reqUrl) {
- request.setHeader(QNetworkRequest::ContentTypeHeader, "application/json");
+BaseAPI::BaseAPI(ComUtils::ServiceType serviceType)
+ : utils(new ComUtils(nullptr)),
+ reqUrl(utils->getUrl(serviceType)),
+ request(reqUrl) {
+ request.setHeader(QNetworkRequest::ContentTypeHeader, "application/json");
}
-BaseAPI::~BaseAPI() {
- utils->deleteLater();
-}
+BaseAPI::~BaseAPI() { utils->deleteLater(); }
QNetworkReply *BaseAPI::send_json_data() {
- rapidjson::StringBuffer sb;
- rapidjson::Writer<rapidjson::StringBuffer> writer(sb);
- document.Accept(writer);
+ rapidjson::StringBuffer sb;
+ rapidjson::Writer<rapidjson::StringBuffer> writer(sb);
+ document.Accept(writer);
- QByteArray postData(sb.GetString());
- qDebug() << "postData" << QString::fromUtf8(postData);
+ QByteArray postData(sb.GetString());
+ qDebug() << "postData" << QString::fromUtf8(postData);
- auto reply = utils->getNetworkManager().post(request, postData);
+ auto reply = utils->getNetworkManager().post(request, postData);
- while (reply->isRunning()) QApplication::processEvents();
+ while (reply->isRunning()) QApplication::processEvents();
- QByteArray replyData = reply->readAll().constData();
- if (utils->checkServerReply(replyData)) {
- good = true, deal_reply();
- }
+ QByteArray replyData = reply->readAll().constData();
+ if (utils->checkServerReply(replyData)) {
+ good = true, deal_reply();
+ }
- return reply;
+ return reply;
}
void BaseAPI::start() {
- construct_json();
- send_json_data()->deleteLater();
+ construct_json();
+ send_json_data()->deleteLater();
}
void BaseAPI::refresh() {
- document.Clear();
- utils->clear();
- good = false;
+ document.Clear();
+ utils->clear();
+ good = false;
}
-bool BaseAPI::result() const {
- return good;
-}
+bool BaseAPI::result() const { return good; }
diff --git a/include/server/BaseAPI.h b/src/server/BaseAPI.h
index 0b724bbc..46766fed 100644
--- a/include/server/BaseAPI.h
+++ b/src/server/BaseAPI.h
@@ -1,7 +1,7 @@
/**
- * This file is part of GPGFrontend.
+ * This file is part of GpgFrontend.
*
- * GPGFrontend is free software: you can redistribute it and/or modify
+ * 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.
@@ -25,49 +25,42 @@
#ifndef GPGFRONTEND_ZH_CN_TS_BASEAPI_H
#define GPGFRONTEND_ZH_CN_TS_BASEAPI_H
-#include "GpgFrontend.h"
#include "ComUtils.h"
-
+#include "GpgFrontend.h"
#include "rapidjson/document.h"
class BaseAPI : public QObject {
-Q_OBJECT
-public:
-
- explicit BaseAPI(ComUtils::ServiceType serviceType);
-
- ~BaseAPI() override;
+ Q_OBJECT
+ public:
+ explicit BaseAPI(ComUtils::ServiceType serviceType);
- void start();
+ ~BaseAPI() override;
- void refresh();
+ void start();
- [[nodiscard]] bool result() const;
+ void refresh();
-private:
+ [[nodiscard]] bool result() const;
- ComUtils *utils;
+ private:
+ ComUtils *utils;
- QUrl reqUrl;
+ QUrl reqUrl;
- QNetworkRequest request;
+ QNetworkRequest request;
- QNetworkReply *send_json_data();
+ QNetworkReply *send_json_data();
-protected:
+ protected:
+ bool good = false;
- bool good = false;
+ rapidjson::Document document;
- rapidjson::Document document;
-
- const ComUtils &getUtils() { return *utils; };
-
- virtual void construct_json() = 0;
-
- virtual void deal_reply() = 0;
+ const ComUtils &getUtils() { return *utils; };
+ virtual void construct_json() = 0;
+ virtual void deal_reply() = 0;
};
-
-#endif //GPGFRONTEND_ZH_CN_TS_BASEAPI_H
+#endif // GPGFRONTEND_ZH_CN_TS_BASEAPI_H
diff --git a/src/server/ComUtils.cpp b/src/server/ComUtils.cpp
index 01be4ea7..6a5ce7b0 100644
--- a/src/server/ComUtils.cpp
+++ b/src/server/ComUtils.cpp
@@ -1,7 +1,7 @@
/**
- * This file is part of GPGFrontend.
+ * This file is part of GpgFrontend.
*
- * GPGFrontend is free software: you can redistribute it and/or modify
+ * 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.
@@ -29,67 +29,71 @@
* @param reply reply data in byte array
* @return if successful
*/
-bool ComUtils::checkServerReply(const QByteArray &reply) {
-
- if(reply.isEmpty()) {
- QMessageBox::critical(this, tr("Error"), tr("Nothing Reply. Please check the Internet connection."));
- return false;
+bool GpgFrontend::ComUtils::checkServerReply(const QByteArray &reply) {
+ if (reply.isEmpty()) {
+ QMessageBox::critical(
+ this, _("Error"),
+ _("Nothing Reply. Please check the Internet connection."));
+ return false;
+ }
+
+ qDebug() << "Reply" << reply;
+
+ /**
+ * Server Reply Format(Except Timeout)
+ * {
+ * "status": 200,
+ * "msg": "OK",
+ * "timestamp": 1628652783895
+ * "data" : {
+ * ...
+ * }
+ * }
+ */
+
+ // check if reply is a json object
+ if (replyDoc.Parse(reply).HasParseError() || !replyDoc.IsObject()) {
+ QMessageBox::critical(this, _("Error"), _("Unknown Error"));
+ return false;
+ }
+
+ // check status(int) and message(string)
+ if (replyDoc.HasMember("status") && replyDoc.HasMember("msg") &&
+ replyDoc.HasMember("timestamp") && replyDoc.HasMember("data") &&
+ replyDoc["status"].IsNumber() && replyDoc["msg"].IsString() &&
+ replyDoc["timestamp"].IsNumber() && replyDoc["data"].IsObject()) {
+ int status = replyDoc["status"].GetInt();
+ QDateTime time;
+ time.setMSecsSinceEpoch(replyDoc["timestamp"].GetInt64());
+ auto message = replyDoc["msg"].GetString();
+ dataVal = replyDoc["data"].GetObject();
+
+ qDebug() << "Reply Date & Time" << time;
+
+ // check reply timestamp
+ if (time < QDateTime::currentDateTime().addSecs(-10)) {
+ QMessageBox::critical(this, _("Network Error"), _("Outdated Reply"));
+ return false;
}
- qDebug() << "Reply" << reply;
-
- /**
- * Server Reply Format(Except Timeout)
- * {
- * "status": 200,
- * "msg": "OK",
- * "timestamp": 1628652783895
- * "data" : {
- * ...
- * }
- * }
- */
-
- // check if reply is a json object
- if (replyDoc.Parse(reply).HasParseError() || !replyDoc.IsObject()) {
- QMessageBox::critical(this, tr("Error"), tr("Unknown Error"));
- return false;
+ // check status code if successful (200-299)
+ // check data object
+ if (status / 100 == 2) {
+ is_good = true;
+ return true;
+ } else {
+ if (dataVal.HasMember("exceptionMessage") &&
+ dataVal["exceptionMessage"].IsString())
+ QMessageBox::critical(this, message,
+ dataVal["exceptionMessage"].GetString());
+ else
+ QMessageBox::critical(this, message, _("Unknown Reason"));
}
- // check status(int) and message(string)
- if (replyDoc.HasMember("status") && replyDoc.HasMember("msg") && replyDoc.HasMember("timestamp") &&
- replyDoc.HasMember("data")
- && replyDoc["status"].IsNumber() && replyDoc["msg"].IsString() && replyDoc["timestamp"].IsNumber() &&
- replyDoc["data"].IsObject()) {
-
- int status = replyDoc["status"].GetInt();
- QDateTime time;
- time.setMSecsSinceEpoch(replyDoc["timestamp"].GetInt64());
- auto message = replyDoc["msg"].GetString();
- dataVal = replyDoc["data"].GetObject();
-
- qDebug() << "Reply Date & Time" << time;
-
- // check reply timestamp
- if (time < QDateTime::currentDateTime().addSecs(-10)) {
- QMessageBox::critical(this, tr("Network Error"), tr("Outdated Reply"));
- return false;
- }
-
- // check status code if successful (200-299)
- // check data object
- if (status / 100 == 2) {
- is_good = true;
- return true;
- } else {
- if (dataVal.HasMember("exceptionMessage") && dataVal["exceptionMessage"].IsString())
- QMessageBox::critical(this, message, dataVal["exceptionMessage"].GetString());
- else QMessageBox::critical(this, message, tr("Unknown Reason"));
- }
-
- } else QMessageBox::critical(this, tr("Network Error"), tr("Unknown Reply Format"));
+ } else
+ QMessageBox::critical(this, _("Network Error"), _("Unknown Reply Format"));
- return false;
+ return false;
}
/**
@@ -97,13 +101,15 @@ bool ComUtils::checkServerReply(const QByteArray &reply) {
* @param key key of value
* @return value in string format
*/
-QString ComUtils::getDataValueStr(const QString &key) const {
- if (is_good) {
- auto k_byte_array = key.toUtf8();
- if (dataVal.HasMember(k_byte_array.data())) {
- return dataVal[k_byte_array.data()].GetString();
- } else return {};
- } else return {};
+QString GpgFrontend::ComUtils::getDataValueStr(const QString &key) const {
+ if (is_good) {
+ auto k_byte_array = key.toUtf8();
+ if (dataVal.HasMember(k_byte_array.data())) {
+ return dataVal[k_byte_array.data()].GetString();
+ } else
+ return {};
+ } else
+ return {};
}
/**
@@ -111,87 +117,97 @@ QString ComUtils::getDataValueStr(const QString &key) const {
* @param type service which server provides
* @return url
*/
-QString ComUtils::getUrl(ComUtils::ServiceType type) const {
- auto host = settings.value("general/currentGpgfrontendServer",
- "service.gpgfrontend.pub").toString();
-
- auto protocol = QString();
- // Localhost Debug Server
- if (host == "localhost") protocol = "http://";
- else protocol = "https://";
-
- auto url = protocol + host + ":9049/";
-
- switch (type) {
- case GetServiceToken:
- url += "/user";
- break;
- case ShortenCryptText:
- url += "/text/new";
- break;
- case GetFullCryptText:
- url += "/text/get";
- break;
- case UploadPubkey:
- url += "/key/upload";
- break;
- case GetPubkey:
- url += "/key/get";
- break;
- }
-
- qDebug() << "ComUtils getUrl" << url;
-
- return url;
+QString GpgFrontend::ComUtils::getUrl(ComUtils::ServiceType type) const {
+ auto host =
+ settings
+ .value("general/currentGpgfrontendServer", "service.gpgfrontend.pub")
+ .toString();
+
+ auto protocol = QString();
+ // Localhost Debug Server
+ if (host == "localhost")
+ protocol = "http://";
+ else
+ protocol = "https://";
+
+ auto url = protocol + host + ":9049/";
+
+ switch (type) {
+ case GetServiceToken:
+ url += "/user";
+ break;
+ case ShortenCryptText:
+ url += "/text/new";
+ break;
+ case GetFullCryptText:
+ url += "/text/get";
+ break;
+ case UploadPubkey:
+ url += "/key/upload";
+ break;
+ case GetPubkey:
+ url += "/key/get";
+ break;
+ }
+
+ qDebug() << "ComUtils getUrl" << url;
+
+ return url;
}
-bool ComUtils::checkDataValueStr(const QString &key) const {
- auto key_byte_array_data = key.toUtf8().constData();
- if (is_good) {
- return dataVal.HasMember(key_byte_array_data) && dataVal[key_byte_array_data].IsString();
- } else return false;
+bool GpgFrontend::ComUtils::checkDataValueStr(const QString &key) const {
+ auto key_byte_array_data = key.toUtf8().constData();
+ if (is_good) {
+ return dataVal.HasMember(key_byte_array_data) &&
+ dataVal[key_byte_array_data].IsString();
+ } else
+ return false;
}
-bool ComUtils::checkServiceTokenFormat(const QString &uuid) const {
- return re_uuid.match(uuid).hasMatch();
+bool GpgFrontend::ComUtils::checkServiceTokenFormat(const QString &uuid) const {
+ return re_uuid.match(uuid).hasMatch();
}
-QByteArray ComUtils::getSignStringBase64(GpgME::GpgContext *ctx, const QString &str, const GpgKey &key) {
- QVector<GpgKey> keys{key};
- QByteArray outSignText;
- auto signData = str.toUtf8();
-
- // The use of multi-threading brings an improvement in UI smoothness
- gpgme_error_t error;
- auto thread = QThread::create([&]() {
- error = ctx->sign(keys, signData, &outSignText, GPGME_SIG_MODE_NORMAL, nullptr, false);
- });
- thread->start();
- while (thread->isRunning()) QApplication::processEvents();
- thread->deleteLater();
-
- return outSignText.toBase64();
+QByteArray GpgFrontend::ComUtils::getSignStringBase64(
+ GpgFrontend::GpgContext *ctx, const QString &str, const GpgKey &key) {
+ std::vector<GpgKey> keys{key};
+ QByteArray outSignText;
+ auto signData = str.toUtf8();
+
+ // The use of multi-threading brings an improvement in UI smoothness
+ gpgme_error_t error;
+ auto thread = QThread::create([&]() {
+ error = ctx->sign(keys, signData, &outSignText, GPGME_SIG_MODE_NORMAL,
+ nullptr, false);
+ });
+ thread->start();
+ while (thread->isRunning()) QApplication::processEvents();
+ thread->deleteLater();
+
+ return outSignText.toBase64();
}
-const rapidjson::Value &ComUtils::getDataValue(const QString &key) const {
- if (is_good) {
- auto k_byte_array = key.toUtf8();
- if (dataVal.HasMember(k_byte_array.data())) {
- return dataVal[k_byte_array.data()];
- }
+const rapidjson::Value &GpgFrontend::ComUtils::getDataValue(
+ const QString &key) const {
+ if (is_good) {
+ auto k_byte_array = key.toUtf8();
+ if (dataVal.HasMember(k_byte_array.data())) {
+ return dataVal[k_byte_array.data()];
}
- throw std::runtime_error("Inner Error");
+ }
+ throw std::runtime_error("Inner Error");
}
-bool ComUtils::checkDataValue(const QString &key) const{
- auto key_byte_array_data = key.toUtf8().constData();
- if (is_good) {
- return dataVal.HasMember(key_byte_array_data);
- } else return false;
+bool GpgFrontend::ComUtils::checkDataValue(const QString &key) const {
+ auto key_byte_array_data = key.toUtf8().constData();
+ if (is_good) {
+ return dataVal.HasMember(key_byte_array_data);
+ } else
+ return false;
}
-void ComUtils::clear() {
- this->dataVal.Clear();
- this->replyDoc.Clear();
- is_good = false;
+void GpgFrontend::ComUtils::clear() {
+ this->dataVal.Clear();
+ this->replyDoc.Clear();
+ is_good = false;
} \ No newline at end of file
diff --git a/src/server/ComUtils.h b/src/server/ComUtils.h
new file mode 100644
index 00000000..f281f256
--- /dev/null
+++ b/src/server/ComUtils.h
@@ -0,0 +1,88 @@
+/**
+ * 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_ZH_CN_TS_COMUTILS_H
+#define GPGFRONTEND_ZH_CN_TS_COMUTILS_H
+
+#include "GpgFrontend.h"
+#include "gpg/GpgContext.h"
+#include "rapidjson/document.h"
+
+namespace GpgFrontend {
+
+class ComUtils : public QWidget {
+ Q_OBJECT
+ public:
+ enum ServiceType {
+ GetServiceToken,
+ ShortenCryptText,
+ GetFullCryptText,
+ UploadPubkey,
+ GetPubkey
+ };
+
+ explicit ComUtils(QWidget *parent)
+ : QWidget(parent),
+ appPath(qApp->applicationDirPath()),
+ settings(RESOURCE_DIR(appPath) + "/conf/gpgfrontend.ini",
+ QSettings::IniFormat) {}
+
+ [[nodiscard]] QString getUrl(ServiceType type) const;
+
+ bool checkServerReply(const QByteArray &reply);
+
+ [[nodiscard]] QString getDataValueStr(const QString &key) const;
+
+ [[nodiscard]] bool checkDataValueStr(const QString &key) const;
+
+ [[nodiscard]] const rapidjson::Value &getDataValue(const QString &key) const;
+
+ [[nodiscard]] bool checkDataValue(const QString &key) const;
+
+ [[nodiscard]] bool checkServiceTokenFormat(const QString &serviceToken) const;
+
+ static QByteArray getSignStringBase64(GpgFrontend::GpgContext *ctx,
+ const QString &str, const GpgKey &key);
+
+ [[nodiscard]] bool good() const { return is_good; }
+
+ QNetworkAccessManager &getNetworkManager() { return networkMgr; }
+
+ void clear();
+
+ private:
+ QString appPath;
+ QSettings settings;
+ rapidjson::Document replyDoc;
+ rapidjson::Value dataVal;
+ QNetworkAccessManager networkMgr;
+ QRegularExpression re_uuid{
+ R"(\b[0-9a-f]{8}\b-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-\b[0-9a-f]{12}\b)"};
+
+ bool is_good = false;
+};
+
+} // namespace GpgFrontend
+
+#endif // GPGFRONTEND_ZH_CN_TS_COMUTILS_H
diff --git a/src/server/api/PubkeyGetter.cpp b/src/server/api/PubkeyGetter.cpp
index 2ba55d11..e2cb8708 100644
--- a/src/server/api/PubkeyGetter.cpp
+++ b/src/server/api/PubkeyGetter.cpp
@@ -1,7 +1,7 @@
/**
- * This file is part of GPGFrontend.
+ * This file is part of GpgFrontend.
*
- * GPGFrontend is free software: you can redistribute it and/or modify
+ * 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.
@@ -24,73 +24,72 @@
#include "server/api/PubkeyGetter.h"
-PubkeyGetter::PubkeyGetter(GpgME::GpgContext *ctx, const QVector<QString> &fprs) : BaseAPI(ComUtils::GetPubkey),
- mCtx(ctx), mFprs(fprs) {
-}
+PubkeyGetter::PubkeyGetter(GpgFrontend::GpgContext *ctx,
+ const QVector<QString> &fprs)
+ : BaseAPI(ComUtils::GetPubkey), mCtx(ctx), mFprs(fprs) {}
void PubkeyGetter::construct_json() {
- document.SetArray();
- QStringList keyIds;
+ document.SetArray();
+ QStringList keyIds;
- rapidjson::Document::AllocatorType &allocator = document.GetAllocator();
+ rapidjson::Document::AllocatorType &allocator = document.GetAllocator();
- for (const auto &fprStr : mFprs) {
- rapidjson::Value fpr;
+ for (const auto &fprStr : mFprs) {
+ rapidjson::Value fpr;
- auto fprByteArray = fprStr.toUtf8();
- fpr.SetString(fprByteArray.constData(), fprByteArray.count());
+ auto fprByteArray = fprStr.toUtf8();
+ fpr.SetString(fprByteArray.constData(), fprByteArray.count());
- document.PushBack(fpr, allocator);
- keyIds.clear();
- }
+ document.PushBack(fpr, allocator);
+ keyIds.clear();
+ }
}
void PubkeyGetter::deal_reply() {
+ const auto &utils = getUtils();
+
+ /**
+ * {
+ * "pubkeys" : [
+ * {
+ * "publicKey" : ...,
+ * "fpr" : ...,
+ * "sha" : ...
+ * },
+ * ...
+ * ]
+ * }
+ */
+
+ if (!utils.checkDataValue("pubkeys")) {
+ QMessageBox::critical(nullptr, _("Error"),
+ _("The communication content with the server does "
+ "not meet the requirements"));
+ } else {
+ auto &pubkeys = utils.getDataValue("pubkeys");
+ qDebug() << "Pubkey Getter" << pubkeys.IsArray()
+ << pubkeys.GetArray().Size();
+ if (pubkeys.IsArray()) {
+ for (const auto &pubkey : pubkeys.GetArray()) {
+ if (pubkey.IsObject() && pubkey.HasMember("publicKey") &&
+ pubkey.HasMember("fpr") && pubkey.HasMember("sha") &&
+ pubkey["publicKey"].IsString() && pubkey["fpr"].IsString() &&
+ pubkey["sha"].IsString()) {
+ auto pubkeyData = QString(pubkey["publicKey"].GetString());
+
+ QCryptographicHash shaGen(QCryptographicHash::Sha256);
+ shaGen.addData(pubkeyData.toUtf8());
+
+ if (shaGen.result().toHex() == pubkey["sha"].GetString()) {
+ mCtx->importKey(pubkeyData.toUtf8());
+ }
+ }
+ }
- const auto &utils = getUtils();
-
- /**
- * {
- * "pubkeys" : [
- * {
- * "publicKey" : ...,
- * "fpr" : ...,
- * "sha" : ...
- * },
- * ...
- * ]
- * }
- */
-
- if (!utils.checkDataValue("pubkeys")) {
- QMessageBox::critical(nullptr, tr("Error"),
- tr("The communication content with the server does not meet the requirements"));
} else {
- auto &pubkeys = utils.getDataValue("pubkeys");
- qDebug() << "Pubkey Getter" << pubkeys.IsArray() << pubkeys.GetArray().Size();
- if (pubkeys.IsArray()) {
- for (const auto &pubkey : pubkeys.GetArray()) {
- if (pubkey.IsObject()
- && pubkey.HasMember("publicKey") && pubkey.HasMember("fpr") && pubkey.HasMember("sha")
- && pubkey["publicKey"].IsString() && pubkey["fpr"].IsString() && pubkey["sha"].IsString()) {
-
- auto pubkeyData = QString(pubkey["publicKey"].GetString());
-
- QCryptographicHash shaGen(QCryptographicHash::Sha256);
- shaGen.addData(pubkeyData.toUtf8());
-
- if (shaGen.result().toHex() == pubkey["sha"].GetString()) {
- mCtx->importKey(pubkeyData.toUtf8());
- }
-
- }
- }
-
- } else {
- QMessageBox::critical(nullptr, tr("Error"),
- tr("The communication content with the server does not meet the requirements"));
- }
+ QMessageBox::critical(nullptr, _("Error"),
+ _("The communication content with the server does "
+ "not meet the requirements"));
}
+ }
}
-
-
diff --git a/include/server/api/PubkeyGetter.h b/src/server/api/PubkeyGetter.h
index 9d3bdb60..6a3d50e9 100644
--- a/include/server/api/PubkeyGetter.h
+++ b/src/server/api/PubkeyGetter.h
@@ -1,7 +1,7 @@
/**
- * This file is part of GPGFrontend.
+ * This file is part of GpgFrontend.
*
- * GPGFrontend is free software: you can redistribute it and/or modify
+ * 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.
@@ -26,8 +26,8 @@
#define GPGFRONTEND_ZH_CN_TS_PUBKEYGETTER_H
#include "GpgFrontend.h"
-#include "server/BaseAPI.h"
#include "gpg/GpgContext.h"
+#include "server/BaseAPI.h"
class ComUtils;
@@ -35,23 +35,18 @@ class ComUtils;
* Get and Import Pubkey from server
*/
class PubkeyGetter : public BaseAPI {
-public:
-
- PubkeyGetter(GpgME::GpgContext *ctx, const QVector<QString> &fprs);
-
-private:
+ public:
+ PubkeyGetter(GpgFrontend::GpgContext *ctx, const QVector<QString> &fprs);
- GpgME::GpgContext *mCtx;
+ private:
+ GpgFrontend::GpgContext *mCtx;
- const QVector<QString> &mFprs;
+ const QVector<QString> &mFprs;
-protected:
-
- void construct_json() final;
-
- void deal_reply() final;
+ protected:
+ void construct_json() final;
+ void deal_reply() final;
};
-
-#endif //GPGFRONTEND_ZH_CN_TS_PUBKEYGETTER_H
+#endif // GPGFRONTEND_ZH_CN_TS_PUBKEYGETTER_H
diff --git a/src/server/api/PubkeyUploader.cpp b/src/server/api/PubkeyUploader.cpp
index c6101c65..35f764d8 100644
--- a/src/server/api/PubkeyUploader.cpp
+++ b/src/server/api/PubkeyUploader.cpp
@@ -1,7 +1,7 @@
/**
- * This file is part of GPGFrontend.
+ * This file is part of GpgFrontend.
*
- * GPGFrontend is free software: you can redistribute it and/or modify
+ * 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.
@@ -24,83 +24,83 @@
#include "server/api/PubkeyUploader.h"
-PubkeyUploader::PubkeyUploader(GpgME::GpgContext *ctx, const QVector<GpgKey> &keys) : BaseAPI(ComUtils::UploadPubkey),
- mCtx(ctx),
- mKeys(keys) {
-}
+PubkeyUploader::PubkeyUploader(GpgFrontend::GpgContext *ctx,
+ const QVector<GpgKey> &keys)
+ : BaseAPI(ComUtils::UploadPubkey), mCtx(ctx), mKeys(keys) {}
void PubkeyUploader::construct_json() {
- document.SetArray();
- QStringList keyIds;
- QCryptographicHash shaGen(QCryptographicHash::Sha256);
-
- auto &allocator = document.GetAllocator();
-
- QVector<QByteArray> keysData;
- for (const auto &key : mKeys) {
- QByteArray keyDataBuf;
- keyIds << key.id;
-
- // The use of multi-threading brings an improvement in UI smoothness
- gpgme_error_t error;
- auto thread = QThread::create([&]() {
- error = mCtx->exportKeys(&keyIds, &keyDataBuf);
- });
- thread->start();
- while (thread->isRunning()) QApplication::processEvents();
- thread->deleteLater();
- keysData.push_back(keyDataBuf);
- keyIds.clear();
- }
-
- int index = 0;
- for (const auto &keyData : keysData) {
- rapidjson::Value publicKeyObj, pubkey, sha, signedFpr;
-
- shaGen.addData(keyData);
- auto shaStr = shaGen.result().toHex();
- shaGen.reset();
-
- auto signFprStr = ComUtils::getSignStringBase64(mCtx, mKeys[index].fpr, mKeys[index]);
- qDebug() << "signFprStr" << signFprStr;
-
- pubkey.SetString(keyData.data(), keyData.count(), allocator);
- sha.SetString(shaStr.data(), shaStr.count(), allocator);
- signedFpr.SetString(signFprStr.data(), signFprStr.count(), allocator);
-
- publicKeyObj.SetObject();
- publicKeyObj.AddMember("publicKey", pubkey, allocator);
- publicKeyObj.AddMember("sha", sha, allocator);
- publicKeyObj.AddMember("signedFpr", signedFpr, allocator);
-
- document.PushBack(publicKeyObj, allocator);
- index++;
- }
+ document.SetArray();
+ QStringList keyIds;
+ QCryptographicHash shaGen(QCryptographicHash::Sha256);
+
+ auto &allocator = document.GetAllocator();
+
+ QVector<QByteArray> keysData;
+ for (const auto &key : mKeys) {
+ QByteArray keyDataBuf;
+ keyIds << key.id;
+
+ // The use of multi-threading brings an improvement in UI smoothness
+ gpgme_error_t error;
+ auto thread = QThread::create(
+ [&]() { error = mCtx->exportKeys(&keyIds, &keyDataBuf); });
+ thread->start();
+ while (thread->isRunning()) QApplication::processEvents();
+ thread->deleteLater();
+ keysData.push_back(keyDataBuf);
+ keyIds.clear();
+ }
+
+ int index = 0;
+ for (const auto &keyData : keysData) {
+ rapidjson::Value publicKeyObj, pubkey, sha, signedFpr;
+
+ shaGen.addData(keyData);
+ auto shaStr = shaGen.result().toHex();
+ shaGen.reset();
+
+ auto signFprStr =
+ ComUtils::getSignStringBase64(mCtx, mKeys[index].fpr, mKeys[index]);
+ qDebug() << "signFprStr" << signFprStr;
+
+ pubkey.SetString(keyData.data(), keyData.count(), allocator);
+ sha.SetString(shaStr.data(), shaStr.count(), allocator);
+ signedFpr.SetString(signFprStr.data(), signFprStr.count(), allocator);
+
+ publicKeyObj.SetObject();
+ publicKeyObj.AddMember("publicKey", pubkey, allocator);
+ publicKeyObj.AddMember("sha", sha, allocator);
+ publicKeyObj.AddMember("signedFpr", signedFpr, allocator);
+
+ document.PushBack(publicKeyObj, allocator);
+ index++;
+ }
}
void PubkeyUploader::deal_reply() {
-
- const auto &utils = getUtils();
-
- /**
- * {
- * "strings" : [
- * "...",
- * "..."
- * ]
- * }
- */
-
- if (!utils.checkDataValue("strings")) {
- QMessageBox::critical(nullptr, tr("Error"),
- tr("The communication content with the server does not meet the requirements"));
+ const auto &utils = getUtils();
+
+ /**
+ * {
+ * "strings" : [
+ * "...",
+ * "..."
+ * ]
+ * }
+ */
+
+ if (!utils.checkDataValue("strings")) {
+ QMessageBox::critical(nullptr, _("Error"),
+ _("The communication content with the server does "
+ "not meet the requirements"));
+ } else {
+ auto &strings = utils.getDataValue("strings");
+ qDebug() << "Pubkey Uploader" << strings.IsArray()
+ << strings.GetArray().Size();
+ if (strings.IsArray() && strings.GetArray().Size() == mKeys.size()) {
+ good = true;
} else {
- auto &strings = utils.getDataValue("strings");
- qDebug() << "Pubkey Uploader" << strings.IsArray() << strings.GetArray().Size();
- if (strings.IsArray() && strings.GetArray().Size() == mKeys.size()) {
- good = true;
- } else {
- good = false;
- }
+ good = false;
}
+ }
}
diff --git a/include/server/api/PubkeyUploader.h b/src/server/api/PubkeyUploader.h
index 7521cdd3..efad27ac 100644
--- a/include/server/api/PubkeyUploader.h
+++ b/src/server/api/PubkeyUploader.h
@@ -1,7 +1,7 @@
/**
- * This file is part of GPGFrontend.
+ * This file is part of GpgFrontend.
*
- * GPGFrontend is free software: you can redistribute it and/or modify
+ * 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.
@@ -26,33 +26,26 @@
#define GPGFRONTEND_ZH_CN_TS_PUBKEYUPLOADER_H
#include "GpgFrontend.h"
-#include "server/BaseAPI.h"
#include "gpg/GpgContext.h"
-
#include "rapidjson/document.h"
+#include "server/BaseAPI.h"
/**
* Upload pubkey into server
*/
class PubkeyUploader : public BaseAPI {
-public:
-
- PubkeyUploader(GpgME::GpgContext *ctx, const QVector<GpgKey> &keys);
-
-private:
+ public:
+ PubkeyUploader(GpgFrontend::GpgContext *ctx, const QVector<GpgKey> &keys);
- const QVector<GpgKey> &mKeys;
+ private:
+ const QVector<GpgKey> &mKeys;
- GpgME::GpgContext *mCtx;
-
-protected:
-
- void construct_json() final;
-
- void deal_reply() final;
+ GpgFrontend::GpgContext *mCtx;
+ protected:
+ void construct_json() final;
+ void deal_reply() final;
};
-
-#endif //GPGFRONTEND_ZH_CN_TS_PUBKEYUPLOADER_H
+#endif // GPGFRONTEND_ZH_CN_TS_PUBKEYUPLOADER_H
diff --git a/include/smtp/SmtpMime b/src/smtp/SmtpMime
index 940996b8..940996b8 100644
--- a/include/smtp/SmtpMime
+++ b/src/smtp/SmtpMime
diff --git a/include/smtp/emailaddress.h b/src/smtp/emailaddress.h
index 90e4c1e9..90e4c1e9 100644
--- a/include/smtp/emailaddress.h
+++ b/src/smtp/emailaddress.h
diff --git a/include/smtp/mimeattachment.h b/src/smtp/mimeattachment.h
index 6b98a65a..6b98a65a 100644
--- a/include/smtp/mimeattachment.h
+++ b/src/smtp/mimeattachment.h
diff --git a/include/smtp/mimecontentformatter.h b/src/smtp/mimecontentformatter.h
index e6e3637f..e6e3637f 100644
--- a/include/smtp/mimecontentformatter.h
+++ b/src/smtp/mimecontentformatter.h
diff --git a/include/smtp/mimefile.h b/src/smtp/mimefile.h
index 46903da9..46903da9 100644
--- a/include/smtp/mimefile.h
+++ b/src/smtp/mimefile.h
diff --git a/include/smtp/mimehtml.h b/src/smtp/mimehtml.h
index 8ce8c454..8ce8c454 100644
--- a/include/smtp/mimehtml.h
+++ b/src/smtp/mimehtml.h
diff --git a/include/smtp/mimeinlinefile.h b/src/smtp/mimeinlinefile.h
index 916f7b76..916f7b76 100644
--- a/include/smtp/mimeinlinefile.h
+++ b/src/smtp/mimeinlinefile.h
diff --git a/src/smtp/mimemessage.cpp b/src/smtp/mimemessage.cpp
index cf653e0a..6c058e89 100644
--- a/src/smtp/mimemessage.cpp
+++ b/src/smtp/mimemessage.cpp
@@ -17,26 +17,26 @@
*/
#include "smtp/mimemessage.h"
-#include "smtp/quotedprintable.h"
#include <QDateTime>
#include <QLocale>
#include <typeinfo>
+#include "smtp/quotedprintable.h"
+
/* [1] Constructors and Destructors */
MimeMessage::MimeMessage(bool createAutoMimeContent)
- : replyTo(nullptr), hEncoding(MimePart::_8Bit) {
- if (createAutoMimeContent)
- this->content = new MimeMultiPart();
+ : replyTo(nullptr), hEncoding(MimePart::_8Bit) {
+ if (createAutoMimeContent) this->content = new MimeMultiPart();
- autoMimeContentCreated = createAutoMimeContent;
+ autoMimeContentCreated = createAutoMimeContent;
}
MimeMessage::~MimeMessage() {
- if (this->autoMimeContentCreated) {
- this->autoMimeContentCreated = false;
- delete (this->content);
- }
+ if (this->autoMimeContentCreated) {
+ this->autoMimeContentCreated = false;
+ delete (this->content);
+ }
}
/* [1] --- */
@@ -45,34 +45,34 @@ MimeMessage::~MimeMessage() {
MimePart &MimeMessage::getContent() { return *content; }
void MimeMessage::setContent(MimePart *content) {
- if (this->autoMimeContentCreated) {
- this->autoMimeContentCreated = false;
- delete (this->content);
- }
- this->content = content;
+ if (this->autoMimeContentCreated) {
+ this->autoMimeContentCreated = false;
+ delete (this->content);
+ }
+ this->content = content;
}
void MimeMessage::setReplyTo(EmailAddress *rto) { replyTo = rto; }
void MimeMessage::setSender(EmailAddress *e) {
- this->sender = e;
- e->setParent(this);
+ this->sender = e;
+ e->setParent(this);
}
void MimeMessage::addRecipient(EmailAddress *rcpt, RecipientType type) {
- switch (type) {
- case To:
- recipientsTo << rcpt;
- break;
- case Cc:
- recipientsCc << rcpt;
- break;
- case Bcc:
- recipientsBcc << rcpt;
- break;
- }
-
- rcpt->setParent(this);
+ switch (type) {
+ case To:
+ recipientsTo << rcpt;
+ break;
+ case Cc:
+ recipientsCc << rcpt;
+ break;
+ case Bcc:
+ recipientsBcc << rcpt;
+ break;
+ }
+
+ rcpt->setParent(this);
}
void MimeMessage::addTo(EmailAddress *rcpt) { this->recipientsTo << rcpt; }
@@ -82,36 +82,36 @@ void MimeMessage::addCc(EmailAddress *rcpt) { this->recipientsCc << rcpt; }
void MimeMessage::addBcc(EmailAddress *rcpt) { this->recipientsBcc << rcpt; }
void MimeMessage::setSubject(const QString &subject) {
- this->subject = subject;
+ this->subject = subject;
}
void MimeMessage::addPart(MimePart *part) {
- if (typeid(*content) == typeid(MimeMultiPart)) {
- ((MimeMultiPart *) content)->addPart(part);
- };
+ if (typeid(*content) == typeid(MimeMultiPart)) {
+ ((MimeMultiPart *)content)->addPart(part);
+ };
}
void MimeMessage::setInReplyTo(const QString &inReplyTo) {
- mInReplyTo = inReplyTo;
+ mInReplyTo = inReplyTo;
}
void MimeMessage::setHeaderEncoding(MimePart::Encoding hEnc) {
- this->hEncoding = hEnc;
+ this->hEncoding = hEnc;
}
const EmailAddress &MimeMessage::getSender() const { return *sender; }
-const QList<EmailAddress *> &
-MimeMessage::getRecipients(RecipientType type) const {
- switch (type) {
- default:
- case To:
- return recipientsTo;
- case Cc:
- return recipientsCc;
- case Bcc:
- return recipientsBcc;
- }
+const QList<EmailAddress *> &MimeMessage::getRecipients(
+ RecipientType type) const {
+ switch (type) {
+ default:
+ case To:
+ return recipientsTo;
+ case Cc:
+ return recipientsCc;
+ case Bcc:
+ return recipientsBcc;
+ }
}
const EmailAddress *MimeMessage::getReplyTo() const { return replyTo; }
@@ -119,13 +119,13 @@ const EmailAddress *MimeMessage::getReplyTo() const { return replyTo; }
const QString &MimeMessage::getSubject() const { return subject; }
const QList<MimePart *> &MimeMessage::getParts() const {
- if (typeid(*content) == typeid(MimeMultiPart)) {
- return ((MimeMultiPart *) content)->getParts();
- } else {
- auto *res = new QList<MimePart *>();
- res->append(content);
- return *res;
- }
+ if (typeid(*content) == typeid(MimeMultiPart)) {
+ return ((MimeMultiPart *)content)->getParts();
+ } else {
+ auto *res = new QList<MimePart *>();
+ res->append(content);
+ return *res;
+ }
}
/* [2] --- */
@@ -133,176 +133,180 @@ const QList<MimePart *> &MimeMessage::getParts() const {
/* [3] Public Methods */
QString MimeMessage::toString() {
- QString mime;
-
- /* =========== MIME HEADER ============ */
-
- /* ---------- Sender / From ----------- */
- mime = "From:";
- if (sender->getName() != "") {
- switch (hEncoding) {
- case MimePart::Base64:
- mime += " =?utf-8?B?" +
- QByteArray().append(sender->getName().toUtf8()).toBase64() + "?=";
- break;
- case MimePart::QuotedPrintable:
- mime += " =?utf-8?Q?" +
- QuotedPrintable::encode(
- QByteArray().append(sender->getName().toUtf8()))
- .replace(' ', "_")
- .replace(':', "=3A") +
- "?=";
- break;
- default:
- mime += " " + sender->getName();
- }
+ QString mime;
+
+ /* =========== MIME HEADER ============ */
+
+ /* ---------- Sender / From ----------- */
+ mime = "From:";
+ if (!sender->getName().isEmpty()) {
+ switch (hEncoding) {
+ case MimePart::Base64:
+ mime += " =?utf-8?B?" +
+ QByteArray().append(sender->getName().toUtf8()).toBase64() +
+ "?=";
+ break;
+ case MimePart::QuotedPrintable:
+ mime += " =?utf-8?Q?" +
+ QuotedPrintable::encode(
+ QByteArray().append(sender->getName().toUtf8()))
+ .replace(' ', "_")
+ .replace(':', "=3A") +
+ "?=";
+ break;
+ default:
+ mime += " " + sender->getName();
}
- mime += " <" + sender->getAddress() + ">\r\n";
- /* ---------------------------------- */
-
- /* ------- Recipients / To ---------- */
- mime += "To:";
- QList<EmailAddress *>::iterator it;
- int i;
- for (i = 0, it = recipientsTo.begin(); it != recipientsTo.end(); ++it, ++i) {
- if (i != 0) {
- mime += ",";
- }
-
- if ((*it)->getName() != "") {
- switch (hEncoding) {
- case MimePart::Base64:
- mime += " =?utf-8?B?" +
- QByteArray().append((*it)->getName().toUtf8()).toBase64() +
- "?=";
- break;
- case MimePart::QuotedPrintable:
- mime += " =?utf-8?Q?" +
- QuotedPrintable::encode(
- QByteArray().append((*it)->getName().toUtf8()))
- .replace(' ', "_")
- .replace(':', "=3A") +
- "?=";
- break;
- default:
- mime += " " + (*it)->getName();
- }
- }
- mime += " <" + (*it)->getAddress() + ">";
+ }
+ mime += " <" + sender->getAddress() + ">\r\n";
+ /* ---------------------------------- */
+
+ /* ------- Recipients / To ---------- */
+ mime += "To:";
+ QList<EmailAddress *>::iterator it;
+ int i;
+ for (i = 0, it = recipientsTo.begin(); it != recipientsTo.end(); ++it, ++i) {
+ if (i != 0) {
+ mime += ",";
}
- mime += "\r\n";
- /* ---------------------------------- */
- /* ------- Recipients / Cc ---------- */
- if (!recipientsCc.empty()) {
- mime += "Cc:";
- }
- for (i = 0, it = recipientsCc.begin(); it != recipientsCc.end(); ++it, ++i) {
- if (i != 0) {
- mime += ",";
- }
-
- if ((*it)->getName() != "") {
- switch (hEncoding) {
- case MimePart::Base64:
- mime += " =?utf-8?B?" +
- QByteArray().append((*it)->getName().toUtf8()).toBase64() +
- "?=";
- break;
- case MimePart::QuotedPrintable:
- mime += " =?utf-8?Q?" +
- QuotedPrintable::encode(
- QByteArray().append((*it)->getName().toUtf8()))
- .replace(' ', "_")
- .replace(':', "=3A") +
- "?=";
- break;
- default:
- mime += " " + (*it)->getName();
- }
- }
- mime += " <" + (*it)->getAddress() + ">";
+ if (!(*it)->getName().isEmpty()) {
+ switch (hEncoding) {
+ case MimePart::Base64:
+ mime += " =?utf-8?B?" +
+ QByteArray().append((*it)->getName().toUtf8()).toBase64() +
+ "?=";
+ break;
+ case MimePart::QuotedPrintable:
+ mime += " =?utf-8?Q?" +
+ QuotedPrintable::encode(
+ QByteArray().append((*it)->getName().toUtf8()))
+ .replace(' ', "_")
+ .replace(':', "=3A") +
+ "?=";
+ break;
+ default:
+ mime += " " + (*it)->getName();
+ }
}
- if (!recipientsCc.empty()) {
- mime += "\r\n";
+ mime += " <" + (*it)->getAddress() + ">";
+ }
+ mime += "\r\n";
+ /* ---------------------------------- */
+
+ /* ------- Recipients / Cc ---------- */
+ if (!recipientsCc.empty()) {
+ mime += "Cc:";
+ }
+ for (i = 0, it = recipientsCc.begin(); it != recipientsCc.end(); ++it, ++i) {
+ if (i != 0) {
+ mime += ",";
}
- /* ---------------------------------- */
- /* ------------ Subject ------------- */
- mime += "Subject: ";
-
- switch (hEncoding) {
+ if ((*it)->getName() != "") {
+ switch (hEncoding) {
case MimePart::Base64:
- mime += "=?utf-8?B?" + QByteArray().append(subject.toUtf8()).toBase64() + "?=";
- break;
+ mime += " =?utf-8?B?" +
+ QByteArray().append((*it)->getName().toUtf8()).toBase64() +
+ "?=";
+ break;
case MimePart::QuotedPrintable:
- mime += "=?utf-8?Q?" +
- QuotedPrintable::encode(QByteArray().append(subject.toUtf8()))
- .replace(' ', "_")
- .replace(':', "=3A") +
- "?=";
- break;
+ mime += " =?utf-8?Q?" +
+ QuotedPrintable::encode(
+ QByteArray().append((*it)->getName().toUtf8()))
+ .replace(' ', "_")
+ .replace(':', "=3A") +
+ "?=";
+ break;
default:
- mime += subject;
+ mime += " " + (*it)->getName();
+ }
}
+ mime += " <" + (*it)->getAddress() + ">";
+ }
+ if (!recipientsCc.empty()) {
mime += "\r\n";
- /* ---------------------------------- */
-
- /* ---------- Reply-To -------------- */
- if (replyTo) {
- mime += "Reply-To: ";
- if (replyTo->getName() != "") {
- switch (hEncoding) {
- case MimePart::Base64:
- mime += " =?utf-8?B?" +
- QByteArray().append(replyTo->getName().toUtf8()).toBase64() + "?=";
- break;
- case MimePart::QuotedPrintable:
- mime += " =?utf-8?Q?" +
- QuotedPrintable::encode(QByteArray().append(replyTo->getName().toUtf8()))
- .replace(' ', "_")
- .replace(':', "=3A") +
- "?=";
- break;
- default:
- mime += " " + replyTo->getName();
- }
- }
- mime += " <" + replyTo->getAddress() + ">\r\n";
- }
-
- /* ---------------------------------- */
-
- mime += "MIME-Version: 1.0\r\n";
- if (!mInReplyTo.isEmpty()) {
- mime += "In-Reply-To: <" + mInReplyTo + ">\r\n";
- mime += "References: <" + mInReplyTo + ">\r\n";
+ }
+ /* ---------------------------------- */
+
+ /* ------------ Subject ------------- */
+ mime += "Subject: ";
+
+ switch (hEncoding) {
+ case MimePart::Base64:
+ mime += "=?utf-8?B?" + QByteArray().append(subject.toUtf8()).toBase64() +
+ "?=";
+ break;
+ case MimePart::QuotedPrintable:
+ mime += "=?utf-8?Q?" +
+ QuotedPrintable::encode(QByteArray().append(subject.toUtf8()))
+ .replace(' ', "_")
+ .replace(':', "=3A") +
+ "?=";
+ break;
+ default:
+ mime += subject;
+ }
+ mime += "\r\n";
+ /* ---------------------------------- */
+
+ /* ---------- Reply-To -------------- */
+ if (replyTo) {
+ mime += "Reply-To: ";
+ if (!replyTo->getName().isEmpty()) {
+ switch (hEncoding) {
+ case MimePart::Base64:
+ mime += " =?utf-8?B?" +
+ QByteArray().append(replyTo->getName().toUtf8()).toBase64() +
+ "?=";
+ break;
+ case MimePart::QuotedPrintable:
+ mime += " =?utf-8?Q?" +
+ QuotedPrintable::encode(
+ QByteArray().append(replyTo->getName().toUtf8()))
+ .replace(' ', "_")
+ .replace(':', "=3A") +
+ "?=";
+ break;
+ default:
+ mime += " " + replyTo->getName();
+ }
}
-
- QDateTime now = QDateTime::currentDateTime();
-#if QT_VERSION_MAJOR < 5 // Qt4 workaround since RFC2822Date isn't defined
- QString shortDayName =
- QLocale::c().dayName(now.date().dayOfWeek(), QLocale::ShortFormat);
- QString shortMonthName =
- QLocale::c().monthName(now.date().month(), QLocale::ShortFormat);
- int utcOffset = now.secsTo(QDateTime(now.date(), now.time(), Qt::UTC)) / 60;
- char timezoneSign = utcOffset >= 0 ? '+' : '-';
- utcOffset = utcOffset >= 0 ? utcOffset : -utcOffset;
- QString timezone = QString("%1%2%3")
- .arg(timezoneSign)
- .arg(utcOffset / 60, 2, 10, QChar('0'))
- .arg(utcOffset % 60, 2, 10, QChar('0'));
- mime += QString("Date: %1\r\n")
- .arg(now.toString("%1, dd %2 yyyy hh:mm:ss %3")
- .arg(shortDayName)
- .arg(shortMonthName)
- .arg(timezone));
-#else // Qt5 supported
- mime += QString("Date: %1\r\n").arg(now.toString(Qt::RFC2822Date));
-#endif // support RFC2822Date
-
- mime += content->toString();
- return mime;
+ mime += " <" + replyTo->getAddress() + ">\r\n";
+ }
+
+ /* ---------------------------------- */
+
+ mime += "MIME-Version: 1.0\r\n";
+ if (!mInReplyTo.isEmpty()) {
+ mime += "In-Reply-To: <" + mInReplyTo + ">\r\n";
+ mime += "References: <" + mInReplyTo + ">\r\n";
+ }
+
+ QDateTime now = QDateTime::currentDateTime();
+#if QT_VERSION_MAJOR < 5 // Qt4 workaround since RFC2822Date isn't defined
+ QString shortDayName =
+ QLocale::c().dayName(now.date().dayOfWeek(), QLocale::ShortFormat);
+ QString shortMonthName =
+ QLocale::c().monthName(now.date().month(), QLocale::ShortFormat);
+ int utcOffset = now.secsTo(QDateTime(now.date(), now.time(), Qt::UTC)) / 60;
+ char timezoneSign = utcOffset >= 0 ? '+' : '-';
+ utcOffset = utcOffset >= 0 ? utcOffset : -utcOffset;
+ QString timezone = QString("%1%2%3")
+ .arg(timezoneSign)
+ .arg(utcOffset / 60, 2, 10, QChar('0'))
+ .arg(utcOffset % 60, 2, 10, QChar('0'));
+ mime += QString("Date: %1\r\n")
+ .arg(now.toString("%1, dd %2 yyyy hh:mm:ss %3")
+ .arg(shortDayName)
+ .arg(shortMonthName)
+ .arg(timezone));
+#else // Qt5 supported
+ mime += QString("Date: %1\r\n").arg(now.toString(Qt::RFC2822Date));
+#endif // support RFC2822Date
+
+ mime += content->toString();
+ return mime;
}
/* [3] --- */
diff --git a/include/smtp/mimemessage.h b/src/smtp/mimemessage.h
index 24e4f108..24e4f108 100644
--- a/include/smtp/mimemessage.h
+++ b/src/smtp/mimemessage.h
diff --git a/src/smtp/mimemultipart.cpp b/src/smtp/mimemultipart.cpp
index 14a813c2..4dd00d1a 100644
--- a/src/smtp/mimemultipart.cpp
+++ b/src/smtp/mimemultipart.cpp
@@ -17,30 +17,31 @@
*/
#include "smtp/mimemultipart.h"
+
#include <QCryptographicHash>
#include <QRandomGenerator>
#include <QTime>
const QString MULTI_PART_NAMES[] = {
- "multipart/mixed", // Mixed
- "multipart/digest", // Digest
- "multipart/alternative", // Alternative
- "multipart/related", // Related
- "multipart/report", // Report
- "multipart/signed", // Signed
- "multipart/encrypted" // Encrypted
+ "multipart/mixed", // Mixed
+ "multipart/digest", // Digest
+ "multipart/alternative", // Alternative
+ "multipart/related", // Related
+ "multipart/report", // Report
+ "multipart/signed", // Signed
+ "multipart/encrypted" // Encrypted
};
MimeMultiPart::MimeMultiPart(MultiPartType type) {
- this->type = type;
- this->cType = MULTI_PART_NAMES[this->type];
- this->cEncoding = _8Bit;
+ this->type = type;
+ this->cType = MULTI_PART_NAMES[this->type];
+ this->cEncoding = _8Bit;
- QRandomGenerator generator;
+ QRandomGenerator generator;
- QCryptographicHash md5(QCryptographicHash::Md5);
- md5.addData(QByteArray().append((char) generator.generate()));
- cBoundary = md5.result().toHex();
+ QCryptographicHash md5(QCryptographicHash::Md5);
+ md5.addData(QByteArray().append((char)generator.generate()));
+ cBoundary = md5.result().toHex();
}
void MimeMultiPart::addPart(MimePart *part) { parts.append(part); }
@@ -48,23 +49,23 @@ void MimeMultiPart::addPart(MimePart *part) { parts.append(part); }
const QList<MimePart *> &MimeMultiPart::getParts() const { return parts; }
void MimeMultiPart::prepare() {
- QList<MimePart *>::iterator it;
+ QList<MimePart *>::iterator it;
- content = "";
- for (it = parts.begin(); it != parts.end(); it++) {
- content += QString("--" + cBoundary + "\r\n").toUtf8();
- (*it)->prepare();
- content += (*it)->toString().toUtf8();
- };
+ content.clear();
+ for (it = parts.begin(); it != parts.end(); it++) {
+ content += QString("--" + cBoundary + "\r\n").toUtf8();
+ (*it)->prepare();
+ content += (*it)->toString().toUtf8();
+ };
- content += QString("--" + cBoundary + "--\r\n").toUtf8();
+ content += QString("--" + cBoundary + "--\r\n").toUtf8();
- MimePart::prepare();
+ MimePart::prepare();
}
void MimeMultiPart::setMimeType(const MultiPartType type) {
- this->type = type;
- this->cType = MULTI_PART_NAMES[type];
+ this->type = type;
+ this->cType = MULTI_PART_NAMES[type];
}
MimeMultiPart::MultiPartType MimeMultiPart::getMimeType() const { return type; }
diff --git a/include/smtp/mimemultipart.h b/src/smtp/mimemultipart.h
index b829a66f..b829a66f 100644
--- a/include/smtp/mimemultipart.h
+++ b/src/smtp/mimemultipart.h
diff --git a/src/smtp/mimepart.cpp b/src/smtp/mimepart.cpp
index 5d33884d..10aa6cbc 100644
--- a/src/smtp/mimepart.cpp
+++ b/src/smtp/mimepart.cpp
@@ -17,14 +17,15 @@
*/
#include "smtp/mimepart.h"
+
#include "smtp/quotedprintable.h"
/* [1] Constructors and Destructors */
MimePart::MimePart() {
- cEncoding = _7Bit;
- prepared = false;
- cBoundary = "";
+ cEncoding = _7Bit;
+ prepared = false;
+ cBoundary.clear();
}
/* [1] --- */
@@ -32,13 +33,13 @@ MimePart::MimePart() {
/* [2] Getters and Setters */
void MimePart::setContent(const QByteArray &content) {
- this->content = content;
+ this->content = content;
}
void MimePart::setHeader(const QString &header) { this->header = header; }
void MimePart::addHeaderLine(const QString &line) {
- this->header += line + "\r\n";
+ this->header += line + "\r\n";
}
const QString &MimePart::getHeader() const { return header; }
@@ -66,7 +67,7 @@ void MimePart::setEncoding(Encoding enc) { this->cEncoding = enc; }
MimePart::Encoding MimePart::getEncoding() const { return this->cEncoding; }
MimeContentFormatter &MimePart::getContentFormatter() {
- return this->formatter;
+ return this->formatter;
}
/* [2] --- */
@@ -74,10 +75,9 @@ MimeContentFormatter &MimePart::getContentFormatter() {
/* [3] Public methods */
QString MimePart::toString() {
- if (!prepared)
- prepare();
+ if (!prepared) prepare();
- return mimeString;
+ return mimeString;
}
/* [3] --- */
@@ -85,75 +85,74 @@ QString MimePart::toString() {
/* [4] Protected methods */
void MimePart::prepare() {
- mimeString = QString();
-
- /* === Header Prepare === */
-
- /* Content-Type */
- mimeString.append("Content-Type: ").append(cType);
-
- if (cName != "")
- mimeString.append("; name=\"").append(cName).append("\"");
-
- if (cCharset != "")
- mimeString.append("; charset=").append(cCharset);
-
- if (cBoundary != "")
- mimeString.append("; boundary=").append(cBoundary);
-
- mimeString.append("\r\n");
- /* ------------ */
-
- /* Content-Transfer-Encoding */
- mimeString.append("Content-Transfer-Encoding: ");
- switch (cEncoding) {
- case _7Bit:
- mimeString.append("7bit\r\n");
- break;
- case _8Bit:
- mimeString.append("8bit\r\n");
- break;
- case Base64:
- mimeString.append("base64\r\n");
- break;
- case QuotedPrintable:
- mimeString.append("quoted-printable\r\n");
- break;
- }
- /* ------------------------ */
-
- /* Content-Id */
- if (cId != NULL)
- mimeString.append("Content-ID: <").append(cId).append(">\r\n");
- /* ---------- */
-
- /* Addition header lines */
-
- mimeString.append(header).append("\r\n");
-
- /* ------------------------- */
-
- /* === End of Header Prepare === */
-
- /* === Content === */
- switch (cEncoding) {
- case _7Bit:
- mimeString.append(QString(content).toLatin1());
- break;
- case _8Bit:
- mimeString.append(content);
- break;
- case Base64:
- mimeString.append(formatter.format(content.toBase64()));
- break;
- case QuotedPrintable:
- mimeString.append(formatter.format(QuotedPrintable::encode(content), true));
- break;
- }
- mimeString.append("\r\n");
- /* === End of Content === */
-
- prepared = true;
+ mimeString = QString();
+
+ /* === Header Prepare === */
+
+ /* Content-Type */
+ mimeString.append("Content-Type: ").append(cType);
+
+ if (!cName.isEmpty())
+ mimeString.append("; name=\"").append(cName).append("\"");
+
+ if (!cCharset.isEmpty()) mimeString.append("; charset=").append(cCharset);
+
+ if (!cBoundary.isEmpty()) mimeString.append("; boundary=").append(cBoundary);
+
+ mimeString.append("\r\n");
+ /* ------------ */
+
+ /* Content-Transfer-Encoding */
+ mimeString.append("Content-Transfer-Encoding: ");
+ switch (cEncoding) {
+ case _7Bit:
+ mimeString.append("7bit\r\n");
+ break;
+ case _8Bit:
+ mimeString.append("8bit\r\n");
+ break;
+ case Base64:
+ mimeString.append("base64\r\n");
+ break;
+ case QuotedPrintable:
+ mimeString.append("quoted-printable\r\n");
+ break;
+ }
+ /* ------------------------ */
+
+ /* Content-Id */
+ if (cId != nullptr)
+ mimeString.append("Content-ID: <").append(cId).append(">\r\n");
+ /* ---------- */
+
+ /* Addition header lines */
+
+ mimeString.append(header).append("\r\n");
+
+ /* ------------------------- */
+
+ /* === End of Header Prepare === */
+
+ /* === Content === */
+ switch (cEncoding) {
+ case _7Bit:
+ mimeString.append(QString(content).toLatin1());
+ break;
+ case _8Bit:
+ mimeString.append(content);
+ break;
+ case Base64:
+ mimeString.append(formatter.format(content.toBase64()));
+ break;
+ case QuotedPrintable:
+ mimeString.append(
+ formatter.format(QuotedPrintable::encode(content), true));
+ break;
+ }
+ mimeString.append("\r\n");
+ /* === End of Content === */
+
+ prepared = true;
}
/* [4] --- */
diff --git a/include/smtp/mimepart.h b/src/smtp/mimepart.h
index 1a1386de..1a1386de 100644
--- a/include/smtp/mimepart.h
+++ b/src/smtp/mimepart.h
diff --git a/include/smtp/mimetext.h b/src/smtp/mimetext.h
index c21a1c5e..c21a1c5e 100644
--- a/include/smtp/mimetext.h
+++ b/src/smtp/mimetext.h
diff --git a/include/smtp/quotedprintable.h b/src/smtp/quotedprintable.h
index 00ca3cf8..00ca3cf8 100644
--- a/include/smtp/quotedprintable.h
+++ b/src/smtp/quotedprintable.h
diff --git a/include/smtp/smtpclient.h b/src/smtp/smtpclient.h
index 29c507dc..29c507dc 100644
--- a/include/smtp/smtpclient.h
+++ b/src/smtp/smtpclient.h
diff --git a/include/smtp/smtpexports.h b/src/smtp/smtpexports.h
index 9ca12bae..4bad0da0 100644
--- a/include/smtp/smtpexports.h
+++ b/src/smtp/smtpexports.h
@@ -1,10 +1,10 @@
-#ifndef SMTPEXPORTS_H
-#define SMTPEXPORTS_H
-
-#ifdef SMTP_BUILD
-#define SMTP_EXPORT
-#else
-#define SMTP_EXPORT
-#endif
-
-#endif // SMTPEXPORTS_H
+#ifndef SMTPEXPORTS_H
+#define SMTPEXPORTS_H
+
+#ifdef SMTP_BUILD
+#define SMTP_EXPORT
+#else
+#define SMTP_EXPORT
+#endif
+
+#endif // SMTPEXPORTS_H
diff --git a/src/ui/CMakeLists.txt b/src/ui/CMakeLists.txt
index b6552227..b80da2ec 100644
--- a/src/ui/CMakeLists.txt
+++ b/src/ui/CMakeLists.txt
@@ -5,10 +5,17 @@ aux_source_directory(./keygen UI_SOURCE)
aux_source_directory(./main_window UI_SOURCE)
aux_source_directory(./help UI_SOURCE)
aux_source_directory(./settings UI_SOURCE)
+aux_source_directory(./function UI_SOURCE)
+
+if (SMTP_SUPPORT)
+ message(STATUS "Build SMTP Support")
+ aux_source_directory(./smtp UI_SOURCE)
+endif ()
+
add_library(gpgfrontend-ui STATIC ${UI_SOURCE})
target_link_libraries(gpgfrontend-ui
Qt5::Network Qt5::PrintSupport Qt5::Widgets Qt5::Test Qt5::Core)
-message(STATUS "UI SOURCE ${UI_SOURCE}") \ No newline at end of file
+target_compile_features(gpgfrontend-ui PUBLIC cxx_std_17) \ No newline at end of file
diff --git a/src/ui/FileEncryptionDialog.cpp b/src/ui/FileEncryptionDialog.cpp
index 23ec0b2a..3e1e9b9a 100755
--- a/src/ui/FileEncryptionDialog.cpp
+++ b/src/ui/FileEncryptionDialog.cpp
@@ -1,7 +1,7 @@
/**
- * This file is part of GPGFrontend.
+ * This file is part of GpgFrontend.
*
- * GPGFrontend is free software: you can redistribute it and/or modify
+ * 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.
@@ -24,266 +24,249 @@
#include "ui/FileEncryptionDialog.h"
-FileEncryptionDialog::FileEncryptionDialog(GpgME::GpgContext *ctx, QStringList keyList, DialogAction action,
- QWidget *parent)
- : QDialog(parent), mAction(action), mCtx(ctx){
+#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(_("Decrypt File"));
+ } else if (mAction == Encrypt) {
+ setWindowTitle(_("Encrypt File"));
+ } else if (mAction == Sign) {
+ setWindowTitle(_("Sign File"));
+ } else if (mAction == Verify) {
+ setWindowTitle(_("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(_("Input Parameters"));
+
+ /* Setup input & Outputfileselection*/
+ inputFileEdit = new QLineEdit();
+ auto* fb1 = new QPushButton("Select");
+ connect(fb1, SIGNAL(clicked()), this, SLOT(slotSelectInputFile()));
+ auto* fl1 = new QLabel(_("Target File"));
+ fl1->setBuddy(inputFileEdit);
+
+ outputFileEdit = new QLineEdit();
+ auto* fb2 = new QPushButton("Select");
+ connect(fb2, SIGNAL(clicked()), this, SLOT(slotSelectOutputFile()));
+ auto* fl2 = new QLabel(_("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(_("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();
+}
- if (mAction == Decrypt) {
- setWindowTitle(tr("Decrypt File"));
- } else if (mAction == Encrypt) {
- setWindowTitle(tr("Encrypt File"));
+void FileEncryptionDialog::slotSelectInputFile() {
+ QString path;
+ if (inputFileEdit->text().size() > 0) {
+ path = QFileInfo(inputFileEdit->text()).absolutePath();
+ }
+
+ // QString infileName = QFileDialog::getOpenFileName(this, _("Open File"),
+ // path, _("Files") + _("All Files (*)"));
+ QString infileName = QFileDialog::getOpenFileName(this, _("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) {
- setWindowTitle(tr("Sign File"));
+ outputFileEdit->setText(infileName + ".sig");
} 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);
+ signFileEdit->setText(infileName + ".sig");
} 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(!GpgME::GpgContext::checkIfKeyCanEncr(key)) return false;
- else return true;
- });
-
- if(mAction == Sign)
- mKeyList->setFilter([](const GpgKey &key) -> bool {
- if(!GpgME::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();
-
-}
-
-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");
- }
- }
+ 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, _("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, _("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;
- }
- }
-
- 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;
- }
+ QFile infile;
+ infile.setFileName(inputFileEdit->text());
+ if (!infile.open(QIODevice::ReadOnly)) {
+ statusLabel->setText(_("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 = GpgKeyGetter::GetInstance().GetKeys(key_ids);
+
+ 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, _("Error"),
+ _("Error Occurred During Encryption"));
+ 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 == 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, _("Error"),
+ _("Error Occurred During Decryption"));
+ 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;
+ }
+
+ 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, _("Error"),
+ _("Error Occurred During Signature"));
+ 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;
- }
- }
+ 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;
+ }
- if (!outfile.open(QFile::WriteOnly)) {
- QMessageBox::warning(this, tr("File"),
- tr("Cannot write file %1:\n%2.")
- .arg(outputFileEdit->text())
- .arg(outfile.errorString()));
- return;
- }
+ write_buffer_to_file(outputFileEdit->text().toStdString(), *out_data);
- 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();
-}
+void FileEncryptionDialog::slotShowKeyList() { mKeyList->show(); }
-void FileEncryptionDialog::slotHideKeyList() {
- mKeyList->hide();
-}
+void FileEncryptionDialog::slotHideKeyList() { mKeyList->hide(); }
+
+} // namespace GpgFrontend::UI
diff --git a/src/ui/FileEncryptionDialog.h b/src/ui/FileEncryptionDialog.h
new file mode 100755
index 00000000..613f84e7
--- /dev/null
+++ b/src/ui/FileEncryptionDialog.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]> starting on May 12, 2021.
+ *
+ */
+
+#ifndef __FILEENCRYPTIONDIALOG_H__
+#define __FILEENCRYPTIONDIALOG_H__
+
+#include "VerifyDetailsDialog.h"
+#include "gpg/GpgContext.h"
+#include "ui/GpgFrontendUI.h"
+#include "ui/widgets/KeyList.h"
+
+namespace GpgFrontend::UI {
+
+/**
+ * @brief
+ *
+ * @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(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;
+};
+
+} // namespace GpgFrontend::UI
+
+#endif // __FILEENCRYPTIONDIALOG_H__
diff --git a/src/ui/FindWidget.cpp b/src/ui/FindWidget.cpp
index fce62223..6326b119 100644
--- a/src/ui/FindWidget.cpp
+++ b/src/ui/FindWidget.cpp
@@ -1,7 +1,7 @@
/**
- * This file is part of GPGFrontend.
+ * This file is part of GpgFrontend.
*
- * GPGFrontend is free software: you can redistribute it and/or modify
+ * 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.
@@ -24,135 +24,140 @@
#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), QString(),
+ this);
+ auto* nextButton = new QPushButton(QIcon(":button_next.png"), QString());
+ auto* previousButton = new QPushButton(QIcon(":button_previous.png"), "");
+
+ auto* notificationWidgetLayout = new QHBoxLayout(this);
+ notificationWidgetLayout->setContentsMargins(10, 0, 0, 0);
+ notificationWidgetLayout->addWidget(new QLabel(QString(_("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..e4cbdaab 100644
--- a/include/ui/FindWidget.h
+++ b/src/ui/FindWidget.h
@@ -1,7 +1,7 @@
/**
- * This file is part of GPGFrontend.
+ * This file is part of GpgFrontend.
*
- * GPGFrontend is free software: you can redistribute it and/or modify
+ * 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.
@@ -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..01f82822
--- /dev/null
+++ b/src/ui/GpgFrontendUI.h
@@ -0,0 +1,53 @@
+/**
+ * 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>
+
+#undef LIBCONFIGXX_STATIC
+#define LIBCONFIGXX_STATIC
+#include <libconfig.h++>
+
+/**
+ * Resources File(s) Path Vars
+ */
+#if defined(MACOS) && defined(RELEASE)
+#define RESOURCE_DIR(appDir) (appDir + "/../Resources/")
+#define RESOURCE_DIR_BOOST_PATH(appDir) (appDir / ".." / "Resources")
+#elif defined(LINUX) && defined(RELEASE)
+#define RESOURCE_DIR(appDir) (appDir + "/../share/")
+#define RESOURCE_DIR_BOOST_PATH(appDir) (appDir / ".." / "share")
+#else
+#define RESOURCE_DIR(appDir) (appDir)
+#define RESOURCE_DIR_BOOST_PATH(appDir) (appDir)
+#endif
+
+#endif // GPGFRONTEND_GPGFRONTENDUI_H
diff --git a/src/ui/KeyImportDetailDialog.cpp b/src/ui/KeyImportDetailDialog.cpp
index 8d303886..48d1e9ee 100644
--- a/src/ui/KeyImportDetailDialog.cpp
+++ b/src/ui/KeyImportDetailDialog.cpp
@@ -1,7 +1,7 @@
/**
- * This file is part of GPGFrontend.
+ * This file is part of GpgFrontend.
*
- * GPGFrontend is free software: you can redistribute it and/or modify
+ * 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.
@@ -22,145 +22,177 @@
*
*/
-#include <ui/KeyImportDetailDialog.h>
+#include "ui/KeyImportDetailDialog.h"
-KeyImportDetailDialog::KeyImportDetailDialog(GpgME::GpgContext *ctx, GpgImportInformation result, bool automatic,
- QWidget *parent)
- : QDialog(parent), mCtx(ctx), mResult(std::move(result)) {
+#include "gpg/function/GpgKeyGetter.h"
- // 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();
+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(parent, _("Key Update Details"),
+ _("No keys found"));
+ else
+ QMessageBox::information(parent, _("Key Import Details"),
+ _("No keys found to import"));
+ emit finished(0);
+ this->close();
+ this->deleteLater();
+ } else {
+ auto* mv_box = new QVBoxLayout();
this->createGeneralInfoBox();
- mvbox->addWidget(generalInfoBox);
+ mv_box->addWidget(generalInfoBox);
this->createKeysTable();
- mvbox->addWidget(keysTable);
+ mv_box->addWidget(keysTable);
this->createButtonBox();
- mvbox->addWidget(buttonBox);
+ mv_box->addWidget(buttonBox);
- this->setLayout(mvbox);
- if(automatic)
- this->setWindowTitle(tr("Key Update Details"));
+ this->setLayout(mv_box);
+ if (automatic)
+ this->setWindowTitle(_("Key Update Details"));
else
- this->setWindowTitle(tr("Key Import Details"));
+ this->setWindowTitle(_("Key Import Details"));
+ auto pos = QPoint(100, 100);
+ LOG(INFO) << "parent" << parent;
+ if (parent) pos += parent->pos();
+ this->move(pos);
this->resize(QSize(600, 300));
this->setModal(true);
- this->exec();
+ this->show();
+ }
}
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(_("General key info"));
+ auto* generalInfoBoxLayout = new QGridLayout(generalInfoBox);
+
+ generalInfoBoxLayout->addWidget(new QLabel(QString(_("Considered")) + ": "),
+ 1, 0);
+ generalInfoBoxLayout->addWidget(
+ new QLabel(QString::number(mResult.considered)), 1, 1);
+ int row = 2;
+ if (mResult.unchanged != 0) {
+ generalInfoBoxLayout->addWidget(
+ new QLabel(QString(_("Public unchanged")) + ": "), row, 0);
+ generalInfoBoxLayout->addWidget(
+ new QLabel(QString::number(mResult.unchanged)), row, 1);
+ row++;
+ }
+ if (mResult.imported != 0) {
+ generalInfoBoxLayout->addWidget(new QLabel(QString(_("Imported")) + ": "),
+ row, 0);
+ generalInfoBoxLayout->addWidget(
+ new QLabel(QString::number(mResult.imported)), row, 1);
+ row++;
+ }
+ if (mResult.not_imported != 0) {
+ generalInfoBoxLayout->addWidget(
+ new QLabel(QString(_("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(QString(_("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(QString(_("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(QString(_("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->getKeyByFpr(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();
+ LOG(INFO) << "KeyImportDetailDialog::createKeysTable() Called";
+
+ keysTable = new QTableWidget(this);
+ keysTable->setRowCount(0);
+ keysTable->setColumnCount(4);
+ keysTable->setEditTriggers(QAbstractItemView::NoEditTriggers);
+ // Nothing is selectable
+ keysTable->setSelectionMode(QAbstractItemView::NoSelection);
+
+ QStringList headerLabels;
+ headerLabels << _("Name") << _("Email") << _("Status") << _("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(_("Private"));
+ keyStatus = keyStatus - 16;
+ } else {
+ statusString.append(_("Public"));
+ }
+ if (keyStatus == 0) {
+ statusString.append(", " + QString(_("Unchanged")));
+ } else {
+ if (keyStatus == 1) {
+ statusString.append(", " + QString(_("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(", " + QString(_("New Subkey")));
+ keyStatus = keyStatus - 8;
+ }
+ if (keyStatus > 3) {
+ statusString.append(", " + QString(_("New Signature")));
+ keyStatus = keyStatus - 4;
+ }
+ if (keyStatus > 1) {
+ statusString.append(", " + QString(_("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 216cdcd0..fe63baaa 100644
--- a/include/ui/KeyImportDetailDialog.h
+++ b/src/ui/KeyImportDetailDialog.h
@@ -1,7 +1,7 @@
/**
- * This file is part of GPGFrontend.
+ * This file is part of GpgFrontend.
*
- * GPGFrontend is free software: you can redistribute it and/or modify
+ * 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.
@@ -25,27 +25,31 @@
#ifndef __KEYIMPORTDETAILSDIALOG_H__
#define __KEYIMPORTDETAILSDIALOG_H__
+#include <gpg/function/GpgKeyImportExportor.h>
+
#include "gpg/GpgContext.h"
+#include "ui/GpgFrontendUI.h"
+
+namespace GpgFrontend::UI {
+class KeyImportDetailDialog : public QDialog {
+ Q_OBJECT
+
+ public:
+ KeyImportDetailDialog(GpgImportInformation result, bool automatic,
+ QWidget* parent = nullptr);
+
+ private:
+ void createGeneralInfoBox();
+ void createKeysTable();
+ void createButtonBox();
+ static QString getStatusString(int keyStatus);
-class KeyImportDetailDialog : public QDialog
-{
- Q_OBJECT
-
-public:
- KeyImportDetailDialog(GpgME::GpgContext *ctx, GpgImportInformation result, bool automatic, QWidget *parent = 0);
-
-private:
- void createGeneralInfoBox();
- void createKeysTable();
- void createButtonBox();
- static QString getStatusString(int keyStatus);
-
- QTableWidget *keysTable{};
- GpgME::GpgContext *mCtx;
- QGroupBox *generalInfoBox{};
- QGroupBox *keyInfoBox{};
- QDialogButtonBox *buttonBox{};
- GpgImportInformation mResult;
+ QTableWidget* keysTable{};
+ 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 77f3b760..7459906d 100755
--- a/src/ui/KeyMgmt.cpp
+++ b/src/ui/KeyMgmt.cpp
@@ -1,7 +1,7 @@
/**
- * This file is part of GPGFrontend.
+ * This file is part of GpgFrontend.
*
- * GPGFrontend is free software: you can redistribute it and/or modify
+ * 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.
@@ -26,331 +26,384 @@
#include <utility>
-KeyMgmt::KeyMgmt(GpgME::GpgContext *ctx, QWidget *parent) :
- QMainWindow(parent), appPath(qApp->applicationDirPath()),
- settings(RESOURCE_DIR(appPath) + "/conf/gpgfrontend.ini", QSettings::IniFormat) {
- mCtx = ctx;
+#include "gpg/function/GpgKeyGetter.h"
+#include "gpg/function/GpgKeyImportExportor.h"
+#include "gpg/function/GpgKeyOpera.h"
+#include "ui/SignalStation.h"
+#include "ui/UserInterfaceUtils.h"
+#include "ui/settings/GlobalSettingStation.h"
+
+namespace GpgFrontend::UI {
+KeyMgmt::KeyMgmt(QWidget* parent) : QMainWindow(parent) {
+ /* 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)));
+
+ auto& settings = GlobalSettingStation::GetInstance().GetUISettings();
+
+ try {
+ int width = settings.lookup("window.icon_size.width");
+ int height = settings.lookup("window.icon_size.height");
+
+ this->setIconSize(QSize(width, height));
+
+ } catch (...) {
+ LOG(ERROR) << _("Setting Operation Error") << _("icon_size");
+ }
+
+ // icon_style
+ try {
+ int s_icon_style = settings.lookup("window.icon_style");
+ auto icon_style = static_cast<Qt::ToolButtonStyle>(s_icon_style);
+ this->setToolButtonStyle(icon_style);
+ } catch (...) {
+ LOG(ERROR) << _("Setting Operation Error") << _("icon_style");
+ }
+
+ auto pos = QPoint(50, 50);
+ LOG(INFO) << "parent" << parent;
+ if (parent) pos += parent->pos();
+ LOG(INFO) << "pos default" << pos.x() << pos.y();
+ auto size = QSize(900, 600);
+
+ try {
+ int x, y, width, height;
+ x = settings.lookup("window.key_management.position.x");
+ y = settings.lookup("window.key_management.position.y");
+ width = settings.lookup("window.key_management.size.width");
+ height = settings.lookup("window.key_management.size.height");
+ pos = QPoint(x, y);
+ size = QSize(width, height);
+
+ std::string window_state =
+ settings.lookup("window.key_management.window_state");
- /* 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)));
+ // state sets pos & size of dock-widgets
+ this->restoreState(
+ QByteArray::fromBase64(QByteArray::fromStdString(window_state)));
- /* Restore the iconstyle */
- this->settings.sync();
+ } catch (...) {
+ LOG(WARNING) << "cannot read pos or size from settings";
+ }
- QSize iconSize = settings.value("toolbar/iconsize", QSize(24, 24)).toSize();
- settings.setValue("toolbar/iconsize", iconSize);
+ this->resize(size);
+ this->move(pos);
- Qt::ToolButtonStyle buttonStyle = static_cast<Qt::ToolButtonStyle>(settings.value("toolbar/iconstyle",
- Qt::ToolButtonTextUnderIcon).toUInt());
- this->setIconSize(iconSize);
- this->setToolButtonStyle(buttonStyle);
+ setWindowTitle(_("KeyPair Management"));
+ mKeyList->addMenuAction(deleteSelectedKeysAct);
+ mKeyList->addMenuAction(showKeyDetailsAct);
- // 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);
+ connect(this, SIGNAL(signalKeyStatusUpdated()), SignalStation::GetInstance(),
+ SIGNAL(KeyDatabaseRefresh()));
}
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(_("Open"), this);
+ openKeyFileAct->setShortcut(QKeySequence(_("Ctrl+O")));
+ openKeyFileAct->setToolTip(_("Open Key File"));
+ connect(importKeyFromFileAct, &QAction::triggered, this,
+ [&]() { CommonUtils::GetInstance()->slotImportKeyFromFile(this); });
+
+ closeAct = new QAction(_("Close"), this);
+ closeAct->setShortcut(QKeySequence(_("Ctrl+Q")));
+ closeAct->setIcon(QIcon(":exit.png"));
+ closeAct->setToolTip(_("Close"));
+ connect(closeAct, SIGNAL(triggered()), this, SLOT(close()));
+
+ generateKeyPairAct = new QAction(_("New Keypair"), this);
+ generateKeyPairAct->setShortcut(QKeySequence(_("Ctrl+N")));
+ generateKeyPairAct->setIcon(QIcon(":key_generate.png"));
+ generateKeyPairAct->setToolTip(_("Generate KeyPair"));
+ connect(generateKeyPairAct, SIGNAL(triggered()), this,
+ SLOT(slotGenerateKeyDialog()));
+
+ generateSubKeyAct = new QAction(_("New Subkey"), this);
+ generateSubKeyAct->setShortcut(QKeySequence(_("Ctrl+Shift+N")));
+ generateSubKeyAct->setIcon(QIcon(":key_generate.png"));
+ generateSubKeyAct->setToolTip(_("Generate Subkey For Selected KeyPair"));
+ connect(generateSubKeyAct, SIGNAL(triggered()), this,
+ SLOT(slotGenerateSubKey()));
+
+ importKeyFromFileAct = new QAction(_("File"), this);
+ importKeyFromFileAct->setIcon(QIcon(":import_key_from_file.png"));
+ importKeyFromFileAct->setToolTip(_("Import New Key From File"));
+ connect(importKeyFromFileAct, &QAction::triggered, this,
+ [&]() { CommonUtils::GetInstance()->slotImportKeyFromFile(this); });
+
+ importKeyFromClipboardAct = new QAction(_("Clipboard"), this);
+ importKeyFromClipboardAct->setIcon(QIcon(":import_key_from_clipboard.png"));
+ importKeyFromClipboardAct->setToolTip(_("Import New Key From Clipboard"));
+ connect(importKeyFromClipboardAct, &QAction::triggered, this, [&]() {
+ CommonUtils::GetInstance()->slotImportKeyFromClipboard(this);
+ });
+
+ importKeyFromKeyServerAct = new QAction(_("Keyserver"), this);
+ importKeyFromKeyServerAct->setIcon(QIcon(":import_key_from_server.png"));
+ importKeyFromKeyServerAct->setToolTip(_("Import New Key From Keyserver"));
+ connect(importKeyFromKeyServerAct, &QAction::triggered, this, [&]() {
+ CommonUtils::GetInstance()->slotImportKeyFromKeyServer(this);
+ });
+
+ exportKeyToClipboardAct = new QAction(_("Export To Clipboard"), this);
+ exportKeyToClipboardAct->setIcon(QIcon(":export_key_to_clipboard.png"));
+ exportKeyToClipboardAct->setToolTip(_("Export Selected Key(s) To Clipboard"));
+ connect(exportKeyToClipboardAct, SIGNAL(triggered()), this,
+ SLOT(slotExportKeyToClipboard()));
+
+ exportKeyToFileAct = new QAction(_("Export To File"), this);
+ exportKeyToFileAct->setIcon(QIcon(":export_key_to_file.png"));
+ exportKeyToFileAct->setToolTip(_("Export Selected Key(s) To File"));
+ connect(exportKeyToFileAct, SIGNAL(triggered()), this,
+ SLOT(slotExportKeyToFile()));
+
+ deleteSelectedKeysAct = new QAction(_("Delete Selected Key(s)"), this);
+ deleteSelectedKeysAct->setToolTip(_("Delete the Selected keys"));
+ connect(deleteSelectedKeysAct, SIGNAL(triggered()), this,
+ SLOT(slotDeleteSelectedKeys()));
+
+ deleteCheckedKeysAct = new QAction(_("Delete Checked Key(s)"), this);
+ deleteCheckedKeysAct->setToolTip(_("Delete the Checked keys"));
+ deleteCheckedKeysAct->setIcon(QIcon(":button_delete.png"));
+ connect(deleteCheckedKeysAct, SIGNAL(triggered()), this,
+ SLOT(slotDeleteCheckedKeys()));
+
+ showKeyDetailsAct = new QAction(_("Show Key Details"), this);
+ showKeyDetailsAct->setToolTip(_("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(_("File"));
+ fileMenu->addAction(openKeyFileAct);
+ fileMenu->addAction(closeAct);
+
+ keyMenu = menuBar()->addMenu(_("Key"));
+ generateKeyMenu = keyMenu->addMenu(_("Generate Key"));
+ generateKeyMenu->addAction(generateKeyPairAct);
+ generateKeyMenu->addAction(generateSubKeyAct);
+
+ importKeyMenu = keyMenu->addMenu(_("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);
-
-}
-
-void KeyMgmt::slotImportKeys(QByteArray inBuffer) {
- GpgImportInformation result = mCtx->importKey(std::move(inBuffer));
- new KeyImportDetailDialog(mCtx, 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();
- }
-}
-
-void KeyMgmt::slotImportKeyFromKeyServer() {
- importDialog = new KeyServerImportDialog(mCtx, mKeyList, false, this);
- importDialog->show();
-}
-
-void KeyMgmt::slotImportKeyFromClipboard() {
- QClipboard *cb = QApplication::clipboard();
- slotImportKeys(cb->text(QClipboard::Clipboard).toUtf8());
+ QToolBar* keyToolBar = addToolBar(_("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(_("Generate"));
+ generateToolButton->setToolTip(_("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(_("Import key"));
+ toolButton->setText(_("Import Key"));
+ toolButton->setToolButtonStyle(Qt::ToolButtonTextUnderIcon);
+ keyToolBar->addWidget(toolButton);
+
+ keyToolBar->addSeparator();
+ keyToolBar->addAction(deleteCheckedKeysAct);
+ keyToolBar->addSeparator();
+ keyToolBar->addAction(exportKeyToFileAct);
+ keyToolBar->addAction(exportKeyToClipboardAct);
}
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->getKeyById(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"
+ */
+
+ LOG(INFO) << "KeyMgmt::deleteKeysWithWarning Called";
+
+ 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, _("Deleting Keys"),
+ "<b>" +
+ QString(
+ _("Are you sure that you want to delete the following keys?")) +
+ "</b><br/><br/>" + keynames + +"<br/>" +
+ _("The action can not be undone."),
+ QMessageBox::No | QMessageBox::Yes);
+
+ if (ret == QMessageBox::Yes) {
+ GpgKeyOpera::GetInstance().DeleteKeys(std::move(key_ids));
+ emit signalKeyStatusUpdated();
+ }
}
void KeyMgmt::slotShowKeyDetails() {
- if (mKeyList->getSelected()->isEmpty()) {
- return;
- }
+ auto keys_selected = mKeyList->getSelected();
+ if (keys_selected->empty()) return;
- auto key = mCtx->getKeyById(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, _("Error"), _("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->getKeyById(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, _("Error"), _("Key Not Found."));
+ return;
+ }
+ QString fileString = QString::fromStdString(key.name() + " " + key.email() +
+ "(" + key.id() + ")_pub.asc");
+
+ QString file_name = QFileDialog::getSaveFileName(
+ this, _("Export Key To File"), fileString,
+ QString(_("Key Files")) + " (*.asc *.txt);;All Files (*)");
+
+ write_buffer_to_file(file_name.toStdString(), *key_export_data);
+
+ emit signalStatusBarChanged(QString(_("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) {
+ slotSaveWindowState();
+ 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->getKeyById(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, _("Invalid Operation"),
+ _("Please select one KeyPair before doing this operation."));
+ return;
+ }
+ const auto key = GpgKeyGetter::GetInstance().GetKey(keys_selected->front());
+ if (!key.good()) {
+ QMessageBox::critical(nullptr, _("Error"), _("Key Not Found."));
+ return;
+ }
+ if (!key.is_private_key()) {
+ QMessageBox::critical(nullptr, _("Invalid Operation"),
+ _("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();
+}
+void KeyMgmt::slotSaveWindowState() {
+ auto& settings =
+ GpgFrontend::UI::GlobalSettingStation::GetInstance().GetUISettings();
+
+ if (!settings.exists("window") ||
+ settings.lookup("window").getType() != libconfig::Setting::TypeGroup)
+ settings.add("window", libconfig::Setting::TypeGroup);
+
+ auto& window = settings["window"];
+
+ if (!window.exists("key_management") ||
+ window.lookup("key_management").getType() !=
+ libconfig::Setting::TypeGroup)
+ window.add("key_management", libconfig::Setting::TypeGroup);
+
+ auto& key_management = window["key_management"];
+
+ if (!key_management.exists("position") ||
+ key_management.lookup("position").getType() !=
+ libconfig::Setting::TypeGroup) {
+ auto& position =
+ key_management.add("position", libconfig::Setting::TypeGroup);
+ position.add("x", libconfig::Setting::TypeInt) = pos().x();
+ position.add("y", libconfig::Setting::TypeInt) = pos().y();
+ } else {
+ key_management["position"]["x"] = pos().x();
+ key_management["position"]["y"] = pos().y();
+ }
+
+ if (!key_management.exists("size") ||
+ key_management.lookup("size").getType() !=
+ libconfig::Setting::TypeGroup) {
+ auto& size = key_management.add("size", libconfig::Setting::TypeGroup);
+ size.add("width", libconfig::Setting::TypeInt) = QWidget::width();
+ size.add("height", libconfig::Setting::TypeInt) = QWidget::height();
+ } else {
+ key_management["size"]["width"] = QWidget::width();
+ key_management["size"]["height"] = QWidget::height();
+ }
+
+ if (!key_management.exists("window_state"))
+ key_management.add("window_state", libconfig::Setting::TypeString) =
+ saveState().toBase64().toStdString();
+
+ GlobalSettingStation::GetInstance().Sync();
}
+
+} // namespace GpgFrontend::UI
diff --git a/src/ui/KeyMgmt.h b/src/ui/KeyMgmt.h
new file mode 100755
index 00000000..bf1c9b5a
--- /dev/null
+++ b/src/ui/KeyMgmt.h
@@ -0,0 +1,102 @@
+/**
+ * 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);
+
+ public slots:
+
+ void slotGenerateSubKey();
+
+ void slotExportKeyToFile();
+
+ void slotExportKeyToClipboard();
+
+ void slotDeleteSelectedKeys();
+
+ void slotDeleteCheckedKeys();
+
+ void slotGenerateKeyDialog();
+
+ void slotShowKeyDetails();
+
+ void slotSaveWindowState();
+
+ signals:
+
+ void signalStatusBarChanged(QString);
+
+ void signalKeyStatusUpdated();
+
+ private:
+ void createMenus();
+
+ void createActions();
+
+ void createToolBars();
+
+ void deleteKeysWithWarning(GpgFrontend::KeyIdArgsListPtr uidList);
+
+ KeyList* mKeyList;
+ QMenu* fileMenu{};
+ QMenu* keyMenu{};
+ QMenu* generateKeyMenu{};
+ QMenu* importKeyMenu{};
+ QAction* openKeyFileAct{};
+ QAction* exportKeyToFileAct{};
+ QAction* exportKeyToClipboardAct{};
+ QAction* deleteCheckedKeysAct{};
+ QAction* deleteSelectedKeysAct{};
+ QAction* generateKeyDialogAct{};
+ QAction* generateKeyPairAct{};
+ QAction* generateSubKeyAct{};
+ QAction* importKeyFromClipboardAct{};
+ QAction* importKeyFromFileAct{};
+ QAction* importKeyFromKeyServerAct{};
+ 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 a1355120..17db7d65 100644
--- a/src/ui/KeyServerImportDialog.cpp
+++ b/src/ui/KeyServerImportDialog.cpp
@@ -1,7 +1,7 @@
/**
- * This file is part of GPGFrontend.
+ * This file is part of GpgFrontend.
*
- * GPGFrontend is free software: you can redistribute it and/or modify
+ * 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.
@@ -26,27 +26,32 @@
#include <utility>
-KeyServerImportDialog::KeyServerImportDialog(GpgME::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) {
+#include "gpg/function/GpgKeyImportExportor.h"
+#include "ui/SignalStation.h"
+#include "ui/settings/GlobalSettingStation.h"
- if(automatic) {
- setWindowFlags(Qt::Window | Qt::WindowTitleHint | Qt::CustomizeWindowHint);
- }
+namespace GpgFrontend::UI {
+
+KeyServerImportDialog::KeyServerImportDialog(bool automatic, QWidget* parent)
+ : QDialog(parent), mAutomatic(automatic) {
+ // Layout for messagebox
+ auto* messageLayout = new QHBoxLayout;
+ if (automatic) {
+ setWindowFlags(Qt::Window | Qt::WindowTitleHint | Qt::CustomizeWindowHint);
+ } else {
// Buttons
- closeButton = createButton(tr("&Close"), SLOT(close()));
- importButton = createButton(tr("&Import ALL"), SLOT(slotImport()));
- searchButton = createButton(tr("&Search"), SLOT(slotSearch()));
+ closeButton = createButton(_("Close"), SLOT(close()));
+ importButton = createButton(_("Import ALL"), SLOT(slotImport()));
+ importButton->setDisabled(true);
+ searchButton = createButton(_("Search"), SLOT(slotSearch()));
// Line edit for search string
- searchLabel = new QLabel(tr("Search String:"));
+ searchLabel = new QLabel(QString(_("Search String")) + _(": "));
searchLineEdit = new QLineEdit();
// combobox for keyserverlist
- keyServerLabel = new QLabel(tr("Key Server:"));
+ keyServerLabel = new QLabel(QString(_("Key Server")) + _(": "));
keyServerComboBox = createComboBox();
// table containing the keys found
@@ -56,421 +61,549 @@ KeyServerImportDialog::KeyServerImportDialog(GpgME::GpgContext *ctx, KeyList *ke
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();
+ }
+
+ // Network Waiting
+ waitingBar = new QProgressBar();
+ waitingBar->setVisible(false);
+ waitingBar->setRange(0, 0);
+ waitingBar->setFixedWidth(200);
+ messageLayout->addWidget(waitingBar);
+
+ 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);
// Layout for import and close button
- auto *buttonsLayout = new QHBoxLayout;
+ auto* buttonsLayout = new QHBoxLayout;
buttonsLayout->addStretch();
- if(!automatic)
- buttonsLayout->addWidget(importButton);
+ 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);
+ mainLayout->addLayout(buttonsLayout, 6, 0, 1, 3);
+ }
+
+ this->setLayout(mainLayout);
+ if (automatic)
+ this->setWindowTitle(_("Update Keys from Keyserver"));
+ else
+ this->setWindowTitle(_("Import Keys from Keyserver"));
+
+ if (automatic) {
+ this->setFixedSize(240, 42);
+ } else {
+ auto pos = QPoint(150, 150);
+ LOG(INFO) << "parent" << parent;
+ if (parent) pos += parent->pos();
+ LOG(INFO) << "pos default" << pos.x() << pos.y();
+ auto size = QSize(800, 500);
+
+ try {
+ auto& settings = GlobalSettingStation::GetInstance().GetUISettings();
+
+ int x, y, width, height;
+ x = settings.lookup("window.import_from_keyserver.position.x");
+ y = settings.lookup("window.import_from_keyserver.position.y");
+ width = settings.lookup("window.import_from_keyserver.size.width");
+ height = settings.lookup("window.import_from_keyserver.size.height");
+ pos = QPoint(x, y);
+ size = QSize(width, height);
+
+ } catch (...) {
+ LOG(WARNING) << "cannot read pos or size from settings";
}
- this->setLayout(mainLayout);
- if(automatic)
- this->setWindowTitle(tr("Update Keys from Keyserver"));
- else
- this->setWindowTitle(tr("Import Keys from Keyserver"));
+ this->resize(size);
+ this->move(pos);
+ }
- 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 {
- 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);
-}
+ connect(this, SIGNAL(signalKeyImported()), SignalStation::GetInstance(),
+ SIGNAL(KeyDatabaseRefresh()));
-QPushButton *KeyServerImportDialog::createButton(const QString &text, const char *member) {
- auto *button = new QPushButton(text);
- connect(button, SIGNAL(clicked()), this, member);
- return button;
+ // save window pos and size to configure file
+ connect(this, SIGNAL(finished(int)), this, SLOT(slotSaveWindowState()));
}
-QComboBox *KeyServerImportDialog::createComboBox() {
- auto *comboBox = new QComboBox;
- comboBox->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Preferred);
+QPushButton* KeyServerImportDialog::createButton(const QString& text,
+ const char* member) {
+ auto* button = new QPushButton(text);
+ connect(button, SIGNAL(clicked()), this, member);
+ return button;
+}
- // Read keylist from ini-file and fill it into combobox
- comboBox->addItems(settings.value("keyserver/keyServerList").toStringList());
+QComboBox* KeyServerImportDialog::createComboBox() {
+ auto* comboBox = new QComboBox;
+ comboBox->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Preferred);
- // set default keyserver in combobox
- QString keyserver = settings.value("keyserver/defaultKeyServer").toString();
- comboBox->setCurrentIndex(comboBox->findText(keyserver));
+ auto& settings = GlobalSettingStation::GetInstance().GetUISettings();
- return comboBox;
+ try {
+ auto& server_list = settings.lookup("keyserver.server_list");
+ const auto server_list_size = server_list.getLength();
+ for (int i = 0; i < server_list_size; i++) {
+ std::string server_url = server_list[i];
+ comboBox->addItem(server_url.c_str());
+ }
+ } catch (...) {
+ LOG(ERROR) << _("Setting Operation Error") << _("server_list");
+ }
+
+ // set default keyserver in combobox
+ try {
+ std::string default_server = settings.lookup("keyserver.default_server");
+ comboBox->setCurrentText(default_server.c_str());
+ } catch (...) {
+ LOG(ERROR) << _("Setting Operation Error") << _("default_server");
+ }
+
+ 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 << _("UID") << _("Creation date") << _("KeyID") << _("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) {
+ if (mAutomatic) return;
+
+ 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>" + QString(_("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() +
+ QUrl url_from_remote = 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()));
-
- setLoading(true);
-
- while (reply->isRunning()) {
- QApplication::processEvents();
- }
-
- setLoading(false);
-
+ qnam = new QNetworkAccessManager(this);
+ QNetworkReply* reply = qnam->get(QNetworkRequest(url_from_remote));
+
+ connect(reply, SIGNAL(finished()), this, SLOT(slotSearchFinished()));
+
+ setLoading(true);
+ this->searchButton->setDisabled(true);
+ this->keyServerComboBox->setDisabled(true);
+ this->searchLineEdit->setReadOnly(true);
+ this->importButton->setDisabled(true);
+
+ while (reply->isRunning()) {
+ QApplication::processEvents();
+ }
+
+ this->searchButton->setDisabled(false);
+ this->keyServerComboBox->setDisabled(false);
+ this->searchLineEdit->setReadOnly(false);
+ this->importButton->setDisabled(false);
+ 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);
- }
+ LOG(INFO) << "KeyServerImportDialog::slotSearchFinished Called";
+
+ auto* reply = qobject_cast<QNetworkReply*>(sender());
+
+ keysTable->clearContents();
+ keysTable->setRowCount(0);
+ QString first_line = QString(reply->readLine(1024));
+
+ auto error = reply->error();
+ if (error != QNetworkReply::NoError) {
+ qDebug() << "Error From Reply" << reply->errorString();
+ switch (error) {
+ case QNetworkReply::ContentNotFoundError:
+ setMessage(_("Not Key Found"), true);
+ break;
+ case QNetworkReply::TimeoutError:
+ setMessage(_("Timeout"), true);
+ break;
+ case QNetworkReply::HostNotFoundError:
+ setMessage(_("Key Server Not Found"), true);
+ break;
+ default:
+ setMessage(_("Connection Error"), true);
+ }
+ return;
+ }
+
+ if (first_line.contains("Error")) {
+ QString text = QString(reply->readLine(1024));
+ if (text.contains("Too many responses")) {
+ setMessage(
+ "<h4>" + QString(_("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>" +
+ QString(_("No keys found, input may be kexId, retrying search "
+ "with 0x.")) +
+ "</h4>",
+ true);
+ searchLineEdit->setText(query.prepend("0x"));
+ this->slotSearch();
return;
+ } else {
+ setMessage(
+ "<h4>" + QString(_("No keys found containing the search string!")) +
+ "</h4>",
+ true);
+ return;
+ }
+ } else if (text.contains("Insufficiently specific words")) {
+ setMessage("<h4>" + QString(_("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(_("revoked"))));
+ }
+ if (flags.contains("d")) {
+ keysTable->setItem(row, 3,
+ new QTableWidgetItem(QString(_("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(
+ QString("<h4>") +
+ QString(_("%1 keys found. Double click a key to import it."))
+ .arg(row) +
+ "</h4>",
+ false);
}
- reply->deleteLater();
+ keysTable->resizeColumnsToContents();
+ importButton->setDisabled(keysTable->size().isEmpty());
+ }
+ reply->deleteLater();
}
void KeyServerImportDialog::slotImport() {
- 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));
+ LOG(INFO) << _("Current Row") << keysTable->currentRow();
+ if (keysTable->currentRow() > -1) {
+ QString keyid = keysTable->item(keysTable->currentRow(), 2)->text();
+ slotImport(QStringList(keyid), keyServerComboBox->currentText());
+ }
}
-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);
+void KeyServerImportDialog::slotImport(const KeyIdArgsListPtr& keys) {
+ std::string target_keyserver;
+ if (keyServerComboBox != nullptr) {
+ target_keyserver = keyServerComboBox->currentText().toStdString();
+ }
+ if (target_keyserver.empty()) {
+ try {
+ auto& settings = GlobalSettingStation::GetInstance().GetUISettings();
+
+ target_keyserver = settings.lookup("keyserver.default_server").c_str();
+
+ LOG(INFO) << _("Set target Key Server to default Key Server")
+ << target_keyserver;
+ } catch (...) {
+ LOG(ERROR) << _("Cannot read default_keyserver From Settings");
+ QMessageBox::critical(
+ nullptr, _("Default Keyserver Not Found"),
+ _("Cannot read default keyserver from your settings, "
+ "please set a default keyserver first"));
+ return;
}
- slotImport(keyIds, QUrl(keyserver));
+ }
+ auto key_ids = QStringList();
+ for (const auto& key_id : *keys)
+ key_ids.append(QString::fromStdString(key_id));
+ slotImport(key_ids, QUrl(target_keyserver.c_str()));
}
+void KeyServerImportDialog::slotImport(const QStringList& keyIds,
+ const QUrl& keyServerUrl) {
+ for (const auto& keyId : keyIds) {
+ QUrl req_url(keyServerUrl.scheme() + "://" + keyServerUrl.host() +
+ "/pks/lookup?op=get&search=0x" + keyId + "&options=mr");
-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));
-
- connect(reply, SIGNAL(finished()),
- this, SLOT(slotImportFinished()));
-
- setLoading(true);
-
- while(reply->isRunning()) {
- QApplication::processEvents();
- }
+ LOG(INFO) << "request url" << req_url.toString().toStdString();
+ auto manager = new QNetworkAccessManager(this);
- setLoading(false);
- }
+ QNetworkReply* reply = manager->get(QNetworkRequest(req_url));
+ connect(reply, &QNetworkReply::finished, this,
+ [&, keyId]() { this->slotImportFinished(keyId); });
+ LOG(INFO) << "loading start";
+ setLoading(true);
+ while (reply->isRunning()) QApplication::processEvents();
+ setLoading(false);
+ LOG(INFO) << "loading done";
+ }
}
-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;
+void KeyServerImportDialog::slotImportFinished(QString keyid) {
+ LOG(INFO) << _("Called");
+
+ auto* reply = qobject_cast<QNetworkReply*>(sender());
+
+ QByteArray key = reply->readAll();
+
+ auto error = reply->error();
+ if (error != QNetworkReply::NoError) {
+ LOG(ERROR) << "Error From Reply" << reply->errorString().toStdString();
+ if (!mAutomatic) {
+ switch (error) {
+ case QNetworkReply::ContentNotFoundError:
+ setMessage(_("Key Not Found"), true);
+ break;
+ case QNetworkReply::TimeoutError:
+ setMessage(_("Timeout"), true);
+ break;
+ case QNetworkReply::HostNotFoundError:
+ setMessage(_("Key Server Not Found"), true);
+ break;
+ default:
+ setMessage(_("Connection Error"), true);
+ }
+ } else {
+ switch (error) {
+ case QNetworkReply::ContentNotFoundError:
+ QMessageBox::critical(
+ nullptr, _("Public key Not Found"),
+ QString(_("Public key fingerprint %1 not found in the Keyserver"))
+ .arg(keyid));
+ break;
+ case QNetworkReply::TimeoutError:
+ QMessageBox::critical(nullptr, _("Timeout"), "Connection timeout");
+ break;
+ case QNetworkReply::HostNotFoundError:
+ QMessageBox::critical(nullptr, _("Host Not Found"),
+ "cannot resolve the default Keyserver");
+ break;
+ default:
+ QMessageBox::critical(nullptr, _("Connection Error"),
+ _("General Connection Error"));
+ }
}
-
- // 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);
+ if (mAutomatic) {
+ setWindowFlags(Qt::Window | Qt::WindowTitleHint |
+ Qt::CustomizeWindowHint | Qt::WindowCloseButtonHint);
}
- reply->deleteLater();
+ return;
+ }
- this->importKeys(key.constData());
- if(mAutomatic) {
- setMessage(tr("<h4>Key Updated</h4>"), false);
- } else {
- setMessage(tr("<h4>Key Imported</h4>"), false);
- }
+ reply->deleteLater();
+ this->importKeys(std::make_unique<ByteArray>(key.constData(), key.length()));
+ if (!mAutomatic) {
+ setMessage(QString("<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));
+ emit signalKeyImported();
+ if (mAutomatic) {
+ auto dialog = new KeyImportDetailDialog(result, true, nullptr);
+ dialog->show();
+ this->accept();
+ } else {
+ auto dialog = new KeyImportDetailDialog(result, false, this);
+ dialog->exec();
+ }
}
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);
- }
+ waitingBar->setVisible(status);
+ if (!mAutomatic) {
+ icon->setVisible(!status);
+ message->setVisible(!status);
+ }
}
-KeyServerImportDialog::KeyServerImportDialog(GpgME::GpgContext *ctx, QWidget *parent)
- : QDialog(parent), appPath(qApp->applicationDirPath()),
- settings(RESOURCE_DIR(appPath) + "/conf/gpgfrontend.ini", QSettings::IniFormat),
- mCtx(ctx), mAutomatic(true) {
+KeyServerImportDialog::KeyServerImportDialog(QWidget* parent)
+ : QDialog(parent), mAutomatic(true) {
+ setWindowFlags(Qt::Window | Qt::WindowTitleHint | Qt::CustomizeWindowHint);
- setWindowFlags(Qt::Window | Qt::WindowTitleHint | Qt::CustomizeWindowHint);
+ message = new QLabel;
+ message->setFixedHeight(24);
+ icon = new QLabel;
+ icon->setFixedHeight(24);
- 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);
- // 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();
- // Layout for messagebox
- auto *messageLayout = new QHBoxLayout;
- messageLayout->addWidget(icon);
- messageLayout->addWidget(message);
- messageLayout->addWidget(waitingBar);
- messageLayout->addStretch();
+ keyServerComboBox = createComboBox();
- keyServerComboBox = createComboBox();
+ auto* mainLayout = new QGridLayout;
- auto *mainLayout = new QGridLayout;
+ mainLayout->addLayout(messageLayout, 0, 0, 1, 3);
- mainLayout->addLayout(messageLayout, 0, 0, 1, 3);
+ this->setLayout(mainLayout);
+ this->setWindowTitle(_("Upload Keys from Keyserver"));
+ this->setFixedSize(200, 42);
+ this->setModal(true);
+}
- this->setLayout(mainLayout);
- this->setWindowTitle(tr("Upload Keys from Keyserver"));
- this->setFixedSize(200, 42);
- this->setModal(true);
+void KeyServerImportDialog::slotSaveWindowState() {
+ LOG(INFO) << _("Called");
+
+ if (mAutomatic) return;
+
+ auto& settings =
+ GpgFrontend::UI::GlobalSettingStation::GetInstance().GetUISettings();
+
+ if (!settings.exists("window") ||
+ settings.lookup("window").getType() != libconfig::Setting::TypeGroup)
+ settings.add("window", libconfig::Setting::TypeGroup);
+
+ auto& window = settings["window"];
+
+ if (!window.exists("import_from_keyserver") ||
+ window.lookup("import_from_keyserver").getType() !=
+ libconfig::Setting::TypeGroup)
+ window.add("import_from_keyserver", libconfig::Setting::TypeGroup);
+
+ auto& import_from_keyserver = window["import_from_keyserver"];
+
+ if (!import_from_keyserver.exists("position") ||
+ import_from_keyserver.lookup("position").getType() !=
+ libconfig::Setting::TypeGroup) {
+ auto& position =
+ import_from_keyserver.add("position", libconfig::Setting::TypeGroup);
+ position.add("x", libconfig::Setting::TypeInt) = pos().x();
+ position.add("y", libconfig::Setting::TypeInt) = pos().y();
+ } else {
+ import_from_keyserver["position"]["x"] = pos().x();
+ import_from_keyserver["position"]["y"] = pos().y();
+ }
+
+ if (!import_from_keyserver.exists("size") ||
+ import_from_keyserver.lookup("size").getType() !=
+ libconfig::Setting::TypeGroup) {
+ auto& size =
+ import_from_keyserver.add("size", libconfig::Setting::TypeGroup);
+ size.add("width", libconfig::Setting::TypeInt) = QWidget::width();
+ size.add("height", libconfig::Setting::TypeInt) = QWidget::height();
+ } else {
+ import_from_keyserver["size"]["width"] = QWidget::width();
+ import_from_keyserver["size"]["height"] = QWidget::height();
+ }
+
+ GlobalSettingStation::GetInstance().Sync();
}
+
+} // namespace GpgFrontend::UI
diff --git a/src/ui/KeyServerImportDialog.h b/src/ui/KeyServerImportDialog.h
new file mode 100644
index 00000000..67571f2f
--- /dev/null
+++ b/src/ui/KeyServerImportDialog.h
@@ -0,0 +1,93 @@
+/**
+ * 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 __KEY_SERVER_IMPORT_DIALOG_H__
+#define __KEY_SERVER_IMPORT_DIALOG_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(bool automatic, QWidget* parent);
+
+ KeyServerImportDialog(QWidget* parent);
+
+ void slotImport(const KeyIdArgsListPtr& keys);
+
+ void slotImport(const QStringList& keyIds, const QUrl& keyserverUrl);
+
+ signals:
+ void signalKeyImported();
+
+ private slots:
+
+ void slotImport();
+
+ void slotSearchFinished();
+
+ void slotImportFinished(QString keyid);
+
+ void slotSearch();
+
+ void slotSaveWindowState();
+
+ 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 = false;
+
+ 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 // __KEY_SERVER_IMPORT_DIALOG_H__
diff --git a/src/ui/KeyUploadDialog.cpp b/src/ui/KeyUploadDialog.cpp
index ab38569f..b2bfff6d 100644
--- a/src/ui/KeyUploadDialog.cpp
+++ b/src/ui/KeyUploadDialog.cpp
@@ -1,7 +1,7 @@
/**
- * This file is part of GPGFrontend.
+ * This file is part of GpgFrontend.
*
- * GPGFrontend is free software: you can redistribute it and/or modify
+ * 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.
@@ -24,105 +24,117 @@
#include "ui/KeyUploadDialog.h"
-KeyUploadDialog::KeyUploadDialog(GpgME::GpgContext *ctx, const QVector<GpgKey> &keys, 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);
+#include <algorithm>
+
+#include "gpg/function/GpgKeyGetter.h"
+#include "gpg/function/GpgKeyImportExportor.h"
+
+namespace GpgFrontend::UI {
+
+KeyUploadDialog::KeyUploadDialog(const KeyIdArgsListPtr& keys_ids,
+ QWidget* parent)
+ : QDialog(parent),
+ appPath(qApp->applicationDirPath()),
+ settings(RESOURCE_DIR(appPath) + "/conf/gpgfrontend.ini",
+ QSettings::IniFormat),
+ mKeys(GpgKeyGetter::GetInstance().GetKeys(keys_ids)) {
+ 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(_("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(*out_data);
}
-void KeyUploadDialog::uploadKeyToServer(QByteArray &keys) {
+void KeyUploadDialog::uploadKeyToServer(
+ const GpgFrontend::ByteArray& 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 = std::string(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 = _("Key Not Found");
+ break;
+ case QNetworkReply::TimeoutError:
+ message = _("Timeout");
+ break;
+ case QNetworkReply::HostNotFoundError:
+ message = _("Key Server Not Found");
+ break;
+ default:
+ message = _("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 b41ced6b..b607c321 100644
--- a/include/ui/KeyUploadDialog.h
+++ b/src/ui/KeyUploadDialog.h
@@ -1,7 +1,7 @@
/**
- * This file is part of GPGFrontend.
+ * This file is part of GpgFrontend.
*
- * GPGFrontend is free software: you can redistribute it and/or modify
+ * 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.
@@ -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(GpgME::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(const GpgFrontend::ByteArray& keys_data);
- GpgME::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..6b0977fd
--- /dev/null
+++ b/src/ui/MainWindow.cpp
@@ -0,0 +1,380 @@
+/**
+ * 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/UserInterfaceUtils.h"
+#ifdef RELEASE
+#include "ui/function/VersionCheckThread.h"
+#endif
+#include "ui/settings/GlobalSettingStation.h"
+
+namespace GpgFrontend::UI {
+
+MainWindow::MainWindow() {
+ this->setMinimumSize(1200, 700);
+ this->setWindowTitle(qApp->applicationName());
+}
+
+void MainWindow::init() noexcept {
+ try {
+ // Check Context Status
+ if (!GpgContext::GetInstance().good()) {
+ QMessageBox::critical(
+ nullptr, _("ENV Loading Failed"),
+ _("Gnupg is not installed correctly, please follow the ReadME "
+ "instructions to install gnupg and then open GpgFrontend."));
+ QCoreApplication::quit();
+ exit(0);
+ }
+
+ networkAccessManager = new QNetworkAccessManager(this);
+
+ /* 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 {
+ return !(key.revoked() || key.disabled() || key.expired());
+ });
+
+ mKeyList->slotRefresh();
+
+ infoBoard = new InfoBoardWidget(this, mKeyList);
+
+ /* List of binary Attachments */
+ attachmentDockCreated = false;
+
+ /* Variable containing if restart is needed */
+ this->slotSetRestartNeeded(false);
+
+ 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();
+
+ auto& settings = GlobalSettingStation::GetInstance().GetUISettings();
+
+ if (!settings.exists("wizard") ||
+ settings.lookup("wizard").getType() != libconfig::Setting::TypeGroup)
+ settings.add("wizard", libconfig::Setting::TypeGroup);
+
+ auto& wizard = settings["wizard"];
+
+ // Show wizard, if the don't show wizard message box wasn't checked
+ // and keylist doesn't contain a private key
+
+ if (!wizard.exists("show_wizard"))
+ wizard.add("show_wizard", libconfig::Setting::TypeBoolean) = true;
+
+ bool show_wizard = true;
+ wizard.lookupValue("show_wizard", show_wizard);
+
+ LOG(INFO) << "wizard show_wizard" << show_wizard;
+
+ if (show_wizard) {
+ slotStartWizard();
+ }
+
+ emit loaded();
+
+#ifdef RELEASE
+ QString baseUrl =
+ "https://api.github.com/repos/saturneric/gpgfrontend/releases/latest";
+ QNetworkRequest request;
+ request.setUrl(QUrl(baseUrl));
+ auto* 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();
+#endif
+ } catch (...) {
+ LOG(FATAL) << _("Critical error occur while loading GpgFrontend.");
+ QMessageBox::critical(nullptr, _("Loading Failed"),
+ _("Critical error occur while loading GpgFrontend."));
+ QCoreApplication::quit();
+ exit(0);
+ }
+}
+
+void MainWindow::restoreSettings() {
+ try {
+ auto& settings = GlobalSettingStation::GetInstance().GetUISettings();
+
+ if (!settings.exists("window") ||
+ settings.lookup("window").getType() != libconfig::Setting::TypeGroup)
+ settings.add("window", libconfig::Setting::TypeGroup);
+
+ auto& window = settings["window"];
+
+ if (!window.exists("window_state"))
+ window.add("window_state", libconfig::Setting::TypeString) =
+ saveState().toBase64().toStdString();
+
+ std::string window_state = settings.lookup("window.window_state");
+ // state sets pos & size of dock-widgets
+ this->restoreState(
+ QByteArray::fromBase64(QByteArray::fromStdString(window_state)));
+
+ if (!window.exists("window_save"))
+ window.add("window_save", libconfig::Setting::TypeBoolean) = true;
+
+ bool window_save;
+ window.lookupValue("window_save", window_save);
+
+ // Restore window size & location
+ if (window_save) {
+ if (!window.exists("window_pos"))
+ window.add("window_pos", libconfig::Setting::TypeGroup);
+
+ auto& window_pos = window["window_pos"];
+
+ if (!window_pos.exists("x"))
+ window_pos.add("x", libconfig::Setting::TypeInt) = 100;
+
+ if (!window_pos.exists("y"))
+ window_pos.add("y", libconfig::Setting::TypeInt) = 100;
+
+ int x, y;
+ window_pos.lookupValue("x", x);
+ window_pos.lookupValue("y", y);
+
+ auto pos = QPoint(x, y);
+
+ if (!window.exists("window_size"))
+ window.add("window_size", libconfig::Setting::TypeGroup);
+
+ auto& window_size = window["window_size"];
+
+ if (!window_size.exists("width"))
+ window_size.add("width", libconfig::Setting::TypeInt) = 800;
+
+ if (!window_size.exists("height"))
+ window_size.add("height", libconfig::Setting::TypeInt) = 450;
+
+ int width, height;
+ window_size.lookupValue("width", width);
+ window_size.lookupValue("height", height);
+
+ auto size = QSize(width, height);
+ this->resize(size);
+ this->move(pos);
+ } else {
+ this->resize(QSize(800, 450));
+ this->move(QPoint(100, 100));
+ }
+
+ if (!window.exists("icon_size"))
+ window.add("icon_size", libconfig::Setting::TypeGroup);
+
+ auto& icon_size = window["icon_size"];
+
+ if (!icon_size.exists("width"))
+ icon_size.add("width", libconfig::Setting::TypeInt) = 24;
+
+ if (!icon_size.exists("height"))
+ icon_size.add("height", libconfig::Setting::TypeInt) = 24;
+
+ int width = icon_size["width"], height = icon_size["height"];
+ LOG(INFO) << "icon_size" << width << height;
+
+ // info board font size
+ if (!window.exists("info_font_size"))
+ window.add("info_font_size", libconfig::Setting::TypeInt) = 10;
+
+ // icons ize
+ this->setIconSize(QSize(width, height));
+ importButton->setIconSize(QSize(width, height));
+ fileEncButton->setIconSize(QSize(width, height));
+
+ if (!settings.exists("keyserver") ||
+ settings.lookup("keyserver").getType() != libconfig::Setting::TypeGroup)
+ settings.add("keyserver", libconfig::Setting::TypeGroup);
+
+ auto& keyserver = settings["keyserver"];
+
+ if (!keyserver.exists("server_list")) {
+ keyserver.add("server_list", libconfig::Setting::TypeList);
+
+ auto& server_list = keyserver["server_list"];
+ server_list.add(libconfig::Setting::TypeString) = "http://keys.gnupg.net";
+ server_list.add(libconfig::Setting::TypeString) =
+ "https://keyserver.ubuntu.com";
+ server_list.add(libconfig::Setting::TypeString) =
+ "http://pool.sks-keyservers.net";
+ }
+
+ if (!keyserver.exists("default_server")) {
+ keyserver.add("default_server", libconfig::Setting::TypeString) =
+ "https://keyserver.ubuntu.com";
+ }
+
+ if (!window.exists("icon_style")) {
+ window.add("icon_style", libconfig::Setting::TypeInt) =
+ Qt::ToolButtonTextUnderIcon;
+ }
+
+ int s_icon_style = window.lookup("icon_style");
+
+ // icon_style
+ auto icon_style = static_cast<Qt::ToolButtonStyle>(s_icon_style);
+ this->setToolButtonStyle(icon_style);
+ importButton->setToolButtonStyle(icon_style);
+ fileEncButton->setToolButtonStyle(icon_style);
+
+ if (!settings.exists("general") ||
+ settings.lookup("general").getType() != libconfig::Setting::TypeGroup)
+ settings.add("general", libconfig::Setting::TypeGroup);
+
+ auto& general = settings["general"];
+
+ if (!general.exists("save_key_checked")) {
+ general.add("save_key_checked", libconfig::Setting::TypeBoolean) = true;
+ }
+
+ bool save_key_checked = true;
+ general.lookupValue("save_key_checked", save_key_checked);
+
+ // Checked Keys
+ if (save_key_checked) {
+ if (!general.exists("save_key_checked_key_ids")) {
+ general.add("save_key_checked_key_ids", libconfig::Setting::TypeList);
+ }
+ auto key_ids_ptr = std::make_unique<KeyIdArgsList>();
+ ;
+ auto& save_key_checked_key_ids = general["save_key_checked_key_ids"];
+ const auto key_ids_size =
+ general.lookup("save_key_checked_key_ids").getLength();
+ for (auto i = 0; i < key_ids_size; i++) {
+ std::string key_id = save_key_checked_key_ids[i];
+ key_ids_ptr->push_back(key_id);
+ }
+ mKeyList->setChecked(key_ids_ptr);
+ }
+ } catch (...) {
+ LOG(ERROR) << "cannot resolve settings";
+ }
+
+ GlobalSettingStation::GetInstance().Sync();
+}
+
+void MainWindow::saveSettings() {
+ auto& settings = GlobalSettingStation::GetInstance().GetUISettings();
+
+ try {
+ // window position and size
+ settings["window"]["window_state"] = saveState().toBase64().toStdString();
+ settings["window"]["window_pos"]["x"] = pos().x();
+ settings["window"]["window_pos"]["y"] = pos().y();
+
+ settings["window"]["window_size"]["width"] = size().width();
+ settings["window"]["window_size"]["height"] = size().height();
+
+ bool save_key_checked = settings.lookup("general.save_key_checked");
+
+ // keyid-list of private checked keys
+ if (save_key_checked) {
+ auto& key_ids = settings.lookup("general.save_key_checked_key_ids");
+ const int key_ids_size = key_ids.getLength();
+ for (auto i = 0; i < key_ids_size; i++) key_ids.remove(i);
+ auto key_ids_need_to_store = mKeyList->getChecked();
+
+ for (size_t i = 0; i < key_ids_need_to_store->size(); i++) {
+ std::string key_id = (*key_ids_need_to_store)[i];
+ key_ids.add(libconfig::Setting::TypeString) = key_id;
+ }
+
+ } else {
+ settings["general"].remove("save_key_checked");
+ }
+ } catch (...) {
+ LOG(ERROR) << "cannot save settings";
+ };
+
+ GlobalSettingStation::GetInstance().Sync();
+}
+
+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..e0bf9f5a
--- /dev/null
+++ b/src/ui/MainWindow.h
@@ -0,0 +1,437 @@
+/**
+ * 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 "gpg/result_analyse/DecryptResultAnalyse.h"
+#include "gpg/result_analyse/EncryptResultAnalyse.h"
+#include "gpg/result_analyse/SignResultAnalyse.h"
+#include "ui/FileEncryptionDialog.h"
+#include "ui/FindWidget.h"
+#include "ui/GpgFrontendUI.h"
+#include "ui/KeyMgmt.h"
+#include "ui/KeyUploadDialog.h"
+#include "ui/WaitingDialog.h"
+#include "ui/Wizard.h"
+#include "ui/help/AboutDialog.h"
+#include "ui/settings/SettingsDialog.h"
+#include "ui/widgets/InfoBoardWidget.h"
+#include "ui/widgets/TextEdit.h"
+
+namespace GpgFrontend::UI {
+/**
+ * @brief
+ *
+ */
+class MainWindow : public QMainWindow {
+ Q_OBJECT
+
+ public:
+ /**
+ * @brief
+ *
+ */
+ MainWindow();
+
+ /**
+ * ONLY Called from main()
+ */
+ void init() noexcept;
+
+ signals:
+ void loaded();
+
+ 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();
+
+#ifdef ADVANCE_SUPPORT
+
+ /**
+ * @details Get full crypto text
+ */
+ QString getCryptText(const QString& shortenCryptoText);
+
+ /**
+ * @details Shorten crypto text
+ */
+ void shortenCryptText();
+
+#endif
+
+ /**
+ * @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 */
+
+ QAction* importKeyFromFileAct{};
+ QAction* importKeyFromClipboardAct{};
+ QAction* importKeyFromKeyServerAct{};
+
+ QLabel* statusBarIcon{}; /**< TODO */
+
+ KeyList* mKeyList{};
+ InfoBoardWidget* infoBoard{};
+
+ 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..a5ed7c3f 100755
--- a/src/ui/QuitDialog.cpp
+++ b/src/ui/QuitDialog.cpp
@@ -1,7 +1,7 @@
/**
- * This file is part of GPGFrontend.
+ * This file is part of GpgFrontend.
*
- * GPGFrontend is free software: you can redistribute it and/or modify
+ * 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.
@@ -24,109 +24,118 @@
#include "ui/QuitDialog.h"
-QuitDialog::QuitDialog(QWidget *parent, const QHash<int, QString>& unsavedDocs)
- : QDialog(parent) {
- setWindowTitle(tr("Unsaved Files"));
- setModal(true);
- discarded = false;
-
- /*
- * 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);
-
- // checkbox in front of filename
- auto *tmp0 = new QTableWidgetItem();
- tmp0->setFlags(Qt::ItemIsUserCheckable | Qt::ItemIsEnabled);
- tmp0->setCheckState(Qt::Checked);
- mFileList->setItem(row, 0, tmp0);
-
- // filename
- auto *tmp1 = new QTableWidgetItem(i.value());
- mFileList->setItem(row, 1, tmp1);
-
- // 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);
-
- /*
- * 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/>"));
-
- /*
- * 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);
-}
+#include <boost/format.hpp>
+namespace GpgFrontend::UI {
-void QuitDialog::slotMyDiscard() {
- discarded = true;
- reject();
+QuitDialog::QuitDialog(QWidget* parent, const QHash<int, QString>& unsavedDocs)
+ : QDialog(parent) {
+ setWindowTitle(_("Unsaved Files"));
+ setModal(true);
+ discarded = false;
+
+ /*
+ * 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);
+
+ // checkbox in front of filename
+ auto* tmp0 = new QTableWidgetItem();
+ tmp0->setFlags(Qt::ItemIsUserCheckable | Qt::ItemIsEnabled);
+ tmp0->setCheckState(Qt::Checked);
+ mFileList->setItem(row, 0, tmp0);
+
+ // filename
+ auto* tmp1 = new QTableWidgetItem(i.value());
+ mFileList->setItem(row, 1, tmp1);
+
+ // 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);
+
+ const auto info =
+ boost::format(_("%1% files contain unsaved information.<br/>Save the "
+ "changes before closing?")) %
+ std::to_string(row);
+ auto* warn_label = new QLabel(QString::fromStdString(info.str()));
+ auto* warnBoxLayout = new QHBoxLayout();
+ warnBoxLayout->addWidget(warn_icon);
+ warnBoxLayout->addWidget(warn_label);
+ warnBoxLayout->setAlignment(Qt::AlignLeft);
+ auto* warnBox = new QWidget(this);
+ warnBox->setLayout(warnBoxLayout);
+
+ /*
+ * Two labels on top and under the filelist
+ */
+ auto* checkLabel = new QLabel(_("Check the files you want to save:"));
+ auto* note_label = new QLabel(
+ "<b>" + QString(_("Note")) + ":</b>" +
+ _("If you don't save these files, all changes are lost.") + "<br/>");
+
+ /*
+ * 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);
}
-bool QuitDialog::isDiscarded() const {
- return discarded;
+void QuitDialog::slotMyDiscard() {
+ discarded = true;
+ reject();
}
+bool QuitDialog::isDiscarded() const { 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..2b1dd37f 100755
--- a/include/ui/QuitDialog.h
+++ b/src/ui/QuitDialog.h
@@ -1,7 +1,7 @@
/**
- * This file is part of GPGFrontend.
+ * This file is part of GpgFrontend.
*
- * GPGFrontend is free software: you can redistribute it and/or modify
+ * 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.
@@ -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
deleted file mode 100644
index 5bea7cb2..00000000
--- a/src/ui/SendMailDialog.cpp
+++ /dev/null
@@ -1,173 +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 "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()));
-
- 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();
-}
-
-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.
-
- 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();
-}
diff --git a/src/ui/ShowCopyDialog.cpp b/src/ui/ShowCopyDialog.cpp
index 3286f6c4..0503e079 100644
--- a/src/ui/ShowCopyDialog.cpp
+++ b/src/ui/ShowCopyDialog.cpp
@@ -1,7 +1,7 @@
/**
- * This file is part of GPGFrontend.
+ * This file is part of GpgFrontend.
*
- * GPGFrontend is free software: you can redistribute it and/or modify
+ * 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.
@@ -24,30 +24,36 @@
#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..fefef7ab 100644
--- a/include/ui/ShowCopyDialog.h
+++ b/src/ui/ShowCopyDialog.h
@@ -1,7 +1,7 @@
/**
- * This file is part of GPGFrontend.
+ * This file is part of GpgFrontend.
*
- * GPGFrontend is free software: you can redistribute it and/or modify
+ * 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.
@@ -25,22 +25,26 @@
#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/SignalStation.cpp b/src/ui/SignalStation.cpp
new file mode 100644
index 00000000..fff2971a
--- /dev/null
+++ b/src/ui/SignalStation.cpp
@@ -0,0 +1,34 @@
+/**
+ * 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 "SignalStation.h"
+
+std::unique_ptr<SignalStation> SignalStation::_instance = nullptr;
+
+SignalStation* SignalStation::GetInstance() {
+ if (_instance == nullptr) {
+ _instance = std::make_unique<SignalStation>();
+ }
+ return _instance.get();
+}
diff --git a/src/ui/SignalStation.h b/src/ui/SignalStation.h
new file mode 100644
index 00000000..38e55d9f
--- /dev/null
+++ b/src/ui/SignalStation.h
@@ -0,0 +1,41 @@
+/**
+ * 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_SIGNALSTATION_H
+#define GPGFRONTEND_SIGNALSTATION_H
+
+#include "ui/GpgFrontendUI.h"
+
+class SignalStation : public QObject {
+ Q_OBJECT
+ static std::unique_ptr<SignalStation> _instance;
+
+ public:
+ static SignalStation* GetInstance();
+
+ signals:
+ void KeyDatabaseRefresh();
+};
+
+#endif // GPGFRONTEND_SIGNALSTATION_H
diff --git a/src/ui/UserInterfaceUtils.cpp b/src/ui/UserInterfaceUtils.cpp
new file mode 100644
index 00000000..e8f27d2c
--- /dev/null
+++ b/src/ui/UserInterfaceUtils.cpp
@@ -0,0 +1,171 @@
+/**
+ * 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 "UserInterfaceUtils.h"
+
+#include "gpg/result_analyse/ResultAnalyse.h"
+#include "ui/SignalStation.h"
+#include "ui/WaitingDialog.h"
+#include "ui/widgets/InfoBoardWidget.h"
+#include "ui/widgets/TextEdit.h"
+
+namespace GpgFrontend::UI {
+
+std::unique_ptr<GpgFrontend::UI::CommonUtils>
+ GpgFrontend::UI::CommonUtils::_instance = nullptr;
+
+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);
+}
+
+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());
+}
+
+void process_result_analyse(TextEdit* edit, InfoBoardWidget* info_board,
+ const ResultAnalyse& result_analyse_a,
+ const ResultAnalyse& result_analyse_b) {
+ LOG(INFO) << "process_result_analyse Started";
+
+ info_board->associateTabWidget(edit->tabWidget);
+ info_board->associateFileTreeView(edit->curFilePage());
+
+ refresh_info_board(
+ info_board,
+ std::min(result_analyse_a.getStatus(), result_analyse_b.getStatus()),
+ result_analyse_a.getResultReport() + result_analyse_b.getResultReport());
+}
+
+void process_operation(QWidget* parent, const std::string& waiting_title,
+ const std::function<void()>& func) {
+ 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();
+}
+
+CommonUtils* CommonUtils::GetInstance() {
+ if (_instance == nullptr) {
+ _instance = std::make_unique<CommonUtils>();
+ }
+ return _instance.get();
+}
+
+CommonUtils::CommonUtils() : QWidget(nullptr) {
+ connect(this, SIGNAL(signalKeyStatusUpdated()), SignalStation::GetInstance(),
+ SIGNAL(KeyDatabaseRefresh()));
+}
+
+void CommonUtils::slotImportKeys(QWidget* parent,
+ const std::string& in_buffer) {
+ GpgImportInformation result = GpgKeyImportExportor::GetInstance().ImportKey(
+ std::make_unique<ByteArray>(in_buffer));
+ emit signalKeyStatusUpdated();
+ new KeyImportDetailDialog(result, false, parent);
+}
+
+void CommonUtils::slotImportKeyFromFile(QWidget* parent) {
+ QString file_name = QFileDialog::getOpenFileName(
+ this, _("Open Key"), QString(),
+ QString(_("Key Files")) + " (*.asc *.txt);;" + _("Keyring files") +
+ " (*.gpg);;All Files (*)");
+ if (!file_name.isNull()) {
+ slotImportKeys(parent, read_all_data_in_file(file_name.toStdString()));
+ }
+}
+
+void CommonUtils::slotImportKeyFromKeyServer(QWidget* parent) {
+ auto dialog = new KeyServerImportDialog(false, parent);
+ dialog->show();
+}
+
+void CommonUtils::slotImportKeyFromClipboard(QWidget* parent) {
+ QClipboard* cb = QApplication::clipboard();
+ slotImportKeys(parent,
+ cb->text(QClipboard::Clipboard).toUtf8().toStdString());
+}
+
+void CommonUtils::slotExecuteGpgCommand(
+ const QStringList& arguments,
+ const std::function<void(QProcess*)>& interact_func) {
+ QEventLoop looper;
+ auto dialog = new WaitingDialog(_("Processing"), nullptr);
+ dialog->show();
+ auto* gpgProcess = new QProcess(&looper);
+ gpgProcess->setProcessChannelMode(QProcess::MergedChannels);
+
+ connect(gpgProcess, qOverload<int, QProcess::ExitStatus>(&QProcess::finished),
+ &looper, &QEventLoop::quit);
+ connect(gpgProcess, qOverload<int, QProcess::ExitStatus>(&QProcess::finished),
+ dialog, &WaitingDialog::deleteLater);
+ connect(gpgProcess, &QProcess::errorOccurred, &looper, &QEventLoop::quit);
+ connect(gpgProcess, &QProcess::started,
+ []() -> void { LOG(ERROR) << "Gpg Process Started Success"; });
+ connect(gpgProcess, &QProcess::readyReadStandardOutput,
+ [interact_func, gpgProcess]() { interact_func(gpgProcess); });
+ connect(gpgProcess, &QProcess::errorOccurred, this, [=]() -> void {
+ LOG(ERROR) << "Error in Process";
+ dialog->close();
+ QMessageBox::critical(nullptr, _("Failure"),
+ _("Failed to execute command."));
+ });
+ connect(gpgProcess, qOverload<int, QProcess::ExitStatus>(&QProcess::finished),
+ this, [=](int, QProcess::ExitStatus status) {
+ dialog->close();
+ if (status == QProcess::NormalExit)
+ QMessageBox::information(nullptr, _("Success"),
+ _("Succeed in executing command."));
+ else
+ QMessageBox::information(nullptr, _("Warning"),
+ _("Finished executing command."));
+ });
+
+ gpgProcess->setProgram(GpgContext::GetInstance().GetInfo().AppPath.c_str());
+ gpgProcess->setArguments(arguments);
+ gpgProcess->start();
+ looper.exec();
+ dialog->close();
+ dialog->deleteLater();
+}
+
+} // namespace GpgFrontend::UI \ No newline at end of file
diff --git a/src/ui/UserInterfaceUtils.h b/src/ui/UserInterfaceUtils.h
new file mode 100644
index 00000000..df974257
--- /dev/null
+++ b/src/ui/UserInterfaceUtils.h
@@ -0,0 +1,82 @@
+/**
+ * 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_USER_INTERFACE_UTILS_H
+#define GPGFRONTEND_USER_INTERFACE_UTILS_H
+
+#include "ui/GpgFrontendUI.h"
+
+namespace GpgFrontend {
+class ResultAnalyse;
+}
+
+namespace GpgFrontend::UI {
+
+class InfoBoardWidget;
+class TextEdit;
+
+void refresh_info_board(InfoBoardWidget* info_board, int status,
+ const std::string& report_text);
+
+void process_result_analyse(TextEdit* edit, InfoBoardWidget* info_board,
+ const ResultAnalyse& result_analyse);
+
+void process_result_analyse(TextEdit* edit, InfoBoardWidget* info_board,
+ const ResultAnalyse& result_analyse_a,
+ const ResultAnalyse& result_analyse_b);
+
+void process_operation(QWidget* parent, const std::string& waiting_title,
+ const std::function<void()>& func);
+
+class CommonUtils : public QWidget {
+ Q_OBJECT
+ public:
+ static CommonUtils* GetInstance();
+
+ CommonUtils();
+
+ signals:
+ void signalKeyStatusUpdated();
+
+ public slots:
+
+ void slotImportKeys(QWidget* parent, const std::string& in_buffer);
+
+ void slotImportKeyFromFile(QWidget* parent);
+
+ void slotImportKeyFromKeyServer(QWidget* parent);
+
+ void slotImportKeyFromClipboard(QWidget* parent);
+
+ void slotExecuteGpgCommand(
+ const QStringList& arguments,
+ const std::function<void(QProcess*)>& interact_func);
+
+ private:
+ static std::unique_ptr<CommonUtils> _instance;
+};
+
+} // namespace GpgFrontend::UI
+
+#endif // GPGFRONTEND_USER_INTERFACE_UTILS_H
diff --git a/src/ui/VerifyDetailsDialog.cpp b/src/ui/VerifyDetailsDialog.cpp
index 641c09e9..1ad9d996 100644
--- a/src/ui/VerifyDetailsDialog.cpp
+++ b/src/ui/VerifyDetailsDialog.cpp
@@ -1,7 +1,7 @@
/**
- * This file is part of GPGFrontend.
+ * This file is part of GpgFrontend.
*
- * GPGFrontend is free software: you can redistribute it and/or modify
+ * 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.
@@ -24,60 +24,74 @@
#include "ui/VerifyDetailsDialog.h"
-VerifyDetailsDialog::VerifyDetailsDialog(QWidget *parent, GpgME::GpgContext *ctx, KeyList *keyList, gpg_error_t error,
- gpgme_verify_result_t result) :
- QDialog(parent), mCtx(ctx), mKeyList(keyList), sign(result->signatures), error(error) {
+#include <boost/format.hpp>
+namespace GpgFrontend::UI {
- this->setWindowTitle(tr("Signature Details"));
+VerifyDetailsDialog::VerifyDetailsDialog(QWidget* parent, KeyList* keyList,
+ GpgError error, GpgVerifyResult result)
+ : QDialog(parent),
+ mKeyList(keyList),
+ mResult(std::move(result)),
+ error(error) {
+ this->setWindowTitle(_("Signature Details"));
- connect(mCtx, SIGNAL(signalKeyInfoChanged()), this, SLOT(slotRefresh()));
- mainLayout = new QHBoxLayout();
- this->setLayout(mainLayout);
+ 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()));
-
- mVboxLayout->addWidget(new QLabel(tr("Status: ") + gpgme_strerror(error)));
-
- 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);
-
- // 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);
- }
+ // Button Box for close button
+ buttonBox = new QDialogButtonBox(QDialogButtonBox::Close);
+ connect(buttonBox, SIGNAL(rejected()), this, SLOT(close()));
+ mVboxLayout->addWidget(new QLabel(QString::fromStdString(
+ std::string(_("Status")) + ": " + gpgme_strerror(error))));
+
+ auto sign = mResult->signatures;
+
+ if (sign == nullptr) {
+ mVboxLayout->addWidget(new QLabel(_("No valid input found")));
mVboxLayout->addWidget(buttonBox);
+ return;
+ }
+
+ // 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(_("Error Validating signature")));
+ } else if (mInputSignature != nullptr) {
+ const auto info = (boost::format(_("File was signed on %1%")) %
+ QLocale::system().toString(timestamp).toStdString())
+ .str() +
+ "<br/>" + _("It Contains") + ": " + "<br/><br/>";
+ mVboxLayout->addWidget(new QLabel(info.c_str()));
+ } else {
+ const auto info = (boost::format(_("Signed on %1%")) %
+ QLocale::system().toString(timestamp).toStdString())
+ .str() +
+ "<br/>" + _("It Contains") + ": " + "<br/><br/>";
+ mVboxLayout->addWidget(new QLabel(info.c_str()));
+ }
+ // 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);
}
+
+} // namespace GpgFrontend::UI \ No newline at end of file
diff --git a/include/ui/VerifyDetailsDialog.h b/src/ui/VerifyDetailsDialog.h
index ece2f1e7..3de4a56f 100644
--- a/include/ui/VerifyDetailsDialog.h
+++ b/src/ui/VerifyDetailsDialog.h
@@ -1,7 +1,7 @@
/**
- * This file is part of GPGFrontend.
+ * This file is part of GpgFrontend.
*
- * GPGFrontend is free software: you can redistribute it and/or modify
+ * 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.
@@ -25,29 +25,33 @@
#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, GpgME::GpgContext *ctx, KeyList *keyList, gpg_error_t error,
- gpgme_verify_result_t result);
-
-private slots:
-
- void slotRefresh();
-
-private:
- GpgME::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..a83845ab 100644
--- a/src/ui/WaitingDialog.cpp
+++ b/src/ui/WaitingDialog.cpp
@@ -1,20 +1,73 @@
+/**
+ * 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);
-
- 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();
+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);
+
+ this->setModal(true);
+ this->raise();
+ this->setWindowFlags(Qt::Window | Qt::WindowTitleHint |
+ Qt::CustomizeWindowHint);
+ this->setWindowTitle(title);
+ this->setAttribute(Qt::WA_DeleteOnClose);
+ this->setFixedSize(240, 42);
+
+ if (parentWidget() == nullptr) {
+ auto* screen = QGuiApplication::primaryScreen();
+ QRect geo = screen->availableGeometry();
+ int screen_width = geo.width();
+ int screen_height = geo.height();
+
+ LOG(INFO) << "primary screen available geometry" << screen_width
+ << screen_height;
+
+ auto pos = QPoint((screen_width - QWidget::width()) / 2,
+ (screen_height - QWidget::height()) / 2);
+ this->move(pos);
+
+ } else {
+ auto pos = QPoint(parent->x() + (parent->width() - QWidget::width()) / 2,
+ parent->y() + (parent->height() - QWidget::height()) / 2);
+ LOG(INFO) << "pos" << pos.x() << pos.y();
+ this->move(pos);
+ }
+
+ this->show();
}
+
+} // namespace GpgFrontend::UI
diff --git a/src/ui/WaitingDialog.h b/src/ui/WaitingDialog.h
new file mode 100644
index 00000000..798c2a3c
--- /dev/null
+++ b/src/ui/WaitingDialog.h
@@ -0,0 +1,46 @@
+/**
+ * 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 __UI_WAITING_DIALOG_H__
+#define __UI_WAITING_DIALOG_H__
+
+#include "ui/GpgFrontendUI.h"
+
+namespace GpgFrontend::UI {
+
+class WaitingDialog : public QDialog {
+ Q_OBJECT
+ public:
+ WaitingDialog(const QString& title, QWidget* parent);
+
+ public slots:
+
+ private slots:
+
+ private:
+};
+
+} // namespace GpgFrontend::UI
+
+#endif // __UI_WAITING_DIALOG_H__
diff --git a/src/ui/Wizard.cpp b/src/ui/Wizard.cpp
index 8b482675..de0107c4 100644
--- a/src/ui/Wizard.cpp
+++ b/src/ui/Wizard.cpp
@@ -1,7 +1,7 @@
/**
- * This file is part of GPGFrontend.
+ * This file is part of GpgFrontend.
*
- * GPGFrontend is free software: you can redistribute it and/or modify
+ * 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.
@@ -24,234 +24,302 @@
#include "ui/Wizard.h"
-Wizard::Wizard(GpgME::GpgContext *ctx, KeyMgmt *keyMgmt, QWidget *parent)
- : QWizard(parent), appPath(qApp->applicationDirPath()),
- settings(RESOURCE_DIR(appPath) + "/conf/gpgfrontend.ini", QSettings::IniFormat) {
- mCtx = ctx;
- mKeyMgmt = keyMgmt;
+#include "ui/settings/GlobalSettingStation.h"
- 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(QWidget* parent) : QWizard(parent) {
+ 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"));
-
- // 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()));
-
+ setWindowTitle(_("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"));
+
+ auto& settings = GlobalSettingStation::GetInstance().GetUISettings();
+ int next_page_id = -1;
+ try {
+ next_page_id = settings.lookup("wizard.next_page");
+ } catch (...) {
+ LOG(ERROR) << _("Setting Operation Error");
+ }
+ setStartId(next_page_id);
+
+ 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());
-
- 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);
+ LOG(INFO) << _("Called");
+ // Don't show is mapped to show -> negation
+ try {
+ auto& settings = GlobalSettingStation::GetInstance().GetUISettings();
+ if (!settings.exists("wizard")) {
+ settings.add("wizard", libconfig::Setting::TypeGroup);
}
- // selected entry from config
- QString langKey = settings.value("int/lang").toString();
- QString langValue = languages.value(langKey);
- if (langKey != "") {
- langSelectBox->setCurrentIndex(langSelectBox->findText(langValue));
+ auto& wizard = settings["wizard"];
+ if (!wizard.exists("show_wizard")) {
+ wizard.add("show_wizard", libconfig::Setting::TypeBoolean) = false;
+ } else {
+ wizard["show_wizard"] = false;
}
-
- 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);
+ GlobalSettingStation::GetInstance().Sync();
+ } catch (...) {
+ LOG(ERROR) << _("Setting Operation Error");
+ }
+ if (field("openHelp").toBool()) {
+ emit signalOpenHelp("docu.html#content");
+ }
}
-int IntroPage::nextId() const {
- return Wizard::Page_Choose;
+IntroPage::IntroPage(QWidget* parent) : QWizardPage(parent) {
+ setTitle(_("Getting Started..."));
+ setSubTitle(_("... with GpgFrontend"));
+
+ auto* topLabel = new QLabel(
+ QString(_("Welcome to use GpgFrontend for decrypting and signing text or "
+ "file!")) +
+ " <br><br><a href='https://gpgfrontend.pub'>GpgFrontend</a> " +
+ _("is a Powerful, Easy-to-Use, Compact, Cross-Platform, and "
+ "Installation-Free OpenPGP Crypto Tool.") +
+ _("For brief information have a look at the") +
+ " <a href='https://gpgfrontend.pub/index.html#/overview'>" +
+ _("Overview") + "</a> (" +
+ _("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(_("If it supports the language currently being used in your "
+ "system, GpgFrontend will automatically set it."));
+ langLabel->setWordWrap(true);
+
+ languages = SettingsDialog::listLanguages();
+ auto* langSelectBox = new QComboBox();
+
+ for (const auto& l : languages) {
+ langSelectBox->addItem(l);
+ }
+ // selected entry from config
+
+ // auto lang = "";
+ // auto& settings = GlobalSettingStation::GetInstance().GetUISettings();
+ // try {
+ // lang = settings.lookup("general.lang");
+ // } catch (...) {
+ // LOG(INFO) << "Read for general.lang failed";
+ // }
+ //
+ // QString langKey = lang;
+ // QString langValue = languages.value(langKey);
+ // LOG(INFO) << "lang key" << langKey.toStdString() << "lang value"
+ // << langValue.toStdString();
+ // 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->addStretch();
+ layout->addWidget(langLabel);
+ // layout->addWidget(langSelectBox);
+
+ setLayout(layout);
}
-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;
+// void IntroPage::slotLangChange(const QString& lang) {
+// auto& settings = GlobalSettingStation::GetInstance().GetUISettings();
+//
+// if (!settings.exists("general") ||
+// settings.lookup("general").getType() != libconfig::Setting::TypeGroup)
+// settings.add("general", libconfig::Setting::TypeGroup);
+//
+// auto& general = settings["general"];
+// if (!general.exists("lang"))
+// general.add("lang", libconfig::Setting::TypeString) =
+// languages.key(lang).toStdString();
+// else {
+// general["lang"] = languages.key(lang).toStdString();
+// }
+//
+// if (!settings.exists("wizard") ||
+// settings.lookup("wizard").getType() != libconfig::Setting::TypeGroup)
+// settings.add("wizard", libconfig::Setting::TypeGroup);
+//
+// auto& wizard = settings["wizard"];
+// if (!wizard.exists("next_page"))
+// wizard.add("next_page", libconfig::Setting::TypeInt) =
+// this->wizard()->currentId();
+// else {
+// wizard["next_page"] = this->wizard()->currentId();
+// }
+//
+// GlobalSettingStation::GetInstance().Sync();
+//
+// qApp->exit(RESTART_CODE);
+// }
+
+int IntroPage::nextId() const { return Wizard::Page_Choose; }
+
+ChoosePage::ChoosePage(QWidget* parent) : QWizardPage(parent) {
+ setTitle(_("Choose your action..."));
+ setSubTitle(_("...by clicking on the appropriate link."));
+
+ auto* keygenLabel = new QLabel(
+ QString(_(
+ "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\">" +
+ _("Generate Key") + "</a><hr>");
+ keygenLabel->setTextFormat(Qt::RichText);
+ keygenLabel->setTextInteractionFlags(Qt::TextBrowserInteraction);
+ keygenLabel->setOpenExternalLinks(true);
+ keygenLabel->setWordWrap(true);
+
+ auto* encrDecyTextLabel = new QLabel(
+ QString(_(
+ "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\">" +
+ _("Encrypt & Decrypt Text") + "</a> " + _("or") +
+ " <a "
+ "href=\"https://gpgfrontend.pub/index.html#/manual/sign-verify-text\">" +
+ _("Sign & Verify Text") + "</a><hr>");
+
+ encrDecyTextLabel->setTextFormat(Qt::RichText);
+ encrDecyTextLabel->setTextInteractionFlags(Qt::TextBrowserInteraction);
+ encrDecyTextLabel->setOpenExternalLinks(true);
+ encrDecyTextLabel->setWordWrap(true);
+
+ auto* signVerifyTextLabel = new QLabel(
+ QString(_("If you want to operate file, you can read ")) +
+ "<a "
+ "href=\"https://gpgfrontend.pub/index.html#/manual/"
+ "encrypt-decrypt-file\">" +
+ _("Encrypt & Sign File") + "</a> " + _("or") +
+ " <a "
+ "href=\"https://gpgfrontend.pub/index.html#/manual/sign-verify-file\">" +
+ _("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;
-}
+int ChoosePage::nextId() const { 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(GpgME::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(_("Create a keypair..."));
+ setSubTitle(_("...for decrypting and signing messages"));
+ auto* topLabel = new QLabel(
+ _("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"
+ ">" +
+ QString(_("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(_("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;
-}
+int KeyGenPage::nextId() const { return Wizard::Page_Conclusion; }
void KeyGenPage::slotGenerateKeyDialog() {
- qDebug() << "Try Opening KeyGenDialog";
- auto *keyGenDialog = new KeyGenDialog(mCtx, this);
- keyGenDialog->show();
- wizard()->next();
+ LOG(INFO) << "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(_("Ready."));
+ setSubTitle(_("Have fun with GpgFrontend!"));
+
+ auto* bottomLabel =
+ new QLabel(QString(_("You are ready to use GpgFrontend now.<br><br>")) +
+ "<a "
+ "href=\"https://saturneric.github.io/GpgFrontend/index.html#/"
+ "overview\">" +
+ _("The Online Document") + "</a>" +
+ _(" 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(_("Open offline help."));
+ openHelpCheckBox->setChecked(Qt::Checked);
+
+ dontShowWizardCheckBox = new QCheckBox(_("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;
-}
+int ConclusionPage::nextId() const { return -1; }
+
+} // namespace GpgFrontend::UI
diff --git a/src/ui/Wizard.h b/src/ui/Wizard.h
new file mode 100644
index 00000000..8d7395db
--- /dev/null
+++ b/src/ui/Wizard.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]> starting on May 12, 2021.
+ *
+ */
+
+#ifndef WIZARD_H
+#define WIZARD_H
+
+#include "gpg/GpgConstants.h"
+#include "ui/GpgFrontendUI.h"
+#include "ui/KeyMgmt.h"
+#include "ui/keygen/KeygenDialog.h"
+#include "ui/settings/SettingsDialog.h"
+
+namespace GpgFrontend::UI {
+
+class Wizard : public QWizard {
+ Q_OBJECT
+ Q_ENUMS(WizardPages)
+
+ public:
+ enum WizardPages { Page_Intro, Page_Choose, Page_GenKey, Page_Conclusion };
+
+ Wizard(QWidget* parent = nullptr);
+
+ 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:
+ 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/function/FileReadThread.cpp b/src/ui/function/FileReadThread.cpp
new file mode 100644
index 00000000..a5a861ea
--- /dev/null
+++ b/src/ui/function/FileReadThread.cpp
@@ -0,0 +1,68 @@
+/**
+ * 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.
+ *
+ */
+
+#include "FileReadThread.h"
+
+#include <boost/filesystem.hpp>
+#include <utility>
+
+namespace GpgFrontend::UI {
+
+FileReadThread::FileReadThread(std::string path) : path(std::move(path)) {}
+
+void FileReadThread::run() {
+ LOG(INFO) << "Started";
+ boost::filesystem::path read_file_path(this->path);
+ if (is_regular_file(read_file_path)) {
+ LOG(INFO) << "Read Open";
+
+ auto fp = fopen(read_file_path.string().c_str(), "r");
+ size_t read_size;
+ LOG(INFO) << "Thread Start Reading";
+
+ char buffer[8192];
+ while ((read_size = fread(buffer, sizeof(char), sizeof buffer, fp)) > 0) {
+ // Check isInterruptionRequested
+ if (QThread::currentThread()->isInterruptionRequested()) {
+ LOG(INFO) << "Read Thread isInterruptionRequested ";
+ fclose(fp);
+ return;
+ }
+ LOG(INFO) << "Read Thread Read block size " << read_size;
+ std::string buffer_str(buffer, read_size);
+
+ emit sendReadBlock(QString::fromStdString(buffer_str));
+#ifdef RELEASE
+ QThread::msleep(16);
+#else
+ QThread::msleep(24);
+#endif
+ }
+ fclose(fp);
+ emit readDone();
+ LOG(INFO) << "Thread End Reading";
+ }
+}
+
+} // namespace GpgFrontend::UI
diff --git a/src/ui/function/FileReadThread.h b/src/ui/function/FileReadThread.h
new file mode 100644
index 00000000..ebfcfb3c
--- /dev/null
+++ b/src/ui/function/FileReadThread.h
@@ -0,0 +1,52 @@
+/**
+ * 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_FILEREADTHREAD_H
+#define GPGFRONTEND_FILEREADTHREAD_H
+
+#include "ui/GpgFrontendUI.h"
+namespace GpgFrontend::UI {
+
+class FileReadThread : public QThread {
+ Q_OBJECT
+
+ public:
+ explicit FileReadThread(std::string path);
+
+ signals:
+
+ void sendReadBlock(const QString& block);
+
+ void readDone();
+
+ protected:
+ void run() override;
+
+ private:
+ std::string path;
+};
+
+} // namespace GpgFrontend::UI
+
+#endif // GPGFRONTEND_FILEREADTHREAD_H
diff --git a/src/ui/function/VersionCheckThread.cpp b/src/ui/function/VersionCheckThread.cpp
new file mode 100644
index 00000000..50a4160e
--- /dev/null
+++ b/src/ui/function/VersionCheckThread.cpp
@@ -0,0 +1,77 @@
+/**
+ * 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 "VersionCheckThread.h"
+
+#include "GpgFrontendBuildInfo.h"
+#include "rapidjson/document.h"
+
+using namespace rapidjson;
+
+namespace GpgFrontend::UI {
+
+void VersionCheckThread::run() {
+ LOG(INFO) << "Start Version Thread to get latest version from Github";
+
+ auto currentVersion = "v" + QString::number(VERSION_MAJOR) + "." +
+ QString::number(VERSION_MINOR) + "." +
+ QString::number(VERSION_PATCH);
+
+ while (mNetworkReply->isRunning()) {
+ QApplication::processEvents();
+ }
+
+ if (mNetworkReply->error() != QNetworkReply::NoError) {
+ LOG(ERROR) << "VersionCheckThread Found Network Error";
+ return;
+ }
+
+ QByteArray bytes = mNetworkReply->readAll();
+
+ Document d;
+ d.Parse(bytes.constData());
+
+ QString latestVersion = d["tag_name"].GetString();
+
+ LOG(INFO) << "Latest Version From Github" << latestVersion.toStdString();
+
+ QRegularExpression re(R"(^[vV](\d+\.)?(\d+\.)?(\*|\d+))");
+ QRegularExpressionMatch match = re.match(latestVersion);
+ if (match.hasMatch()) {
+ latestVersion = match.captured(0); // matched == "23 def"
+ LOG(INFO) << "Latest Version Matched" << latestVersion.toStdString();
+ } else {
+ latestVersion = currentVersion;
+ LOG(WARNING) << "Latest Version Unknown" << latestVersion.toStdString();
+ }
+
+ if (latestVersion != currentVersion) {
+ emit upgradeVersion(currentVersion, latestVersion);
+ }
+}
+
+VersionCheckThread::VersionCheckThread(QNetworkReply* networkReply)
+ : mNetworkReply(networkReply) {}
+
+} // namespace GpgFrontend::UI
diff --git a/include/ui/help/VersionCheckThread.h b/src/ui/function/VersionCheckThread.h
index 7ee90077..181ee947 100644
--- a/include/ui/help/VersionCheckThread.h
+++ b/src/ui/function/VersionCheckThread.h
@@ -1,7 +1,7 @@
/**
- * This file is part of GPGFrontend.
+ * This file is part of GpgFrontend.
*
- * GPGFrontend is free software: you can redistribute it and/or modify
+ * 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.
@@ -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/help/AboutDialog.cpp b/src/ui/help/AboutDialog.cpp
index 8fb504db..7358ced5 100644
--- a/src/ui/help/AboutDialog.cpp
+++ b/src/ui/help/AboutDialog.cpp
@@ -1,7 +1,7 @@
/**
- * This file is part of GPGFrontend.
+ * This file is part of GpgFrontend.
*
- * GPGFrontend is free software: you can redistribute it and/or modify
+ * 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.
@@ -23,197 +23,218 @@
*/
#include "ui/help/AboutDialog.h"
-#include "GpgFrontendBuildInfo.h"
+#include "GpgFrontendBuildInfo.h"
#include "rapidjson/document.h"
#include "rapidjson/writer.h"
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(QString(_("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, _("General"));
+ tabWidget->addTab(translatorsTab, _("Translators"));
+ tabWidget->addTab(updateTab, _("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()));
+
+ auto* mainLayout = new QVBoxLayout;
+ mainLayout->addWidget(tabWidget);
+ mainLayout->addWidget(buttonBox);
+ setLayout(mainLayout);
- this->resize(320, 580);
-
- this->show();
+ this->resize(320, 580);
+ 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 ") + GpgME::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>" +
+ _("<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>.") +
+ "<br><br> " + _("Built with Qt") + " " + qVersion() + " " +
+ _("and GPGME") + " " +
+ GpgFrontend::GpgContext::getGpgmeVersion().c_str() + "<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>" +
+ QString(_("It is recommended that you always check the version "
+ "of GpgFrontend and upgrade to the latest version.")) +
+ "</center><br><center>" +
+ _("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>" + QString(_("Current Version")) +
+ _(": ") + "<b>" + currentVersion +
+ "</b></center>");
+ currentVersionLabel->setWordWrap(true);
+
+ latestVersionLabel = new QLabel();
+ latestVersionLabel->setWordWrap(true);
+
+ upgradeLabel = new QLabel();
+ upgradeLabel->setText(
+ "<center>" +
+ QString(
+ _("The current version is inconsistent with the latest version on "
+ "github.")) +
+ "</center><br><center>" + _("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";
+ qDebug() << "Try to get latest version";
- QString baseUrl = "https://api.github.com/repos/saturneric/gpgfrontend/releases/latest";
+ QString baseUrl =
+ "https://api.github.com/repos/saturneric/gpgfrontend/releases/latest";
- 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();
+ 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";
- qDebug() << "Try to Process Reply Data From Update Server";
-
- this->pb->setHidden(true);
+ 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;
- }
+ Document d;
+ if (d.Parse(data.constData()).HasParseError() || !d.IsObject()) {
+ qDebug() << "VersionCheckThread Found Network Error";
+ auto latestVersion = "Unknown";
+ latestVersionLabel->setText(QString("<center><b>") +
+ _("Latest Version From Github") + ": " +
+ latestVersion + "</b></center>");
+ return;
+ }
- QString latestVersion = d["tag_name"].GetString();
+ QString latestVersion = d["tag_name"].GetString();
- qDebug() << "Latest Version From Github" << latestVersion;
+ 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";
+ 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>");
+ latestVersionLabel->setText("<center><b>" +
+ QString(_("Latest Version From Github")) + ": " +
+ latestVersion + "</b></center>");
- if(latestVersion > currentVersion) upgradeLabel->setHidden(false);
+ 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..a7d7099b 100644
--- a/include/ui/help/AboutDialog.h
+++ b/src/ui/help/AboutDialog.h
@@ -1,7 +1,7 @@
/**
- * This file is part of GPGFrontend.
+ * This file is part of GpgFrontend.
*
- * GPGFrontend is free software: you can redistribute it and/or modify
+ * 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.
@@ -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
deleted file mode 100644
index bf1bbeda..00000000
--- a/src/ui/help/VersionCheckThread.cpp
+++ /dev/null
@@ -1,75 +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 "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";
-
- auto currentVersion = "v" + QString::number(VERSION_MAJOR) + "."
- + QString::number(VERSION_MINOR) + "."
- + QString::number(VERSION_PATCH);
-
- while(mNetworkReply->isRunning()) {
- QApplication::processEvents();
- }
-
- if(mNetworkReply->error() != QNetworkReply::NoError) {
- qDebug() << "VersionCheckThread Found Network Error";
- return;
- }
-
- QByteArray bytes = mNetworkReply->readAll();
-
- Document d;
- d.Parse(bytes.constData());
-
- QString latestVersion = d["tag_name"].GetString();
-
- qDebug() << "Latest Version From Github" << 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) {
-
-}
diff --git a/src/ui/keygen/KeygenDialog.cpp b/src/ui/keygen/KeygenDialog.cpp
index 98216dc6..382be5cb 100644
--- a/src/ui/keygen/KeygenDialog.cpp
+++ b/src/ui/keygen/KeygenDialog.cpp
@@ -1,7 +1,7 @@
/**
- * This file is part of GPGFrontend.
+ * This file is part of GpgFrontend.
*
- * GPGFrontend is free software: you can redistribute it and/or modify
+ * 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.
@@ -23,339 +23,358 @@
*/
#include "ui/keygen/KeygenDialog.h"
+
+#include "gpg/function/GpgKeyOpera.h"
+#include "ui/SignalStation.h"
#include "ui/WaitingDialog.h"
-KeyGenDialog::KeyGenDialog(GpgME::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(_("Generate Key"));
+ this->setModal(true);
-void KeyGenDialog::generateKeyDialog() {
+ connect(this, SIGNAL(KeyGenerated()), SignalStation::GetInstance(),
+ SIGNAL(KeyDatabaseRefresh()));
- keyUsageGroupBox = create_key_usage_group_box();
+ generateKeyDialog();
+}
- auto *groupGrid = new QGridLayout(this);
- groupGrid->addWidget(create_basic_info_group_box(), 0, 0);
- groupGrid->addWidget(keyUsageGroupBox, 1, 0);
+void KeyGenDialog::generateKeyDialog() {
+ keyUsageGroupBox = create_key_usage_group_box();
- auto *nameList = new QWidget(this);
- nameList->setLayout(groupGrid);
+ auto* groupGrid = new QGridLayout(this);
+ groupGrid->addWidget(create_basic_info_group_box(), 0, 0);
+ groupGrid->addWidget(keyUsageGroupBox, 1, 0);
- auto *vbox2 = new QVBoxLayout();
- vbox2->addWidget(nameList);
- vbox2->addWidget(errorLabel);
- vbox2->addWidget(buttonBox);
+ auto* nameList = new QWidget(this);
+ nameList->setLayout(groupGrid);
- this->setLayout(vbox2);
+ auto* vbox2 = new QVBoxLayout();
+ vbox2->addWidget(nameList);
+ vbox2->addWidget(errorLabel);
+ vbox2->addWidget(buttonBox);
- set_signal_slot();
+ this->setLayout(vbox2);
- refresh_widgets_state();
+ set_signal_slot();
+ refresh_widgets_state();
}
void KeyGenDialog::slotKeyGenAccept() {
- QString errorString = "";
-
+ std::stringstream error_stream;
+
+ /**
+ * check for errors in keygen dialog input
+ */
+ if ((nameEdit->text()).size() < 5) {
+ error_stream << " " << _("Name must contain at least five characters.")
+ << std::endl;
+ }
+ if (emailEdit->text().isEmpty() || !check_email_address(emailEdit->text())) {
+ error_stream << " " << _("Please give a email address.") << std::endl;
+ }
+
+ /**
+ * primary keys should have a reasonable expiration date (no more than 2 years
+ * in the future)
+ */
+ if (dateEdit->dateTime() > QDateTime::currentDateTime().addYears(2)) {
+ error_stream << " " << _("Expiration time no more than 2 years.")
+ << std::endl;
+ }
+
+ auto err_string = error_stream.str();
+
+ if (err_string.empty()) {
/**
- * 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())
+ .toStdString());
- genKeyInfo.setUserid(QString("%1 (%3) <%2>").arg(nameEdit->text(), emailEdit->text(), commentEdit->text()));
+ 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) {
+ auto* msg_box = new QMessageBox(nullptr);
+ msg_box->setAttribute(Qt::WA_DeleteOnClose);
+ msg_box->setStandardButtons(QMessageBox::Ok);
+ msg_box->setWindowTitle(_("Success"));
+ msg_box->setText(_("The new key pair has been generated."));
+ msg_box->setModal(false);
+ msg_box->open();
+ emit KeyGenerated();
+ this->close();
} else {
- /**
- * create error message
- */
- errorLabel->setAutoFillBackground(true);
- QPalette error = errorLabel->palette();
- error.setColor(QPalette::Window, "#ff8080");
- errorLabel->setPalette(error);
- errorLabel->setText(errorString);
-
- this->show();
+ QMessageBox::critical(this, _("Failure"), _(gpgme_strerror(error)));
}
+
+ } else {
+ /**
+ * create error message
+ */
+ errorLabel->setAutoFillBackground(true);
+ QPalette error = errorLabel->palette();
+ error.setColor(QPalette::Window, "#ff8080");
+ errorLabel->setPalette(error);
+ errorLabel->setText(err_string.c_str());
+
+ 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() {
-
- auto *groupBox = new QGroupBox(this);
- auto *grid = new QGridLayout(this);
+QGroupBox* KeyGenDialog::create_key_usage_group_box() {
+ auto* groupBox = new QGroupBox(this);
+ auto* grid = new QGridLayout(this);
- groupBox->setTitle(tr("Key Usage"));
+ groupBox->setTitle(_("Key Usage"));
- auto* encrypt = new QCheckBox(tr("Encryption"), groupBox);
- encrypt->setTristate(false);
+ auto* encrypt = new QCheckBox(_("Encryption"), groupBox);
+ encrypt->setTristate(false);
- auto* sign = new QCheckBox(tr("Signing"),groupBox);
- sign->setTristate(false);
+ auto* sign = new QCheckBox(_("Signing"), groupBox);
+ sign->setTristate(false);
- auto* cert = new QCheckBox(tr("Certification"),groupBox);
- cert->setTristate(false);
+ auto* cert = new QCheckBox(_("Certification"), groupBox);
+ cert->setTristate(false);
- auto* auth = new QCheckBox(tr("Authentication"), groupBox);
- auth->setTristate(false);
+ auto* auth = new QCheckBox(_("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();
+ 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(QString(_("Name")) + ": "), 0, 0);
+ vbox1->addWidget(new QLabel(QString(_("Email Address")) + ": "), 1, 0);
+ vbox1->addWidget(new QLabel(QString(_("Comment")) + ": "), 2, 0);
+ vbox1->addWidget(new QLabel(QString(_("Expiration Date")) + ": "), 3, 0);
+ vbox1->addWidget(new QLabel(QString(_("Never Expire")) + ": "), 3, 3);
+ vbox1->addWidget(new QLabel(QString(_("KeySize (in Bit)")) + ": "), 4, 0);
+ vbox1->addWidget(new QLabel(QString(_("Key Type")) + ": "), 5, 0);
+ vbox1->addWidget(new QLabel(QString(_("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(_("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..c16a2e76
--- /dev/null
+++ b/src/ui/keygen/KeygenDialog.h
@@ -0,0 +1,117 @@
+/**
+ * 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);
+
+ signals:
+ void KeyGenerated();
+
+ 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 3d709d81..593b1cae 100644
--- a/src/ui/keygen/SubkeyGenerateDialog.cpp
+++ b/src/ui/keygen/SubkeyGenerateDialog.cpp
@@ -1,7 +1,7 @@
/**
- * This file is part of GPGFrontend.
+ * This file is part of GpgFrontend.
*
- * GPGFrontend is free software: you can redistribute it and/or modify
+ * 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.
@@ -23,277 +23,300 @@
*/
#include "ui/keygen/SubkeyGenerateDialog.h"
+
+#include "gpg/function/GpgKeyGetter.h"
+#include "gpg/function/GpgKeyOpera.h"
+#include "ui/SignalStation.h"
#include "ui/WaitingDialog.h"
-SubkeyGenerateDialog::SubkeyGenerateDialog(GpgME::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(_("Generate New Subkey"));
+ this->setLayout(vbox2);
+ this->setModal(true);
- this->setLayout(vbox2);
- this->setModal(true);
+ connect(this, SIGNAL(SubKeyGenerated()), SignalStation::GetInstance(),
+ SIGNAL(KeyDatabaseRefresh()));
- 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(_("Encryption"), groupBox);
+ encrypt->setTristate(false);
- auto* sign = new QCheckBox(tr("Signing"),groupBox);
- sign->setTristate(false);
+ auto* sign = new QCheckBox(_("Signing"), groupBox);
+ sign->setTristate(false);
- auto* cert = new QCheckBox(tr("Certification"),groupBox);
- cert->setTristate(false);
+ auto* cert = new QCheckBox(_("Certification"), groupBox);
+ cert->setTristate(false);
- auto* auth = new QCheckBox(tr("Authentication"), groupBox);
- auth->setTristate(false);
+ auto* auth = new QCheckBox(_("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();
+ 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(QString(_("Expiration Date")) + ": "), 2, 0);
+ vbox1->addWidget(new QLabel(QString(_("Never Expire")) + ": "), 2, 3);
+ vbox1->addWidget(new QLabel(QString(_("KeySize (in Bit)")) + ": "), 1, 0);
+ vbox1->addWidget(new QLabel(QString(_("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(_("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. "));
- }
+ std::stringstream err_stream;
- 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)) {
+ err_stream << " " << _("Expiration time no more than 2 years.") << " ";
+ }
- genKeyInfo.setKeySize(keySizeSpinBox->value());
+ auto err_string = err_stream.str();
- if (expireCheckBox->checkState()) {
- genKeyInfo.setNonExpired(true);
- } else {
- genKeyInfo.setExpired(dateEdit->dateTime());
- }
+ if (err_string.empty()) {
+ genKeyInfo->setKeySize(keySizeSpinBox->value());
- gpgme_error_t error = false;
- auto thread = QThread::create([&]() {
- error = mCtx->generateSubkey(mKey, &genKeyInfo);
- });
- thread->start();
-
- auto *dialog = new WaitingDialog("Generating", this);
- dialog->show();
-
- while (thread->isRunning()) {
- QCoreApplication::processEvents();
- }
+ if (expireCheckBox->checkState()) {
+ genKeyInfo->setNonExpired(true);
+ } else {
+ genKeyInfo->setExpired(
+ boost::posix_time::from_time_t(dateEdit->dateTime().toTime_t())
+ .date());
+ }
- dialog->close();
+ GpgError error;
+ auto thread = QThread::create([&]() {
+ LOG(INFO) << "SubkeyGenerateDialog::slotKeyGenAccept() Thread Started";
+ error = GpgKeyOpera::GetInstance().GenerateSubkey(mKey, genKeyInfo);
+ });
+ thread->start();
- 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)));
+ auto* dialog = new WaitingDialog("Generating", this);
+ dialog->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();
+ while (thread->isRunning()) {
+ QCoreApplication::processEvents();
}
+ dialog->close();
+
+ if (check_gpg_error_2_err_code(error) == GPG_ERR_NO_ERROR) {
+ auto* msg_box = new QMessageBox(nullptr);
+ msg_box->setAttribute(Qt::WA_DeleteOnClose);
+ msg_box->setStandardButtons(QMessageBox::Ok);
+ msg_box->setWindowTitle(_("Success"));
+ msg_box->setText(_("The new subkey has been generated."));
+ msg_box->setModal(false);
+ msg_box->open();
+
+ emit SubKeyGenerated();
+ this->close();
+ } else
+ QMessageBox::critical(this, _("Failure"), _(gpgme_strerror(error)));
+
+ } else {
+ /**
+ * create error message
+ */
+ errorLabel->setAutoFillBackground(true);
+ QPalette error = errorLabel->palette();
+ error.setColor(QPalette::Window, "#ff8080");
+ errorLabel->setPalette(error);
+ errorLabel->setText(err_string.c_str());
+
+ 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..ec7c9fb1
--- /dev/null
+++ b/src/ui/keygen/SubkeyGenerateDialog.h
@@ -0,0 +1,97 @@
+/**
+ * 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"
+#include "gpg/GpgGenKeyInfo.h"
+#include "ui/GpgFrontendUI.h"
+
+namespace GpgFrontend::UI {
+
+class SubkeyGenerateDialog : public QDialog {
+ Q_OBJECT
+
+ public:
+ explicit SubkeyGenerateDialog(const KeyId& key_id, QWidget* parent);
+
+ signals:
+ void SubKeyGenerated();
+
+ private:
+ GpgKey mKey;
+
+ std::unique_ptr<GenKeyInfo> genKeyInfo = std::make_unique<GenKeyInfo>(true);
+
+ 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/src/ui/keypair_details/EditSubKeyDialog.cpp b/src/ui/keypair_details/EditSubKeyDialog.cpp
index e44c987f..6c2e0ce1 100644
--- a/src/ui/keypair_details/EditSubKeyDialog.cpp
+++ b/src/ui/keypair_details/EditSubKeyDialog.cpp
@@ -1,7 +1,7 @@
/**
- * This file is part of GPGFrontend.
+ * This file is part of GpgFrontend.
*
- * GPGFrontend is free software: you can redistribute it and/or modify
+ * 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.
diff --git a/include/ui/keypair_details/EditSubKeyDialog.h b/src/ui/keypair_details/EditSubKeyDialog.h
index 6577d382..51842405 100644
--- a/include/ui/keypair_details/EditSubKeyDialog.h
+++ b/src/ui/keypair_details/EditSubKeyDialog.h
@@ -1,7 +1,7 @@
/**
- * This file is part of GPGFrontend.
+ * This file is part of GpgFrontend.
*
- * GPGFrontend is free software: you can redistribute it and/or modify
+ * 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.
@@ -25,10 +25,6 @@
#ifndef GPGFRONTEND_EDITSUBKEY_H
#define GPGFRONTEND_EDITSUBKEY_H
+class EditSubKeyDialog {};
-class EditSubKeyDialog {
-
-};
-
-
-#endif //GPGFRONTEND_EDITSUBKEY_H
+#endif // GPGFRONTEND_EDITSUBKEY_H
diff --git a/src/ui/keypair_details/KeyDetailsDialog.cpp b/src/ui/keypair_details/KeyDetailsDialog.cpp
index c80374d4..f3cab771 100644
--- a/src/ui/keypair_details/KeyDetailsDialog.cpp
+++ b/src/ui/keypair_details/KeyDetailsDialog.cpp
@@ -1,7 +1,7 @@
/**
- * This file is part of GPGFrontend.
+ * This file is part of GpgFrontend.
*
- * GPGFrontend is free software: you can redistribute it and/or modify
+ * 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.
@@ -24,21 +24,22 @@
#include "ui/keypair_details/KeyDetailsDialog.h"
-KeyDetailsDialog::KeyDetailsDialog(GpgME::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), _("KeyPair"));
+ tabWidget->addTab(new KeyPairUIDTab(key.id(), tabWidget), _("UIDs"));
+ tabWidget->addTab(new KeyPairSubkeyTab(key.id(), tabWidget), _("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(_("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 94fb1223..51fc01cf 100644
--- a/include/ui/keypair_details/KeyDetailsDialog.h
+++ b/src/ui/keypair_details/KeyDetailsDialog.h
@@ -1,7 +1,7 @@
/**
- * This file is part of GPGFrontend.
+ * This file is part of GpgFrontend.
*
- * GPGFrontend is free software: you can redistribute it and/or modify
+ * 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.
@@ -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(GpgME::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 e12af750..809a05f8 100644
--- a/src/ui/keypair_details/KeyNewUIDDialog.cpp
+++ b/src/ui/keypair_details/KeyNewUIDDialog.cpp
@@ -1,7 +1,7 @@
/**
- * This file is part of GPGFrontend.
+ * This file is part of GpgFrontend.
*
- * GPGFrontend is free software: you can redistribute it and/or modify
+ * 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.
@@ -24,79 +24,86 @@
#include "ui/keypair_details/KeyNewUIDDialog.h"
-KeyNewUIDDialog::KeyNewUIDDialog(GpgME::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"
+#include "ui/SignalStation.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(_("Name")), 0, 0);
+ gridLayout->addWidget(new QLabel(_("Email")), 1, 0);
+ gridLayout->addWidget(new QLabel(_("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(
+ new QLabel(_("Notice: The New UID Created will be set as Primary.")), 4,
+ 0, 1, 2);
+ gridLayout->addWidget(errorLabel, 5, 0, 1, 2);
+
+ connect(createButton, SIGNAL(clicked(bool)), this, SLOT(slotCreateNewUID()));
+
+ this->setLayout(gridLayout);
+ this->setWindowTitle(_("Create New UID"));
+ this->setAttribute(Qt::WA_DeleteOnClose, true);
+ this->setModal(true);
+
+ connect(this, SIGNAL(signalUIDCreated()), SignalStation::GetInstance(),
+ SIGNAL(KeyDatabaseRefresh()));
}
void KeyNewUIDDialog::slotCreateNewUID() {
-
- QString errorString = "";
-
+ std::stringstream error_stream;
+
+ /**
+ * check for errors in keygen dialog input
+ */
+ if ((name->text()).size() < 5) {
+ error_stream << " " << _("Name must contain at least five characters.")
+ << std::endl;
+ }
+ if (email->text().isEmpty() || !check_email_address(email->text())) {
+ error_stream << " " << _("Please give a email address.") << std::endl;
+ }
+ auto error_string = error_stream.str();
+ if (error_string.empty()) {
+ if (UidOperator::GetInstance().addUID(mKey, name->text().toStdString(),
+ comment->text().toStdString(),
+ email->text().toStdString())) {
+ emit finished(1);
+ emit signalUIDCreated();
+ } 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(error_string.c_str());
+
+ 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/src/ui/keypair_details/KeyNewUIDDialog.h b/src/ui/keypair_details/KeyNewUIDDialog.h
new file mode 100644
index 00000000..2e38a7f4
--- /dev/null
+++ b/src/ui/keypair_details/KeyNewUIDDialog.h
@@ -0,0 +1,64 @@
+/**
+ * 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_KEYNEWUIDDIALOG_H
+#define GPGFRONTEND_KEYNEWUIDDIALOG_H
+
+#include "gpg/GpgContext.h"
+#include "ui/GpgFrontendUI.h"
+
+namespace GpgFrontend::UI {
+class KeyNewUIDDialog : public QDialog {
+ Q_OBJECT
+
+ public:
+ KeyNewUIDDialog(const KeyId& key, QWidget* parent = nullptr);
+
+ signals:
+ void signalUIDCreated();
+
+ private slots:
+
+ void slotCreateNewUID();
+
+ private:
+ GpgKey mKey;
+
+ QLineEdit* name{};
+ QLineEdit* email{};
+ QLineEdit* comment{};
+
+ QPushButton* createButton{};
+
+ 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);
+};
+} // namespace GpgFrontend::UI
+
+#endif // GPGFRONTEND_KEYNEWUIDDIALOG_H
diff --git a/src/ui/keypair_details/KeyPairDetailTab.cpp b/src/ui/keypair_details/KeyPairDetailTab.cpp
index c0a2df99..f88e9edc 100644
--- a/src/ui/keypair_details/KeyPairDetailTab.cpp
+++ b/src/ui/keypair_details/KeyPairDetailTab.cpp
@@ -1,7 +1,7 @@
/**
- * This file is part of GPGFrontend.
+ * This file is part of GpgFrontend.
*
- * GPGFrontend is free software: you can redistribute it and/or modify
+ * 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.
@@ -23,330 +23,384 @@
*/
#include "ui/keypair_details/KeyPairDetailTab.h"
+
+#include "gpg/function/GpgKeyGetter.h"
+#include "gpg/function/GpgKeyImportExportor.h"
+#include "ui/SignalStation.h"
+#include "ui/UserInterfaceUtils.h"
#include "ui/WaitingDialog.h"
-KeyPairDetailTab::KeyPairDetailTab(GpgME::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(GpgKeyGetter::GetInstance().GetKey(key_id)) {
+ keyid = mKey.id();
+
+ ownerBox = new QGroupBox(_("Owner"));
+ keyBox = new QGroupBox(_("Master Key"));
+ fingerprintBox = new QGroupBox(_("Fingerprint"));
+ additionalUidBox = new QGroupBox(_("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() ? _("Exists") : _("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(QString(_("Name")) + ": "), 0, 0);
+ vboxOD->addWidget(new QLabel(QString(_("Email Address")) + ": "), 1, 0);
+ vboxOD->addWidget(new QLabel(QString(_("Comment")) + ": "), 2, 0);
+ vboxOD->addWidget(nameVarLabel, 0, 1);
+ vboxOD->addWidget(emailVarLabel, 1, 1);
+ vboxOD->addWidget(commentVarLabel, 2, 1);
+
+ vboxKD->addWidget(new QLabel(QString(_("Key ID")) + ": "), 0, 0);
+ vboxKD->addWidget(new QLabel(QString(_("Algorithm")) + ": "), 1, 0);
+ vboxKD->addWidget(new QLabel(QString(_("Key Size")) + ": "), 2, 0);
+ vboxKD->addWidget(new QLabel(QString(_("Nominal Usage")) + ": "), 3, 0);
+ vboxKD->addWidget(new QLabel(QString(_("Actual Usage")) + ": "), 4, 0);
+ vboxKD->addWidget(new QLabel(QString(_("Expires on")) + ": "), 5, 0);
+ vboxKD->addWidget(new QLabel(QString(_("Last Update")) + ": "), 6, 0);
+ vboxKD->addWidget(new QLabel(QString(_("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(_("Copy"));
+ copyFingerprintButton->setFlat(true);
+ copyFingerprintButton->setToolTip(_("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(_("Operations"));
+ auto* vboxPK = new QVBoxLayout();
+
+ auto* exportButton =
+ new QPushButton(_("Export Private Key (Include Subkey)"));
+ vboxPK->addWidget(exportButton);
+ connect(exportButton, SIGNAL(clicked()), this,
+ SLOT(slotExportPrivateKey()));
+
+ if (mKey.has_master_key()) {
+ auto* editExpiresButton =
+ new QPushButton(_("Modify Expiration Datetime (Master Key)"));
+ vboxPK->addWidget(editExpiresButton);
+ connect(editExpiresButton, SIGNAL(clicked()), this,
+ SLOT(slotModifyEditDatetime()));
+
+ auto hBoxLayout = new QHBoxLayout();
+ auto* keyServerOperaButton =
+ new QPushButton(_("Key Server Operation (Pubkey)"));
+ keyServerOperaButton->setStyleSheet("text-align:center;");
+
+ auto* revokeCertGenButton =
+ new QPushButton(_("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(_("Warning: The Master Key has expired."));
+ }
+ if (mKey.revoked()) {
+ expLabel->setText(_("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);
+ }
+
+ // when key database updated
+ connect(SignalStation::GetInstance(), SIGNAL(KeyDatabaseRefresh()), this,
+ SLOT(slotRefreshKey()));
+
+ 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->getKeyById(*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, _("Exporting private Key"),
+ "<h3>" + QString(_("You are about to export your")) +
+ "<font color=\"red\">" + _(" PRIVATE KEY ") + "</font>!</h3>\n" +
+ _("This is NOT your Public Key, so DON'T give it away.") + "<br />" +
+ _("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, _("Error"), _("Key Not Found."));
+ return;
}
+ auto fileString =
+ key.name() + " " + key.email() + "(" + key.id() + ")_secret.asc";
+ auto fileName =
+ QFileDialog::getSaveFileName(
+ this, _("Export Key To File"), QString::fromStdString(fileString),
+ QString(_("Key Files")) + " (*.asc *.txt);;All Files (*)")
+ .toStdString();
+
+ if (!write_buffer_to_file(fileName, *keyArray)) {
+ QMessageBox::critical(
+ nullptr, _("Export Error"),
+ QString(_("Couldn't open %1 for writing")).arg(fileName.c_str()));
+ 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(" ", QString());
+ 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.id(), this);
+ dialog->show();
}
void KeyPairDetailTab::slotRefreshKeyInfo() {
+ nameVarLabel->setText(QString::fromStdString(mKey.name()));
+ emailVarLabel->setText(QString::fromStdString(mKey.email()));
- nameVarLabel->setText(mKey.name);
- emailVarLabel->setText(mKey.email);
-
- commentVarLabel->setText(mKey.comment);
- keyidVarLabel->setText(mKey.id);
+ commentVarLabel->setText(QString::fromStdString(mKey.comment()));
+ keyidVarLabel->setText(QString::fromStdString(mKey.id()));
- QString usage;
- QTextStream usage_steam(&usage);
+ 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 ";
+ 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);
+ usageVarLabel->setText(usage);
- QString actualUsage;
- QTextStream actual_usage_steam(&actualUsage);
+ QString actualUsage;
+ QTextStream actual_usage_steam(&actualUsage);
- if (GpgME::GpgContext::checkIfKeyCanCert(mKey))
- actual_usage_steam << "Cert ";
- if (GpgME::GpgContext::checkIfKeyCanEncr(mKey))
- actual_usage_steam << "Encr ";
- if (GpgME::GpgContext::checkIfKeyCanSign(mKey))
- actual_usage_steam << "Sign ";
- if (GpgME::GpgContext::checkIfKeyCanAuth(mKey))
- actual_usage_steam << "Auth ";
+ 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);
+ actualUsageVarLabel->setText(actualUsage);
- QString keySizeVal, keyExpireVal, keyCreateTimeVal, keyAlgoVal;
+ 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();
- }
+ keySizeVal = QString::number(mKey.length());
- keyAlgoVal = mKey.pubkey_algo;
- keyCreateTimeVal = mKey.create_time.toString();
+ if (to_time_t(boost::posix_time::ptime(mKey.expires())) == 0) {
+ keyExpireVal = _("Never Expire");
+ } else {
+ keyExpireVal =
+ QString::fromStdString(boost::gregorian::to_iso_string(mKey.expires()));
+ }
- keySizeVarLabel->setText(keySizeVal);
- expireVarLabel->setText(keyExpireVal);
- createdVarLabel->setText(keyCreateTimeVal);
- algorithmVarLabel->setText(keyAlgoVal);
+ keyAlgoVal = QString::fromStdString(mKey.pubkey_algo());
+ keyCreateTimeVal = QString::fromStdString(to_iso_string(mKey.create_time()));
- fingerPrintVarLabel->setText(beautifyFingerprint(mKey.fpr));
+ 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);
+ 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()));
+ auto* uploadKeyPair = new QAction(_("Upload Key Pair to Key Server"), this);
+ connect(uploadKeyPair, SIGNAL(triggered()), this,
+ SLOT(slotUploadKeyToServer()));
+ auto* updateKeyPair = new QAction(_("Update Key Pair"), this);
+ connect(updateKeyPair, SIGNAL(triggered()), this,
+ SLOT(slotUpdateKeyToServer()));
- keyServerOperaMenu->addAction(uploadKeyPair);
- // TODO Solve Refresh Problem
-// keyServerOperaMenu->addAction(updateKeyPair);
+ keyServerOperaMenu->addAction(uploadKeyPair);
+ 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);
+ dialog->show();
+ dialog->slotUpload();
}
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->slotImport(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 literal = QStringLiteral("%1 (*.rev)").arg(_("Revocation Certificates"));
+ QString m_output_file_name;
+
+ QFileDialog dialog(this, "Generate revocation certificate", QString(),
+ literal);
+ dialog.setDefaultSuffix(".rev");
+ dialog.setAcceptMode(QFileDialog::AcceptSave);
+
+ if (dialog.exec()) m_output_file_name = dialog.selectedFiles().front();
+
+ if (!m_output_file_name.isEmpty())
+ CommonUtils::GetInstance()->slotExecuteGpgCommand(
+ {"--command-fd", "0", "--status-fd", "1", "--no-tty", "-o",
+ m_output_file_name, "--gen-revoke", mKey.fpr().c_str()},
+ [](QProcess* proc) -> void {
+ // Code From Gpg4Win
+ while (proc->canReadLine()) {
+ const QString line = QString::fromUtf8(proc->readLine()).trimmed();
+ LOG(INFO) << "line" << line.toStdString();
+ if (line == QLatin1String("[GNUPG:] GET_BOOL gen_revoke.okay")) {
+ proc->write("y\n");
+ } else if (line == QLatin1String("[GNUPG:] GET_LINE "
+ "ask_revocation_reason.code")) {
+ proc->write("0\n");
+ } else if (line == QLatin1String("[GNUPG:] GET_LINE "
+ "ask_revocation_reason.text")) {
+ proc->write("\n");
+ } else if (line ==
+ QLatin1String(
+ "[GNUPG:] GET_BOOL openfile.overwrite.okay")) {
+ // We asked before
+ proc->write("y\n");
+ } else if (line == QLatin1String("[GNUPG:] GET_BOOL "
+ "ask_revocation_reason.okay")) {
+ proc->write("y\n");
+ }
+ }
+ });
+}
+void KeyPairDetailTab::slotRefreshKey() {
+ LOG(INFO) << _("Called");
+ this->mKey = GpgKeyGetter::GetInstance().GetKey(mKey.id());
+ this->slotRefreshKeyInfo();
}
+} // 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..782696ac
--- /dev/null
+++ b/src/ui/keypair_details/KeyPairDetailTab.h
@@ -0,0 +1,105 @@
+/**
+ * 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 "KeySetExpireDateDialog.h"
+#include "gpg/GpgContext.h"
+#include "ui/GpgFrontendUI.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();
+
+ void slotRefreshKey();
+
+ 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 6a924394..4458be50 100644
--- a/src/ui/keypair_details/KeyPairSubkeyTab.cpp
+++ b/src/ui/keypair_details/KeyPairSubkeyTab.cpp
@@ -1,7 +1,7 @@
/**
- * This file is part of GPGFrontend.
+ * This file is part of GpgFrontend.
*
- * GPGFrontend is free software: you can redistribute it and/or modify
+ * 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.
@@ -24,243 +24,278 @@
#include "ui/keypair_details/KeyPairSubkeyTab.h"
-KeyPairSubkeyTab::KeyPairSubkeyTab(GpgME::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"
+#include "ui/SignalStation.h"
+
+namespace GpgFrontend::UI {
+
+KeyPairSubkeyTab::KeyPairSubkeyTab(const std::string& key_id, QWidget* parent)
+ : QWidget(parent), mKey(GpgKeyGetter::GetInstance().GetKey(key_id)) {
+ createSubkeyList();
+ createSubkeyOperaMenu();
+
+ listBox = new QGroupBox("Subkey List");
+ detailBox = new QGroupBox("Detail of Selected Subkey");
+
+ auto uidButtonsLayout = new QGridLayout();
+
+ auto addSubkeyButton = new QPushButton(_("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(QString(_("Key ID")) + ": "), 0, 0);
+ subkeyDetailLayout->addWidget(new QLabel(QString(_("Algorithm")) + ": "), 1,
+ 0);
+ subkeyDetailLayout->addWidget(new QLabel(QString(_("Key Size")) + ": "), 2,
+ 0);
+ subkeyDetailLayout->addWidget(new QLabel(QString(_("Usage")) + ": "), 3, 0);
+ subkeyDetailLayout->addWidget(new QLabel(QString(_("Expires On")) + ": "), 4,
+ 0);
+ subkeyDetailLayout->addWidget(new QLabel(QString(_("Last Update")) + ": "), 5,
+ 0);
+ subkeyDetailLayout->addWidget(new QLabel(QString(_("Existence")) + ": "), 6,
+ 0);
+ subkeyDetailLayout->addWidget(new QLabel(QString(_("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()));
+
+ // key database refresh signal
+ connect(SignalStation::GetInstance(), SIGNAL(KeyDatabaseRefresh()), this,
+ SLOT(slotRefreshKeyInfo()));
+ connect(SignalStation::GetInstance(), SIGNAL(KeyDatabaseRefresh()), this,
+ SLOT(slotRefreshSubkeyList()));
+
+ 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 << _("Subkey ID") << _("Key Size") << _("Algo") << _("Create Date")
+ << _("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);
+ LOG(INFO) << "KeyPairSubkeyTab::slotRefreshSubkeyList Called";
+ 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
+ ? _("Never Expire")
+ : QString::fromStdString(to_iso_string(subkeys.expires())));
+ tmp4->setTextAlignment(Qt::AlignCenter);
+ subkeyList->setItem(row, 4, tmp4);
+
+ if (!row) {
+ for (auto i = 0; i < subkeyList->columnCount(); i++) {
+ subkeyList->item(row, i)->setForeground(QColor(65, 105, 255));
+ }
}
- subkeyList->setRowCount(buffered_subkeys.size());
-
- for(const auto& subkeys : buffered_subkeys) {
+ row++;
+ }
- 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);
- }
+ if (subkeyList->rowCount() > 0) {
+ subkeyList->selectRow(0);
+ }
}
void KeyPairSubkeyTab::slotAddSubkey() {
- auto dialog = new SubkeyGenerateDialog(mCtx, mKey, this);
- dialog->show();
+ auto dialog = new SubkeyGenerateDialog(mKey.id(), 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
+ ? _("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(_("Revoke Subkey"));
+ auto* editSubkeyAct = new QAction(_("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();
-}
-
-void KeyPairSubkeyTab::slotRevokeSubkey() {
+ LOG(INFO) << "KeyPairSubkeyTab::slotEditSubkey Fpr"
+ << getSelectedSubkey().fpr();
+ auto dialog =
+ new KeySetExpireDateDialog(mKey.id(), getSelectedSubkey().fpr(), this);
+ dialog->show();
}
-void KeyPairSubkeyTab::contextMenuEvent(QContextMenuEvent *event) {
- if (!subkeyList->selectedItems().isEmpty()) {
- subkeyOperaMenu->exec(event->globalPos());
- }
+void KeyPairSubkeyTab::slotRevokeSubkey() {}
+
+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];
}
+void KeyPairSubkeyTab::slotRefreshKeyInfo() {
+ mKey = GpgKeyGetter::GetInstance().GetKey(mKey.id());
+}
+
+} // 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..018f6ddc
--- /dev/null
+++ b/src/ui/keypair_details/KeyPairSubkeyTab.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_KEYPAIRSUBKEYTAB_H
+#define GPGFRONTEND_KEYPAIRSUBKEYTAB_H
+
+#include "KeySetExpireDateDialog.h"
+#include "gpg/GpgContext.h"
+#include "ui/GpgFrontendUI.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();
+
+ void slotRefreshKeyInfo();
+
+ 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 2954aadb..3d56699a 100644
--- a/src/ui/keypair_details/KeyPairUIDTab.cpp
+++ b/src/ui/keypair_details/KeyPairUIDTab.cpp
@@ -1,7 +1,7 @@
/**
- * This file is part of GPGFrontend.
+ * This file is part of GpgFrontend.
*
- * GPGFrontend is free software: you can redistribute it and/or modify
+ * 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.
@@ -24,488 +24,511 @@
#include "ui/keypair_details/KeyPairUIDTab.h"
-KeyPairUIDTab::KeyPairUIDTab(GpgME::GpgContext *ctx, const GpgKey &key, QWidget *parent) : QWidget(parent), mKey(key) {
+#include "gpg/function/GpgKeyGetter.h"
+#include "gpg/function/GpgKeyManager.h"
+#include "gpg/function/UidOperator.h"
+#include "ui/SignalStation.h"
- mCtx = ctx;
+namespace GpgFrontend::UI {
- createUIDList();
- createSignList();
- createManageUIDMenu();
- createUIDPopupMenu();
- createSignPopupMenu();
+KeyPairUIDTab::KeyPairUIDTab(const std::string& key_id, QWidget* parent)
+ : QWidget(parent), mKey(GpgKeyGetter::GetInstance().GetKey(key_id)) {
+ 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(_("New UID"));
+ auto manageUIDButton = new QPushButton(_("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(_("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(_("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(uidList, SIGNAL(itemSelectionChanged()), this,
+ SLOT(slotRefreshSigList()));
- connect(addUIDButton, SIGNAL(clicked(bool)), this, SLOT(slotAddUID()));
- connect(mCtx, SIGNAL(signalKeyInfoChanged()), this, SLOT(slotRefreshUIDList()));
- connect(uidList, SIGNAL(itemSelectionChanged()), this, SLOT(slotRefreshSigList()));
+ // Key Database Refresh
+ connect(SignalStation::GetInstance(), SIGNAL(KeyDatabaseRefresh()), this,
+ SLOT(slotRefreshKey()));
- setLayout(vboxLayout);
- setAttribute(Qt::WA_DeleteOnClose, true);
+ connect(this, SIGNAL(signalUpdateUIDInfo()), SignalStation::GetInstance(),
+ SIGNAL(KeyDatabaseRefresh()));
- slotRefreshUIDList();
+ setLayout(vboxLayout);
+ setAttribute(Qt::WA_DeleteOnClose, true);
+
+ 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 << _("Select") << _("Name") << _("Email") << _("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 << _("Key ID") << _("Name") << _("Email") << _("Create Date")
+ << _("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());
-
- for(const auto& uid : buffered_uids) {
+ uidList->setRowCount(buffered_uids.size());
- auto *tmp0 = new QTableWidgetItem(uid->name);
- uidList->setItem(row, 1, tmp0);
+ for (const auto& uid : buffered_uids) {
+ auto* tmp0 = new QTableWidgetItem(QString::fromStdString(uid.name()));
+ uidList->setItem(row, 1, tmp0);
- auto *tmp1 = new QTableWidgetItem(uid->email);
- uidList->setItem(row, 2, tmp1);
+ auto* tmp1 = new QTableWidgetItem(QString::fromStdString(uid.email()));
+ uidList->setItem(row, 2, tmp1);
- auto *tmp2 = new QTableWidgetItem(uid->comment);
- uidList->setItem(row, 3, tmp2);
+ auto* tmp2 = new QTableWidgetItem(QString::fromStdString(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++;
+ if (!row) {
+ for (auto i = 0; i < uidList->columnCount(); i++) {
+ uidList->item(row, i)->setForeground(QColor(65, 105, 255));
+ }
}
- if(uidList->rowCount() > 0) {
- uidList->selectRow(0);
- }
+ row++;
+ }
- slotRefreshSigList();
+ if (uidList->rowCount() > 0) {
+ uidList->selectRow(0);
+ }
+
+ 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
+ ? _("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() {
-
- 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 keySignDialog = new KeyUIDSignDialog(mCtx, mKey, selected_uids, this);
- keySignDialog->show();
+ auto selected_uids = getUIDChecked();
+
+ if (selected_uids->empty()) {
+ QMessageBox::information(
+ nullptr, _("Invalid Operation"),
+ _("Please select one or more UIDs before doing this operation."));
+ return;
+ }
+
+ auto keySignDialog =
+ new KeyUIDSignDialog(mKey, std::move(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(_("Sign Selected UID(s)"), this);
+ connect(signUIDAct, SIGNAL(triggered()), this, SLOT(slotAddSign()));
+ auto* delUIDAct = new QAction(_("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, _("Successful Operation"),
+ _("Successfully added a new UID."));
+ } else if (result == -1) {
+ QMessageBox::critical(nullptr, _("Operation Failed"),
+ _("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;
- }
-
- 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."));
- }
-
+ auto selected_uids = getUIDChecked();
+
+ if (selected_uids->empty()) {
+ QMessageBox::information(
+ nullptr, _("Invalid Operation"),
+ _("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, _("Deleting UIDs"),
+ "<b>" +
+ QString(
+ _("Are you sure that you want to delete the following UIDs?")) +
+ "</b><br/><br/>" + keynames + +"<br/>" +
+ _("The action can not be undone."),
+ QMessageBox::No | QMessageBox::Yes);
+
+ if (ret == QMessageBox::Yes) {
+ for (const auto& uid : *selected_uids) {
+ LOG(INFO) << "KeyPairUIDTab::slotDelUID UID" << uid;
+ if (!UidOperator::GetInstance().revUID(mKey, uid)) {
+ QMessageBox::critical(
+ nullptr, _("Operation Failed"),
+ QString(_("An error occurred during the delete %1 operation."))
+ .arg(uid.c_str()));
+ }
}
+ emit signalUpdateUIDInfo();
+ }
}
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, _("Set Primary UID"),
+ "<b>" +
+ QString(_("Are you sure that you want to set the Primary UID to?")) +
+ "</b><br/><br/>" + keynames + +"<br/>" +
+ _("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, _("Operation Failed"),
+ _("An error occurred during the operation."));
+ } else {
+ emit signalUpdateUIDInfo();
}
+ }
}
-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 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(_("Set As Primary"), this);
+ connect(serPrimaryUIDAct, SIGNAL(triggered()), this,
+ SLOT(slotSetPrimaryUID()));
+ auto* signUIDAct = new QAction(_("Sign UID"), this);
+ connect(signUIDAct, SIGNAL(triggered()), this, SLOT(slotAddSignSingle()));
+ auto* delUIDAct = new QAction(_("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() {
-
- GpgUID selected_uid;
-
- 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 selected_uids = getUIDSelected();
+
+ if (selected_uids->empty()) {
+ QMessageBox::information(
+ nullptr, _("Invalid Operation"),
+ _("Please select one UID before doing this operation."));
+ return;
+ }
+
+ auto keySignDialog =
+ new KeyUIDSignDialog(mKey, std::move(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, _("Invalid Operation"),
+ _("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, _("Deleting UID"),
+ "<b>" +
+ QString(
+ _("Are you sure that you want to delete the following uid?")) +
+ "</b><br/><br/>" + keynames + +"<br/>" +
+ _("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, _("Operation Failed"),
+ _("An error occurred during the operation."));
+ } else {
+ emit signalUpdateUIDInfo();
}
+ }
}
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(_("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, _("Invalid Operation"),
+ _("Please select one Key Signature before doing this operation."));
+ return;
+ }
+
+ if (!GpgKeyGetter::GetInstance()
+ .GetKey(selected_signs->front().first)
+ .good()) {
+ QMessageBox::critical(
+ nullptr, _("Invalid Operation"),
+ _("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, _("Deleting Key Signature"),
+ "<b>" +
+ QString(_("Are you sure that you want to delete "
+ "the following signature?")) +
+ "</b><br/><br/>" + keynames + +"<br/>" +
+ _("The action can not be undone."),
+ QMessageBox::No | QMessageBox::Yes);
+
+ if (ret == QMessageBox::Yes) {
+ if (!GpgKeyManager::GetInstance().revSign(mKey, selected_signs)) {
+ QMessageBox::critical(nullptr, _("Operation Failed"),
+ _("An error occurred during the operation."));
}
+ }
}
+void KeyPairUIDTab::slotRefreshKey() {
+ this->mKey = GpgKeyGetter::GetInstance().GetKey(this->mKey.id());
+ this->slotRefreshUIDList();
+ this->slotRefreshSigList();
+}
+
+} // namespace GpgFrontend::UI
diff --git a/src/ui/keypair_details/KeyPairUIDTab.h b/src/ui/keypair_details/KeyPairUIDTab.h
new file mode 100644
index 00000000..6dece8d5
--- /dev/null
+++ b/src/ui/keypair_details/KeyPairUIDTab.h
@@ -0,0 +1,100 @@
+/**
+ * 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_KEYPAIRUIDTAB_H
+#define GPGFRONTEND_KEYPAIRUIDTAB_H
+
+#include "KeyNewUIDDialog.h"
+#include "KeyUIDSignDialog.h"
+#include "gpg/GpgContext.h"
+#include "ui/GpgFrontendUI.h"
+
+namespace GpgFrontend::UI {
+
+class KeyPairUIDTab : public QWidget {
+ Q_OBJECT
+
+ public:
+ KeyPairUIDTab(const std::string& key_id, QWidget* parent);
+
+ signals:
+ void signalUpdateUIDInfo();
+
+ private:
+ GpgKey mKey;
+ QTableWidget* uidList{};
+ QTableWidget* sigList{};
+ QMenu* manageSelectedUIDMenu{};
+ QMenu* uidPopupMenu{};
+ QMenu* signPopupMenu{};
+ std::vector<GpgUID> buffered_uids;
+ std::vector<GpgKeySignature> buffered_signatures;
+
+ void createUIDList();
+
+ void createSignList();
+
+ void createManageUIDMenu();
+
+ void createUIDPopupMenu();
+
+ void createSignPopupMenu();
+
+ UIDArgsListPtr getUIDChecked();
+
+ UIDArgsListPtr getUIDSelected();
+
+ SignIdArgsListPtr getSignSelected();
+
+ private slots:
+
+ void slotRefreshUIDList();
+
+ void slotRefreshSigList();
+
+ void slotAddSign();
+
+ void slotAddSignSingle();
+
+ void slotAddUID();
+
+ void slotDelUID();
+
+ void slotDelUIDSingle();
+
+ void slotSetPrimaryUID();
+
+ void slotDelSign();
+
+ void slotRefreshKey();
+
+ static void slotAddUIDResult(int result);
+
+ protected:
+ void contextMenuEvent(QContextMenuEvent* event) override;
+};
+
+} // namespace GpgFrontend::UI
+
+#endif // GPGFRONTEND_KEYPAIRUIDTAB_H
diff --git a/src/ui/keypair_details/KeySetExpireDateDialog.cpp b/src/ui/keypair_details/KeySetExpireDateDialog.cpp
index f76fa3ab..d197a76b 100644
--- a/src/ui/keypair_details/KeySetExpireDateDialog.cpp
+++ b/src/ui/keypair_details/KeySetExpireDateDialog.cpp
@@ -1,7 +1,7 @@
/**
- * This file is part of GPGFrontend.
+ * This file is part of GpgFrontend.
*
- * GPGFrontend is free software: you can redistribute it and/or modify
+ * 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.
@@ -24,51 +24,99 @@
#include "ui/keypair_details/KeySetExpireDateDialog.h"
-KeySetExpireDateDialog::KeySetExpireDateDialog(GpgME::GpgContext *ctx, const GpgKey &key, const GpgSubKey *subkey, QWidget *parent) :
-QDialog(parent), mKey(key), mSubkey(subkey), mCtx(ctx) {
-
- 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"));
-
- 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);
+#include <utility>
+
+#include "gpg/function/GpgKeyGetter.h"
+#include "gpg/function/GpgKeyOpera.h"
+#include "ui/SignalStation.h"
+
+namespace GpgFrontend::UI {
+
+KeySetExpireDateDialog::KeySetExpireDateDialog(const KeyId& key_id,
+ QWidget* parent)
+ : QDialog(parent), mKey(GpgKeyGetter::GetInstance().GetKey(key_id)) {
+ init();
+}
+
+KeySetExpireDateDialog::KeySetExpireDateDialog(const KeyId& key_id,
+ std::string subkey_fpr,
+ QWidget* parent)
+ : QDialog(parent),
+ mKey(GpgKeyGetter::GetInstance().GetKey(key_id)),
+ mSubkey(std::move(subkey_fpr)) {
+ init();
}
void KeySetExpireDateDialog::slotConfirm() {
- QDateTime *expires = nullptr;
- if(this->nonExpiredCheck->checkState() == Qt::Unchecked) {
- expires = new QDateTime(this->dateTimeEdit->dateTime());
- }
-
- if(!mCtx->setExpire(mKey, mSubkey, expires)) {
- QMessageBox::critical(nullptr,
- tr("Operation Failed"),
- tr("An error occurred during the operation."));
- }
- delete expires;
- this->close();
+ LOG(INFO) << "KeySetExpireDateDialog::slotConfirm Called";
+
+ 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());
+ LOG(INFO) << "KeySetExpireDateDialog::slotConfirm" << mKey.id() << mSubkey
+ << *expires;
+ } else {
+ LOG(INFO) << "KeySetExpireDateDialog::slotConfirm" << mKey.id() << mSubkey
+ << "Non Expired";
+ }
+
+ auto err = GpgKeyOpera::GetInstance().SetExpire(mKey, mSubkey, expires);
+
+ if (check_gpg_error_2_err_code(err) == GPG_ERR_NO_ERROR) {
+ auto* msg_box = new QMessageBox(nullptr);
+ msg_box->setAttribute(Qt::WA_DeleteOnClose);
+ msg_box->setStandardButtons(QMessageBox::Ok);
+ msg_box->setWindowTitle(_("Success"));
+ msg_box->setText(_("The expire date of the key pair has been updated."));
+ msg_box->setModal(false);
+ msg_box->open();
+
+ emit signalKeyExpireDateUpdated();
+
+ } else {
+ QMessageBox::critical(this, _("Failure"), _(gpgme_strerror(err)));
+ }
+
+ 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(_("Confirm"));
+
+ auto* gridLayout = new QGridLayout();
+ gridLayout->addWidget(dateTimeEdit, 0, 0, 1, 2);
+ gridLayout->addWidget(nonExpiredCheck, 0, 2, 1, 1, Qt::AlignRight);
+ gridLayout->addWidget(new QLabel(_("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);
+
+ connect(this, SIGNAL(signalKeyExpireDateUpdated()),
+ SignalStation::GetInstance(), SIGNAL(KeyDatabaseRefresh()));
}
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 118bc5ed..37a7f7e4 100644
--- a/include/ui/keypair_details/KeySetExpireDateDialog.h
+++ b/src/ui/keypair_details/KeySetExpireDateDialog.h
@@ -1,7 +1,7 @@
/**
- * This file is part of GPGFrontend.
+ * This file is part of GpgFrontend.
*
- * GPGFrontend is free software: you can redistribute it and/or modify
+ * 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.
@@ -25,29 +25,40 @@
#ifndef GPGFRONTEND_KEYSETEXPIREDATEDIALOG_H
#define GPGFRONTEND_KEYSETEXPIREDATEDIALOG_H
-#include "GpgFrontend.h"
#include "gpg/GpgContext.h"
-#include "gpg/GpgKey.h"
-#include "gpg/GpgSubKey.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(GpgME::GpgContext *ctx, const GpgKey &key, const GpgSubKey *subkey, QWidget *parent = nullptr);
-
-private:
- GpgME::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, std::string subkey_fpr,
+ QWidget* parent = nullptr);
+
+ signals:
+ void signalKeyExpireDateUpdated();
+
+ 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 9232cfce..6cce116b 100644
--- a/src/ui/keypair_details/KeyUIDSignDialog.cpp
+++ b/src/ui/keypair_details/KeyUIDSignDialog.cpp
@@ -1,7 +1,7 @@
/**
- * This file is part of GPGFrontend.
+ * This file is part of GpgFrontend.
*
- * GPGFrontend is free software: you can redistribute it and/or modify
+ * 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.
@@ -24,88 +24,105 @@
#include "ui/keypair_details/KeyUIDSignDialog.h"
-KeyUIDSignDialog::KeyUIDSignDialog(GpgME::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"
+#include "ui/SignalStation.h"
+
+namespace GpgFrontend::UI {
+
+KeyUIDSignDialog::KeyUIDSignDialog(const GpgKey& key, UIDArgsListPtr uid,
+ QWidget* parent)
+ : QDialog(parent), mUids(std::move(uid)), mKey(key) {
+ 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(_("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(_("Sign For Key's UID(s)"));
+ this->adjustSize();
+
+ setAttribute(Qt::WA_DeleteOnClose, true);
+
+ connect(this, SIGNAL(signalKeyUIDSignUpdate()), SignalStation::GetInstance(),
+ SIGNAL(KeyDatabaseRefresh()));
}
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));
- }
-
+ LOG(INFO) << "KeyUIDSignDialog::slotSignKey Called";
+
+ // Set Signers
+ auto key_ids = mKeyList->getChecked();
+ auto keys = GpgKeyGetter::GetInstance().GetKeys(key_ids);
+
+ LOG(INFO) << "KeyUIDSignDialog::slotSignKey Key Info Got";
+ auto expires = std::make_unique<boost::gregorian::date>(
+ boost::posix_time::from_time_t(expiresEdit->dateTime().toTime_t())
+ .date());
+
+ LOG(INFO) << "KeyUIDSignDialog::slotSignKey Sign Start";
+ for (const auto& uid : *mUids) {
+ LOG(INFO) << "KeyUIDSignDialog::slotSignKey Sign UID" << uid;
+ // Sign For mKey
+ if (!GpgKeyManager::GetInstance().signKey(mKey, *keys, uid, expires)) {
+ QMessageBox::critical(
+ nullptr, _("Unsuccessful Operation"),
+ QString(_("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"));
-
- this->close();
+ QMessageBox::information(nullptr, _("Operation Complete"),
+ _("The signature operation of the UID is complete"));
+ this->close();
+ emit signalKeyUIDSignUpdate();
}
+
+} // namespace GpgFrontend::UI
diff --git a/include/ui/keypair_details/KeyUIDSignDialog.h b/src/ui/keypair_details/KeyUIDSignDialog.h
index 88549e95..8a83977a 100644
--- a/include/ui/keypair_details/KeyUIDSignDialog.h
+++ b/src/ui/keypair_details/KeyUIDSignDialog.h
@@ -1,7 +1,7 @@
/**
- * This file is part of GPGFrontend.
+ * This file is part of GpgFrontend.
*
- * GPGFrontend is free software: you can redistribute it and/or modify
+ * 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.
@@ -25,40 +25,40 @@
#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:
+namespace GpgFrontend::UI {
- explicit KeyUIDSignDialog(GpgME::GpgContext *ctx, const GpgKey &key, const QVector<GpgUID> &uid, QWidget *parent = nullptr);
-
-private:
-
- GpgME::GpgContext *mCtx;
+class KeyUIDSignDialog : public QDialog {
+ Q_OBJECT
- KeyList *mKeyList;
+ public:
+ explicit KeyUIDSignDialog(const GpgKey& key, UIDArgsListPtr uid,
+ QWidget* parent = nullptr);
- QPushButton *signKeyButton;
+ signals:
+ void signalKeyUIDSignUpdate();
- QDateTimeEdit *expiresEdit;
+ private:
+ KeyList* mKeyList;
- QCheckBox *nonExpireCheck;
+ QPushButton* signKeyButton;
- const QVector<GpgUID> mUids;
+ QDateTimeEdit* expiresEdit;
- const GpgKey &mKey;
+ QCheckBox* nonExpireCheck;
+ 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 e391c666..25445dcc 100644
--- a/src/ui/main_window/MainWindowFileSlotFunction.cpp
+++ b/src/ui/main_window/MainWindowFileSlotFunction.cpp
@@ -1,7 +1,7 @@
/**
- * This file is part of GPGFrontend.
+ * This file is part of GpgFrontend.
*
- * GPGFrontend is free software: you can redistribute it and/or modify
+ * 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.
@@ -23,588 +23,458 @@
*/
#include "MainWindow.h"
+#include "gpg/function/GpgFileOpera.h"
+#include "gpg/function/GpgKeyGetter.h"
+#include "ui/UserInterfaceUtils.h"
+#include "ui/widgets/SignersPicker.h"
+
+namespace GpgFrontend::UI {
+
+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, _("Error"),
+ _("Select a file before doing it."));
+ return false;
+ }
+ if (!file_info.isReadable()) {
+ QMessageBox::critical(parent, _("Error"),
+ _("No permission to read this file."));
+ return false;
+ }
+ if (!path_info.isWritable()) {
+ QMessageBox::critical(parent, _("Error"),
+ _("No permission to create file."));
+ return false;
+ }
+ return true;
+}
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);
-
- if (keys.empty()) {
- QMessageBox::critical(this, tr("No Key Selected"), tr("No Key Selected"));
- return;
- }
-
- for (const auto &key : keys) {
- if (!GpgME::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_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();
- }
-
- 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;
- }
+ 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, _("Warning"),
+ _("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, _("No Key Selected"), _("No Key Selected"));
+ return;
+ }
+
+ for (const auto& key : *keys) {
+ if (!key.CanEncrActual()) {
+ QMessageBox::information(
+ this, _("Invalid Operation"),
+ QString(
+ _("The selected key contains a key that does not actually have a "
+ "encrypt usage.")) +
+ "<br/><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, _("Encrypting"), [&]() {
+ try {
+ error = GpgFileOpera::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, _("Error"),
+ _("An error occurred during operation."));
+ return;
+ }
}
void MainWindow::slotFileDecrypt() {
+ auto fileTreeView = edit->slotCurPageFileTreeView();
+ auto path = fileTreeView->getSelected();
- auto fileTreeView = edit->slotCurPageFileTreeView();
- auto path = fileTreeView->getSelected();
+ if (!file_pre_check(this, path)) return;
- 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 = QFileInfo(path).suffix();
- QString outFileName, fileExtension = fileInfo.suffix();
+ if (fileExtension == "asc" || fileExtension == "gpg") {
+ int pos = path.lastIndexOf(QChar('.'));
+ outFileName = path.left(pos);
+ } else {
+ outFileName = path + ".out";
+ }
- 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, _("Warning"),
+ _("The target file already exists, do you need to overwrite it?"),
+ QMessageBox::Ok | QMessageBox::Cancel);
- 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;
+ }
- 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;
+ GpgDecrResult result = nullptr;
+ gpgme_error_t error;
+ bool if_error = false;
+ process_operation(this, _("Decrypting"), [&]() {
+ try {
+ error = GpgFileOpera::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);
+ fileTreeView->update();
+ } else {
+ QMessageBox::critical(this, _("Error"),
+ _("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 (!GpgME::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, _("Warning"),
+ _("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, _("No Key Selected"), _("No Key Selected"));
+ return;
+ }
+
+ for (const auto& key : *keys) {
+ if (!key.CanSignActual()) {
+ QMessageBox::information(
+ this, _("Invalid Operation"),
+ QString(_("The selected key contains a key that does not actually "
+ "have a sign usage.")) +
+ "<br/><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, _("Signing"), [&]() {
+ try {
+ error =
+ GpgFileOpera::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, _("Error"),
+ _("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;
- }
-
- 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;
+ 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, _("Error"),
+ _("Please select the appropriate target file or signature file. "
+ "Ensure that both are in this directory."));
+ return;
+ }
+ if (!dataFileInfo.isReadable()) {
+ QMessageBox::critical(this, _("Error"),
+ _("No permission to read target file."));
+ return;
+ }
+ if (!fileInfo.isReadable()) {
+ QMessageBox::critical(this, _("Error"),
+ _("No permission to read signature file."));
+ return;
+ }
+
+ GpgVerifyResult result = nullptr;
+ gpgme_error_t error;
+ bool if_error = false;
+ process_operation(this, _("Verifying"), [&]() {
+ try {
+ error = GpgFileOpera::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() == -2) {
+ QMessageBox::StandardButton reply;
+ reply = QMessageBox::question(
+ this, _("Public key not found locally"),
+ _("There is no target public key content in local for GpgFrontend to "
+ "gather enough information about this Signature. Do you want to "
+ "import the public key from Keyserver now?"),
+ QMessageBox::Yes | QMessageBox::No);
+ if (reply == QMessageBox::Yes) {
+ qDebug() << "Yes was clicked";
+ auto dialog = KeyServerImportDialog(true, this);
+ auto key_ids = std::make_unique<KeyIdArgsList>();
+ auto* signature = resultAnalyse.GetSignatures();
+ while (signature != nullptr) {
+ LOG(INFO) << "signature fpr" << signature->fpr;
+ key_ids->push_back(signature->fpr);
+ signature = signature->next;
}
- });
- connect(thread, SIGNAL(finished()), thread, SLOT(deleteLater()));
- thread->start();
+ dialog.slotImport(key_ids);
+ dialog.show();
- auto *dialog = new WaitingDialog(tr("Verifying"), this);
- while (thread->isRunning()) {
- QApplication::processEvents();
+ } else {
+ qDebug() << "Yes was *not* clicked";
+ }
}
- 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;
+ // if (resultAnalyse.getStatus() >= 0) {
+ // infoBoard->resetOptionActionsMenu();
+ // infoBoard->addOptionalAction(
+ // "Show Verify Details", [this, error, &result]() {
+ // VerifyDetailsDialog(this, mKeyList, error, result);
+ // });
+ // }
- fileTreeView->update();
- } else {
- QMessageBox::critical(this, tr("Error"), tr("An error occurred during operation."));
- return;
- }
+ fileTreeView->update();
+ } else {
+ QMessageBox::critical(this, _("Error"),
+ _("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;
+ auto fileTreeView = edit->slotCurPageFileTreeView();
+ auto path = fileTreeView->getSelected();
- mKeyList->getCheckedKeys(keys);
+ if (!file_pre_check(this, path)) return;
- if (keys.empty()) {
- QMessageBox::critical(this, tr("No Key Selected"), tr("No Key Selected"));
- return;
- }
+ if (QFile::exists(path + ".gpg")) {
+ auto ret = QMessageBox::warning(
+ this, _("Warning"),
+ _("The target file already exists, do you need to overwrite it?"),
+ QMessageBox::Ok | QMessageBox::Cancel);
- bool can_sign = false, can_encr = false;
+ if (ret == QMessageBox::Cancel) return;
+ }
- for (const auto &key : keys) {
- bool key_can_sign = GpgME::GpgContext::checkIfKeyCanSign(key);
- bool key_can_encr = GpgME::GpgContext::checkIfKeyCanEncr(key);
+ auto key_ids = mKeyList->getChecked();
+ auto p_keys = GpgKeyGetter::GetInstance().GetKeys(key_ids);
- 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 (p_keys->empty()) {
+ QMessageBox::critical(this, _("No Key Selected"), _("No Key Selected"));
+ return;
+ }
- if (key_can_sign) can_sign = true;
- if (key_can_encr) can_encr = true;
- }
+ for (const auto& key : *p_keys) {
+ bool key_can_encrypt = key.CanEncrActual();
- if (!can_encr) {
- QMessageBox::critical(nullptr,
- tr("Incomplete Operation"),
- tr("None of the selected key pairs can provide the encryption function."));
- return;
+ if (!key_can_encrypt) {
+ QMessageBox::critical(
+ nullptr, _("Invalid KeyPair"),
+ QString(_("The selected keypair cannot be used for encryption.")) +
+ "<br/><br/>" + _("For example the Following Key:") + " <br/>" +
+ QString::fromStdString(key.uids()->front().uid()));
+ return;
}
+ }
- if (!can_sign) {
- QMessageBox::warning(nullptr,
- tr("Incomplete Operation"),
- tr("None of the selected key pairs can provide the signature function."));
- }
+ auto signersPicker = new SignersPicker(this);
+ QEventLoop loop;
+ connect(signersPicker, SIGNAL(finished(int)), &loop, SLOT(quit()));
+ loop.exec();
- gpgme_encrypt_result_t encr_result = nullptr;
- gpgme_sign_result_t sign_result = nullptr;
+ auto signer_key_ids = signersPicker->getCheckedSigners();
+ auto p_signer_keys = GpgKeyGetter::GetInstance().GetKeys(signer_key_ids);
- gpgme_error_t error;
- bool if_error = false;
+ for (const auto& key : *p_keys) {
+ LOG(INFO) << "Keys " << key.email();
+ }
- 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();
+ for (const auto& signer : *p_signer_keys) {
+ LOG(INFO) << "Signers " << signer.email();
+ }
- auto *dialog = new WaitingDialog(tr("Encrypting and Signing"), this);
- while (thread->isRunning()) {
- QApplication::processEvents();
- }
- dialog->close();
+ GpgEncrResult encr_result = nullptr;
+ GpgSignResult sign_result = nullptr;
- if (!if_error) {
+ gpgme_error_t error;
+ bool if_error = false;
- 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);
+ process_operation(this, _("Encrypting and Signing"), [&]() {
+ try {
+ error = GpgFileOpera::EncryptSignFile(
+ std::move(p_keys), std::move(p_signer_keys), path.toStdString(),
+ encr_result, sign_result);
+ } catch (const std::runtime_error& e) {
+ if_error = true;
+ }
+ });
- delete resultAnalyseEncr;
- delete resultAnalyseSign;
+ 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);
- fileTreeView->update();
+ fileTreeView->update();
- } else {
- QMessageBox::critical(this, tr("Error"), tr("An error occurred during operation."));
- return;
- }
+ } else {
+ QMessageBox::critical(this, _("Error"),
+ _("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;
-
- 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 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, _("Decrypting and Verifying"), [&]() {
+ try {
+ error = GpgFileOpera::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);
+ // });
+ // }
-
- 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, _("Error"),
+ _("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);
+ new FileEncryptionDialog(mKeyList->getChecked(),
+ FileEncryptionDialog::Decrypt, this);
}
void MainWindow::slotFileSignCustom() {
- QStringList *keyList;
- keyList = mKeyList->getChecked();
- new FileEncryptionDialog(mCtx, *keyList, FileEncryptionDialog::Sign, this);
+ new FileEncryptionDialog(mKeyList->getChecked(), FileEncryptionDialog::Sign,
+ this);
}
void MainWindow::slotFileVerifyCustom() {
- QStringList *keyList;
- keyList = mKeyList->getChecked();
- new FileEncryptionDialog(mCtx, *keyList, FileEncryptionDialog::Verify, this);
+ 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 3a7e9f71..17491db7 100644
--- a/src/ui/main_window/MainWindowServerSlotFunction.cpp
+++ b/src/ui/main_window/MainWindowServerSlotFunction.cpp
@@ -1,7 +1,7 @@
/**
- * This file is part of GPGFrontend.
+ * This file is part of GpgFrontend.
*
- * GPGFrontend is free software: you can redistribute it and/or modify
+ * 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.
@@ -23,216 +23,240 @@
*/
#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->getKeyById(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, _("Invalid Own Key"),
+ _("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, _("Error"),
+ _("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(_("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, _("Error"),
+ _("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, _("Error"), _("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, _("Invalid Service Token"),
+ _("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, _("Invalid Own Key"),
+ _("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(_("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, _("Error"),
+ _("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->getKeyById(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,
+ _("Notice: Use Decrypt & Verify operation to "
+ "decrypt this short crypto text."),
+ this);
+ dialog->show();
+ } else {
+ QMessageBox::critical(
+ this, _("Error"),
+ _("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 501418d6..205b9440 100644
--- a/src/ui/main_window/MainWindowSlotFunction.cpp
+++ b/src/ui/main_window/MainWindowSlotFunction.cpp
@@ -1,7 +1,7 @@
/**
- * This file is part of GPGFrontend.
+ * This file is part of GpgFrontend.
*
- * GPGFrontend is free software: you can redistribute it and/or modify
+ * 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.
@@ -23,559 +23,542 @@
*/
#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
+#ifdef SMTP_SUPPORT
+#include "ui/smtp/SendMailDialog.h"
+#endif
+#include "gpg/function/BasicOperator.h"
+#include "gpg/function/GpgKeyGetter.h"
+#include "gpg/function/GpgKeyImportExportor.h"
+#include "ui/UserInterfaceUtils.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) {
+ if (edit->slotCurPageTextEdit() != nullptr) {
+ auto key_ids = mKeyList->getChecked();
- 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 (!GpgME::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();
-
- gpgme_encrypt_result_t result = nullptr;
+ if (key_ids->empty()) {
+ QMessageBox::critical(nullptr, _("No Key Selected"),
+ _("No Key Selected"));
+ return;
+ }
- gpgme_error_t error;
+ auto key_getter = GpgFrontend::GpgKeyGetter::GetInstance();
+ auto keys = GpgKeyGetter::GetInstance().GetKeys(key_ids);
+ for (const auto& key : *keys) {
+ if (!key.CanEncrActual()) {
+ QMessageBox::information(
+ nullptr, _("Invalid Operation"),
+ QString(_(
+ "The selected key contains a key that does not actually have a "
+ "encrypt usage.")) +
+ "<br/><br/>" + _("For example the Following Key:") + " <br/>" +
+ QString::fromStdString(key.uids()->front().uid()));
+ return;
+ }
+ }
- auto thread = QThread::create([&]() {
- error = mCtx->encrypt(keys, edit->curTextPage()->toPlainText().toUtf8(), &tmp, &result);
+ auto tmp = std::make_unique<ByteArray>();
+
+ GpgEncrResult result = nullptr;
+ GpgError error;
+ bool if_error = false;
+ process_operation(this, _("Encrypting"), [&]() {
+ try {
+ auto buffer = edit->curTextPage()->toPlainText().toUtf8().toStdString();
+ error = GpgFrontend::BasicOperator::GetInstance().Encrypt(
+ std::move(keys), buffer, tmp, 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);
+
+ if (check_gpg_error_2_err_code(error) == GPG_ERR_NO_ERROR)
+ edit->slotFillTextEditWithText(QString::fromStdString(*tmp));
+#ifdef SMTP_SUPPORT
+ // 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, _("Function Disabled"),
+ _("Please go to the settings interface to "
+ "enable and configure this function."));
+ }
});
- connect(thread, SIGNAL(finished()), thread, SLOT(deleteLater()));
- thread->start();
-
- auto *dialog = new WaitingDialog(tr("Encrypting"), this);
-
- while (thread->isRunning())
- QApplication::processEvents();
-
- dialog->close();
-
- auto resultAnalyse = new EncryptResultAnalyse(error, result);
- auto &reportText = resultAnalyse->getResultReport();
-
- 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);
-
- // 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."));
- }
- });
- }
+ }
+#endif
- delete resultAnalyse;
- } else if (edit->slotCurPageFileTreeView() != nullptr) {
- this->slotFileEncrypt();
+ } else {
+ QMessageBox::critical(this, _("Error"),
+ _("An error occurred during operation."));
+ return;
}
+
+ } 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;
-
- mKeyList->getPrivateCheckedKeys(keys);
-
- if (keys.isEmpty()) {
- QMessageBox::critical(this, tr("No Key Selected"), tr("No Key Selected"));
- return;
- }
-
- for (const auto &key : keys) {
- if (!GpgME::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();
-
- 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();
-
- auto *dialog = new WaitingDialog(tr("Signing"), this);
- while (thread->isRunning()) {
- QApplication::processEvents();
- }
- dialog->close();
-
- infoBoard->associateTextEdit(edit->curTextPage());
- edit->slotFillTextEditWithText(QString::fromUtf8(tmp));
+ if (edit->slotCurPageTextEdit() != nullptr) {
+ auto key_ids = mKeyList->getPrivateChecked();
- auto resultAnalyse = new SignResultAnalyse(mCtx, error, result);
+ if (key_ids->empty()) {
+ QMessageBox::critical(this, _("No Key Selected"), _("No Key Selected"));
+ return;
+ }
- 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 keys = GpgKeyGetter::GetInstance().GetKeys(key_ids);
+ for (const auto& key : *keys) {
+ if (!key.CanSignActual()) {
+ QMessageBox::information(
+ this, _("Invalid Operation"),
+ QString(_(
+ "The selected key contains a key that does not actually have a "
+ "signature usage.")) +
+ "<br/><br/>" + _("For example the Following Key:") + "<br/>" +
+ key.uids()->front().uid().c_str());
+ return;
+ }
+ }
- delete resultAnalyse;
- } else if (edit->slotCurPageFileTreeView() != nullptr) {
- this->slotFileSign();
+ auto tmp = std::make_unique<ByteArray>();
+
+ GpgSignResult result = nullptr;
+ gpgme_error_t error;
+ bool if_error = false;
+
+ process_operation(this, _("Signing"), [&]() {
+ try {
+ auto buffer = edit->curTextPage()->toPlainText().toUtf8().toStdString();
+ error = GpgFrontend::BasicOperator::GetInstance().Sign(
+ std::move(keys), buffer, tmp, GPGME_SIG_MODE_CLEAR, 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);
+
+ if (check_gpg_error_2_err_code(error) == GPG_ERR_NO_ERROR)
+ edit->slotFillTextEditWithText(QString::fromStdString(*tmp));
+ } else {
+ QMessageBox::critical(this, _("Error"),
+ _("An error occurred during operation."));
+ return;
}
+ } 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();
- GpgME::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_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();
- }
-
- dialog->close();
-
- infoBoard->associateTextEdit(edit->curTextPage());
-
- if (gpgme_err_code(error) == GPG_ERR_NO_ERROR)
- edit->slotFillTextEditWithText(QString::fromUtf8(decrypted));
-
- 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);
+ if (edit->tabCount() == 0) return;
+
+ if (edit->slotCurPageTextEdit() != nullptr) {
+ auto decrypted = std::make_unique<ByteArray>();
+ QByteArray text = edit->curTextPage()->toPlainText().toUtf8();
+
+ if (text.trimmed().startsWith(
+ GpgConstants::GPG_FRONTEND_SHORT_CRYPTO_HEAD)) {
+ QMessageBox::critical(
+ this, _("Notice"),
+ _("Short Crypto Text only supports Decrypt & Verify."));
+ return;
+ }
- delete resultAnalyse;
- } else if (edit->slotCurPageFileTreeView() != nullptr) {
- this->slotFileDecrypt();
+ GpgDecrResult result = nullptr;
+ gpgme_error_t error;
+ bool if_error = false;
+ process_operation(this, _("Decrypting"), [&]() {
+ try {
+ auto buffer = text.toStdString();
+ error = GpgFrontend::BasicOperator::GetInstance().Decrypt(
+ buffer, decrypted, 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);
+
+ if (check_gpg_error_2_err_code(error) == GPG_ERR_NO_ERROR)
+ edit->slotFillTextEditWithText(QString::fromStdString(*decrypted));
+ } else {
+ QMessageBox::critical(this, _("Error"),
+ _("An error occurred during operation."));
+ return;
}
+ } 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) {
+ auto text = edit->curTextPage()->toPlainText().toUtf8();
+ // TODO(Saturneric) PreventNoDataErr
+
+ auto sig_buffer = std::make_unique<ByteArray>();
+ sig_buffer.reset();
+
+ GpgVerifyResult result = nullptr;
+ GpgError error;
+ bool if_error = false;
+ process_operation(this, _("Verifying"), [&]() {
+ try {
+ auto buffer = text.toStdString();
+ error = GpgFrontend::BasicOperator::GetInstance().Verify(
+ buffer, sig_buffer, 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);
+ // });
+ // }
- if (edit->tabCount() == 0) return;
-
- if (edit->slotCurPageTextEdit() != nullptr) {
-
- QByteArray text = edit->curTextPage()->toPlainText().toUtf8();
- GpgME::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();
+ } else {
+ QMessageBox::critical(this, _("Error"),
+ _("An error occurred during operation."));
+ return;
}
+ } 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 = GpgME::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) {
+ auto key_ids = mKeyList->getChecked();
- QVector<GpgKey> signerKeys;
-
- auto signersPicker = new SignersPicker(mCtx, this);
-
- QEventLoop loop;
- connect(signersPicker, SIGNAL(finished(int)), &loop, SLOT(quit()));
- loop.exec();
+ if (key_ids->empty()) {
+ QMessageBox::critical(nullptr, _("No Key Selected"),
+ _("No Key Selected"));
+ return;
+ }
- signersPicker->getCheckedSigners(signerKeys);
+ auto keys = GpgKeyGetter::GetInstance().GetKeys(key_ids);
- for (const auto &key : keys) {
- qDebug() << "Keys " << key.email;
- }
+ for (const auto& key : *keys) {
+ bool key_can_encrypt = key.CanEncrActual();
- for (const auto &signer : signerKeys) {
- qDebug() << "Signers " << signer.email;
- }
+ if (!key_can_encrypt) {
+ QMessageBox::critical(
+ nullptr, _("Invalid KeyPair"),
+ QString(_("The selected keypair cannot be used for encryption.")) +
+ "<br/><br/>" + _("For example the Following Key:") + " <br/>" +
+ QString::fromStdString(key.uids()->front().uid()));
+ return;
+ }
+ }
+ auto signersPicker = new SignersPicker(this);
+ QEventLoop loop;
+ connect(signersPicker, SIGNAL(finished(int)), &loop, SLOT(quit()));
+ loop.exec();
- auto tmp = QByteArray();
- gpgme_encrypt_result_t encr_result = nullptr;
- gpgme_sign_result_t sign_result = nullptr;
+ auto signer_key_ids = signersPicker->getCheckedSigners();
+ auto signer_keys = GpgKeyGetter::GetInstance().GetKeys(signer_key_ids);
- 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();
+ for (const auto& key : *keys) {
+ LOG(INFO) << "Keys " << key.email();
+ }
- auto *dialog = new WaitingDialog(tr("Encrypting and Signing"), this);
- while (thread->isRunning()) {
- QApplication::processEvents();
- }
+ for (const auto& signer : *signer_keys) {
+ LOG(INFO) << "Signers " << signer.email();
+ }
- 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."));
- }
+ GpgEncrResult encr_result = nullptr;
+ GpgSignResult sign_result = nullptr;
+ GpgError error;
+ bool if_error = false;
+
+ auto tmp = std::make_unique<ByteArray>();
+ process_operation(this, _("Encrypting and Signing"), [&]() {
+ try {
+ auto buffer = edit->curTextPage()->toPlainText().toUtf8().toStdString();
+ error = GpgFrontend::BasicOperator::GetInstance().EncryptSign(
+ std::move(keys), std::move(signer_keys), buffer, tmp, encr_result,
+ sign_result);
+ } catch (const std::runtime_error& e) {
+ if_error = true;
+ }
+ });
+
+ if (!if_error) {
+#ifdef ADVANCE_SUPPORT
+ if (settings.value("advanced/autoPubkeyExchange").toBool()) {
+ PubkeyUploader pubkeyUploader(mCtx, signerKeys);
+ pubkeyUploader.start();
+ if (!pubkeyUploader.result()) {
+ QMessageBox::warning(
+ nullptr, _("Automatic Key Exchange Warning"),
+ _("Part of the automatic key exchange failed, "
+ "which may be related to your key.") +
+ _("If possible, try to use the RSA algorithm "
+ "compatible with the server for signing."));
}
-
- dialog->close();
-
- if (gpgme_err_code(error) == GPG_ERR_NO_ERROR) {
- auto tmp2 = QString(tmp);
- edit->slotFillTextEditWithText(tmp2);
+ }
+#endif
+ LOG(INFO) << "ResultAnalyse Started";
+ 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);
+ if (check_gpg_error_2_err_code(error) == GPG_ERR_NO_ERROR)
+ edit->slotFillTextEditWithText(QString::fromStdString(*tmp));
+
+#ifdef SMTP_SUPPORT
+ infoBoard->resetOptionActionsMenu();
+ infoBoard->addOptionalAction("Send Mail", [this]() {
+ if (settings.value("sendMail/enable", false).toBool())
+ new SendMailDialog(edit->curTextPage()->toPlainText(), this);
+ else {
+ QMessageBox::warning(nullptr, _("Function Disabled"),
+ _("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();
- }
- });
+ });
+#endif
+
+#ifdef ADVANCE_SUPPORT
+ infoBoard->addOptionalAction("Shorten Ciphertext", [this]() {
+ if (settings.value("general/serviceToken").toString().isEmpty())
+ QMessageBox::warning(nullptr, _("Service Token Empty"),
+ _("Please go to the settings interface to set "
+ "Own Key and get Service Token."));
+ else {
+ shortenCryptText();
}
+ });
+#endif
- delete resultAnalyseEncr;
- delete resultAnalyseSign;
- } else if (edit->slotCurPageFileTreeView() != nullptr) {
- this->slotFileEncryptSign();
+ } else {
+ QMessageBox::critical(this, _("Error"),
+ _("An error occurred during operation."));
+ return;
}
+ } 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;
- }
- }
-
- QByteArray text = plainText.toUtf8();
-
- GpgME::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";
-
- 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";
-
- } else if (edit->slotCurPageFileTreeView() != nullptr) {
- this->slotFileDecryptVerify();
+ if (edit->tabCount() == 0) return;
+
+ if (edit->slotCurPageTextEdit() != nullptr) {
+ QString plainText = edit->curTextPage()->toPlainText();
+
+#ifdef ADVANCE_SUPPORT
+ if (plainText.trimmed().startsWith(
+ GpgConstants::GPG_FRONTEND_SHORT_CRYPTO_HEAD)) {
+ auto cryptoText = getCryptText(plainText);
+ if (!cryptoText.isEmpty()) {
+ plainText = cryptoText;
+ }
+ }
+#endif
+
+ QByteArray text = plainText.toUtf8();
+
+ GpgDecrResult d_result = nullptr;
+ GpgVerifyResult v_result = nullptr;
+ gpgme_error_t error;
+ bool if_error = false;
+
+#ifdef ADVANCE_SUPPORT
+ // 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();
+ }
+#endif
+ auto decrypted = std::make_unique<ByteArray>();
+ process_operation(this, _("Decrypting and Verifying"), [&]() {
+ try {
+ auto buffer = text.toStdString();
+ error = BasicOperator::GetInstance().DecryptVerify(buffer, decrypted,
+ 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);
+
+ edit->slotFillTextEditWithText(QString::fromStdString(*decrypted));
+
+ // if (verify_res.getStatus() >= 0) {
+ // infoBoard->resetOptionActionsMenu();
+ // infoBoard->addOptionalAction(
+ // "Show Verify Details", [this, error, v_result]() {
+ // VerifyDetailsDialog(this, mCtx, mKeyList, error,
+ // v_result);
+ // });
+ // }
+ } else {
+ QMessageBox::critical(this, _("Error"),
+ _("An error occurred during operation."));
+ return;
}
-}
+ } 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 exported = std::make_unique<ByteArray>();
+ auto key_ids = mKeyList->getSelected();
- auto *keyArray = new QByteArray();
- mCtx->exportKeys(mKeyList->getSelected(), keyArray);
- edit->curTextPage()->append(*keyArray);
+ GpgKeyImportExportor::GetInstance().ExportKeys(key_ids, exported);
+ edit->curTextPage()->append(QString::fromStdString(*exported));
}
void MainWindow::slotCopyMailAddressToClipboard() {
- if (mKeyList->getSelected()->isEmpty()) {
- return;
- }
- auto key = mCtx->getKeyById(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);
+ auto key_ids = mKeyList->getSelected();
+ if (key_ids->empty()) return;
+
+ auto key = GpgKeyGetter::GetInstance().GetKey(key_ids->front());
+ if (!key.good()) {
+ QMessageBox::critical(nullptr, _("Error"), _("Key Not Found."));
+ return;
+ }
+ QClipboard* cb = QApplication::clipboard();
+ cb->setText(QString::fromStdString(key.email()));
}
void MainWindow::slotShowKeyDetails() {
- if (mKeyList->getSelected()->isEmpty()) {
- return;
- }
- auto key = mCtx->getKeyById(mKeyList->getSelected()->first());
- if (key.good) {
- new KeyDetailsDialog(mCtx, key, this);
- } else {
- QMessageBox::critical(nullptr, tr("Error"), tr("Key Not Found."));
- }
+ auto key_ids = mKeyList->getSelected();
+ if (key_ids->empty()) return;
+
+ auto key = GpgKeyGetter::GetInstance().GetKey(key_ids->front());
+ if (key.good()) {
+ new KeyDetailsDialog(key, this);
+ } else {
+ QMessageBox::critical(nullptr, _("Error"), _("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());
+ auto key_ids = mKeyList->getSelected();
+ if (key_ids->empty()) return;
+ auto* dialog = new KeyServerImportDialog(true, this);
+ dialog->show();
+ dialog->slotImport(key_ids);
}
void MainWindow::uploadKeyToServer() {
- QVector<GpgKey> keys;
- keys.append(mKeyList->getSelectedKey());
- auto *dialog = new KeyUploadDialog(mCtx, keys, this);
- dialog->show();
- dialog->slotUpload();
+ auto key_ids = mKeyList->getSelected();
+ auto* dialog = new KeyUploadDialog(key_ids, 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, _("Outdated Version"),
+ QString(_("This version(%1) is out of date, please update "
+ "the latest version in time. "))
+ .arg(currentVersion) +
+ QString(_("You can download the latest version(%1) on "
+ "Github Releases Page.<br/>"))
+ .arg(latestVersion));
+ } else if (currentVersion > latestVersion) {
+ QMessageBox::warning(
+ this, _("Unreleased Version"),
+ QString(
+ _("This version(%1) has not been officially released and is not "
+ "recommended for use in a production environment. <br/>"))
+ .arg(currentVersion) +
+ QString(
+ _("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..35eb74ac 100644
--- a/src/ui/main_window/MainWindowSlotUI.cpp
+++ b/src/ui/main_window/MainWindowSlotUI.cpp
@@ -1,7 +1,7 @@
/**
- * This file is part of GPGFrontend.
+ * This file is part of GpgFrontend.
*
- * GPGFrontend is free software: you can redistribute it and/or modify
+ * 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.
@@ -23,198 +23,174 @@
*/
#include "MainWindow.h"
+#include "ui/UserInterfaceUtils.h"
+#include "ui/settings/GlobalSettingStation.h"
-void MainWindow::slotAbout() {
- new AboutDialog(0, this);
-}
+namespace GpgFrontend::UI {
-void MainWindow::slotCheckUpdate() {
- new AboutDialog(2, this);
-}
+void MainWindow::slotAbout() { new AboutDialog(0, this); }
-void MainWindow::slotSetStatusBarText(const QString &text) {
- statusBar()->showMessage(text, 20000);
-}
+void MainWindow::slotCheckUpdate() { new AboutDialog(2, this); }
-void MainWindow::slotStartWizard() {
- auto *wizard = new Wizard(mCtx, keyMgmt, this);
- wizard->show();
- wizard->setModal(true);
+void MainWindow::slotSetStatusBarText(const QString& text) {
+ statusBar()->showMessage(text, 20000);
}
-
-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();
- } else {
- statusBarIcon->hide();
- }
+void MainWindow::slotStartWizard() {
+ auto* wizard = new Wizard(this);
+ wizard->show();
+ wizard->setModal(true);
}
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;
+ CommonUtils::GetInstance()->slotImportKeys(
+ this, edit->curTextPage()->toPlainText().toStdString());
}
void MainWindow::slotOpenKeyManagement() {
- keyMgmt->show();
- keyMgmt->raise();
- keyMgmt->activateWindow();
+ auto* dialog = new KeyMgmt(this);
+ dialog->show();
+ dialog->raise();
}
-void MainWindow::slotOpenFileTab() {
- edit->slotNewFileTab();
-}
+void MainWindow::slotOpenFileTab() { edit->slotNewFileTab(); }
void MainWindow::slotDisableTabActions(int number) {
- bool 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);
+}
- if (number == -1)
- disable = true;
- else
- disable = false;
+void MainWindow::slotOpenSettingsDialog() {
+ auto dialog = new SettingsDialog(this);
- if(edit->curFilePage() != nullptr) {
- disable = true;
- }
+ connect(dialog, &SettingsDialog::finished, this, [&]() -> void {
+ LOG(INFO) << "Setting Dialog Finished";
- 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);
-}
+ auto& settings = GlobalSettingStation::GetInstance().GetUISettings();
-void MainWindow::slotOpenSettingsDialog() {
+ int icon_width = settings["window"]["icon_size"]["width"];
+ int icon_height = settings["window"]["icon_size"]["height"];
+
+ this->setIconSize(QSize(icon_width, icon_height));
+ importButton->setIconSize(QSize(icon_width, icon_height));
+ fileEncButton->setIconSize(QSize(icon_width, icon_height));
+
+ // Iconstyle
- 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());
- }
- });
+ int icon_style = settings["window"]["icon_style"];
+ auto button_style = static_cast<Qt::ToolButtonStyle>(icon_style);
+ this->setToolButtonStyle(button_style);
+ importButton->setToolButtonStyle(button_style);
+ fileEncButton->setToolButtonStyle(button_style);
+ // restart mainwindow if necessary
+ if (getRestartNeeded()) {
+ if (edit->maybeSaveAnyTab()) {
+ saveSettings();
+ qApp->exit(RESTART_CODE);
+ }
+ }
+#ifdef ADVANCED_SUPPORT
+ // steganography hide/show
+ if (!settings.value("advanced/steganography").toBool()) {
+ this->menuBar()->removeAction(steganoMenu->menuAction());
+ } else {
+ this->menuBar()->insertAction(viewMenu->menuAction(),
+ steganoMenu->menuAction());
+ }
+#endif
+ });
}
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;
-}
+bool MainWindow::getRestartNeeded() const { return this->restartNeeded; }
+
+} // namespace GpgFrontend::UI
diff --git a/src/ui/main_window/MainWindowUI.cpp b/src/ui/main_window/MainWindowUI.cpp
index 21f6e3b7..ee7a1bc0 100644
--- a/src/ui/main_window/MainWindowUI.cpp
+++ b/src/ui/main_window/MainWindowUI.cpp
@@ -1,7 +1,7 @@
/**
- * This file is part of GPGFrontend.
+ * This file is part of GpgFrontend.
*
- * GPGFrontend is free software: you can redistribute it and/or modify
+ * 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.
@@ -23,428 +23,476 @@
*/
#include "MainWindow.h"
+#include "ui/UserInterfaceUtils.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(_("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(_("Open a new file"));
+ connect(newTabAct, SIGNAL(triggered()), edit, SLOT(slotNewTab()));
+
+ openAct = new QAction(_("Open..."), this);
+ openAct->setIcon(QIcon(":fileopen.png"));
+ openAct->setShortcut(QKeySequence::Open);
+ openAct->setToolTip(_("Open an existing file"));
+ connect(openAct, SIGNAL(triggered()), edit, SLOT(slotOpen()));
+
+ browserAct = new QAction(_("Browser"), this);
+ browserAct->setShortcut(QKeySequence(Qt::CTRL + Qt::Key_B));
+ browserAct->setToolTip(_("Open a file browser"));
+ connect(browserAct, SIGNAL(triggered()), this, SLOT(slotOpenFileTab()));
+
+ saveAct = new QAction(_("Save"), this);
+ saveAct->setIcon(QIcon(":filesave.png"));
+ saveAct->setShortcut(QKeySequence::Save);
+ saveAct->setToolTip(_("Save the current File"));
+ connect(saveAct, SIGNAL(triggered()), edit, SLOT(slotSave()));
+
+ saveAsAct = new QAction(QString(_("Save As")) + "...", this);
+ saveAsAct->setIcon(QIcon(":filesaveas.png"));
+ saveAsAct->setShortcut(QKeySequence::SaveAs);
+ saveAsAct->setToolTip(_("Save the current File as..."));
+ connect(saveAsAct, SIGNAL(triggered()), edit, SLOT(slotSaveAs()));
+
+ printAct = new QAction(_("Print"), this);
+ printAct->setIcon(QIcon(":fileprint.png"));
+ printAct->setShortcut(QKeySequence::Print);
+ printAct->setToolTip(_("Print Document"));
+ connect(printAct, SIGNAL(triggered()), edit, SLOT(slotPrint()));
+
+ closeTabAct = new QAction(_("Close"), this);
+ closeTabAct->setShortcut(QKeySequence::Close);
+ closeTabAct->setToolTip(_("Close file"));
+ connect(closeTabAct, SIGNAL(triggered()), edit, SLOT(slotCloseTab()));
+
+ quitAct = new QAction(_("Quit"), this);
+ quitAct->setShortcut(QKeySequence::Quit);
+ quitAct->setIcon(QIcon(":exit.png"));
+ quitAct->setToolTip(_("Quit Program"));
+ connect(quitAct, SIGNAL(triggered()), this, SLOT(close()));
+
+ /* Edit Menu
+ */
+ undoAct = new QAction(_("Undo"), this);
+ undoAct->setShortcut(QKeySequence::Undo);
+ undoAct->setToolTip(_("Undo Last Edit Action"));
+ connect(undoAct, SIGNAL(triggered()), edit, SLOT(slotUndo()));
+
+ redoAct = new QAction(_("Redo"), this);
+ redoAct->setShortcut(QKeySequence::Redo);
+ redoAct->setToolTip(_("Redo Last Edit Action"));
+ connect(redoAct, SIGNAL(triggered()), edit, SLOT(slotRedo()));
+
+ zoomInAct = new QAction(_("Zoom In"), this);
+ zoomInAct->setShortcut(QKeySequence::ZoomIn);
+ connect(zoomInAct, SIGNAL(triggered()), edit, SLOT(slotZoomIn()));
+
+ zoomOutAct = new QAction(_("Zoom Out"), this);
+ zoomOutAct->setShortcut(QKeySequence::ZoomOut);
+ connect(zoomOutAct, SIGNAL(triggered()), edit, SLOT(slotZoomOut()));
+
+ pasteAct = new QAction(_("Paste"), this);
+ pasteAct->setIcon(QIcon(":button_paste.png"));
+ pasteAct->setShortcut(QKeySequence::Paste);
+ pasteAct->setToolTip(_("Paste Text From Clipboard"));
+ connect(pasteAct, SIGNAL(triggered()), edit, SLOT(slotPaste()));
+
+ cutAct = new QAction(_("Cut"), this);
+ cutAct->setIcon(QIcon(":button_cut.png"));
+ cutAct->setShortcut(QKeySequence::Cut);
+ cutAct->setToolTip(
+ _("Cut the current selection's contents to the "
+ "clipboard"));
+ connect(cutAct, SIGNAL(triggered()), edit, SLOT(slotCut()));
+
+ copyAct = new QAction(_("Copy"), this);
+ copyAct->setIcon(QIcon(":button_copy.png"));
+ copyAct->setShortcut(QKeySequence::Copy);
+ copyAct->setToolTip(
+ _("Copy the current selection's contents to the "
+ "clipboard"));
+ connect(copyAct, SIGNAL(triggered()), edit, SLOT(slotCopy()));
+
+ quoteAct = new QAction(_("Quote"), this);
+ quoteAct->setIcon(QIcon(":quote.png"));
+ quoteAct->setToolTip(_("Quote whole text"));
+ connect(quoteAct, SIGNAL(triggered()), edit, SLOT(slotQuote()));
+
+ selectAllAct = new QAction(_("Select All"), this);
+ selectAllAct->setIcon(QIcon(":edit.png"));
+ selectAllAct->setShortcut(QKeySequence::SelectAll);
+ selectAllAct->setToolTip(_("Select the whole text"));
+ connect(selectAllAct, SIGNAL(triggered()), edit, SLOT(slotSelectAll()));
+
+ findAct = new QAction(_("Find"), this);
+ findAct->setShortcut(QKeySequence::Find);
+ findAct->setToolTip(_("Find a word"));
+ connect(findAct, SIGNAL(triggered()), this, SLOT(slotFind()));
+
+ cleanDoubleLinebreaksAct = new QAction(_("Remove spacing"), this);
+ cleanDoubleLinebreaksAct->setIcon(QIcon(":format-line-spacing-triple.png"));
+ // cleanDoubleLineBreaksAct->setShortcut(QKeySequence::SelectAll);
+ cleanDoubleLinebreaksAct->setToolTip(
+ _("Remove double linebreaks, e.g. in pasted text from Web Mailer"));
+ connect(cleanDoubleLinebreaksAct, SIGNAL(triggered()), this,
+ SLOT(slotCleanDoubleLinebreaks()));
+
+ openSettingsAct = new QAction(_("Settings"), this);
+ openSettingsAct->setToolTip(_("Open settings dialog"));
+ openSettingsAct->setShortcut(QKeySequence::Preferences);
+ connect(openSettingsAct, SIGNAL(triggered()), this,
+ SLOT(slotOpenSettingsDialog()));
+
+ /* Crypt Menu
+ */
+ encryptAct = new QAction(_("Encrypt"), this);
+ encryptAct->setIcon(QIcon(":encrypted.png"));
+ encryptAct->setShortcut(QKeySequence(Qt::CTRL + Qt::Key_E));
+ encryptAct->setToolTip(_("Encrypt Message"));
+ connect(encryptAct, SIGNAL(triggered()), this, SLOT(slotEncrypt()));
+
+ encryptSignAct = new QAction(_("Encrypt Sign"), this);
+ encryptSignAct->setIcon(QIcon(":encrypted_signed.png"));
+ encryptSignAct->setShortcut(QKeySequence(Qt::CTRL + Qt::SHIFT + Qt::Key_E));
+ encryptSignAct->setToolTip(_("Encrypt and Sign Message"));
+ connect(encryptSignAct, SIGNAL(triggered()), this, SLOT(slotEncryptSign()));
+
+ decryptAct = new QAction(_("Decrypt"), this);
+ decryptAct->setIcon(QIcon(":decrypted.png"));
+ decryptAct->setShortcut(QKeySequence(Qt::CTRL + Qt::Key_D));
+ decryptAct->setToolTip(_("Decrypt Message"));
+ connect(decryptAct, SIGNAL(triggered()), this, SLOT(slotDecrypt()));
+
+ decryptVerifyAct = new QAction(_("Decrypt Verify"), this);
+ decryptVerifyAct->setIcon(QIcon(":decrypted_verified.png"));
+ decryptVerifyAct->setShortcut(QKeySequence(Qt::CTRL + Qt::SHIFT + Qt::Key_D));
+ decryptVerifyAct->setToolTip(_("Decrypt and Verify Message"));
+ connect(decryptVerifyAct, SIGNAL(triggered()), this,
+ SLOT(slotDecryptVerify()));
+
+ /*
+ * File encryption submenu
+ */
+ fileEncryptAct = new QAction(_("Encrypt File"), this);
+ fileEncryptAct->setToolTip(_("Encrypt File"));
+ connect(fileEncryptAct, SIGNAL(triggered()), this,
+ SLOT(slotFileEncryptCustom()));
+
+ fileDecryptAct = new QAction(_("Decrypt File"), this);
+ fileDecryptAct->setToolTip(_("Decrypt File"));
+ connect(fileDecryptAct, SIGNAL(triggered()), this,
+ SLOT(slotFileDecryptCustom()));
+
+ fileSignAct = new QAction(_("Sign File"), this);
+ fileSignAct->setToolTip(_("Sign File"));
+ connect(fileSignAct, SIGNAL(triggered()), this, SLOT(slotFileSignCustom()));
+
+ fileVerifyAct = new QAction(_("Verify File"), this);
+ fileVerifyAct->setToolTip(_("Verify File"));
+ connect(fileVerifyAct, SIGNAL(triggered()), this,
+ SLOT(slotFileVerifyCustom()));
+
+ signAct = new QAction(_("Sign"), this);
+ signAct->setIcon(QIcon(":signature.png"));
+ signAct->setShortcut(QKeySequence(Qt::CTRL + Qt::SHIFT + Qt::Key_I));
+ signAct->setToolTip(_("Sign Message"));
+ connect(signAct, SIGNAL(triggered()), this, SLOT(slotSign()));
+
+ verifyAct = new QAction(_("Verify"), this);
+ verifyAct->setIcon(QIcon(":verify.png"));
+ verifyAct->setShortcut(QKeySequence(Qt::CTRL + Qt::SHIFT + Qt::Key_V));
+ verifyAct->setToolTip(_("Verify Message"));
+ connect(verifyAct, SIGNAL(triggered()), this, SLOT(slotVerify()));
+
+ /* Key Menu
+ */
+
+ importKeyFromFileAct = new QAction(_("File"), this);
+ importKeyFromFileAct->setIcon(QIcon(":import_key_from_file.png"));
+ importKeyFromFileAct->setToolTip(_("Import New Key From File"));
+ connect(importKeyFromFileAct, &QAction::triggered, this,
+ [&]() { CommonUtils::GetInstance()->slotImportKeyFromFile(this); });
+
+ importKeyFromClipboardAct = new QAction(_("Clipboard"), this);
+ importKeyFromClipboardAct->setIcon(QIcon(":import_key_from_clipboard.png"));
+ importKeyFromClipboardAct->setToolTip(_("Import New Key From Clipboard"));
+ connect(importKeyFromClipboardAct, &QAction::triggered, this, [&]() {
+ CommonUtils::GetInstance()->slotImportKeyFromClipboard(this);
+ });
+
+ importKeyFromKeyServerAct = new QAction(_("Keyserver"), this);
+ importKeyFromKeyServerAct->setIcon(QIcon(":import_key_from_server.png"));
+ importKeyFromKeyServerAct->setToolTip(_("Import New Key From Keyserver"));
+ connect(importKeyFromKeyServerAct, &QAction::triggered, this, [&]() {
+ CommonUtils::GetInstance()->slotImportKeyFromKeyServer(this);
+ });
+
+ importKeyFromEditAct = new QAction(_("Editor"), this);
+ importKeyFromEditAct->setIcon(QIcon(":txt.png"));
+ importKeyFromEditAct->setToolTip(_("Import New Key From Editor"));
+ connect(importKeyFromEditAct, SIGNAL(triggered()), this,
+ SLOT(slotImportKeyFromEdit()));
+
+ openKeyManagementAct = new QAction(_("Manage Keys"), this);
+ openKeyManagementAct->setIcon(QIcon(":keymgmt.png"));
+ openKeyManagementAct->setToolTip(_("Open Key Management"));
+ connect(openKeyManagementAct, SIGNAL(triggered()), this,
+ SLOT(slotOpenKeyManagement()));
+
+ /*
+ * About Menu
+ */
+ aboutAct = new QAction(_("About"), this);
+ aboutAct->setIcon(QIcon(":help.png"));
+ aboutAct->setToolTip(_("Show the application's About box"));
+ connect(aboutAct, SIGNAL(triggered()), this, SLOT(slotAbout()));
+
+ /*
+ * Check Update Menu
+ */
+ checkUpdateAct = new QAction(_("Check for Updates"), this);
+ checkUpdateAct->setIcon(QIcon(":help.png"));
+ checkUpdateAct->setToolTip(_("Check for updates"));
+ connect(checkUpdateAct, SIGNAL(triggered()), this, SLOT(slotCheckUpdate()));
+
+ startWizardAct = new QAction(_("Open Wizard"), this);
+ startWizardAct->setToolTip(_("Open the wizard"));
+ connect(startWizardAct, SIGNAL(triggered()), this, SLOT(slotStartWizard()));
+
+ /* Popup-Menu-Action for KeyList
+ */
+ appendSelectedKeysAct =
+ new QAction(_("Append Selected Key(s) To Text"), this);
+ appendSelectedKeysAct->setToolTip(
+ _("Append The Selected Keys To Text in Editor"));
+ connect(appendSelectedKeysAct, SIGNAL(triggered()), this,
+ SLOT(slotAppendSelectedKeys()));
+
+ copyMailAddressToClipboardAct = new QAction(_("Copy Email"), this);
+ copyMailAddressToClipboardAct->setToolTip(
+ _("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(_("Show Key Details"), this);
+ showKeyDetailsAct->setToolTip(_("Show Details for this Key"));
+ connect(showKeyDetailsAct, SIGNAL(triggered()), this,
+ SLOT(slotShowKeyDetails()));
+
+ refreshKeysFromKeyserverAct =
+ new QAction(_("Refresh Key From Key Server"), this);
+ refreshKeysFromKeyserverAct->setToolTip(
+ _("Refresh key from default key server"));
+ connect(refreshKeysFromKeyserverAct, SIGNAL(triggered()), this,
+ SLOT(refreshKeysFromKeyserver()));
+
+ uploadKeyToServerAct = new QAction(_("Upload Public Key(s) To Server"), this);
+ uploadKeyToServerAct->setToolTip(
+ _("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(_("Remove PGP Header"), this);
+ connect(cutPgpHeaderAct, SIGNAL(triggered()), this, SLOT(slotCutPgpHeader()));
+
+ addPgpHeaderAct = new QAction(_("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(_("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(_("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(_("File..."));
+ fileEncMenu->addAction(fileEncryptAct);
+ fileEncMenu->addAction(fileDecryptAct);
+ fileEncMenu->addAction(fileSignAct);
+ fileEncMenu->addAction(fileVerifyAct);
+
+ cryptMenu = menuBar()->addMenu(_("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(_("Keys"));
+ importKeyMenu = keyMenu->addMenu(_("Import Key"));
+ importKeyMenu->setIcon(QIcon(":key_import.png"));
+ importKeyMenu->addAction(importKeyFromFileAct);
+ importKeyMenu->addAction(importKeyFromEditAct);
+ importKeyMenu->addAction(importKeyFromClipboardAct);
+ importKeyMenu->addAction(importKeyFromKeyServerAct);
+ keyMenu->addAction(openKeyManagementAct);
+
+ steganoMenu = menuBar()->addMenu(_("Steganography"));
+ steganoMenu->addAction(cutPgpHeaderAct);
+ steganoMenu->addAction(addPgpHeaderAct);
+
+#ifdef ADVANCED_SUPPORT
+ // Hide menu, when steganography menu is disabled in settings
+ if (!settings.value("advanced/steganography").toBool()) {
+ this->menuBar()->removeAction(steganoMenu->menuAction());
+ }
+#endif
+
+ viewMenu = menuBar()->addMenu(_("View"));
+
+ helpMenu = menuBar()->addMenu(_("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(_("File"));
+ fileToolBar->setObjectName("fileToolBar");
+ fileToolBar->addAction(newTabAct);
+ fileToolBar->addAction(openAct);
+ fileToolBar->addAction(saveAct);
+ fileToolBar->hide();
+ viewMenu->addAction(fileToolBar->toggleViewAction());
+
+ cryptToolBar = addToolBar(_("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(_("Key"));
+ keyToolBar->setObjectName("keyToolBar");
+ keyToolBar->addAction(openKeyManagementAct);
+ viewMenu->addAction(keyToolBar->toggleViewAction());
+
+ editToolBar = addToolBar(_("Edit"));
+ editToolBar->setObjectName("editToolBar");
+ editToolBar->addAction(copyAct);
+ editToolBar->addAction(pasteAct);
+ editToolBar->addAction(selectAllAct);
+ viewMenu->addAction(editToolBar->toggleViewAction());
+
+ specialEditToolBar = addToolBar(_("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(_("Import key from..."));
+ importButton->setText(_("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(_("Browser to view and operate file"));
+ fileEncButton->setText(_("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(_("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-Dock window
+ */
+ keyListDock = new QDockWidget(_("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(_("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/GlobalSettingStation.cpp b/src/ui/settings/GlobalSettingStation.cpp
new file mode 100644
index 00000000..e88de93b
--- /dev/null
+++ b/src/ui/settings/GlobalSettingStation.cpp
@@ -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.
+ *
+ */
+
+#include "GlobalSettingStation.h"
+
+std::unique_ptr<GpgFrontend::UI::GlobalSettingStation>
+ GpgFrontend::UI::GlobalSettingStation::_instance = nullptr;
+
+GpgFrontend::UI::GlobalSettingStation&
+GpgFrontend::UI::GlobalSettingStation::GetInstance() {
+ if (_instance == nullptr) {
+ _instance = std::make_unique<GlobalSettingStation>();
+ }
+ return *_instance;
+}
+
+void GpgFrontend::UI::GlobalSettingStation::Sync() noexcept {
+ using namespace libconfig;
+ try {
+ ui_cfg.writeFile(ui_config_path.string().c_str());
+ LOG(INFO) << _("Updated ui configuration successfully written to")
+ << ui_config_path;
+
+ } catch (const FileIOException& fioex) {
+ LOG(ERROR) << _("I/O error while writing ui configuration file")
+ << ui_config_path;
+ }
+}
+
+GpgFrontend::UI::GlobalSettingStation::GlobalSettingStation() noexcept {
+ using namespace boost::filesystem;
+ using namespace libconfig;
+
+ el::Loggers::addFlag(el::LoggingFlag::AutoSpacing);
+
+ LOG(INFO) << _("App Path") << app_path;
+ LOG(INFO) << _("App Configure Path") << app_configure_path;
+ LOG(INFO) << _("App Data Path") << app_data_path;
+ LOG(INFO) << _("App Log Path") << app_log_path;
+ LOG(INFO) << _("App Locale Path") << app_locale_path;
+
+ if (!is_directory(app_configure_path)) create_directory(app_configure_path);
+
+ if (!is_directory(app_data_path)) create_directory(app_data_path);
+
+ if (!is_directory(app_log_path)) create_directory(app_log_path);
+
+ if (!is_directory(ui_config_dir_path)) create_directory(ui_config_dir_path);
+
+ if (!exists(ui_config_path)) {
+ try {
+ this->ui_cfg.writeFile(ui_config_path.string().c_str());
+ LOG(INFO) << _("UserInterface configuration successfully written to")
+ << ui_config_path;
+
+ } catch (const FileIOException& fioex) {
+ LOG(ERROR)
+ << _("I/O error while writing UserInterface configuration file")
+ << ui_config_path;
+ }
+ } else {
+ try {
+ this->ui_cfg.readFile(ui_config_path.string().c_str());
+ LOG(INFO) << _("UserInterface configuration successfully read from")
+ << ui_config_path;
+ } catch (const FileIOException& fioex) {
+ LOG(ERROR) << _("I/O error while reading UserInterface configure file");
+ } catch (const ParseException& pex) {
+ LOG(ERROR) << _("Parse error at ") << pex.getFile() << ":"
+ << pex.getLine() << " - " << pex.getError();
+ }
+ }
+}
diff --git a/src/ui/settings/GlobalSettingStation.h b/src/ui/settings/GlobalSettingStation.h
new file mode 100644
index 00000000..ef2c6a9a
--- /dev/null
+++ b/src/ui/settings/GlobalSettingStation.h
@@ -0,0 +1,90 @@
+/**
+ * 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_GLOBALSETTINGSTATION_H
+#define GPGFRONTEND_GLOBALSETTINGSTATION_H
+
+#include <boost/filesystem/operations.hpp>
+#include <boost/filesystem/path.hpp>
+
+#include "ui/GpgFrontendUI.h"
+
+namespace GpgFrontend::UI {
+
+class GlobalSettingStation : public QObject {
+ Q_OBJECT
+ public:
+ static GlobalSettingStation& GetInstance();
+
+ GlobalSettingStation() noexcept;
+
+ libconfig::Setting& GetUISettings() noexcept { return ui_cfg.getRoot(); }
+
+ [[nodiscard]] boost::filesystem::path GetAppDir() const { return app_path; }
+
+ [[nodiscard]] boost::filesystem::path GetLogDir() const {
+ return app_log_path;
+ }
+
+ [[nodiscard]] boost::filesystem::path GetLocaleDir() const {
+ return app_locale_path;
+ }
+
+ void Sync() noexcept;
+
+ private:
+ // Program Location
+ boost::filesystem::path app_path = qApp->applicationDirPath().toStdString();
+
+ // Program Data Location
+ boost::filesystem::path app_data_path =
+ QStandardPaths::writableLocation(QStandardPaths::AppLocalDataLocation)
+ .toStdString();
+
+ // Program Data Location
+ boost::filesystem::path app_log_path = app_data_path / "logs";
+
+ // Program Data Location
+ boost::filesystem::path app_locale_path =
+ RESOURCE_DIR_BOOST_PATH(app_path) / "locales";
+
+ // Program Configure Location
+ boost::filesystem::path app_configure_path =
+ QStandardPaths::writableLocation(QStandardPaths::AppConfigLocation)
+ .toStdString();
+
+ // Configure File Directory Location
+ boost::filesystem::path ui_config_dir_path =
+ app_configure_path / "UserInterface";
+
+ // UI Configure File Location
+ boost::filesystem::path ui_config_path = ui_config_dir_path / "ui.cfg";
+
+ libconfig::Config ui_cfg;
+
+ static std::unique_ptr<GlobalSettingStation> _instance;
+};
+} // namespace GpgFrontend::UI
+
+#endif // GPGFRONTEND_GLOBALSETTINGSTATION_H
diff --git a/src/ui/settings/SettingsAdvanced.cpp b/src/ui/settings/SettingsAdvanced.cpp
index 30414250..b64ec8e9 100644
--- a/src/ui/settings/SettingsAdvanced.cpp
+++ b/src/ui/settings/SettingsAdvanced.cpp
@@ -1,7 +1,7 @@
/**
- * This file is part of GPGFrontend.
+ * This file is part of GpgFrontend.
*
- * GPGFrontend is free software: you can redistribute it and/or modify
+ * 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.
@@ -22,46 +22,51 @@
*
*/
-#include "ui/SettingsDialog.h"
+#include "SettingsAdvanced.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(_("Show Steganography Options"));
+ auto* steganoBoxLayout = new QHBoxLayout();
+ steganoCheckBox = new QCheckBox(_("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(_("Pubkey Exchange"));
+ auto* pubkeyExchangeBoxLayout = new QHBoxLayout();
+ autoPubkeyExchangeCheckBox = new QCheckBox(_("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/SettingsAdvanced.h b/src/ui/settings/SettingsAdvanced.h
new file mode 100644
index 00000000..d8ec8089
--- /dev/null
+++ b/src/ui/settings/SettingsAdvanced.h
@@ -0,0 +1,54 @@
+/**
+ * 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_SETTINGSADVANCED_H
+#define GPGFRONTEND_SETTINGSADVANCED_H
+
+#include "ui/GpgFrontendUI.h"
+
+namespace GpgFrontend::UI {
+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);
+};
+} // namespace GpgFrontend::UI
+
+#endif // GPGFRONTEND_SETTINGSADVANCED_H
diff --git a/src/ui/settings/SettingsAppearance.cpp b/src/ui/settings/SettingsAppearance.cpp
index aeb7ed70..49dc349c 100644
--- a/src/ui/settings/SettingsAppearance.cpp
+++ b/src/ui/settings/SettingsAppearance.cpp
@@ -1,7 +1,7 @@
/**
- * This file is part of GPGFrontend.
+ * This file is part of GpgFrontend.
*
- * GPGFrontend is free software: you can redistribute it and/or modify
+ * 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.
@@ -22,84 +22,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);
+#include "SettingsAppearance.h"
+
+#include "GlobalSettingStation.h"
+
+namespace GpgFrontend::UI {
+
+AppearanceTab::AppearanceTab(QWidget* parent) : QWidget(parent) {
+ /*****************************************
+ * Icon-Size-Box
+ *****************************************/
+ auto* iconSizeBox = new QGroupBox(_("Icon Size"));
+ iconSizeGroup = new QButtonGroup();
+ iconSizeSmall = new QRadioButton(_("small"));
+ iconSizeMedium = new QRadioButton(_("medium"));
+ iconSizeLarge = new QRadioButton(_("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(_("Icon Style"));
+ iconStyleGroup = new QButtonGroup();
+ iconTextButton = new QRadioButton(_("just text"));
+ iconIconsButton = new QRadioButton(_("just icons"));
+ iconAllButton = new QRadioButton(_("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(_("Window State"));
+ auto* windowSizeBoxLayout = new QHBoxLayout();
+ windowSizeCheckBox =
+ new QCheckBox(_("Save window size and position on exit."), this);
+ windowSizeBoxLayout->addWidget(windowSizeCheckBox);
+ windowSizeBox->setLayout(windowSizeBoxLayout);
+
+ /*****************************************
+ * Info-Board-Font-Size-Box
+ *****************************************/
+
+ auto* infoBoardBox = new QGroupBox(_("Information Board"));
+ auto* infoBoardLayout = new QHBoxLayout();
+ infoBoardFontSizeSpin = new QSpinBox();
+ infoBoardFontSizeSpin->setRange(9, 18);
+ infoBoardFontSizeSpin->setValue(10);
+ infoBoardFontSizeSpin->setSingleStep(1);
+ infoBoardLayout->addWidget(new QLabel(_("Font Size in Information Board")));
+ 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 +109,70 @@ 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;
+ auto& settings = GlobalSettingStation::GetInstance().GetUISettings();
+
+ try {
+ int width = settings.lookup("window.icon_size.width");
+ int height = settings.lookup("window.icon_size.height");
+
+ auto icon_size = QSize(width, height);
+
+ switch (icon_size.height()) {
+ case 12:
+ iconSizeSmall->setChecked(true);
+ break;
+ case 24:
+ iconSizeMedium->setChecked(true);
+ break;
+ case 32:
+ iconSizeLarge->setChecked(true);
+ break;
}
- // Window Save and Position
- if (settings.value("window/windowSave").toBool())
- windowSizeCheckBox->setCheckState(Qt::Checked);
+ } catch (...) {
+ LOG(ERROR) << _("Setting Operation Error") << _("icon_size");
+ }
+
+ // icon_style
+ try {
+ int s_icon_style = settings.lookup("window.icon_style");
+ auto icon_style = static_cast<Qt::ToolButtonStyle>(s_icon_style);
+
+ switch (icon_style) {
+ case Qt::ToolButtonTextOnly:
+ iconTextButton->setChecked(true);
+ break;
+ case Qt::ToolButtonIconOnly:
+ iconIconsButton->setChecked(true);
+ break;
+ case Qt::ToolButtonTextUnderIcon:
+ iconAllButton->setChecked(true);
+ break;
+ default:
+ break;
+ }
- // infoBoardFontSize
- auto infoBoardFontSize = settings.value("informationBoard/fontSize", 10).toInt();
- if (infoBoardFontSize < 9 || infoBoardFontSize > 18)
- infoBoardFontSize = 10;
- infoBoardFontSizeSpin->setValue(infoBoardFontSize);
+ } catch (...) {
+ LOG(ERROR) << _("Setting Operation Error") << _("icon_style");
+ }
+
+ // Window Save and Position
+ try {
+ bool window_save = settings.lookup("window.window_save");
+ if (window_save) windowSizeCheckBox->setCheckState(Qt::Checked);
+
+ } catch (...) {
+ LOG(ERROR) << _("Setting Operation Error") << _("window_save");
+ }
+
+ // info board font size
+ try {
+ int info_font_size = settings.lookup("window.info_font_size");
+ if (info_font_size < 9 || info_font_size > 18) info_font_size = 10;
+ infoBoardFontSizeSpin->setValue(info_font_size);
+ } catch (...) {
+ LOG(ERROR) << _("Setting Operation Error") << _("info_font_size");
+ }
}
/***********************************
@@ -156,32 +180,70 @@ 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());
+ auto& settings =
+ GpgFrontend::UI::GlobalSettingStation::GetInstance().GetUISettings();
+
+ if (!settings.exists("window") ||
+ settings.lookup("window").getType() != libconfig::Setting::TypeGroup)
+ settings.add("window", libconfig::Setting::TypeGroup);
+
+ auto& window = settings["window"];
+
+ int icon_size = 24;
+ switch (iconSizeGroup->checkedId()) {
+ case 1:
+ icon_size = 12;
+ break;
+ case 2:
+ icon_size = 24;
+ break;
+ case 3:
+ icon_size = 32;
+ break;
+ }
+
+ if (!window.exists("icon_size")) {
+ auto& icon_size_settings =
+ window.add("icon_size", libconfig::Setting::TypeGroup);
+ icon_size_settings.add("width", libconfig::Setting::TypeInt) = icon_size;
+ icon_size_settings.add("height", libconfig::Setting::TypeInt) = icon_size;
+ } else {
+ window["icon_size"]["width"] = icon_size;
+ window["icon_size"]["height"] = icon_size;
+ }
+
+ auto icon_style = Qt::ToolButtonTextUnderIcon;
+ switch (iconStyleGroup->checkedId()) {
+ case 1:
+ icon_style = Qt::ToolButtonTextOnly;
+ break;
+ case 2:
+ icon_style = Qt::ToolButtonIconOnly;
+ break;
+ case 3:
+ icon_style = Qt::ToolButtonTextUnderIcon;
+ break;
+ }
+
+ if (!window.exists("icon_style")) {
+ window.add("icon_style", libconfig::Setting::TypeInt) = icon_style;
+ } else {
+ window["icon_style"] = icon_style;
+ }
+
+ if (!window.exists("window_save")) {
+ window.add("window_save", libconfig::Setting::TypeBoolean) =
+ windowSizeCheckBox->isChecked();
+ } else {
+ window["window_save"] = windowSizeCheckBox->isChecked();
+ }
+
+ if (!window.exists("info_font_size")) {
+ window.add("info_font_size", libconfig::Setting::TypeBoolean) =
+ infoBoardFontSizeSpin->value();
+ } else {
+ window["info_font_size"] = infoBoardFontSizeSpin->value();
+ }
}
+} // namespace GpgFrontend::UI
diff --git a/src/ui/settings/SettingsAppearance.h b/src/ui/settings/SettingsAppearance.h
new file mode 100644
index 00000000..c0a0247b
--- /dev/null
+++ b/src/ui/settings/SettingsAppearance.h
@@ -0,0 +1,61 @@
+/**
+ * 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_SETTINGSAPPEARANCE_H
+#define GPGFRONTEND_SETTINGSAPPEARANCE_H
+
+#include "ui/GpgFrontendUI.h"
+
+namespace GpgFrontend::UI {
+
+class AppearanceTab : public QWidget {
+ Q_OBJECT
+
+ public:
+ explicit AppearanceTab(QWidget* parent = nullptr);
+
+ void setSettings();
+
+ void applySettings();
+
+ private:
+ 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);
+};
+
+} // namespace GpgFrontend::UI
+
+#endif // GPGFRONTEND_SETTINGSAPPEARANCE_H
diff --git a/src/ui/settings/SettingsDialog.cpp b/src/ui/settings/SettingsDialog.cpp
index 0ca188f7..fcef70c7 100644
--- a/src/ui/settings/SettingsDialog.cpp
+++ b/src/ui/settings/SettingsDialog.cpp
@@ -1,7 +1,7 @@
/**
- * This file is part of GPGFrontend.
+ * This file is part of GpgFrontend.
*
- * GPGFrontend is free software: you can redistribute it and/or modify
+ * 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.
@@ -22,184 +22,136 @@
*
*/
-#include "ui/SettingsDialog.h"
-#include "ui/WaitingDialog.h"
-
-SettingsDialog::SettingsDialog(GpgME::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();
-}
+#include "SettingsDialog.h"
-bool SettingsDialog::getRestartNeeded() const { return this->restartNeeded; }
+#include "GlobalSettingStation.h"
+#include "SettingsAdvanced.h"
+#include "SettingsAppearance.h"
+#include "SettingsGeneral.h"
+#include "SettingsKeyServer.h"
-void SettingsDialog::slotSetRestartNeeded(bool needed) {
- this->restartNeeded = needed;
-}
+#ifdef SMTP_SUPPORT
+#include "SettingsSendMail.h"
+#endif
-void SettingsDialog::slotAccept() {
- generalTab->applySettings();
- sendMailTab->applySettings();
- appearanceTab->applySettings();
- keyserverTab->applySettings();
- advancedTab->applySettings();
- gpgPathsTab->applySettings();
- if (getRestartNeeded()) {
- emit signalRestartNeeded(true);
- }
- close();
-}
+namespace GpgFrontend::UI {
-// 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;
+SettingsDialog::SettingsDialog(QWidget* parent) : QDialog(parent) {
+ tabWidget = new QTabWidget;
+ generalTab = new GeneralTab();
+ appearanceTab = new AppearanceTab;
+#ifdef SMTP_SUPPORT
+ sendMailTab = new SendMailTab;
+#endif
+ keyserverTab = new KeyserverTab;
+#ifdef ADVANCED_SUPPORT
+ advancedTab = new AdvancedTab;
+#endif
- languages.insert("", tr("System Default"));
+ tabWidget->addTab(generalTab, _("General"));
+ tabWidget->addTab(appearanceTab, _("Appearance"));
+#ifdef SMTP_SUPPORT
+ tabWidget->addTab(sendMailTab, _("Send Mail"));
+#endif
+ tabWidget->addTab(keyserverTab, _("Key Server"));
+ // tabWidget->addTab(gpgPathsTab, _("Gpg paths"));
+#ifdef ADVANCED_SUPPORT
+ tabWidget->addTab(advancedTab, _("Advanced"));
+#endif
- QString appPath = qApp->applicationDirPath();
- QDir qmDir = QDir(RESOURCE_DIR(appPath) + "/ts/");
- QStringList fileNames = qmDir.entryList(QStringList("gpgfrontend_*.qm"));
+ 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(_("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)));
+#ifdef SMTP_SUPPORT
+ connect(sendMailTab, SIGNAL(signalRestartNeeded(bool)), this,
+ SLOT(slotSetRestartNeeded(bool)));
+#endif
+ connect(keyserverTab, SIGNAL(signalRestartNeeded(bool)), this,
+ SLOT(slotSetRestartNeeded(bool)));
+#ifdef ADVANCED_SUPPORT
+ connect(advancedTab, SIGNAL(signalRestartNeeded(bool)), this,
+ SLOT(slotSetRestartNeeded(bool)));
+#endif
- for (int i = 0; i < fileNames.size(); ++i) {
- QString locale = fileNames[i];
- locale.truncate(locale.lastIndexOf('.'));
- locale.remove(0, locale.indexOf('_') + 1);
+ connect(this, SIGNAL(signalRestartNeeded(bool)), parent,
+ SLOT(slotSetRestartNeeded(bool)));
- // this works in qt 4.8
- QLocale qloc(locale);
-#if QT_VERSION < 0x040800
- QString language =
- QLocale::languageToString(qloc.language()) + " (" + locale +
- ")"; //+ " (" + QLocale::languageToString(qloc.language()) + ")";
-#else
- QString language = qloc.nativeLanguageName() + " (" + locale + ")";
-#endif
- languages.insert(locale, language);
- }
- return languages;
+ this->resize(480, 640);
+ this->show();
}
-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);
+bool SettingsDialog::getRestartNeeded() const { return this->restartNeeded; }
+
+void SettingsDialog::slotSetRestartNeeded(bool needed) {
+ this->restartNeeded = needed;
}
-QString GpgPathsTab::getRelativePath(const QString &dir1, const QString &dir2) {
- QDir dir(dir1);
- QString s;
+void SettingsDialog::slotAccept() {
+ generalTab->applySettings();
+#ifdef SMTP_SUPPORT
+ sendMailTab->applySettings();
+#endif
+ appearanceTab->applySettings();
+ keyserverTab->applySettings();
+#ifdef ADVANCED_SUPPORT
+ advancedTab->applySettings();
+#endif
- s = dir.relativeFilePath(dir2);
- qDebug() << "relative path: " << s;
- if (s.isEmpty()) {
- s = ".";
- }
- return s;
-}
+ // write settings to filesystem
+ GlobalSettingStation::GetInstance().Sync();
-void GpgPathsTab::setKeydbPathToDefault() {
- accKeydbPath = ".";
- keydbLabel->setText(".");
+ if (getRestartNeeded()) {
+ emit signalRestartNeeded(true);
+ }
+ close();
}
-QString GpgPathsTab::chooseKeydbDir() {
- QString dir = QFileDialog::getExistingDirectory(
- this, tr("Choose keydb directory"), accKeydbPath,
- QFileDialog::ShowDirsOnly);
+QHash<QString, QString> SettingsDialog::listLanguages() {
+ QHash<QString, QString> languages;
- accKeydbPath = getRelativePath(defKeydbPath, dir);
- keydbLabel->setText(accKeydbPath);
- return "";
-}
+ languages.insert(QString(), _("System Default"));
-void GpgPathsTab::setSettings() {
- defKeydbPath = qApp->applicationDirPath() + "/keydb";
+ auto locale_path = GlobalSettingStation::GetInstance().GetLocaleDir();
- accKeydbPath = settings.value("gpgpaths/keydbpath").toString();
- if (accKeydbPath.isEmpty()) {
- accKeydbPath = ".";
- }
-}
+ auto locale_dir = QDir(QString::fromStdString(locale_path.string()) );
+ QStringList file_names = locale_dir.entryList(QStringList("*"));
+
+ for (int i = 0; i < file_names.size(); ++i) {
+ QString locale = file_names[i];
+ LOG(INFO) << "locale" << locale.toStdString();
+ if (locale == "." || locale == "..") continue;
-void GpgPathsTab::applySettings() {
- settings.setValue("gpgpaths/keydbpath", accKeydbPath);
+ // this works in qt 4.8
+ QLocale q_locale(locale);
+ if (q_locale.nativeCountryName().isEmpty()) continue;
+#if QT_VERSION < 0x040800
+ QString language =
+ QLocale::languageToString(q_locale.language()) + " (" + locale +
+ ")"; //+ " (" + QLocale::languageToString(q_locale.language()) + ")";
+#else
+ auto language = q_locale.nativeLanguageName() + " (" + locale + ")";
+#endif
+ languages.insert(locale, language);
+ }
+ return languages;
}
+
+} // namespace GpgFrontend::UI
diff --git a/src/ui/settings/SettingsDialog.h b/src/ui/settings/SettingsDialog.h
new file mode 100755
index 00000000..b8277906
--- /dev/null
+++ b/src/ui/settings/SettingsDialog.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 __SETTINGSDIALOG_H__
+#define __SETTINGSDIALOG_H__
+
+#include "ui/GpgFrontendUI.h"
+#include "ui/widgets/KeyList.h"
+
+namespace GpgFrontend::UI {
+
+class GeneralTab;
+
+#ifdef SMTP_SUPPORT
+class SendMailTab;
+#endif
+
+class AppearanceTab;
+class KeyserverTab;
+
+#ifdef ADVANCED_SUPPORT
+class AdvancedTab;
+#endif
+
+class SettingsDialog : public QDialog {
+ Q_OBJECT
+
+ public:
+ explicit SettingsDialog(QWidget* parent = nullptr);
+
+ GeneralTab* generalTab;
+#ifdef SMTP_SUPPORT
+ SendMailTab* sendMailTab;
+#endif
+ AppearanceTab* appearanceTab;
+ KeyserverTab* keyserverTab;
+#ifdef ADVANCED_SUPPORT
+ AdvancedTab* advancedTab;
+#endif
+
+ 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/settings/SettingsGeneral.cpp b/src/ui/settings/SettingsGeneral.cpp
index bec66154..98610e12 100644
--- a/src/ui/settings/SettingsGeneral.cpp
+++ b/src/ui/settings/SettingsGeneral.cpp
@@ -1,7 +1,7 @@
/**
- * This file is part of GPGFrontend.
+ * This file is part of GpgFrontend.
*
- * GPGFrontend is free software: you can redistribute it and/or modify
+ * 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.
@@ -22,122 +22,145 @@
*
*/
-#include "ui/SettingsDialog.h"
-#include "ui/WaitingDialog.h"
+#include "SettingsGeneral.h"
+
+#ifdef SERVER_SUPPORT
#include "server/ComUtils.h"
+#endif
-#include "rapidjson/prettywriter.h"
+#ifdef MULTI_LANG_SUPPORT
+#include "SettingsDialog.h"
+#endif
-GeneralTab::GeneralTab(GpgME::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->getKeyById(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);
+#include "GlobalSettingStation.h"
+#include "gpg/function/GpgKeyGetter.h"
+#include "rapidjson/prettywriter.h"
+#include "ui/widgets/KeyList.h"
+
+namespace GpgFrontend::UI {
+
+GeneralTab::GeneralTab(QWidget* parent) : QWidget(parent) {
+#ifdef SERVER_SUPPORT
+ /*****************************************
+ * GpgFrontend Server
+ *****************************************/
+ auto* serverBox = new QGroupBox(_("GpgFrontend Server"));
+ auto* serverBoxLayout = new QVBoxLayout();
+ serverSelectBox = new QComboBox();
+ serverBoxLayout->addWidget(serverSelectBox);
+ serverBoxLayout->addWidget(new QLabel(
+ _("Server that provides short key and key exchange services")));
+
+ serverBox->setLayout(serverBoxLayout);
+#endif
+
+ /*****************************************
+ * Save-Checked-Keys-Box
+ *****************************************/
+ auto* saveCheckedKeysBox = new QGroupBox(_("Save Checked Keys"));
+ auto* saveCheckedKeysBoxLayout = new QHBoxLayout();
+ saveCheckedKeysCheckBox = new QCheckBox(
+ _("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(_("Confirm drag'n'drop key import"));
+ auto* importConfirmationBoxLayout = new QHBoxLayout();
+ importConfirmationCheckBox = new QCheckBox(
+ _("Import files dropped on the Key List without confirmation."), this);
+ importConfirmationBoxLayout->addWidget(importConfirmationCheckBox);
+ importConfirmationBox->setLayout(importConfirmationBoxLayout);
+
+#ifdef MULTI_LANG_SUPPORT
+ /*****************************************
+ * Language Select Box
+ *****************************************/
+ auto* langBox = new QGroupBox(_("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(
+ "<b>" + QString(_("NOTE")) + _(": ") + "</b>" +
+ _("GpgFrontend will restart automatically if you change the language!")));
+ langBox->setLayout(langBoxLayout);
+ connect(langSelectBox, SIGNAL(currentIndexChanged(int)), this,
+ SLOT(slotLanguageChanged()));
+#endif
+
+#ifdef SERVER_SUPPORT
+ /*****************************************
+ * Own Key Select Box
+ *****************************************/
+ auto* ownKeyBox = new QGroupBox(_("Own key"));
+ auto* ownKeyBoxLayout = new QVBoxLayout();
+ auto* ownKeyServiceTokenLayout = new QHBoxLayout();
+ ownKeySelectBox = new QComboBox;
+ getServiceTokenButton = new QPushButton(_("Get Service Token"));
+ serviceTokenLabel = new QLabel(_("No Service Token Found"));
+ serviceTokenLabel->setAlignment(Qt::AlignCenter);
+
+ ownKeyBox->setLayout(ownKeyBoxLayout);
+
+ mKeyList = new KeyList();
+
+ // Fill the keyid hashmap
+ keyIds.insert({QString(), "<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(
+ _("Key pair for synchronization and identity authentication")));
+ ownKeyBoxLayout->addWidget(ownKeySelectBox);
+ ownKeyBoxLayout->addLayout(ownKeyServiceTokenLayout);
+ ownKeyServiceTokenLayout->addWidget(getServiceTokenButton);
+ ownKeyServiceTokenLayout->addWidget(serviceTokenLabel);
+ ownKeyServiceTokenLayout->stretch(0);
+#endif
+
+ /*****************************************
+ * Mainlayout
+ *****************************************/
+ auto* mainLayout = new QVBoxLayout;
+#ifdef SERVER_SUPPORT
+ mainLayout->addWidget(serverBox);
+#endif
+ mainLayout->addWidget(saveCheckedKeysBox);
+ mainLayout->addWidget(importConfirmationBox);
+#ifdef MULTI_LANG_SUPPORT
+ mainLayout->addWidget(langBox);
+#endif
+#ifdef SERVER_SUPPORT
+ mainLayout->addWidget(ownKeyBox);
+#endif
+
+ setSettings();
+ mainLayout->addStretch(1);
+ setLayout(mainLayout);
}
/**********************************
@@ -146,55 +169,76 @@ GeneralTab::GeneralTab(GpgME::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>");
+ auto& settings = GlobalSettingStation::GetInstance().GetUISettings();
+ try {
+ bool save_key_checked = settings.lookup("general.save_key_checked");
+ if (save_key_checked) saveCheckedKeysCheckBox->setCheckState(Qt::Checked);
+ } catch (...) {
+ LOG(ERROR) << _("Setting Operation Error") << _("save_key_checked");
+ }
+
+#ifdef SERVER_SUPPORT
+ 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);
+ });
+#endif
+
+#ifdef MULTI_LANG_SUPPORT
+ try {
+ std::string lang_key = settings.lookup("general.lang");
+ QString lang_value = lang.value(lang_key.c_str());
+ LOG(INFO) << "lang settings current" << lang_value.toStdString();
+ if (!lang.empty()) {
+ langSelectBox->setCurrentIndex(langSelectBox->findText(lang_value));
} 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);
+ langSelectBox->setCurrentIndex(0);
}
+ } catch (...) {
+ LOG(ERROR) << _("Setting Operation Error") << _("lang");
+ }
+#endif
+
+#ifdef SERVER_SUPPORT
+ 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));
+ }
+#endif
+
+ try {
+ bool confirm_import_keys = settings.lookup("general.confirm_import_keys");
+ LOG(INFO) << "confirm_import_keys" << confirm_import_keys;
+ if (confirm_import_keys)
+ importConfirmationCheckBox->setCheckState(Qt::Checked);
+ } catch (...) {
+ LOG(ERROR) << _("Setting Operation Error") << _("confirm_import_keys");
+ }
}
/***********************************
@@ -202,157 +246,194 @@ void GeneralTab::setSettings() {
* write them to settings-file
*************************************/
void GeneralTab::applySettings() {
- settings.setValue("keys/saveKeyChecked",
- saveCheckedKeysCheckBox->isChecked());
-
- 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;
-
- settings.setValue("int/lang", lang.key(langSelectBox->currentText()));
-
- settings.setValue("general/ownKeyId",
- keyIdsList[ownKeySelectBox->currentIndex()]);
-
- settings.setValue("general/serviceToken",
- serviceToken);
-
- settings.setValue("general/confirmImportKeys",
- importConfirmationCheckBox->isChecked());
+ auto& settings =
+ GpgFrontend::UI::GlobalSettingStation::GetInstance().GetUISettings();
+
+ if (!settings.exists("general") ||
+ settings.lookup("general").getType() != libconfig::Setting::TypeGroup)
+ settings.add("general", libconfig::Setting::TypeGroup);
+
+ auto& general = settings["general"];
+
+ if (!general.exists("save_key_checked"))
+ general.add("save_key_checked", libconfig::Setting::TypeBoolean) =
+ saveCheckedKeysCheckBox->isChecked();
+ else {
+ general["save_key_checked"] = saveCheckedKeysCheckBox->isChecked();
+ }
+
+#ifdef SERVER_SUPPORT
+ 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;
+#endif
+
+#ifdef MULTI_LANG_SUPPORT
+ if (!general.exists("lang"))
+ general.add("lang", libconfig::Setting::TypeBoolean) =
+ lang.key(langSelectBox->currentText()).toStdString();
+ else {
+ general["lang"] = lang.key(langSelectBox->currentText()).toStdString();
+ }
+#endif
+
+#ifdef SERVER_SUPPORT
+ settings.setValue(
+ "general/ownKeyId",
+ QString::fromStdString(keyIdsList[ownKeySelectBox->currentIndex()]));
+
+ settings.setValue("general/serviceToken",
+ QString::fromStdString(serviceToken));
+#endif
+
+ if (!general.exists("confirm_import_keys"))
+ general.add("confirm_import_keys", libconfig::Setting::TypeBoolean) =
+ importConfirmationCheckBox->isChecked();
+ else {
+ general["confirm_import_keys"] = importConfirmationCheckBox->isChecked();
+ }
}
+#ifdef MULTI_LANG_SUPPORT
void GeneralTab::slotLanguageChanged() { emit signalRestartNeeded(true); }
+#endif
+#ifdef SERVER_SUPPORT
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(_("No Service Token Found"));
+ serviceToken.clear();
}
+#endif
+#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, _("Invalid Operation"),
+ _("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, _("Error"), _("Key Not Exists"));
+ return;
+ }
- GpgKey key = mCtx->getKeyById(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->getKeyByFpr(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, _("Error"),
+ _("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, _("Notice"),
+ _("Succeed in getting service token"));
+ } else {
+ QMessageBox::critical(
+ this, _("Error"),
+ _("There is a problem with the communication with the server"));
+ }
+ }
}
+#endif
+
+} // namespace GpgFrontend::UI
diff --git a/src/ui/settings/SettingsGeneral.h b/src/ui/settings/SettingsGeneral.h
new file mode 100644
index 00000000..7e118f98
--- /dev/null
+++ b/src/ui/settings/SettingsGeneral.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_SETTINGSGENERAL_H
+#define GPGFRONTEND_SETTINGSGENERAL_H
+
+#include "ui/GpgFrontendUI.h"
+
+namespace GpgFrontend::UI {
+class KeyList;
+
+class GeneralTab : public QWidget {
+ Q_OBJECT
+
+ public:
+ explicit GeneralTab(QWidget* parent = nullptr);
+
+ void setSettings();
+
+ void applySettings();
+
+ private:
+ QCheckBox* saveCheckedKeysCheckBox;
+ QCheckBox* importConfirmationCheckBox;
+
+#ifdef MULTI_LANG_SUPPORT
+ QComboBox* langSelectBox;
+ QHash<QString, QString> lang;
+#endif
+
+#ifdef SERVER_SUPPORT
+ QComboBox* serverSelectBox;
+ QComboBox* ownKeySelectBox;
+ QPushButton* getServiceTokenButton;
+ QLabel* serviceTokenLabel;
+ std::string serviceToken;
+ std::unordered_map<std::string, std::string> keyIds;
+#endif
+
+ std::vector<std::string> keyIdsList;
+
+ KeyList* mKeyList{};
+
+ private slots:
+
+#ifdef MULTI_LANG_SUPPORT
+
+ void slotLanguageChanged();
+
+#endif
+
+#ifdef SERVER_SUPPORT
+
+ void slotOwnKeyIdChanged();
+
+#endif
+
+ signals:
+
+ void signalRestartNeeded(bool needed);
+};
+} // namespace GpgFrontend::UI
+
+#endif // GPGFRONTEND_SETTINGSGENERAL_H
diff --git a/src/ui/settings/SettingsKeyServer.cpp b/src/ui/settings/SettingsKeyServer.cpp
index b49eb9e0..f05ad7fb 100644
--- a/src/ui/settings/SettingsKeyServer.cpp
+++ b/src/ui/settings/SettingsKeyServer.cpp
@@ -1,7 +1,7 @@
/**
- * This file is part of GPGFrontend.
+ * This file is part of GpgFrontend.
*
- * GPGFrontend is free software: you can redistribute it and/or modify
+ * 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.
@@ -22,68 +22,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();
+#include "SettingsKeyServer.h"
+
+#include "GlobalSettingStation.h"
+
+namespace GpgFrontend::UI {
+
+KeyserverTab::KeyserverTab(QWidget* parent) : QWidget(parent) {
+ auto generalGroupBox = new QGroupBox(_("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 << _("No.") << _("Address") << _("Available");
+ keyServerTable->setHorizontalHeaderLabels(labels);
+
+ auto* mainLayout = new QVBoxLayout(this);
+ auto* label = new QLabel(QString(_("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(_("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 +93,38 @@ KeyserverTab::KeyserverTab(QWidget *parent)
* appropriately
**********************************/
void KeyserverTab::setSettings() {
-
- keyServerStrList = settings.value("keyserver/keyServerList").toStringList();
-
- for (const auto &keyServer : keyServerStrList) {
- comboBox->addItem(keyServer);
- qDebug() << "KeyserverTab Get ListItemText" << keyServer;
+ auto& settings = GlobalSettingStation::GetInstance().GetUISettings();
+
+ try {
+ auto& server_list = settings.lookup("keyserver.server_list");
+ const auto server_list_size = server_list.getLength();
+ for (int i = 0; i < server_list_size; i++) {
+ std::string server_url = server_list[i];
+ comboBox->addItem(server_url.c_str());
+ keyServerStrList.append(server_url.c_str());
}
-
- comboBox->setCurrentText(
- settings.value("keyserver/defaultKeyServer").toString());
-
+ } catch (...) {
+ LOG(ERROR) << _("Setting Operation Error") << _("server_list");
+ }
+
+ try {
+ std::string default_server = settings.lookup("keyserver.default_server");
+ comboBox->setCurrentText(default_server.c_str());
+ } catch (...) {
+ LOG(ERROR) << _("Setting Operation Error") << _("default_server");
+ }
}
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 +132,51 @@ void KeyserverTab::addKeyServer() {
* write them to settings-file
*************************************/
void KeyserverTab::applySettings() {
- settings.setValue("keyserver/keyServerList", keyServerStrList);
- settings.setValue("keyserver/defaultKeyServer", comboBox->currentText());
+ auto& settings = GlobalSettingStation::GetInstance().GetUISettings();
+
+ if (!settings.exists("keyserver") ||
+ settings.lookup("keyserver").getType() != libconfig::Setting::TypeGroup)
+ settings.add("keyserver", libconfig::Setting::TypeGroup);
+
+ auto& keyserver = settings["keyserver"];
+
+ if (keyserver.exists("server_list"))
+ keyserver.remove("server_list");
+
+ keyserver.add("server_list", libconfig::Setting::TypeList);
+
+ auto& server_list = keyserver["server_list"];
+ for (const auto& key_server_url : keyServerStrList) {
+ server_list.add(libconfig::Setting::TypeString) =
+ key_server_url.toStdString();
+ }
+
+ if (!keyserver.exists("default_server")) {
+ keyserver.add("default_server", libconfig::Setting::TypeString) =
+ comboBox->currentText().toStdString();
+ } else {
+ keyserver["default_server"] = comboBox->currentText().toStdString();
+ }
}
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++;
- }
+ LOG(INFO) << "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/include/gpg/GpgUID.h b/src/ui/settings/SettingsKeyServer.h
index 6fb09446..5042aaa5 100644
--- a/include/gpg/GpgUID.h
+++ b/src/ui/settings/SettingsKeyServer.h
@@ -1,7 +1,7 @@
/**
- * This file is part of GPGFrontend.
+ * This file is part of GpgFrontend.
*
- * GPGFrontend is free software: you can redistribute it and/or modify
+ * 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.
@@ -22,39 +22,38 @@
*
*/
-#ifndef GPGFRONTEND_GPGUID_H
-#define GPGFRONTEND_GPGUID_H
+#ifndef GPGFRONTEND_SETTINGSKEYSERVER_H
+#define GPGFRONTEND_SETTINGSKEYSERVER_H
-#include <utility>
+#include "ui/GpgFrontendUI.h"
-#include "GpgFrontend.h"
-#include "GpgKeySignature.h"
+namespace GpgFrontend::UI {
+class KeyserverTab : public QWidget {
+ Q_OBJECT
-struct GpgUID {
+ public:
+ explicit KeyserverTab(QWidget* parent = nullptr);
- QString name{};
+ void setSettings();
- QString email{};
+ void applySettings();
- QString comment{};
+ private:
+ QComboBox* comboBox;
+ QLineEdit* newKeyServerEdit;
+ QTableWidget* keyServerTable;
+ QStringList keyServerStrList;
- QString uid{};
+ private slots:
- bool revoked{};
+ void addKeyServer();
- bool invalid{};
+ void refreshTable();
- QVector<GpgKeySignature> signatures;
-
- GpgUID() = default;
-
- explicit GpgUID(gpgme_user_id_t user_id);
-
- GpgUID(GpgUID &&) noexcept = default;
- GpgUID(const GpgUID &) = default;
- GpgUID& operator=(GpgUID &&) noexcept = default;
- GpgUID& operator=(const GpgUID &) = default;
+ signals:
+ void signalRestartNeeded(bool needed);
};
+} // namespace GpgFrontend::UI
-#endif //GPGFRONTEND_GPGUID_H \ No newline at end of file
+#endif // GPGFRONTEND_SETTINGSKEYSERVER_H
diff --git a/src/ui/settings/SettingsSendMail.cpp b/src/ui/settings/SettingsSendMail.cpp
index a5e3274f..2518991d 100644
--- a/src/ui/settings/SettingsSendMail.cpp
+++ b/src/ui/settings/SettingsSendMail.cpp
@@ -1,7 +1,7 @@
/**
- * This file is part of GPGFrontend.
+ * This file is part of GpgFrontend.
*
- * GPGFrontend is free software: you can redistribute it and/or modify
+ * 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.
@@ -22,75 +22,80 @@
*
*/
-#include "ui/SettingsDialog.h"
-#include "smtp/SmtpMime"
+#include "SettingsSendMail.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();
+#ifdef SMTP_SUPPORT
+#include "smtp/SmtpMime"
+#endif
+
+namespace GpgFrontend::UI {
+
+SendMailTab::SendMailTab(QWidget* parent)
+ : QWidget(parent),
+ appPath(qApp->applicationDirPath()),
+ settings(RESOURCE_DIR(appPath) + "/conf/gpgfrontend.ini",
+ QSettings::IniFormat) {
+ enableCheckBox = new QCheckBox(_("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(_("Check Connection"));
+
+ auto generalGroupBox = new QGroupBox(_("General"));
+ auto connectGroupBox = new QGroupBox(_("Connection"));
+ auto preferenceGroupBox = new QGroupBox(_("Preference"));
+
+ auto generalLayout = new QGridLayout();
+ generalLayout->addWidget(enableCheckBox);
+
+ auto connectLayout = new QGridLayout();
+ connectLayout->addWidget(new QLabel(_("SMTP Address")), 1, 0);
+ connectLayout->addWidget(smtpAddress, 1, 1, 1, 4);
+ connectLayout->addWidget(new QLabel(_("Username")), 2, 0);
+ connectLayout->addWidget(username, 2, 1, 1, 4);
+ connectLayout->addWidget(new QLabel(_("Password")), 3, 0);
+ connectLayout->addWidget(password, 3, 1, 1, 4);
+ connectLayout->addWidget(new QLabel(_("Port")), 4, 0);
+ connectLayout->addWidget(portSpin, 4, 1, 1, 1);
+ connectLayout->addWidget(new QLabel(_("Connection Security")), 5, 0);
+ connectLayout->addWidget(connectionTypeComboBox, 5, 1, 1, 1);
+ connectLayout->addWidget(checkConnectionButton, 6, 0);
+
+ auto preferenceLayout = new QGridLayout();
+
+ preferenceLayout->addWidget(new QLabel(_("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)));
+
+ this->setLayout(vBox);
+ setSettings();
}
/**********************************
@@ -99,27 +104,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 +133,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, _("Fail"), _("Fail to Connect SMTP Server"));
+ if_success = false;
+ }
+ if (if_success && !smtp.login()) {
+ QMessageBox::critical(this, _("Fail"), _("Fail to Login"));
+ if_success = false;
+ }
+
+ if (if_success)
+ QMessageBox::information(this, _("Success"),
+ _("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/settings/SettingsSendMail.h b/src/ui/settings/SettingsSendMail.h
new file mode 100644
index 00000000..ec8f83c9
--- /dev/null
+++ b/src/ui/settings/SettingsSendMail.h
@@ -0,0 +1,46 @@
+//
+// Created by saturneric on 2021/11/28.
+//
+
+#ifndef GPGFRONTEND_SETTINGSSENDMAIL_H
+#define GPGFRONTEND_SETTINGSSENDMAIL_H
+
+#include "ui/GpgFrontendUI.h"
+
+namespace GpgFrontend::UI {
+class SendMailTab : public QWidget {
+ Q_OBJECT
+
+ public:
+ explicit SendMailTab(QWidget* parent = nullptr);
+
+ void setSettings();
+
+ void applySettings();
+
+ private slots:
+
+ 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);
+};
+} // namespace GpgFrontend::UI
+
+#endif // GPGFRONTEND_SETTINGSSENDMAIL_H
diff --git a/src/ui/smtp/SendMailDialog.cpp b/src/ui/smtp/SendMailDialog.cpp
new file mode 100644
index 00000000..7c8933a0
--- /dev/null
+++ b/src/ui/smtp/SendMailDialog.cpp
@@ -0,0 +1,195 @@
+/**
+ * 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 "SendMailDialog.h"
+
+#include <utility>
+
+#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, _("Incomplete configuration"),
+ _("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);
+
+#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();
+}
+
+#ifdef STMP_ENABLED
+
+void SendMailDialog::slotConfirm() {
+ QString errString;
+ errorLabel->clear();
+
+ QStringList rcptStringList = recipientEdit->toPlainText().split(';');
+
+ if (rcptStringList.isEmpty()) {
+ errString.append(QString(" ") + _("Recipient cannot be empty") + " \n");
+ } else {
+ for (const auto& reci : rcptStringList) {
+ qDebug() << "Receiver" << reci.trimmed();
+ if (!check_email_address(reci.trimmed())) {
+ errString.append(QString(" ") +
+ _("One or more Recipient's Email Address is invalid") +
+ " \n");
+ break;
+ }
+ }
+ }
+ if (senderEdit->text().isEmpty()) {
+ errString.append(QString(" ") + _("Sender cannot be empty") + " \n");
+ } else if (!check_email_address(senderEdit->text())) {
+ errString.append(QString(" ") + _("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, _("Fail"), _("Fail to Connect SMTP Server"));
+ return;
+ }
+ if (!smtp.login()) {
+ qDebug() << "Login to SMTP Server Failed";
+ QMessageBox::critical(this, _("Fail"), _("Fail to Login into SMTP Server"));
+ return;
+ }
+ if (!smtp.sendMail(message)) {
+ qDebug() << "Send Mail to SMTP Server Failed";
+ QMessageBox::critical(this, _("Fail"),
+ _("Fail to Send Mail to SMTP Server"));
+ return;
+ }
+ smtp.quit();
+
+ // Close after sending email
+ QMessageBox::information(this, _("Success"),
+ _("Succeed in Sending Mail to SMTP Server"));
+ deleteLater();
+}
+
+#endif
+
+} // namespace GpgFrontend::UI
diff --git a/src/ui/smtp/SendMailDialog.h b/src/ui/smtp/SendMailDialog.h
new file mode 100644
index 00000000..87dfd81f
--- /dev/null
+++ b/src/ui/smtp/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/widgets/EditorPage.cpp b/src/ui/widgets/EditorPage.cpp
index beb37b96..94c98036 100644
--- a/src/ui/widgets/EditorPage.cpp
+++ b/src/ui/widgets/EditorPage.cpp
@@ -1,7 +1,7 @@
/**
- * This file is part of GPGFrontend.
+ * This file is part of GpgFrontend.
*
- * GPGFrontend is free software: you can redistribute it and/or modify
+ * 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.
@@ -24,84 +24,131 @@
#include "ui/widgets/EditorPage.h"
+#include <boost/filesystem.hpp>
#include <utility>
-EditorPage::EditorPage(QString filePath, QWidget *parent) : QWidget(parent),
- fullFilePath(std::move(filePath)) {
- // Set the Textedit properties
- textPage = new QTextEdit();
- textPage->setAcceptRichText(false);
+#include "ui/function/FileReadThread.h"
- // Set the layout style
- mainLayout = new QVBoxLayout();
- mainLayout->setSpacing(0);
- mainLayout->addWidget(textPage);
- mainLayout->setContentsMargins(0, 0, 0, 0);
- setLayout(mainLayout);
+namespace GpgFrontend::UI {
- setAttribute(Qt::WA_DeleteOnClose);
- textPage->setFocus();
+EditorPage::EditorPage(QString filePath, QWidget* parent)
+ : QWidget(parent), fullFilePath(std::move(filePath)) {
+ // Set the Textedit properties
+ textPage = new QTextEdit();
+ textPage->setAcceptRichText(false);
- // Front in same width
- this->setFont({"Courier"});
-}
+ // Set the layout style
+ mainLayout = new QVBoxLayout();
+ mainLayout->setSpacing(0);
+ mainLayout->addWidget(textPage);
+ mainLayout->setContentsMargins(0, 0, 0, 0);
+ setLayout(mainLayout);
-const QString &EditorPage::getFilePath() const {
- return fullFilePath;
-}
+ textPage->setFocus();
-QTextEdit *EditorPage::getTextPage() {
- return textPage;
+ // Front in same width
+ this->setFont({"Courier"});
+ this->setAttribute(Qt::WA_DeleteOnClose);
}
-void EditorPage::setFilePath(const QString &filePath) {
- fullFilePath = filePath;
+const QString& EditorPage::getFilePath() const { return fullFilePath; }
+
+QTextEdit* EditorPage::getTextPage() { return textPage; }
+
+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(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);
+}
- 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);
+void EditorPage::ReadFile() {
+ LOG(INFO) << "Called";
+
+ readDone = false;
+
+ auto text_page = this->getTextPage();
+ text_page->setReadOnly(true);
+ auto thread = new FileReadThread(this->fullFilePath.toStdString());
+
+ connect(thread, &FileReadThread::sendReadBlock, this,
+ &EditorPage::slotInsertText);
+
+ connect(thread, &FileReadThread::readDone, this, [=]() {
+ LOG(INFO) << "Thread read done";
+ text_page->document()->setModified(false);
+ text_page->setReadOnly(false);
+ });
+
+ connect(thread, &FileReadThread::finished, this, [=]() {
+ LOG(INFO) << "Thread finished";
+ thread->deleteLater();
+ readDone = true;
+ readThread = nullptr;
+ });
+
+ connect(this, &EditorPage::destroyed, [=]() {
+ LOG(INFO) << "RequestInterruption for readThread";
+ thread->requestInterruption();
+ readThread = nullptr;
+ });
+ this->readThread = thread;
+ thread->start();
+}
+void EditorPage::slotInsertText(const QString& text) {
+ this->getTextPage()->insertPlainText(text);
+}
+void EditorPage::PrepareToDestroy() {
+ if (readThread) {
+ readThread->requestInterruption();
+ readThread = nullptr;
+ }
}
+
+} // namespace GpgFrontend::UI
diff --git a/src/ui/widgets/EditorPage.h b/src/ui/widgets/EditorPage.h
new file mode 100644
index 00000000..a0a05dab
--- /dev/null
+++ b/src/ui/widgets/EditorPage.h
@@ -0,0 +1,113 @@
+/**
+ * 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.
+ */
+ [[nodiscard]] 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);
+
+ void ReadFile();
+
+ [[nodiscard]] bool ReadDone() const { return this->readDone; }
+
+ void PrepareToDestroy();
+
+ 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 */
+ bool readDone = false;
+ QThread* readThread = nullptr;
+
+ private slots:
+
+ /**
+ * @details Format the gpg header in another font-style
+ */
+ void slotFormatGpgHeader();
+
+ void slotInsertText(const QString& text);
+};
+
+} // namespace GpgFrontend::UI
+
+#endif // __EDITORPAGE_H__
diff --git a/src/ui/widgets/FilePage.cpp b/src/ui/widgets/FilePage.cpp
index b9602d58..2c8df5e4 100644
--- a/src/ui/widgets/FilePage.cpp
+++ b/src/ui/widgets/FilePage.cpp
@@ -1,7 +1,7 @@
/**
- * This file is part of GPGFrontend.
+ * This file is part of GpgFrontend.
*
- * GPGFrontend is free software: you can redistribute it and/or modify
+ * 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.
@@ -24,244 +24,258 @@
#include "ui/widgets/FilePage.h"
-#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());
+#include <boost/filesystem.hpp>
- 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);
+#include "MainWindow.h"
+namespace GpgFrontend::UI {
+
+FilePage::FilePage(QWidget* parent) : QWidget(parent) {
+ firstParent = parent;
+ LOG(INFO) << "New File Page";
+
+ dirModel = new QFileSystemModel();
+ dirModel->setRootPath(QDir::currentPath());
+
+ dirTreeView = new QTreeView();
+ dirTreeView->setModel(dirModel);
+ dirTreeView->setAnimated(true);
+ dirTreeView->setIndentation(20);
+ dirTreeView->setContextMenuPolicy(Qt::CustomContextMenu);
+ dirTreeView->setColumnWidth(0, 320);
+ dirTreeView->setRootIndex(dirModel->index(QDir::currentPath()));
+ mPath = boost::filesystem::path(dirModel->rootPath().toStdString());
+
+ createPopupMenu();
+
+ upLevelButton = new QPushButton();
+ connect(upLevelButton, SIGNAL(clicked(bool)), this, SLOT(slotUpLevel()));
+
+ QString buttonStyle =
+ "QPushButton{border:none;background-color:rgba(255, 255, 255, 0);}";
+
+ 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&)));
+
+ // refresh
+ slotGoPath();
}
-void FilePage::fileTreeViewItemClicked(const QModelIndex &index) {
- selectedPath = dirModel->fileInfo(index).absoluteFilePath();
- qDebug() << "selectedPath" << selectedPath;
+void FilePage::fileTreeViewItemClicked(const QModelIndex& index) {
+ selectedPath = boost::filesystem::path(
+ dirModel->fileInfo(index).absoluteFilePath().toStdString());
+ LOG(INFO) << "selected path" << 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 = boost::filesystem::path(
+ dirModel->fileInfo(currentRoot).absoluteFilePath().toStdString());
-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);
+ if (mPath.has_parent_path()) {
+ mPath = mPath.parent_path();
+ auto fileInfo = QFileInfo(QString::fromStdString(mPath.string()));
+ if (fileInfo.isDir() && fileInfo.isReadable() && fileInfo.isExecutable()) {
+ pathEdit->setText(QString::fromStdString(mPath.string()));
+ slotGoPath();
}
- qDebug() << "Index mPath" << mPath;
- emit pathChanged(mPath);
+ LOG(INFO) << "Current Root mPath" << mPath;
+ emit pathChanged(QString::fromStdString(mPath.string()));
+ }
}
-QString FilePage::getSelected() const {
- return selectedPath;
+void FilePage::fileTreeViewItemDoubleClicked(const QModelIndex& index) {
+ mPath = boost::filesystem::path(
+ dirModel->fileInfo(index).absoluteFilePath().toStdString());
+ auto fileInfo = QFileInfo(QString::fromStdString(mPath.string()));
+ auto targetModelIndex =
+ dirTreeView->model()->index(index.row(), 0, index.parent());
+ if (fileInfo.isDir() && fileInfo.isReadable() && fileInfo.isExecutable()) {
+ dirTreeView->setRootIndex(targetModelIndex);
+ pathEdit->setText(QString::fromStdString(mPath.string()));
+ }
+ for (int i = 1; i < dirModel->columnCount(); ++i)
+ dirTreeView->resizeColumnToContents(i);
+ LOG(INFO) << "Index mPath" << mPath;
+ emit pathChanged(QString::fromStdString(mPath.string()));
}
+QString FilePage::getSelected() const { return QString::fromStdString(selectedPath.string()); }
+
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 = boost::filesystem::path(fileInfo.filePath().toStdString());
+ LOG(INFO) << "Set Path" << mPath;
+ dirTreeView->setRootIndex(dirModel->index(fileInfo.filePath()));
+ for (int i = 1; i < dirModel->columnCount(); ++i)
+ dirTreeView->resizeColumnToContents(i);
+ } else {
+ QMessageBox::critical(this, "Error",
+ "The path is unprivileged or unreachable.");
+ }
+ emit pathChanged(QString::fromStdString(mPath.string()));
}
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(_("Open"), this);
+ connect(openItemAct, SIGNAL(triggered()), this, SLOT(slotOpenItem()));
+ auto deleteItemAct = new QAction(_("Delete"), this);
+ connect(deleteItemAct, SIGNAL(triggered()), this, SLOT(slotDeleteItem()));
+ encryptItemAct = new QAction(_("Encrypt and Sign"), this);
+ connect(encryptItemAct, SIGNAL(triggered()), this, SLOT(slotEncryptItem()));
+ decryptItemAct = new QAction(_("Decrypt and Verify"), this);
+ connect(decryptItemAct, SIGNAL(triggered()), this, SLOT(slotDecryptItem()));
+ signItemAct = new QAction(_("Only Sign"), this);
+ connect(signItemAct, SIGNAL(triggered()), this, SLOT(slotSignItem()));
+ verifyItemAct = new QAction(_("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 = boost::filesystem::path(
+ dirModel->fileInfo(index).absoluteFilePath().toStdString());
+ LOG(INFO) << "FilePage::onCustomContextMenu Right Click" << selectedPath;
+ if (index.isValid()) {
+ QFileInfo info(QString::fromStdString(selectedPath.string()));
+ 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(QString::fromStdString(selectedPath.string()));
+ if (info.isDir()) {
+ LOG(INFO) << "FilePage::slotOpenItem getSelected"
+ << pathEdit->text().toStdString();
+ if (info.isReadable() && info.isExecutable()) {
+ LOG(INFO) << "FilePage::slotOpenItem Set Path"
+ << info.filePath().toStdString();
+ 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);
+ LOG(INFO) << "FilePage::slotOpenItem Open Item" << selectedPath;
+ auto qt_path = QString::fromStdString(selectedPath.string());
+ if (mainWindow != nullptr) mainWindow->slotOpenFile(qt_path);
+ }
}
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, _("Warning"),
+ _("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, _("Error"),
+ _("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..31be81f3
--- /dev/null
+++ b/src/ui/widgets/FilePage.h
@@ -0,0 +1,90 @@
+/**
+ * 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 <boost/filesystem.hpp>
+
+#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;
+
+ // using boost path
+ boost::filesystem::path mPath;
+ boost::filesystem::path 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/GroupKeyList.cpp b/src/ui/widgets/GroupKeyList.cpp
new file mode 100644
index 00000000..efba4428
--- /dev/null
+++ b/src/ui/widgets/GroupKeyList.cpp
@@ -0,0 +1,25 @@
+/**
+ * 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 "GroupKeyList.h"
diff --git a/include/ui/WaitingDialog.h b/src/ui/widgets/GroupKeyList.h
index df781073..163c7126 100644
--- a/include/ui/WaitingDialog.h
+++ b/src/ui/widgets/GroupKeyList.h
@@ -1,7 +1,7 @@
/**
- * This file is part of GPGFrontend.
+ * This file is part of GpgFrontend.
*
- * GPGFrontend is free software: you can redistribute it and/or modify
+ * 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.
@@ -22,19 +22,13 @@
*
*/
-#include "GpgFrontend.h"
-
-class WaitingDialog : public QDialog {
-Q_OBJECT
-public:
-
- WaitingDialog(const QString &title, QWidget *parent);
-
-public slots:
-
-private slots:
-
-private:
+#ifndef GPGFRONTEND_GROUPKEYLIST_H
+#define GPGFRONTEND_GROUPKEYLIST_H
+#include "ui/GpgFrontendUI.h"
+class GroupKeyList : public QWidget {
+ Q_OBJECT
};
+
+#endif // GPGFRONTEND_GROUPKEYLIST_H
diff --git a/src/ui/widgets/HelpPage.cpp b/src/ui/widgets/HelpPage.cpp
index e018da81..7b1e86c0 100644
--- a/src/ui/widgets/HelpPage.cpp
+++ b/src/ui/widgets/HelpPage.cpp
@@ -1,7 +1,7 @@
/**
- * This file is part of GPGFrontend.
+ * This file is part of GpgFrontend.
*
- * GPGFrontend is free software: you can redistribute it and/or modify
+ * 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.
@@ -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,29 @@ 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 b9372c59..cd469422 100644
--- a/src/ui/widgets/InfoBoardWidget.cpp
+++ b/src/ui/widgets/InfoBoardWidget.cpp
@@ -1,7 +1,7 @@
/**
- * This file is part of GPGFrontend.
+ * This file is part of GpgFrontend.
*
- * GPGFrontend is free software: you can redistribute it and/or modify
+ * 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.
@@ -24,170 +24,193 @@
#include "ui/widgets/InfoBoardWidget.h"
-InfoBoardWidget::InfoBoardWidget(QWidget *parent, GpgME::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);
+#include "ui/settings/GlobalSettingStation.h"
+
+namespace GpgFrontend::UI {
+
+InfoBoardWidget::InfoBoardWidget(QWidget* parent, KeyList* keyList)
+ : QWidget(parent), mKeyList(keyList) {
+ 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(_("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(_("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);
+
+ // set default size
+ infoBoard->resize(480, 120);
+ resize(480, 120);
}
void InfoBoardWidget::slotImportFromKeyserver() {
- auto *importDialog = new KeyServerImportDialog(mCtx, mKeyList, false, this);
- importDialog->slotImport(*keysNotInList);
+ auto* importDialog = new KeyServerImportDialog(false, this);
+ auto key_ids = std::make_unique<KeyIdArgsList>();
+ for (const auto& key_id : *keysNotInList) {
+ key_ids->push_back(key_id.toStdString());
+ }
+ importDialog->slotImport(key_ids);
}
-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& settings = GlobalSettingStation::GetInstance().GetUISettings();
+
+ // info board font size
+ auto info_font_size = 10;
+ try {
+ info_font_size = settings.lookup("window.info_font_size");
+ if (info_font_size < 9 || info_font_size > 18) info_font_size = 10;
+ } catch (...) {
+ LOG(ERROR) << _("Setting Operation Error") << _("info_font_size");
+ }
+ infoBoard->setFont(QFont("Times", info_font_size));
}
-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..1a13e1a2
--- /dev/null
+++ b/src/ui/widgets/InfoBoardWidget.h
@@ -0,0 +1,115 @@
+/**
+ * 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:
+ 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 9c9c6763..f9f33d78 100644
--- a/src/ui/widgets/KeyList.cpp
+++ b/src/ui/widgets/KeyList.cpp
@@ -1,7 +1,7 @@
/**
- * This file is part of GPGFrontend.
+ * This file is part of GpgFrontend.
*
- * GPGFrontend is free software: you can redistribute it and/or modify
+ * 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.
@@ -26,394 +26,385 @@
#include <utility>
-KeyList::KeyList(GpgME::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);
- }
+#include "gpg/function/GpgKeyGetter.h"
+#include "ui/SignalStation.h"
+
+namespace GpgFrontend::UI {
+
+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);
+
+ // table items not editable
+ mKeyList->setEditTriggers(QAbstractItemView::NoEditTriggers);
+ // no focus (rectangle around table items)
+ // maybe 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 << _("Select") << _("Type") << _("Name") << _("Email Address")
+ << _("Usage") << _("Validity") << _("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);
+
+ // register key database refresh signal
+ connect(SignalStation::GetInstance(), SIGNAL(KeyDatabaseRefresh()), this,
+ SLOT(slotRefresh()));
+ connect(mKeyList, SIGNAL(doubleClicked(const QModelIndex&)), this,
+ SLOT(slotDoubleClicked(const QModelIndex&)));
+
+ setAcceptDrops(true);
+ slotRefresh();
+}
- QStringList labels;
- labels << tr("Select") << tr("Type") << tr("Name") << tr("Email Address")
- << tr("Usage") << tr("Validity") << tr("Finger Print");
+void KeyList::slotRefresh() {
+ LOG(INFO) << "KeyList::slotRefresh Called";
- mKeyList->setHorizontalHeaderLabels(labels);
- mKeyList->horizontalHeader()->setStretchLastSection(false);
+ 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(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 (GpgME::GpgContext::checkIfKeyCanCert(*it))
- usage_steam << "C";
- if (GpgME::GpgContext::checkIfKeyCanEncr(*it))
- usage_steam << "E";
- if (GpgME::GpgContext::checkIfKeyCanSign(*it))
- usage_steam << "S";
- if (GpgME::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(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 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 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 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 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);
-}
-
-void KeyList::contextMenuEvent(QContextMenuEvent *event) {
- if (mKeyList->selectedItems().length() > 0) {
- popupMenu->exec(event->globalPos());
- }
-
+ mKeyList->setColumnWidth(row, size);
}
-void KeyList::addSeparator() {
- popupMenu->addSeparator();
+void KeyList::contextMenuEvent(QContextMenuEvent* event) {
+ if (mKeyList->selectedItems().length() > 0) {
+ popupMenu->exec(event->globalPos());
+ }
}
-void KeyList::addMenuAction(QAction *act) {
- popupMenu->addAction(act);
-}
-
-void KeyList::dropEvent(QDropEvent *event) {
+void KeyList::addSeparator() { popupMenu->addSeparator(); }
- auto *dialog = new QDialog();
+void KeyList::addMenuAction(QAction* act) { popupMenu->addAction(act); }
- 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");
+void KeyList::dropEvent(QDropEvent* event) {
+ auto* dialog = new QDialog();
- // "always import keys"-CheckBox
- auto *checkBox = new QCheckBox(tr("Always import without bothering."));
- if (settings.value("general/confirmImportKeys").toBool()) checkBox->setCheckState(Qt::Unchecked);
+ dialog->setWindowTitle(_("Import Keys"));
+ QLabel* label;
+ label =
+ new QLabel(QString(_("You've dropped something on the table.")) + "\n " +
+ _("GpgFrontend "
+ "will now try to import key(s).") +
+ "\n");
- // 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()));
+ // "always import keys"-CheckBox
+ auto* checkBox = new QCheckBox(_("Always import without bothering."));
+ if (settings.value("general/confirmImportKeys").toBool())
+ checkBox->setCheckState(Qt::Unchecked);
- auto *vbox = new QVBoxLayout();
- vbox->addWidget(label);
- vbox->addWidget(checkBox);
- vbox->addWidget(buttonBox);
+ // 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()));
- dialog->setLayout(vbox);
+ auto* vbox = new QVBoxLayout();
+ vbox->addWidget(label);
+ vbox->addWidget(checkBox);
+ vbox->addWidget(buttonBox);
- 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);
+ 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)) {
+ LOG(INFO) << _("Couldn't Open File") << ":"
+ << tmp.toString().toStdString();
+ }
+ 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;
- }
-}
-
-void KeyList::importKeys(QByteArray inBuffer) {
- GpgImportInformation result = mCtx->importKey(std::move(inBuffer));
- new KeyImportDetailDialog(mCtx, result, false, this);
+[[maybe_unused]] void KeyList::markKeys(QStringList* keyIds) {
+ foreach (QString id, *keyIds) { qDebug() << "marked: " << id; }
}
-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::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::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::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::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 = mCtx->getKeyById(buffered_keys[index.row()].id);
- mAction(key, this);
- }
-
+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::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..524b2bd0
--- /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 00df5fdd..3e4b3bb5 100644
--- a/src/ui/widgets/SignersPicker.cpp
+++ b/src/ui/widgets/SignersPicker.cpp
@@ -1,7 +1,7 @@
/**
- * This file is part of GPGFrontend.
+ * This file is part of GpgFrontend.
*
- * GPGFrontend is free software: you can redistribute it and/or modify
+ * 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.
@@ -24,36 +24,46 @@
#include "ui/widgets/SignersPicker.h"
-SignersPicker::SignersPicker(GpgME::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(QWidget* parent) : QDialog(parent) {
+ auto confirmButton = new QPushButton(_("Confirm"));
+ connect(confirmButton, SIGNAL(clicked(bool)), this, SLOT(accept()));
- mKeyList->setFilter([](const GpgKey &key) -> bool {
- if (!GpgME::GpgContext::checkIfKeyCanSign(key)) return false;
- else return true;
- });
+ /*Setup KeyList*/
+ mKeyList = new KeyList(
+ KeyListRow::ONLY_SECRET_KEY,
+ KeyListColumn::NAME | KeyListColumn::EmailAddress | KeyListColumn::Usage);
- mKeyList->slotRefresh();
+ mKeyList->setFilter([](const GpgKey& key) -> bool {
+ if (!key.CanSignActual())
+ 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);
+ mKeyList->slotRefresh();
- this->setModal(true);
- this->setWindowTitle("Signers Picker");
- this->setMinimumWidth(480);
- this->show();
+ auto* vbox2 = new QVBoxLayout();
+ vbox2->addWidget(new QLabel(QString(_("Select Signer(s)")) + ": "));
+ vbox2->addWidget(mKeyList);
+ vbox2->addWidget(new QLabel(
+ _("Selecting Nothing will eventually use default key to sign.")));
+ vbox2->addWidget(confirmButton);
+ vbox2->addStretch(0);
+ setLayout(vbox2);
+ this->setWindowFlags(Qt::Window | Qt::WindowTitleHint |
+ Qt::CustomizeWindowHint);
+ this->setModal(true);
+ this->setWindowTitle("Signers Picker");
+ this->setMinimumWidth(480);
+ this->show();
}
-void SignersPicker::getCheckedSigners(QVector<GpgKey> &keys) {
- mKeyList->getPrivateCheckedKeys(keys);
+GpgFrontend::KeyIdArgsListPtr SignersPicker::getCheckedSigners() {
+ return mKeyList->getPrivateChecked();
}
+
+} // namespace GpgFrontend::UI
diff --git a/include/ui/widgets/SignersPicker.h b/src/ui/widgets/SignersPicker.h
index afa95a05..055b6ef6 100644
--- a/include/ui/widgets/SignersPicker.h
+++ b/src/ui/widgets/SignersPicker.h
@@ -1,7 +1,7 @@
/**
- * This file is part of GPGFrontend.
+ * This file is part of GpgFrontend.
*
- * GPGFrontend is free software: you can redistribute it and/or modify
+ * 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.
@@ -27,22 +27,22 @@
#include "GpgFrontend.h"
#include "gpg/GpgContext.h"
-
#include "ui/widgets/KeyList.h"
-class SignersPicker : public QDialog {
-Q_OBJECT
+namespace GpgFrontend::UI {
-public:
+class SignersPicker : public QDialog {
+ Q_OBJECT
- explicit SignersPicker(GpgME::GpgContext *ctx, QWidget *parent = nullptr);
+ public:
+ explicit SignersPicker(QWidget* parent = nullptr);
- void getCheckedSigners(QVector<GpgKey> &keys);
+ GpgFrontend::KeyIdArgsListPtr getCheckedSigners();
-private:
- GpgME::GpgContext *mCtx;
- KeyList *mKeyList;
+ private:
+ 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..8d4ea4a0 100644
--- a/src/ui/widgets/TextEdit.cpp
+++ b/src/ui/widgets/TextEdit.cpp
@@ -1,7 +1,7 @@
/**
- * This file is part of GPGFrontend.
+ * This file is part of GpgFrontend.
*
- * GPGFrontend is free software: you can redistribute it and/or modify
+ * 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.
@@ -24,14 +24,18 @@
#include "ui/widgets/TextEdit.h"
-TextEdit::TextEdit(QWidget *parent) : QWidget(parent) {
+#include <boost/format.hpp>
+
+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);
@@ -39,20 +43,14 @@ TextEdit::TextEdit(QWidget *parent) : QWidget(parent) {
connect(tabWidget, SIGNAL(tabCloseRequested(int)), this,
SLOT(removeTab(int)));
- connect(this, &TextEdit::insertTargetTextPage, this,
- &TextEdit::slotInsertTargetTextPage);
- connect(this, &TextEdit::readTargetTextPageStart, this,
- &TextEdit::slotReadTargetTextPageStart);
- connect(this, &TextEdit::readTargetTextPageDone, this,
- &TextEdit::slotReadTargetTextPageDone);
slotNewTab();
setAcceptDrops(false);
}
void TextEdit::slotNewTab() {
- QString header = tr("untitled") + QString::number(++countPage) + ".txt";
+ QString header = _("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,131 +58,59 @@ 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);
- pagesHashMap.insert(page->uuid, page);
+ LOG(INFO) << " path" << path.toStdString();
+ auto result = file.open(QIODevice::ReadOnly | QIODevice::Text);
+ if (result) {
+ auto* page = new EditorPage(path);
QApplication::setOverrideCursor(Qt::WaitCursor);
-
- auto read_thread = QThread::create([&, page]() {
- QFile targetFile(path);
-
- if (targetFile.open(QIODevice::ReadOnly | QIODevice::Text)) {
- emit readTargetTextPageStart(page->uuid);
- QTextStream in(&targetFile);
- QString readText;
- qDebug() << "Thread Start Reading" << path;
- while (!((readText = in.read(8192)).isEmpty())) {
- emit insertTargetTextPage(page->uuid, readText);
- QThread::msleep(64);
- }
- targetFile.close();
- emit readTargetTextPageDone(page->uuid);
- qDebug() << "Thread End Reading" << path;
- }
- });
-
- page->setFilePath(path);
- QTextDocument *document = page->getTextPage()->document();
- document->setModified(false);
-
tabWidget->addTab(page, strippedName(path));
tabWidget->setCurrentIndex(tabWidget->count() - 1);
QApplication::restoreOverrideCursor();
page->getTextPage()->setFocus();
-
- file.close();
- read_thread->start();
-
+ page->ReadFile();
} else {
- QMessageBox::warning(
- this, tr("Warning"),
- tr("Cannot read file %1:\n%2.").arg(path).arg(file.errorString()));
+ QMessageBox::warning(this, _("Warning"),
+ (boost::format(_("Cannot read file %1%:\n%2%.")) %
+ path.toStdString() % file.errorString().toStdString())
+ .str()
+ .c_str());
}
-}
-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());
- if (taregtTextPage != nullptr) {
- taregtTextPage->getTextPage()->insertPlainText(text);
- taregtTextPage->getTextPage()->document()->setModified(false);
- }
- }
-}
-
-void TextEdit::slotReadTargetTextPageStart(const QString &pagePtr) {
- auto it = pagesHashMap.find(pagePtr);
- if (it != pagesHashMap.end()) {
- auto *taregtTextPage = qobject_cast<EditorPage *>(it.value());
- if (taregtTextPage != nullptr) {
- qDebug() << "Setting TextEdit At Start" << pagePtr;
- taregtTextPage->getTextPage()->setReadOnly(true);
- auto index = tabWidget->indexOf(taregtTextPage);
- if (index != -1) {
- tabWidget->setTabText(
- index, "[Loading] " + strippedName(taregtTextPage->getFilePath()));
- }
- }
- }
-}
-
-void TextEdit::slotReadTargetTextPageDone(const QString &pagePtr) {
- auto it = pagesHashMap.find(pagePtr);
- if (it != pagesHashMap.end()) {
- auto *taregtTextPage = qobject_cast<EditorPage *>(it.value());
- if (taregtTextPage != nullptr) {
- qDebug() << "Setting TextEdit At End" << pagePtr;
- taregtTextPage->getTextPage()->setReadOnly(false);
- auto index = tabWidget->indexOf(taregtTextPage);
- if (index != -1) {
- tabWidget->setTabText(index,
- strippedName(taregtTextPage->getFilePath()));
- }
- taregtTextPage->getTextPage()->document()->setModified(false);
- connect(taregtTextPage->getTextPage()->document(),
- SIGNAL(modificationChanged(bool)), this,
- SLOT(slotShowModified()));
- }
- }
+ file.close();
+ LOG(INFO) << "done";
}
void TextEdit::slotOpen() {
QStringList fileNames =
- QFileDialog::getOpenFileNames(this, tr("Open file"), QDir::currentPath());
- for (const auto &fileName : fileNames) {
+ QFileDialog::getOpenFileNames(this, _("Open file"), QDir::currentPath());
+ 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));
@@ -197,10 +123,12 @@ void TextEdit::slotOpen() {
// enableAction(true)
file.close();
} else {
- QMessageBox::warning(this, tr("Warning"),
- tr("Cannot read file %1:\n%2.")
- .arg(fileName)
- .arg(file.errorString()));
+ QMessageBox::warning(
+ this, _("Warning"),
+ (boost::format(_("Cannot read file %1%:\n%2%.")) %
+ fileName.toStdString() % file.errorString().toStdString())
+ .str()
+ .c_str());
}
}
}
@@ -222,7 +150,7 @@ void TextEdit::slotSave() {
}
}
-bool TextEdit::saveFile(const QString &fileName) {
+bool TextEdit::saveFile(const QString& fileName) {
if (fileName.isEmpty()) {
return false;
}
@@ -230,44 +158,47 @@ 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);
int curIndex = tabWidget->currentIndex();
tabWidget->setTabText(curIndex, strippedName(fileName));
page->setFilePath(fileName);
- // statusBar()->showMessage(tr("File saved"), 2000);
+ // statusBar()->showMessage(_("File saved"), 2000);
file.close();
return true;
} else {
QMessageBox::warning(
- this, tr("File"),
- tr("Cannot write file %1:\n%2.").arg(fileName).arg(file.errorString()));
+ this, _("Warning"),
+ (boost::format(_("Cannot read file %1%:\n%2%.")) %
+ fileName.toStdString() % file.errorString().toStdString())
+ .str()
+ .c_str());
return false;
}
}
bool TextEdit::slotSaveAs() {
- if (tabWidget->count() == 0 || slotCurPageTextEdit() == 0) {
+ if (tabWidget->count() == 0 || slotCurPageTextEdit() == nullptr) {
return true;
}
- EditorPage *page = slotCurPageTextEdit();
+ EditorPage* page = slotCurPageTextEdit();
QString path;
- if (page->getFilePath() != "") {
+ if (!page->getFilePath().isEmpty()) {
path = page->getFilePath();
} else {
path = tabWidget->tabText(tabWidget->currentIndex()).remove(0, 2);
}
- QString fileName = QFileDialog::getSaveFileName(this, tr("Save file"), path);
+ QString fileName = QFileDialog::getSaveFileName(this, _("Save file"), path);
return saveFile(fileName);
}
@@ -312,34 +243,35 @@ 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()) {
+ if (page->ReadDone() && document->isModified()) {
QMessageBox::StandardButton result = QMessageBox::Cancel;
// write title of tab to docname and remove the leading *
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"),
- tr("The document \"%1\" has been modified. Do you want to "
- "save your changes?<br/>")
+ this, _("Unsaved document"),
+ QString(_("The document \"%1\" has been modified. Do you want to "
+ "save your changes?"))
.arg(docname) +
- tr("<b>Note:</b> If you don't save these files, all changes are "
- "lost.<br/>"),
+ "<br/><b>" + _("Note:") + "</b>" +
+ _("If you don't save these files, all changes are "
+ "lost.") +
+ "<br/>",
QMessageBox::Save | QMessageBox::Discard | QMessageBox::Cancel);
}
if ((result == QMessageBox::Save) || (!askToSave)) {
- if (filePath == "") {
+ if (filePath.isEmpty()) {
// QString docname = tabWidget->tabText(tabWidget->currentIndex());
// docname.remove(0,2);
return slotSaveAs();
@@ -352,6 +284,9 @@ bool TextEdit::maybeSaveCurrentTab(bool askToSave) {
return false;
}
}
+
+ // destroy
+ page->PrepareToDestroy();
return true;
}
@@ -381,7 +316,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();
@@ -394,28 +329,24 @@ bool TextEdit::maybeSaveAnyTab() {
return false;
}
} else {
- bool allsaved = true;
+ bool all_saved = true;
QList<int> tabIdsToSave = dialog->getTabIdsToSave();
- foreach (int tabId, tabIdsToSave) {
+ for (const auto& tabId : tabIdsToSave) {
tabWidget->setCurrentIndex(tabId);
if (!maybeSaveCurrentTab(false)) {
- allsaved = false;
+ all_saved = false;
}
}
- if (allsaved) {
- return true;
- } else {
- return false;
- }
+ return all_saved;
}
}
// code should never reach this statement
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 +354,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 {
@@ -434,13 +365,13 @@ FilePage *TextEdit::curFilePage() const {
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 +397,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,12 +405,15 @@ 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(
- this, tr("Application"),
- tr("Cannot read file %1:\n%2.").arg(fileName).arg(file.errorString()));
+ this, _("Warning"),
+ (boost::format(_("Cannot read file %1%:\n%2%.")) %
+ fileName.toStdString() % file.errorString().toStdString())
+ .str()
+ .c_str());
return;
}
QTextStream in(&file);
@@ -489,10 +423,10 @@ void TextEdit::loadFile(const QString &fileName) {
slotCurPageTextEdit()->setFilePath(fileName);
tabWidget->setTabText(tabWidget->currentIndex(), strippedName(fileName));
file.close();
- // statusBar()->showMessage(tr("File loaded"), 2000);
+ // statusBar()->showMessage(_("File loaded"), 2000);
}
-QString TextEdit::strippedName(const QString &fullFileName) {
+QString TextEdit::strippedName(const QString& fullFileName) {
return QFileInfo(fullFileName).fileName();
}
@@ -502,19 +436,19 @@ 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;
}
document->print(&printer);
- // statusBar()->showMessage(tr("Ready"), 2000);
+ // statusBar()->showMessage(_("Ready"), 2000);
#endif
}
@@ -549,16 +483,19 @@ 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));
- if (ep != nullptr && ep->getTextPage()->document()->isModified()) {
- QString docname = tabWidget->tabText(i);
+ auto* ep = qobject_cast<EditorPage*>(tabWidget->widget(i));
+ if (ep != nullptr && ep->ReadDone() &&
+ ep->getTextPage()->document()->isModified()) {
+ QString doc_name = tabWidget->tabText(i);
+ LOG(INFO) << "unsaved" << doc_name.toStdString();
+
// remove * before name of modified doc
- docname.remove(0, 2);
- unsavedDocs.insert(i, docname);
+ doc_name.remove(0, 2);
+ unsavedDocs.insert(i, doc_name);
}
}
return unsavedDocs;
@@ -633,7 +570,7 @@ void TextEdit::slotSelectAll() const {
curTextPage()->selectAll();
}
-void TextEdit::slotFilePagePathChanged(const QString &path) {
+void TextEdit::slotFilePagePathChanged(const QString& path) const {
int index = tabWidget->currentIndex();
QString mPath;
QFileInfo fileInfo(path);
@@ -644,6 +581,7 @@ void TextEdit::slotFilePagePathChanged(const QString &path) {
mPath = tPath;
}
mPath.prepend("[Browser] ");
- 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..3cff74e7
--- /dev/null
+++ b/src/ui/widgets/TextEdit.h
@@ -0,0 +1,282 @@
+/**
+ * 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.
+ *
+ */
+ EditorPage* slotCurPageTextEdit() const;
+
+ /**
+ * @details Return pointer to the currently activated file treeview tab page.
+ *
+ */
+ 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;
+
+ 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 */
+
+ private slots:
+
+ void slotFilePagePathChanged(const QString& path) const;
+
+ /**
+ * @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 e0f79c3e..cd5b6641 100644
--- a/src/ui/widgets/VerifyKeyDetailBox.cpp
+++ b/src/ui/widgets/VerifyKeyDetailBox.cpp
@@ -1,7 +1,7 @@
/**
- * This file is part of GPGFrontend.
+ * This file is part of GpgFrontend.
*
- * GPGFrontend is free software: you can redistribute it and/or modify
+ * 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.
@@ -24,180 +24,198 @@
#include "ui/widgets/VerifyKeyDetailBox.h"
-VerifyKeyDetailBox::VerifyKeyDetailBox(QWidget *parent, GpgME::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(_("Import from keyserver"));
+ connect(importButton, SIGNAL(clicked()), this,
+ SLOT(slotImportFormKeyserver()));
- auto grid = new QGridLayout();
+ this->setTitle(QString(_("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(QString(_("Status")) + _(":")), 0, 0);
+ // grid->addWidget(new QLabel(_("Fingerprint:")), 1, 0);
+ grid->addWidget(new QLabel(_("Key not present in key list")), 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(QString(_("A Signature")) + ":");
+ auto gird = createKeyInfoGrid(signature);
+ if (gird != nullptr) {
+ vbox->addLayout(gird);
+ } else {
+ vbox->addWidget(new QLabel(_("Key Information is NOT Available")));
+ if (signature->fpr != nullptr) {
+ vbox->addWidget(new QLabel(QString(_("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(QString(_("Status")) + ":" + _("Cert Revoked")));
+ auto gird = createKeyInfoGrid(signature);
+ if (gird != nullptr) {
+ vbox->addLayout(gird);
+ } else {
+ vbox->addWidget(new QLabel(_("Key Information is NOT Available")));
+ if (signature->fpr != nullptr) {
+ vbox->addWidget(new QLabel(QString(_("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(QString(_("Status")) + ":" + _("Signature Expired")));
+ auto gird = createKeyInfoGrid(signature);
+ if (gird != nullptr) {
+ vbox->addLayout(gird);
+ } else {
+ vbox->addWidget(new QLabel(_("Key Information is NOT Available")));
+ if (signature->fpr != nullptr) {
+ vbox->addWidget(new QLabel(QString(_("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(QString(_("Status")) + ":" + _("Key Expired")));
+ vbox->addWidget(
+ new QLabel(QString(_("Status")) + ":" + _("Key Expired")));
+ auto gird = createKeyInfoGrid(signature);
+ if (gird != nullptr) {
+ vbox->addLayout(gird);
+ } else {
+ vbox->addWidget(new QLabel(_("Key Information is NOT Available")));
+ if (signature->fpr != nullptr) {
+ vbox->addWidget(new QLabel(QString(_("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(QString(_("Status")) + ":" + _("General Error")));
+ auto gird = createKeyInfoGrid(signature);
+ if (gird != nullptr) {
+ vbox->addLayout(gird);
+ } else {
+ vbox->addWidget(new QLabel(_("Key Information is NOT Available")));
+ if (signature->fpr != nullptr) {
+ vbox->addWidget(new QLabel(QString(_("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(QString(_("Status")) + ":" + _("Unknown Error "));
+ auto gird = createKeyInfoGrid(signature);
+ if (gird != nullptr) {
+ vbox->addLayout(gird);
+ } else {
+ vbox->addWidget(new QLabel(_("Key Information is NOT Available")));
+ if (signature->fpr != nullptr) {
+ vbox->addWidget(new QLabel(QString(_("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(false, this);
+ auto key_ids = std::make_unique<KeyIdArgsList>();
+ key_ids->push_back(fpr.toStdString());
+ importDialog->slotImport(key_ids);
}
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->getKeyByFpr(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(QString(_("Signer Name")) + ":"), 0, 0);
+ grid->addWidget(new QLabel(QString(_("Signer Email")) + ":"), 1, 0);
+ grid->addWidget(new QLabel(QString(_("Key's Fingerprint")) + ":"), 2, 0);
+ grid->addWidget(new QLabel(QString(_("Valid")) + ":"), 3, 0);
+ grid->addWidget(new QLabel(QString(_("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(_("Fully Valid")), 3, 1);
+ } else {
+ grid->addWidget(new QLabel(_("NOT Fully Valid")), 3, 1);
+ }
+
+ QString flags;
+ QTextStream textStream(&flags);
+
+ if (signature->summary & GPGME_SIGSUM_GREEN) {
+ textStream << _("Good") << " ";
+ }
+ if (signature->summary & GPGME_SIGSUM_RED) {
+ textStream << _("Bad") << " ";
+ }
+ if (signature->summary & GPGME_SIGSUM_SIG_EXPIRED) {
+ textStream << _("Expired") << " ";
+ }
+ if (signature->summary & GPGME_SIGSUM_KEY_MISSING) {
+ textStream << _("Missing Key") << " ";
+ }
+ if (signature->summary & GPGME_SIGSUM_KEY_REVOKED) {
+ textStream << _("Revoked Key") << " ";
+ }
+ if (signature->summary & GPGME_SIGSUM_KEY_EXPIRED) {
+ textStream << _("Expired Key") << " ";
+ }
+ if (signature->summary & GPGME_SIGSUM_CRL_MISSING) {
+ textStream << _("Missing CRL") << " ";
+ }
+
+ grid->addWidget(new QLabel(_(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 66f01a8e..c1b26bb2 100644
--- a/include/ui/widgets/VerifyKeyDetailBox.h
+++ b/src/ui/widgets/VerifyKeyDetailBox.h
@@ -1,7 +1,7 @@
/**
- * This file is part of GPGFrontend.
+ * This file is part of GpgFrontend.
*
- * GPGFrontend is free software: you can redistribute it and/or modify
+ * 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.
@@ -25,29 +25,31 @@
#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, GpgME::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:
- GpgME::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/CMakeLists.txt b/test/CMakeLists.txt
new file mode 100644
index 00000000..8a5859f4
--- /dev/null
+++ b/test/CMakeLists.txt
@@ -0,0 +1,20 @@
+find_package(GTest REQUIRED)
+
+# Set configure for test
+file(COPY ${CMAKE_SOURCE_DIR}/test/conf DESTINATION ${CMAKE_CURRENT_BINARY_DIR}/ FOLLOW_SYMLINK_CHAIN)
+file(COPY ${CMAKE_SOURCE_DIR}/test/data DESTINATION ${CMAKE_CURRENT_BINARY_DIR}/ FOLLOW_SYMLINK_CHAIN)
+
+aux_source_directory(. TEST_SOURCE)
+
+add_executable(
+ ${AppName}
+ ${TEST_SOURCE}
+)
+
+if(GPG_CORE)
+ target_link_libraries(${AppName} gpg_core)
+endif()
+
+target_link_libraries(${AppName} gtest gtest_main)
+
+add_test(AllTestsInGpgFrontend ${AppName})
diff --git a/test/GpgCoreTestBasicOpera.cpp b/test/GpgCoreTestBasicOpera.cpp
new file mode 100644
index 00000000..40972982
--- /dev/null
+++ b/test/GpgCoreTestBasicOpera.cpp
@@ -0,0 +1,174 @@
+/**
+ * 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 <gtest/gtest.h>
+
+#include <string>
+#include <vector>
+
+#include "GpgFrontendTest.h"
+#include "gpg/GpgConstants.h"
+#include "gpg/function/BasicOperator.h"
+#include "gpg/function/GpgKeyGetter.h"
+#include "gpg/model/GpgKey.h"
+
+using namespace GpgFrontend;
+
+TEST_F(GpgCoreTest, CoreEncryptDecrTest) {
+ auto encrpyt_key = GpgKeyGetter::GetInstance(default_channel)
+ .GetPubkey("467F14220CE8DCF780CF4BAD8465C55B25C9B7D1");
+ ByteArray encrypt_text = "Hello GpgFrontend!";
+ ByteArrayPtr encr_out_data;
+ GpgEncrResult e_result;
+ std::vector<GpgKey> keys;
+ keys.push_back(std::move(encrpyt_key));
+ auto err =
+ BasicOperator::GetInstance(default_channel)
+ .Encrypt(std::move(keys), encrypt_text, encr_out_data, e_result);
+ ASSERT_EQ(e_result->invalid_recipients, nullptr);
+ ASSERT_EQ(check_gpg_error_2_err_code(err), GPG_ERR_NO_ERROR);
+
+ GpgDecrResult d_result;
+ 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);
+ ASSERT_NE(d_result->recipients, nullptr);
+ ASSERT_EQ(std::string(d_result->recipients->keyid), "F89C95A05088CC93");
+ ASSERT_EQ(*decr_out_data, encrypt_text);
+}
+
+TEST_F(GpgCoreTest, CoreSignVerifyNormalTest) {
+ auto encrpyt_key = GpgKeyGetter::GetInstance(default_channel)
+ .GetPubkey("467F14220CE8DCF780CF4BAD8465C55B25C9B7D1");
+ ByteArray sign_text = "Hello GpgFrontend!";
+ ByteArrayPtr sign_out_data;
+ GpgSignResult s_result;
+ std::vector<GpgKey> keys;
+ keys.push_back(std::move(encrpyt_key));
+ auto err = BasicOperator::GetInstance(default_channel)
+ .Sign(std::move(keys), sign_text, sign_out_data,
+ GPGME_SIG_MODE_NORMAL, s_result);
+ ASSERT_EQ(check_gpg_error_2_err_code(err), GPG_ERR_NO_ERROR);
+ ASSERT_EQ(s_result->invalid_signers, nullptr);
+
+ GpgVerifyResult v_result;
+ 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);
+ ASSERT_NE(v_result->signatures, nullptr);
+ ASSERT_EQ(std::string(v_result->signatures->fpr),
+ "467F14220CE8DCF780CF4BAD8465C55B25C9B7D1");
+ ASSERT_EQ(v_result->signatures->next, nullptr);
+}
+
+TEST_F(GpgCoreTest, CoreSignVerifyDetachTest) {
+ auto encrpyt_key = GpgKeyGetter::GetInstance(default_channel)
+ .GetPubkey("467F14220CE8DCF780CF4BAD8465C55B25C9B7D1");
+ ByteArray sign_text = "Hello GpgFrontend!";
+ ByteArrayPtr sign_out_data;
+ GpgSignResult s_result;
+ std::vector<GpgKey> keys;
+ keys.push_back(std::move(encrpyt_key));
+ auto err = BasicOperator::GetInstance(default_channel)
+ .Sign(std::move(keys), sign_text, sign_out_data,
+ GPGME_SIG_MODE_DETACH, s_result);
+ ASSERT_EQ(check_gpg_error_2_err_code(err), GPG_ERR_NO_ERROR);
+ ASSERT_EQ(s_result->invalid_signers, nullptr);
+
+ GpgVerifyResult v_result;
+ err = BasicOperator::GetInstance(default_channel)
+ .Verify(sign_text, sign_out_data, v_result);
+ ASSERT_EQ(check_gpg_error_2_err_code(err), GPG_ERR_NO_ERROR);
+ ASSERT_NE(v_result->signatures, nullptr);
+ ASSERT_EQ(std::string(v_result->signatures->fpr),
+ "467F14220CE8DCF780CF4BAD8465C55B25C9B7D1");
+ ASSERT_EQ(v_result->signatures->next, nullptr);
+}
+
+TEST_F(GpgCoreTest, CoreSignVerifyClearTest) {
+ auto sign_key = GpgKeyGetter::GetInstance(default_channel)
+ .GetKey("467F14220CE8DCF780CF4BAD8465C55B25C9B7D1");
+ ByteArray sign_text = "Hello GpgFrontend!";
+ ByteArrayPtr sign_out_data;
+ GpgSignResult s_result;
+ std::vector<GpgKey> keys;
+ keys.push_back(std::move(sign_key));
+ auto err = BasicOperator::GetInstance(default_channel)
+ .Sign(std::move(keys), sign_text, sign_out_data,
+ GPGME_SIG_MODE_CLEAR, s_result);
+ ASSERT_EQ(check_gpg_error_2_err_code(err), GPG_ERR_NO_ERROR);
+ ASSERT_EQ(s_result->invalid_signers, nullptr);
+
+ GpgVerifyResult v_result;
+ 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);
+ ASSERT_NE(v_result->signatures, nullptr);
+ ASSERT_EQ(std::string(v_result->signatures->fpr),
+ "467F14220CE8DCF780CF4BAD8465C55B25C9B7D1");
+ ASSERT_EQ(v_result->signatures->next, nullptr);
+}
+
+TEST_F(GpgCoreTest, CoreEncryptSignDecrVerifyTest) {
+ auto encrpyt_key = GpgKeyGetter::GetInstance(default_channel)
+ .GetPubkey("467F14220CE8DCF780CF4BAD8465C55B25C9B7D1");
+ auto sign_key = GpgKeyGetter::GetInstance(default_channel)
+ .GetKey("8933EB283A18995F45D61DAC021D89771B680FFB");
+ // Question?
+ // ASSERT_FALSE(encrpyt_key.is_private_key());
+ ASSERT_TRUE(sign_key.is_private_key());
+ ASSERT_TRUE(sign_key.CanSignActual());
+ ByteArray encrypt_text = "Hello GpgFrontend!";
+ ByteArrayPtr encr_out_data;
+ GpgEncrResult e_result;
+ GpgSignResult s_result;
+
+ std::vector<GpgKey> keys, sign_keys;
+ keys.push_back(std::move(encrpyt_key));
+ sign_keys.push_back(std::move(sign_key));
+
+ auto err = BasicOperator::GetInstance(default_channel)
+ .EncryptSign(std::move(keys), std::move(sign_keys),
+ encrypt_text, encr_out_data, e_result, s_result);
+ ASSERT_EQ(check_gpg_error_2_err_code(err), GPG_ERR_NO_ERROR);
+ ASSERT_EQ(e_result->invalid_recipients, nullptr);
+ ASSERT_EQ(s_result->invalid_signers, nullptr);
+
+ GpgDecrResult d_result;
+ GpgVerifyResult v_result;
+ 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);
+ ASSERT_NE(d_result->recipients, nullptr);
+ ASSERT_EQ(std::string(d_result->recipients->keyid), "F89C95A05088CC93");
+ ASSERT_EQ(*decr_out_data, encrypt_text);
+ ASSERT_NE(v_result->signatures, nullptr);
+ ASSERT_EQ(std::string(v_result->signatures->fpr),
+ "8933EB283A18995F45D61DAC021D89771B680FFB");
+ ASSERT_EQ(v_result->signatures->next, nullptr);
+}
diff --git a/test/GpgCoreTestImportExport.cpp b/test/GpgCoreTestImportExport.cpp
new file mode 100644
index 00000000..9d01cc3e
--- /dev/null
+++ b/test/GpgCoreTestImportExport.cpp
@@ -0,0 +1,34 @@
+/**
+ * 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 <string>
+#include <vector>
+
+#include "GpgFrontendTest.h"
+#include "gpg/GpgConstants.h"
+#include "gpg/function/GpgKeyGetter.h"
+#include "gpg/function/GpgKeyImportExportor.h"
+#include "gpg/model/GpgKey.h"
+
+TEST_F(GpgCoreTest, CoreExportSecretTest) {} \ No newline at end of file
diff --git a/test/GpgCoreTestKeyModel.cpp b/test/GpgCoreTestKeyModel.cpp
new file mode 100644
index 00000000..4e85a8cf
--- /dev/null
+++ b/test/GpgCoreTestKeyModel.cpp
@@ -0,0 +1,169 @@
+/**
+ * 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 "GpgFrontendTest.h"
+#include "gpg/function/GpgKeyGetter.h"
+
+// Should be used once and once-only
+INITIALIZE_EASYLOGGINGPP
+
+TEST_F(GpgCoreTest, CoreInitTest) {
+ auto& ctx = GpgFrontend::GpgContext::GetInstance(default_channel);
+ auto& ctx_default = GpgFrontend::GpgContext::GetInstance();
+ ASSERT_TRUE(ctx.good());
+ ASSERT_TRUE(ctx_default.good());
+ ASSERT_EQ(ctx_default.GetInfo().DatabasePath, "default");
+}
+
+TEST_F(GpgCoreTest, GpgDataTest) {
+ auto data_buff = std::string(
+ "cqEh8fyKWtmiXrW2zzlszJVGJrpXDDpzgP7ZELGxhfZYFi8rMrSVKDwrpFZBSWMG");
+
+ GpgFrontend::GpgData data(data_buff.data(), data_buff.size());
+
+ auto out_buffer = data.Read2Buffer();
+ ASSERT_EQ(out_buffer->size(), 64);
+}
+
+TEST_F(GpgCoreTest, GpgKeyTest) {
+ auto key = GpgFrontend::GpgKeyGetter::GetInstance(default_channel)
+ .GetKey("9490795B78F8AFE9F93BD09281704859182661FB");
+ ASSERT_TRUE(key.good());
+ ASSERT_TRUE(key.is_private_key());
+ ASSERT_TRUE(key.has_master_key());
+
+ ASSERT_FALSE(key.disabled());
+ ASSERT_FALSE(key.revoked());
+
+ ASSERT_EQ(key.protocol(), "OpenPGP");
+
+ ASSERT_EQ(key.subKeys()->size(), 2);
+ ASSERT_EQ(key.uids()->size(), 1);
+
+ ASSERT_TRUE(key.can_certify());
+ ASSERT_TRUE(key.can_encrypt());
+ ASSERT_TRUE(key.can_sign());
+ ASSERT_FALSE(key.can_authenticate());
+ ASSERT_TRUE(key.CanEncrActual());
+ ASSERT_TRUE(key.CanEncrActual());
+ ASSERT_TRUE(key.CanSignActual());
+ ASSERT_FALSE(key.CanAuthActual());
+
+ ASSERT_EQ(key.name(), "GpgFrontendTest");
+ ASSERT_TRUE(key.comment().empty());
+ ASSERT_EQ(key.email(), "[email protected]");
+ ASSERT_EQ(key.id(), "81704859182661FB");
+ ASSERT_EQ(key.fpr(), "9490795B78F8AFE9F93BD09281704859182661FB");
+ ASSERT_EQ(key.expires(), boost::gregorian::from_simple_string("2023-09-05"));
+ ASSERT_EQ(key.pubkey_algo(), "RSA");
+ ASSERT_EQ(key.length(), 3072);
+ ASSERT_EQ(key.last_update(),
+ boost::gregorian::from_simple_string("1970-01-01"));
+ ASSERT_EQ(key.create_time(),
+ boost::gregorian::from_simple_string("2021-09-05"));
+
+ ASSERT_EQ(key.owner_trust(), "Unknown");
+
+ using namespace boost::posix_time;
+ ASSERT_EQ(key.expired(), key.expires() < second_clock::local_time().date());
+}
+
+TEST_F(GpgCoreTest, GpgSubKeyTest) {
+ auto key = GpgFrontend::GpgKeyGetter::GetInstance(default_channel)
+ .GetKey("9490795B78F8AFE9F93BD09281704859182661FB");
+ auto sub_keys = key.subKeys();
+ ASSERT_EQ(sub_keys->size(), 2);
+
+ auto& sub_key = sub_keys->back();
+
+ ASSERT_FALSE(sub_key.revoked());
+ ASSERT_FALSE(sub_key.disabled());
+ ASSERT_EQ(sub_key.timestamp(),
+ boost::gregorian::from_simple_string("2021-09-05"));
+
+ ASSERT_FALSE(sub_key.is_cardkey());
+ ASSERT_TRUE(sub_key.is_private_key());
+ ASSERT_EQ(sub_key.id(), "2B36803235B5E25B");
+ ASSERT_EQ(sub_key.fpr(), "50D37E8F8EE7340A6794E0592B36803235B5E25B");
+ ASSERT_EQ(sub_key.length(), 3072);
+ ASSERT_EQ(sub_key.pubkey_algo(), "RSA");
+ ASSERT_FALSE(sub_key.can_certify());
+ ASSERT_FALSE(sub_key.can_authenticate());
+ ASSERT_FALSE(sub_key.can_sign());
+ ASSERT_TRUE(sub_key.can_encrypt());
+ ASSERT_EQ(key.expires(), boost::gregorian::from_simple_string("2023-09-05"));
+
+ using namespace boost::posix_time;
+ ASSERT_EQ(sub_key.expired(),
+ sub_key.expires() < second_clock::local_time().date());
+}
+
+TEST_F(GpgCoreTest, GpgUIDTest) {
+ auto key = GpgFrontend::GpgKeyGetter::GetInstance(default_channel)
+ .GetKey("9490795B78F8AFE9F93BD09281704859182661FB");
+ auto uids = key.uids();
+ ASSERT_EQ(uids->size(), 1);
+ auto& uid = uids->front();
+
+ ASSERT_EQ(uid.name(), "GpgFrontendTest");
+ ASSERT_TRUE(uid.comment().empty());
+ ASSERT_EQ(uid.email(), "[email protected]");
+ ASSERT_EQ(uid.uid(), "GpgFrontendTest <[email protected]>");
+ ASSERT_FALSE(uid.invalid());
+ ASSERT_FALSE(uid.revoked());
+}
+
+TEST_F(GpgCoreTest, GpgKeySignatureTest) {
+ auto key = GpgFrontend::GpgKeyGetter::GetInstance(default_channel)
+ .GetKey("9490795B78F8AFE9F93BD09281704859182661FB");
+ auto uids = key.uids();
+ ASSERT_EQ(uids->size(), 1);
+ auto& uid = uids->front();
+
+ auto signatures = uid.signatures();
+ ASSERT_EQ(signatures->size(), 1);
+ auto& signature = signatures->front();
+
+ ASSERT_EQ(signature.name(), "GpgFrontendTest");
+ ASSERT_TRUE(signature.comment().empty());
+ ASSERT_EQ(signature.email(), "[email protected]");
+ ASSERT_EQ(signature.keyid(), "81704859182661FB");
+ ASSERT_EQ(signature.pubkey_algo(), "RSA");
+
+ ASSERT_FALSE(signature.revoked());
+ ASSERT_FALSE(signature.invalid());
+ ASSERT_EQ(GpgFrontend::check_gpg_error_2_err_code(signature.status()),
+ GPG_ERR_NO_ERROR);
+ ASSERT_EQ(signature.uid(), "GpgFrontendTest <[email protected]>");
+}
+
+TEST_F(GpgCoreTest, GpgKeyGetterTest) {
+ auto key = GpgFrontend::GpgKeyGetter::GetInstance(default_channel)
+ .GetKey("9490795B78F8AFE9F93BD09281704859182661FB");
+ ASSERT_TRUE(key.good());
+ auto keys =
+ GpgFrontend::GpgKeyGetter::GetInstance(default_channel).FetchKey();
+ ASSERT_GE(keys->size(), secret_keys_.size());
+ ASSERT_TRUE(find(keys->begin(), keys->end(), key) != keys->end());
+}
diff --git a/test/GpgFrontendTest.h b/test/GpgFrontendTest.h
new file mode 100644
index 00000000..181c513e
--- /dev/null
+++ b/test/GpgFrontendTest.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 _GPGFRONTENDTEST_H
+#define _GPGFRONTENDTEST_H
+
+#include <easyloggingpp/easylogging++.h>
+#include <gpg-error.h>
+#include <gtest/gtest.h>
+
+#include <boost/date_time/gregorian/parsers.hpp>
+#include <boost/dll.hpp>
+#include <boost/filesystem/operations.hpp>
+#include <boost/filesystem/path.hpp>
+#include <memory>
+#include <string>
+#include <vector>
+
+#include "gpg/GpgConstants.h"
+#include "gpg/function/GpgKeyImportExportor.h"
+
+class GpgCoreTest : public ::testing::Test {
+ protected:
+ // Secret Keys Imported
+ std::vector<GpgFrontend::StdBypeArrayPtr> secret_keys_;
+
+ // Program Location
+ boost::filesystem::path parent_path =
+ boost::dll::program_location().parent_path();
+
+ // Configure File Location
+ boost::filesystem::path config_path = parent_path / "conf" / "core.cfg";
+
+ // Data File Directory Location
+ boost::filesystem::path data_path;
+
+ int default_channel = 0;
+
+ GpgCoreTest() = default;
+
+ virtual ~GpgCoreTest() = default;
+
+ virtual void SetUp() {
+ using namespace libconfig;
+ Config cfg;
+ ASSERT_NO_THROW(cfg.readFile(config_path.c_str()));
+ Setting& root = cfg.getRoot();
+
+ if (root.exists("data_path")) {
+ std::string relative_data_path;
+ root.lookupValue("data_path", relative_data_path);
+ data_path = parent_path / relative_data_path;
+ };
+
+ configure_independent_database(root);
+
+ dealing_private_keys(root);
+ import_data();
+ }
+
+ virtual void TearDown() {}
+
+ private:
+ void import_data() {
+ GpgFrontend::GpgContext::GetInstance(default_channel)
+ .SetPassphraseCb(GpgFrontend::GpgContext::test_passphrase_cb);
+ for (auto& secret_key : secret_keys_) {
+ GpgFrontend::GpgKeyImportExportor::GetInstance(default_channel)
+ .ImportKey(std::move(secret_key));
+ }
+ }
+ void dealing_private_keys(const libconfig::Setting& root) {
+ if (root.exists("load_keys.private_keys")) {
+ auto& private_keys = root.lookup("load_keys.private_keys");
+ for (auto it = private_keys.begin(); it != private_keys.end(); it++) {
+ if (it->exists("filename")) {
+ std::string filename;
+ it->lookupValue("filename", filename);
+ auto data_file_path = data_path / filename;
+ std::string data =
+ GpgFrontend::read_all_data_in_file(data_file_path.string());
+ secret_keys_.push_back(std::make_unique<std::string>(data));
+ }
+ }
+ }
+ }
+
+ void configure_independent_database(const libconfig::Setting& root) {
+ bool independent_database = false;
+ if (root.exists("independent_database")) {
+ root.lookupValue("independent_database", independent_database);
+ if (independent_database && root.exists("independent_db_path")) {
+ default_channel = 1;
+ std::string relative_db_path;
+ root.lookupValue("independent_db_path", relative_db_path);
+ auto db_path = parent_path / relative_db_path;
+ if (!boost::filesystem::exists(db_path)) {
+ boost::filesystem::create_directory(db_path);
+ }
+ GpgFrontend::GpgContext::CreateInstance(
+ 1,
+ std::make_unique<GpgFrontend::GpgContext>(true, db_path.c_str()));
+ }
+ }
+ }
+};
+
+#endif // _GPGFRONTENDTEST_H
diff --git a/test/conf/core.cfg b/test/conf/core.cfg
new file mode 100644
index 00000000..69395963
--- /dev/null
+++ b/test/conf/core.cfg
@@ -0,0 +1,24 @@
+# core test configuration file
+version = "1.0";
+independent_database = true;
+independent_db_path = "db"
+data_path = "data"
+load_keys =
+{
+ private_keys = (
+ {
+ filename = "pv1.key";
+ md5 = "1d6ceb1aa836b582fa3750cb162ce90c";
+ },{
+ filename = "pv2.key";
+ md5 = "ce52f1557a1d7e74c4f157fdf8f56d41";
+ },{
+ filename = "pv3.key";
+ md5 = "ab7bc39ccb46ccdd71867a391f2d2306";
+ },
+ {
+ filename = "pv4.key";
+ md5 = "c88ff29f7c75fa118776a62313035442";
+ }
+ );
+}; \ No newline at end of file
diff --git a/test/data/pv1.key b/test/data/pv1.key
new file mode 100644
index 00000000..345fdf4f
--- /dev/null
+++ b/test/data/pv1.key
@@ -0,0 +1,82 @@
+-----BEGIN PGP PRIVATE KEY BLOCK-----
+
+lQVYBGE0XVEBDADHYmnEbRB8hxqyQmaLmIRU71PTMZc162qWoWTMaPd7a8gQcQwc
+MUFYHp3mAmoHYUAKyT0lgpyj7UqGDdiAOt8z+nW6tR2Wu2xe6o0su/oK8qGtX37e
+bexiWcsMftrk/uR+l2G7JcCKMTAszLbyDgg1IaJ/SaVicKaO1CRjD5ZlNa2IQVOG
+bw0va1CevF6yw5rvc5r300p/kwcKX4taUyPaCT10ZxZnpZUhdsAIX5DfvWURoZ0q
+jy4JdQFlufhPzSJZ2VoCXn37FeXwEz1Vm8VzyVV70pPWN5osMcNBsRO4nr8cYIxo
+1PiErm3VdDUHPZ8dKKMlrLaGh3De3ohK47GSLDqBGg/FNnekRwNqBT+HLvfk5Kko
+lNsC7eyRSagI7IRY+KgjKNpT/9QUGYP9llTonQ2V58XarDFDy8SU/3yOqWaeu0Op
+A/fpqkp7JF3mGLXzKOZ4ueEOMkh+DsAOPTOQTcbYvnCz8jvHUPlSUqU1Y/7xU6BW
+rzgqajU563xoxCMAEQEAAQAL/2IGy5NsP8fJsOFlbf9B/AW6KM9TuVEkLiJitSke
+jlZa1mDnA5o0yTimzODR3QlF0fO7ntl7TsH1n0crNX9N8oEeqZUjCKob+Zrs3H3a
+6YNKaRzRL5HyH173YLIDCGG/w91NVhpp5DDNIC9WcretGHHu2HKWZb5xPiJIwJ8H
+gdy+uFOeMo+Mt8HRlDCG0lQ3gUwq3Uzsz9rLEZITCXNeHulK07EQId7RdPGf7afw
+PE0UU8WIXLoY7PxvT0GRXjj11AheEGNHcebirHbgbLWoevY/+h+r/yAdRns+S2l+
+PsShh6ki8bH7InI7L79v+021l89FfTZYixwscvwLBN4QWp6FLwqwDJjEHnZRxjCX
+Y5v7j9gHhhyK2vNbwU1vx/drx/cllIHfYOVRoZtxaAnfW0u51x/uKTknHBoL1GvW
+zrJHLMC4cHuPYAR6vS5sy7QcqVeB709mrTNVGHa0w6u4U8mlxpIQ/izdxy9k2sgV
+OAfZMxojIehGymu7LP0DP+ElUQYA2Rr5l81OIO9JCA+pg6B4ZigGYMvGDnBv9kuy
+lJWWV1O7jPMAfdK0lkehTpw/E4TkRk1t7PiQhXtGprYUAihdR2rx8DyDc438mhvw
+aN95MURkZ0v9U+04tPzHg/OTfkhNs/C6KfCxYpZD6I8lMZyIXX0BcjBPgl62EQCX
+QhU6zfF/1muGGQJ6tYvZ7Z/iMqwpqBzi0h5gCQcxSIhP4z8hdfT920LezUhibuqr
+HrTisZ1rQPPOJ1TxZYwaqKDOUy/rBgDrGrV7Z3k7EaKPEbL/C38FtZT+ZDFGvvPs
+4HVn/tRhVJPYsW5a0m6qSnd+NZqmKX2twv7IZK+DP3MQeNoJZj1MwDTW0lHDzNPp
+Ey3fO6+R4oFY4QbBFAqXLLAviAtAigwNJ87lgieeW5SQKluHdC82nqVzVyh89XaM
+nSe3niVtgIoimTELg5P5uWFcRA4dTENrSTuhKD09fzceSKlqrDVAmygwoQNuGr2t
+00mT+5Mzctf1cogNvTxE9EfmpPQT5qkGAOoSeWmg5MTAOJsc+A7kzu47COqGsldZ
+xejz9je45+XFRyE2ywH6EaJ8Fy8yzuLQVw8sRtCB/tC5nE5aKSlgwoJ0A1B8nLl9
+ANCC3gszj3uGKkf3ITqggtojkrJSFv4kndOqWtBe7GlM1FDyaTS3Va72NqUVLGOo
+tSVziTGqyXH90p52EKEffnl40/1AZjkRs6cQvvd0cGXoXodubRKm48CXOMJ+cXL5
+a205komAn1las2wOheK2HNsUQpV87Atk1t1ctC1HcGdGcm9udGVuZFRlc3QgPGdw
+Z2Zyb250ZW5kQGdwZ2Zyb250ZW5kLnB1Yj6JAdgEEwEIAEIWIQSUkHlbePiv6fk7
+0JKBcEhZGCZh+wUCYTRdUQIbAwUJA8JKbwULCQgHAgMiAgEGFQoJCAsCBBYCAwEC
+HgcCF4AACgkQgXBIWRgmYfsYpQwAow3gK+CGoyc/mQ60UbtCUlxJX6xN4palxY24
+cc7rbBhBJgp4oomPSCjiZjs6Wdiwmm5tC8M4chvfJ2Aw2xHL7W4DrPykKkvrhbRw
+S82eQyI3VMN6ED9EAGAmhaNME21gRvaUgI+qV7k753nqHTasXI2lB6UZryFbiPRH
+3BIjPx7msSvNaukVoTvBpHJ/Z9/u4M6TQCCLpQOgHN+0JHW/87O9YTycdqePBVj+
+pKEHJimebg2w8BWTYFpvusczlGcJdc97lXEV5gQTP/zq4SGNnvghlnjEFD7hRS/G
+NwQCd7IL56koCxPgvdLLQPTlsLYYo0myJr0ePjdOQWg7heOfdywqBn1pbH9MqpiP
+d5iNp9kDEAxnJ2H4ToeDF05hGdrfWr7G5yuGDTBiP4Rgr6DwE2gHN6ELzGMqH2Fg
+9x2sWgf25Z3bocXIzhZLVqA/YWbGtJLDlHiWVhrG20edgpb/KsvJUVcpy6mIM57l
+2Pk5LCmIZLdlsLY1Mx5IT5UDzUULnQVYBGE0XVEBDADS0miBA8Alwk2WCrF6vm1t
+5H9nXguOBrTIGntxoLQoUVwB5Ei+7Nrb+c7Y6aMNyEW/Xno28jdsSSwtqbEt2VLb
+rrshggqi4oPHDHu5qZUf/b3HNyNwJ6w1vdGryHVg/Vg5pKvyYveH/MVHunrCKUQ6
+imP4lTg8qL6Igq/qD5bOg8582LAxHwsIznpLVEqgN2eO6EGirlvhw0Qyw+CHFJbf
+bvyGyDcTRZPjOZRufDezsLvC30soL7ZQI6acX8Q18Hi6aXf4iAE2ZpPChzCBnFKw
+VHfB/MB4zOpphDvxZF53j0p7bZuIoG/aItUHZogrtap0YR45AjMQkHLwIiihL4cd
+CBxffooai10mW0gos/gutZfIxrrtGpURlSE18lICcFIYctSAt4gxIPpAVcN6bY/k
+aIaKpvaMtoLuCeBXN6y0sV8vBiVxpvSUZTfzfeOki7CQctdhJPWAELNzzFXvFjyx
+QHAkZgjNlft1zrOy7ODlXhNPRsFK3VwaZ6iE2f9Lr68AEQEAAQAL/1xpz1V+h2QF
+4Gy9Ez9y6hUZ7J8rInWHiweMVEBi6ZYi0+ogX6MRwH5c6sc64zbPa4OPrpMXaiQV
+j0AU+o3WjfOujGkL0A3GrW07k6C3LZ9wYxhIm0g2m86S/q4GmS2C4IGkJZuCtm7t
+5qyimd0yqa3frCLzhktQzPSaFPLNEpZEQOeJNPLTYMrjd8g9ktjYcJS8Ssk9FRnJ
+tsNqCaos5FXdGOUcLshL35/jRaWI3gHunt+1cgSTpZ9LgWVatW/PkNAmug3q94+M
+67A4vsjdqWfezXaJcSfgdPc5b5cznJoqbXX9N+Q/SYMBgCOFfYbFQpWB6/wbJww/
+Ibit5e2lD97Y4g2lO1QAJaDfvA/LCf49+SLmVN+rkYC+6Le7ygYFNRpvYik2NLY8
+EnnvEacjPfkCz5BJtP8JTceba/KdCLZQ4FN/vwGl7ykH0oN5TYcVE4CnURzK6Y/2
+jQ9tT+mKdDIpaNr7QCnCJcL2HFTOQ7IIHmhN6UJu3G9Uf5TfsdagwQYA14HVwvC2
+K4xmW8I9pqKrru+K2+CjNX5KqOgYM9h3Lfg/1Kr+OSIVrPm7zoEHeGXxH4C5Z5EF
+6eIB0QRgLbL0roS3dvxVF5cBdUbH5Ec/iOIlRD9RTO7QMW5dvHgr9/PWYs3znM+C
+h8wMGJ5Y/xbtwPu3++hmwFd79ghl2K+Mdopq8hAHvPCJ5USPfTjBhRU9ntv4C75U
+jBnzMGqN0Sbn9BLwmBx12jy8EMgcQovtUK9jeEjV/5WMeLgfBnjO1m31BgD6bzTP
+Y3z+aHEm2sWkwXTEuaQQm6dWrvbMrAw1kbcdnPZCSieHCQesmVnogNU2LH61AXVy
+NQ0lxVgHheC6rZHl2Eqv1whfmYVjCrC/jKSaokNjPdgSFl8tteZGm5FQto5j+lA9
+KEW2A6d0MjcrYSN9mVuKUCii0x1YcxT+6kMAi0UvDzADzLkckNX8i47oMLR6lRMN
+k6B/52EJ5tBBDzeu3rJWkeeZASNnWAKh1JQM6dplUXTO4SodJodXv0183JMF/A76
+mVjZOT79SBImVTdQyp0WRhYxJJKVQ3q6fHC47igQypZtPy0Itn8Ll0fu6FTPbWJ7
+Su/UuJKq/FDQ+jM/fhdZ7bfLsXssSl4opyBc1xtbDN0wdab1vy2OOgq1stdE2sr4
+BX65rUbdflsBNf/YxX+NfAmP1h8YCvPxoIVZOVDCCvbf8K/jKvautLt2op/8wwUj
+eHmkZSmBBWTKUdFlYD+T0IWe55lgvLWjrLGXnS41v0/a7WgYlOcgrZPI22qcQ+rT
+iQG8BBgBCAAmFiEElJB5W3j4r+n5O9CSgXBIWRgmYfsFAmE0XVECGwwFCQPCSm8A
+CgkQgXBIWRgmYftO8QwAxE+6jsIAlNzNKn9ScSuCBOPumtPzlAjADEymR3qxJ3N0
+7qnzOD3dwwSsX8S5P/aMfUm9KPleYebTwZ/iMM7MBZcxrSPwOhO9i8tnRRCqppC0
+EcSGSxDe5iP5xFiQkVvr524eVz04orW1ZgAwWh7L5m3GSjq5V77zUetOBHv9WAGL
+sPOMQAMZUQavL370gxnttR7cn0Of9TM3Ia5L6p0Yi7PD0QztnkkczjaDySSFpxzS
+XSTo+en5Nul0pY0kt/TBY7+il8lWxCUChEch/SAdnSocoYN+Bd1KQ/J+KUukl71m
+ZHz67G9t1qso7IH0SksB0dSpxwhs645rG605DlJKnUHgtwE46nnwR22YolcTbTCh
+tKmdMppPdabbL1gI/I+Jmh6Z+UDDKbl7uUKrz5vua/gxfySFqmNvcKO1ocjbKDcf
+cqEh8fyKWtmiXrW2zzlszJVGJrpXDDpzgP7ZELGxhfZYFi8rMrSVKDwrpFZBSWMG
+T2R+xoMRGcJJphKWpVjZ
+=u+uG
+-----END PGP PRIVATE KEY BLOCK----- \ No newline at end of file
diff --git a/test/data/pv2.key b/test/data/pv2.key
new file mode 100644
index 00000000..54bea6f5
--- /dev/null
+++ b/test/data/pv2.key
@@ -0,0 +1,41 @@
+-----BEGIN PGP PRIVATE KEY BLOCK-----
+
+lQNTBGFH/swRCACXbOQ1YArP3l7QUAq+vwov0A3ig1royr1j36Ce6v65o6gCUPak
+bu1P1rV+0aVhKVzBC5E8/4XuO7EGZHz0odIjSEVOuIzILQfGYg3GzrnhUWFuvnZh
+LHULvtJ+WMM4QrCjZ/DPhQ1b2y7y54SsZ9yf9JmRVOC0hSruDgxuiWJdMggboZuy
+oWxP+UvHABV8qGQJuOCp9s8Kp1DNwy0tfzmFnigqcRvw01LGNewSO7U1qDucvVnG
+57hRnqz86nW6cuvEzLDoHC3J7f1Aa+MY8eEMrjkgRjzNiCslFRQI1v5HaZzC/qhY
+PQ42/XANFFbwTzhiv/MfMnBB8hZfZJ3M3oQbAQCjZDPQOLRFd+N+lgmeWWpcqs1n
+V4tVw7Ei+JZ7j48o+wf/a8wgUyKr5auo4/yfJdn29Aj0wopJPvlW43JNvb/niZ9J
+GgFhRyGGPxY645Or1fK7U0B0dDRM4/WJg74BTs7bKx1rGE6GGEwHX4Ju89OwROTj
+mhqyyhg1WYyApb6+IFNRqdxtpy7SLdDjn2qyLDob3z3p/4YqR/RpoxnGZlCCbzlD
+wUh+GuAKUYS9EB01WBB6j5+wphtL3shS+R6pAtVLpkRjfwzEm8abqa3DTmi+O7w7
+chZKTS0hv0MXLEIq2EeIxgiDpoa/uE3UoPcAxyIQHDj48ObM0OWq94RZCPeMaKcY
+xck6bWXsJ4grlBFhzrMt5nxGdk2gn95fP0WX2opodAf/WwdNVrP7j1Ens1Fuz4dM
+PNvzJfLjQc9n2eB2b38U+hziBklvxQTKKRqh+hngdGrhn56yW+e3Hu+lf4NTG5y1
+xapJk4bJrbMZvaX0rCnnHme2JFm8XintsxuK3SpGLvBWqCMc6lrQDH0oBfHiF4al
++5uWASmlJlWLDnicm4Xj8HDVfG3GssZEnerGx4pWsGsCe3PuyqeUYuxGuvBhGE7B
+oU9f0ZK80sggvCgRnmBLNggQc1f1w0MQw8dHxfwgF3lK7OgfSapxfIrIZDtOhyGj
+D3c5z5+cx63sUComjU0jOZJVRgARgVVMEvKb+MEbcasg8MQURdwGE+wQM3yXuGub
+kgAA/1GtbLY+caOngd542Hcz96mVuY5kQv7t2QdNNYiqq4ppErC0LGdwZ2Zyb250
+ZW5kRFNBIDxncGdmcm9udGVuZEBncGdmcm9udGVuZC5wdWI+iJQEExEIADwWIQSz
+j4VkVyO/IjMCy10G8cfnJAyU6AUCYUf+zAIbIwULCQgHAgMiAgEGFQoJCAsCBBYC
+AwECHgcCF4AACgkQBvHH5yQMlOhAtwD/TTw5qkM+69/0ATyXhvvm1HHnZ0QvfUQH
+JBXuSSdnquABAJb5cTjlKquenKOmFA34sXi1iGpvnHlk6wBXz1vinbAEnQI9BGFH
+/swQCACQRlZpLhm2JqiRUPFdVqmQInceq+fd7ymk38lok9lM37Oq7bglg4tPWSC6
+hZEBuVdQkZk6bBe/+PgnxGJP+llzkkxXnaBznJ6R6b3o/f5zqxb7Ja9tm45hclSJ
+Rs3uGMQwITE0yMCGlW9r9ocKq+gkhWQY0JZr3woIJVwqeleXyyPEITIJaEu584JT
+AnfpOac/Ur0FOFkDokfAdjddASTiEd5r1qAY+eocaKe/X75AQVfpSc61nDlKjgSV
+0lXdpx0ngNR1bLGdrj+KRnInSCoSn+lnDjwQMmvLax+SIqbTa4NBKpeygYv4IBsq
+p+e5RgRd9XhjOv607+RtGp3Ek2T3AAMFB/9rmWwOIMe6wk+bxizzYb4l3hPAnFUi
+VolkV3Rv+evFhTRaqHbpsnhzl1SwVqtHU1begYkuW3D5xFiP4DLI8BpAR1qhQhh0
+xXgRktMVBqDIxygglesIdNIn1ouV1MAkt8f6fzDyXZl3r8UJ2EUV3OImH23WFR8C
+gVPTfQBPpoQHpK71a6NZIucEQcQ0H6AB288j4y3hbvKHFC0gm6Lztn+MoOCnK7bC
+r9DdWe0YFOgzgJTdgbzc4olgpA6lAzTWJ7KRIW+hnpvWxiJ1y8uBaldB8UmB6fTs
+/7XGOnKJcGCsM12nSdVA236PLcyCKMl5mEkr3CRV1Dxxc9zieLe4qzxwAAFUC9yI
+gT4W31gakO6thBlz+WDNbW4YKGLMNcY18XV7eJy0eRhWzbhLwwb57hXUiHgEGBEI
+ACAWIQSzj4VkVyO/IjMCy10G8cfnJAyU6AUCYUf+zAIbDAAKCRAG8cfnJAyU6EIQ
+AQCNkM4dvMFv68VMpeiBjGYMui6xpXxia1N/BXQ1XgzxZQEAjAXkypyAvVeua/FC
+VFT4TeJBu/bR1d3DxY8XrO5J8zc=
+=7sPJ
+-----END PGP PRIVATE KEY BLOCK----- \ No newline at end of file
diff --git a/test/data/pv3.key b/test/data/pv3.key
new file mode 100644
index 00000000..616bc4d8
--- /dev/null
+++ b/test/data/pv3.key
@@ -0,0 +1,106 @@
+-----BEGIN PGP PRIVATE KEY BLOCK-----
+
+lQcYBGFH/8cBEAC65xE3JrrRMzx4+1KCurbylGOgUo2DI0fP9pNzxpkWne5S40oW
+6iUtgPROdGkfKAVcoHVV07bIPBppGYmiPWdNW9mZ79eL67Fgb/bCmbk1pKCCvPQ1
+XmNWOEtRDaTTaHS3Wzm4hALM7tur6Hy+viMFZzYI/0kXFgcIpr3uwsQMQezqo9fQ
+EmX7WRMQjrtqYkUfKFqfJnKwJ8LxIyJf117YSCumgR5PWeDkc78aGZhzsASV8mUy
+phSsiEpJ32O7j1jtDRQNnS+DsxiLjBZu/o5s6hqUC3HJtqZr9I+HMbkgzl4HSdZ7
+rP96ZCcqzetmkAfPK1I8BbfYAENCNiiHSEW37DisAcaEt3glLfsL+HGrh/e1eSdQ
+tyjYONX0gIQ6kisHY91omiGuHnLVk2Q0GS5G6vNNcqdJ6xY5/DsdJKJWbxxH8+Qb
+c9P/ylaWgIvXA2/9znMsM7Kj2XaF9Jtwz4qvs24SWs1m2YyJM1YdbuoaiNukLmSu
+QYrooEkJ/2wSdmedInNKSaa17VS+YpwHOcyxhnkbKxyPibiNHfLa2Mba32y/zqYg
+B6vLSkbciG5pwEm5vofjgXrBotTEQJJYhkhvugTyUQgnx5TgqFWr7dhQ6o0fywL0
+X2YPibr8TIUMtydjwhpqwoHoF3b44pfsFC1oLkZj2DHJTrcEk16lSh5KKwARAQAB
+AA/+I8YWhXfkSiaEbKOuJ1eVrNi6OPWUIIWgOS35Cy/4HVwdQcA/biNi+lK0cE/X
+zx7Z5+DOlJ7xXWIjq/o3XdZi72ulOtGtcBqs2MiVcqn5yUq5bky8cXqfiOE9iUYT
+RmO382CCq86YuqD9auoU9m1uRpp6vT4fv0t4DS/dKtYcsDvuHPs/U5Qx8OobvA+V
+z8b/c/dFYTD6wrzZk04mRjHy9XLa6APOyWFqqk99RIGhrIMEXa8Hr6oaSuvLTFh1
+vnCxlK3sKK7taUfeatdlc9lFaZNlgvCt1u4e7Iri7f2WcbEOTlbTtthmDgcdeBPx
++q+WzxB7rQFrLuzd8s5q83nh3f6cSMehs1R162tGL2a2KWJj/DoDfAfZta8EAHaH
+z3nd+X3mZdDuSpqaTC3BnWaGnDkxY+LEjh99QWS/vvRhx5bGF8ad+tSRdNgdzsVL
+l+1owsSZ7MuSzEMa5io3QUZ9kaxTDviBPQuyfaxnEGC7fmjrg6rM9M7a+uLhd2eI
+6aOIdobrFLq4VeHLQSIOhP/Mu5CSI7skSzJsyu+iPSjtuDIkir28GKASXJGs0gXG
+zdyJubwyHO/LrV1EV/UpwXieZAaJkDsus48pDR836xzFCyYlRhhFDJyVju2UWMOk
+FnagNvyz3fkrgEsodFBkyhh8Kqbr35+u0u5Cn2jaEas6EAEIANoo/zqkvWeD8GJu
+TbrohdL9xBTtzO2m3MeopPAr+KilSjSVw/5BmGA7x5QjIIoh/9tT8G169eyMmN5b
+Sf4Yx0/KMAw5YNY34wnx08ULqgbsL6dZeomG2mhCX5LfrQGH1AZYlWxlgNqWAg3L
+LPJJuBhrGUjC7O1momo1ExtXkRCkWTqiYWneNS5YRvUK+XWOtG0/yQZ8EE05OYvC
+m3ZfCNHCgHOIXYEt8Udow6BHAu+/LXu5HGUJX63jF/EsRA1iZmWSlvht43SKZOmA
+Un/p4ZaSjxTB3oLqFHnKY0K7Y3MKL/afuvn55rOGQHpAyU0FyX3Mje9UMzmQanYc
+4O02uMkIANtSIubrBjT9Wf7IR8XpeMw2tLKZEJ32RwTlz6zpHU5474352lY9kFZH
+PijExF9K6lSRtWzWbq/wJFdSCPGf2GrL6zzGIMSK8M0S/Mqi2Dsx160Ln+t8R7Bn
+jXYH8EJHluccHVktVg748uyhNY1dIwCQSSKuK9z2XHV/1g3empznTgplPk6JeGBE
+5YYQQbggCt4rMTgOFPoMcQgfqPPQ8MAEbvuhOM7B1qncEAmbPujgTCPfPpUVW+WP
+7w4OwsqIt5i9pbK/MMazs71sphGFIWKp/SuT7K9g+GLP0LZCmQwkG7HJ0NLJcehV
+TXOVSgRqKwjVIW3LkuB3TXjRjWXO2VMIAI5m5m5seCX6EQ7xXCz4z73XlLa3+sNr
+EdKTuNb6CopzlWR56u50sSI0OldY0/qxw3F0wzoCxLy5KozgzwVhA/EA1waMUbuJ
+soOsViTby8n6n1eSoW7YBcqmbGcgFe0bQ8h3TskGMSABr0tEVeP2BMMTE/rvS/A9
+VxZ9O3Uqqm+RXFk4twAgCCcV+Yz7lt1QdvyzJE+qipFaMMrIsCbqmm54nCdVbXv+
+3r8uKVfoArKtO8WCYz7odHiKAKJ9u2yMYaVJkcYbGSv1pUkHepyv9Kl88H1VN2EB
+l+3FKOEpFXvGcvFJ5n1pbgvx775wnM6GtkylSqqwaHnPi38EJUHKqOOY/rQsZ3Bn
+ZnJvbnRlbmRSU0EgPGdwZ2Zyb250ZW5kQGdwZ2Zyb250ZW5kLnB1Yj6JAlIEEwEI
+ADwWIQRGfxQiDOjc94DPS62EZcVbJcm30QUCYUf/xwIbAwULCQgHAgMiAgEGFQoJ
+CAsCBBYCAwECHgcCF4AACgkQhGXFWyXJt9E8MQ//ZUAbZkn0Jg4SZbjC8Yh55IoP
+pedXCovR/fzGlYVP5VV5AdftJaN0lsfZtjUiRIBYOOavTZwMjwcf+m7xcjuhNO0e
+INcI2zkuqyjtSoMrEeOqoLEUXI7Lv0nNm0Z2gGQ6sHMSlot+GH7BpYmuq+9CkYOg
+802QWaSDE4Z3EtjlLpR5u0gQUJyW5A0WlXQTOy4BMM0/uM78V2X0oOkGVnt2FyNA
+9Qv5Bg3T64FtdyAvUVbkoY1K2UuO4fIfQhGrjzP4SjHyX/GgR72FdW1DkhkedEwY
+1uEAmsWsSCHAI4jCzNTbcmYmivm/4BSJFv2mwz2ArV6Mbcf8Y0NeScQYt/MZjm6r
+LQECvAW7yunpP+f4Im7MNbpasK0/EM+Owl/roAlOwtEwScA3mzQK7AnbE4MfLqvU
+w/eKXmwE2iVRC+r1AsYGIKHtorMkye8yytqC1nXkSYl55GPN0hxvilvlrOrqD8s3
+T3em82L9peKfdwEKNHhDfX8wNj/OKzUYZHjtodlbqwa0RyKtHQtxq8Hqj29QjKce
+pvulZe3RVL3Rd2JfTQsJKCN6/iXYwusR/73OaHdiGEEgnDTSFPl1HOck0pNmQVDf
+8KjBPwaKCwb6O1VjS6EWX8KGYqf4942I0YWD267MazQ18lnQvOrDwPX4XIW/MRfD
+s9qiYnK4GFV9xevxwLCdBxgEYUf/xwEQALqXND2We6wz8+FnFHbAvS22HmtUTmgY
+QSNZnXQrNwy53p/spoI5LZAHfzl5dRrchU5xPeGwBLun2Afy3a9dpDZxJ1Awx3Rl
+6cz/Mud/74Pmde1yqW5+1a0I7alzmB85SZfgL8zsPNWDTFimiQ95s81QyYBErePs
+aVbaSkIglnxRj9LOXnrTq1pGScHys4C/C17fjRxcCMM7t5vhxqvEV+qzTVRlba6L
+f65vbp4McNn964bP/9qPDjFpoUY5rm848ZPoePg9TnFPxvkMd3GuznImXcpY7nHe
+ZzAteaf2z2ABkK5W+M4TEnhWvNQqxdEP+qktOPe+utrgA/68WTTiR+uHDieAd+Os
+dtespkLnNV2/uAxu3WpVy5SF1cWVPIjy9K1+fB/MQsdfoPG5wjkC03lZfCfGxqVg
+o90S7SFvrjmZRpYi29eQ4crenFNn91ds7ahWktoWj0El8bdLd3qIEITJMDQF/c+4
+8jMiYvFF97k5NI6Rg8FuL2R0Ih7P+mtphyD1uHgsXGcTkZyBvhYUkW2FOtsBMh7c
+Etz6r+VYYFRFoF7u+B+GiIzAXWTldFJqz0g6G9LLHk2ivr8q0A7Vj/Y5DCa8L7Ys
+ftlyetlzy1twxFr2cujBOqy+7LHkiND11pVU78Xx1bb4Kgc/ONRYirb1/HtMJM8B
+JHDPLrktCPD7ABEBAAEAD/wNYtmcQtZ+hSpNlRU9Fm4RVcvFjBfP6frfrAcwFVru
+rnWlPYIN55zi2gGA6xDBVj64tkZn5uEqtqDjTm4kWEXL+L7cRujtldN5zHknbeCO
+CD4/mbFEEb9cmZO19hVcxWxdLqKJ7gzIjecv7kqjnJSPTz4VgK0vo9SZfDGa9Yw2
+QQJeGkYMQ8aQRGii4bmKVqpcf7yM40wRouV06R6qpfxfWcZbc/y0FU1Erg6JMiqf
+yP1Y/5ptte5LvItAZtT3z7sCZHQr7aIEs7d6QzBdLIWiX37tDFzsOGC+GRUYPWGl
+PpeARRG2dFx9MPkns3sw7heKhDReZFrdZvgtEfAdwM9t8Rki+icOcGDnufNTVMAQ
+im0Ilz39RCS4FWzdTt8fRqn5Oa0oneDuf5hgD8gf05nW1Z2pKmo13508FotEVOCq
+oyhgd7zbqwvnIg27w2ahn4NeTQCpGm0i3OyLsTfC6JLQPUvEa7LRLs8SsNXjnfeA
+hEWcZMMDP6t4e+5Auj8pmPMLpd4quTyQFNeg+maOCK+wjrlVxDxwgJWQX8dpb0jr
+ZrgK3jj+I1+TKvkEp2fPsoFGVR/u3CUZoNxz1cImntPodMBVpNhvRggXK4CQRsFC
+CRNU3ZrPsgP4+Qxoxoq76R8Wu/pK4MJYjcBi+m7ZgY4ou5GWKuyrsRrR602nOFzr
+EQgAyFz0VvZp0l9gnAqMDyQiROYWSPMIUFMkof2/tK7uj4oCC8GT1J0yAvIzDqvt
+h7Kjn1mFiHjIcauNNjvQDMeMzlSSh9XCVEDK1DrN39TnoxPrnRyNN05SBH3M0l7Y
+jt4ziR49PpHgrBFfC2fPyxVO4eN2PipLxckfyRI6i93MkagPT1u1Q78mtsVYWrlX
+qhp1IpXSgVPvcZuyNf2xma3x3U4u4r7K8rG+D2Zaw18BNXCmvumU/WPTPcQ6zG5D
+1hXpeCBQPTpqAUofWWu0mFObsyY4C62Xleok6Aw4BiovXCM/4ndFHW4qRxs85nbq
+MXKZxNuW+1o2SAr65NEsviHmGQgA7mc3z5KdAIzQjNuH8Pu6NbYnylZhr/yXDIm9
+eYM7S88Bts4YlqAi3Sb8g3l8TNjLKEtkONtguiq6xnVN0jZuuxBO2Pf+s0KFkci/
+kR1/qVhXOtpH1wTTNpxyWo/jBX+8TwsQfWBhA4kQ7qOgBt2iRbRo3w+gYY8Kv8j7
+TpcQ7O0aM/m9xLwt3TjYy8UIge3WOTJkTinBl2Z4wbHmbQ8OH1E/jRydwT8xSU1z
+tFNUKvQMDVKDIX2wdtVYWCz0/02DbyaMZkU9cTUPkX8HtblMb7Me2uOqPRniAWFr
+mw+12FW1OAu0TJQy3S7EPXhI+v2i4OPQjyTgGXbNewXW4cgqMwgA48cWa6RziMQE
+UkMOB/NsvBy6FZFcYmBgG06m7HuobAj5iinnkCJoxsXI9l73KkUk5guI6FqIIvTE
+qCFvETthORomSQ0lfbNsAeG8YiGlE+FeyU/ZcZeoYkKOtXsd7hA8b8blT9nVC8+t
+nAWClz9ArUh1y5A84qzIV9azgcS07zJ3bsmBOj/4DeSKWpduJvpGIzFsVli1y8Cg
+tlv3qaorJZar3yGiWP+yIdHltaHbVZqiFcrsU/tQ8rGErNrMAwv0MfJE46+fZCXh
+bMUfeYOHCvYlEw3AMkuv6Cl9bVNRxZBA0xvri/+X2Org9zLHE2w3ZMhaLCOWRj5h
+OVUgk9AH/n+ziQI2BBgBCAAgFiEERn8UIgzo3PeAz0uthGXFWyXJt9EFAmFH/8cC
+GwwACgkQhGXFWyXJt9GPzA/+NUJxPjJ+5WPvDvY5YfzPlMDE7bHJ14Z0qIdUylQv
+NYWvn3D0HqpTDdaj7a6ynfqNpz0uAw78ZEPn+D0rYqYgIlZbG/MdqL5N6xNppaP3
+HwOi7vKR5wkeS5aKBgoRFjTu9Ue2jCzqte087diuygUXRHnB0cFgKnkWZls7xWD2
+P3KF3w2HlB0G1JXyCJHHrUQqC7IFw2MHkz2PV/TN3fg1P1ALGG1qRWDoSLdAdyLE
+M4gY7F+7QclrzPNfkDmf0S6xDuBw2/efRcwVE1Tnzu6XIiA49CcEA0CPgn8PAX2y
+qKD+zkNZUDuHDdcFEeGjp3RPeVgu30qmg4luW9eyVKphVqBpZSMfmI+yD9dvjcg+
+e4bSu6a6Go5RCYZVrpVX8rYMGazSUt0JGVRGcoW1kf8NU5egcv/JB6j3pRaW4MTb
+ol4BikP6/6237yiy6rR3DRXroIn2mUp4TDlyuuuDvtXkbKWwA3UGqrCPG5WvWpjw
+dA8qqosC5bmpHfgv5WhCvGxT/NPfbb4HhO9MtOLN93kI5F7Lec2/mfiKO2gmhZqu
+eBF6aL09+Kpv2k3cNqn06nTSlNyNQVbXtEcXg6FzVLXhMb+3XsX/lk1CjQsdZk6T
+4xIHUtpWXdr/34k3DVoD/9Bw9QYXAC/UeV6akU3wLOu07alqm1BuGWXqVoouvnlb
+s68=
+=u5ok
+-----END PGP PRIVATE KEY BLOCK-----
diff --git a/test/data/pv4.key b/test/data/pv4.key
new file mode 100644
index 00000000..8b79e893
--- /dev/null
+++ b/test/data/pv4.key
@@ -0,0 +1,82 @@
+-----BEGIN PGP PRIVATE KEY BLOCK-----
+
+lQVXBGFH/+gBDAC2j46PTi2Cv+S8LVPyi6s/e2/BI8ojN1cmtJGHxSuDIhtbwtY5
+4iWrRjhcAISIatpCMBuyeGLD95N/q+31DkVMlaXq1dqxGq09VK6TO5U0PIZnIDVc
+XTnjxab6GwKK85ZVKFX7owgWM+s9oEbRIqwuCxdUfzqF0/JfbQJYFNNgGGJEVcI6
+gg9xHHVKEA/Q7gTUOZHQqN8NlBv/4pnVUbgMj7TZaF+bgggg7U5RMkntrneOahb9
+rIOE9Fk5IHq6szXQ39aKe7rH4rgW1k/zlpf18M6lxXOCIhZp4xO0g3mHRxvRvgJz
+DGkzfhlpFXAxgP+t/o+coMBGGUwA/v5obPr1+owFfyXNTZNBq/S6Opgm3uzZtoG0
+Ty9+jmQTJjjoDJUlpODUGro6smXr49nrPfzt/dOSMKSMM9YbzI1JZuoz+GqwRyXf
+6/+egyWiYWL2DhVnUO9rq5Gx2CxHzOSNcD5voiaycgXM9GfCRXwOmeLWvYdQV5Qv
+sScILlHHqaMFtWkAEQEAAQAL+Ju6GYFkzq2ZwyRCBjn/qjSctteqD+O6cT0zCnEm
+X9ecYHoF2XfG0Rso6yqPxn4Xp9aN8xJqXtWLeuaNYo6HfdW2UbHgeoxYlS6b7c7q
+JHxKpNuTPfFsFNWW5Li0EZc18ibyIWZly6Ak6aXH8qCzUuxzyZLqdKF0CmwcMMOy
+AB0Yr7pa7TO7fjCede6XhOZUIwplkVzMsHiEvt2oDlFJRBZy/3H09plQcl6kDwp0
+O1vkV1fEZ5g8cHQZe4KfkhFwjCZmTggpujAO68Tc+eeHvWOsDUV04KW0k/9Da53V
+PuPGqS/nkR2n9Llixxa0p6ltVIobxfzscCFK3gDxpHFso8nddsZZNhDh1ik1QOn7
+WLQyS9ppE1T+t2fH8OFGd8wxijTTh8oVHEm9vNxG2RJNBSycne8g+mXvGo8DJalO
+HvRO+SUpHW2iW4s3kUuS9X776jdAXm247XnPDSnN8XYvVnvkWUVSf6zp3ts+AJ/P
+8CAqPknWduPnDD5WLk98sYDRBgDP5ldNgX5OCFhb5DK72M8N04H8Sq+HvCyGvW/l
++1WeubyeChWwSsW7eomSmY+wEl9VKJyLt8j1iBa43BYWgGdBYLsnyMKE4xnaWbkV
+zpW/p6mtnVLRaRillqinrAtvnbbOVPK69frAyuFYS4vEIR2VRhQbpPtwTtaOu29K
+N5MH9zYJRgJ/t9nd0iaGNeDtuA5Dg+t9eXfrQOrTpY13vzMYjYlfYp6krxS4H9rx
+/ZfZMmQzKlpSjGWBJ9vTvwZ6UlEGAODMaqgiOuR9fRf052sFkLsVmhmSCXYf5dcG
+FakDr5cNYsMV9BBOYFlHswlaCM/hOj//DXnkgpvDeTiII8zKVjQVDO3CII/2iAG4
+B6AK/VmJnayD8hUUC4jQo+6FWJ0GSP2kWdBUMl3L8E7/qZ+JydW0n1FUhOH4C7jk
+VCiQdOhjLWE+Fe/PlMP5ZtgCxAneQ91qJnLZ6E6Xz1WMw/FYxWP/2x5mRsZ8qVOT
+jQvUV/Vc/DCSL8dRqzqrHD8KHMaTmQX8DTzVGE9iuVICHSeCEJaXCyzB6V83+rZo
+X99/iCWHRv+SoEFY1sa0db+NWhas7czgPKK3vydYKOJbUZlxLXRpAeJreq4GBiIl
+u1sRqCfnmG2bARPMXlOjVJeGgs/B891C6NYhW9Ekc1eCn8hVnqLVUOnFcgwVsB9j
+iUp+6UqGF+jbxLuvf1JWh4x9L4kb+V7vV+uEs8gI/sbql9s+UAXRzdBknL1bunXa
+uJC8N+oS5SlJZdVa4DXjoSCn1kQKcx9D6oa0LWdwZ2Zyb250ZW5kUlNBMiA8Z3Bn
+ZnJvbnRlbmRAZ3BnZnJvbnRlbmQucHViPokB0gQTAQgAPAIbAwULCQgHAgMiAgEG
+FQoJCAsCBBYCAwECHgcCF4AWIQSJM+soOhiZX0XWHawCHYl3G2gP+wUCYUgAGQAK
+CRACHYl3G2gP+0PHDACrQFZBzpXZk112Et0IBWZB950bmRt0B6AiGps4YKd+F5vz
++rbBMHkrhf5urfQue7/cm5ERm/AkvVUj+MLnVJxMmEDN5g0u3C2FhX7fNTUVzdo8
+cWMkON1KGbkv8JxqAoKvrs5ktrVpZxXur+kWi339TL6vFjmd2G2DOXp3DyMWnbXQ
+i3d65XVpFmKhoJjQv11ywrcp3yY+T2nEmvmq3lFPbySM4f17J2Sy1JNTAVHcB43t
+WhDc75E0wqqSvZaXSLKcyKZxt5fcMXXWxATTf21nzN80a66T8Jl2KY6FYS1FFFB+
+8lCHD7s83B+bL9A7xxMd3qcLPYxUfGDXkkiXf7O4ThRB7EqLc+H89rBs+wux3dDb
+2rwlYn9yzL3Qqmf/ClA/rG6qtRBZPZz6sTJz6T3npb1G3vh0ih8+tBT7qagUGqYZ
+NQSba8et5to61c3SX4m7Ei2qDCqmTx5FxV7EkMxmhI/O3LvMLVALmPe3wwWyWU9h
+q5KTaWQLDcsSmiOPjsCdBVgEYUf/6AEMAMQrw9eO/+yjVyu3HPrLyNQmgDFzh9bA
+c1cENBgwcZg177sUe9pVEJ1/ubpl1T2ss0QuXT4TY1gHGkAKfXNoM7REz69ybOnh
+DEKt/MbncMpDc5avhkVHUOqrITUfbbwhGMPq3hvrOv1Xgjj5tddsELNfm1r5IXeR
+b7/NLLckMz29WttDZ0/bCrd5Nasy87kzszQP7W238zPjVJttdJ1Nmc+90hovH2SO
+d4heq8rZcMRlrcRS09zKByS4lFbYzCT1bivoSkd/S5bW+Lv2dJKk6oY1+ZoaFptM
+LrBh0H6XJ8lQo21qRarl+PKwkr7uFT4VA0uFqJnmZzgfne+9lbcWd2RYvSWSAQFN
+CBga/1Jfj5jxBHCssh3jNnXjOfB5DbvhwaFhECjQBSN1G7P8Lh69ZfUxYg+hyEvc
+J/MUKA4MTXanf9vh2hoR5eYiUKAacNxXD7yqRamcrkMLOiRqeYtmGSh/r1b3v01h
+fFPz4R7CcMZlZN8UcnyvZWuhFNfD4VeUowARAQABAAv/YGbZcP7XCaUjW1o7JYwr
+fwYEjUinAoPEqohoSVLVH+Wxj4/7ZUnURnHUBaOxbQOHfQQD0lOYyFOFNN9y0tns
+PrRqE1/54d00NzhlNiHaLauEDBLpuvXW79t1EDQHqyHgl7a9u56XeJQebH1aPSjf
+9CYRpF01cxrHfcwII1/oxnhdQ88V4ApWc99e3mjFmMetUvJYzUhOfbtDgrYBTqQp
+6ArySufJV5MjbqKHbcH5RqppAEdr0d5+MC98xkj32Vm6EptCfR+Zv+BrMRd04BQn
+9z2vH6N/KHPRmgDKZyaeAqdyYFU1MtuUMgfSLuIKILOuouvWwCg7rVMeJoTc/uXq
+oWI50WuiOrr4miFonrr8bJP5ysiJn5KTx+UPEYYU7jU6JiXmOvNSWN42pT8KRhaB
+JO2WmNQv1MtPDI4L8BJYOdem+owOD2FMNVeuuQVXpCNZglvDNQjuh35Z+V07tQ9b
+waW9oQEkRInthbHyjxkCzK9+7Pe7HQyBR9ljyPL9heyBBgDHYn7Q1FG47mL5JxTi
+C368Nih4nnjcsfZCLBWo0dyAtRC64sLQsq5Xcd1/BL5lDrlzpWWehQ7GGLVH6mqX
+bEzZJSs5QE9+AWfK5RFMe/GaE5TiuSRNCJHdzZ41wwmnm3XrNHCyeoaMj5zRhhQl
+7PjcJPAtWyMTs82XzHJOkHBbHhSIOyDOhhpMNpLFj2LXpV17c2ozMrk3fZUpFpiO
+xeb7LY2aRx+CX4NWPTAzK1ppVCKcaWf474iKqseMMSuPd+EGAPvfp9FlJYalG1pX
+ZPi4Af6z6ykf7ZU+rmiQJwjz+ezZyczoKB+28o1p8qwwTGGWQ031xhcIy/487uf+
+5BAkLzkllh93W5VIMpVGUHXP0L6OR0OIJWo/vcWwKF8NRkpnpW1Usqjsgw4f3Bzf
+MFS6bg5kMBSFsLSgkoIX7v6YZctNYhaxATh5V2Zx8vpiu6gdOxqnALhnasOPy3z2
+pX7Vw75wS58ZKDaeDit0liwPARQ41MkT3p1xb+GwJgJn6OrNAwX7BuwW0hybcYyB
+VhvHrQlKjJGdDqPa1ZE+g8lsYpLC/A9RHu7PlarSPPj3Kzn7MYGrr3GOb0yr/8fg
+39OkskYk8x25NDnatYtJCa9HW35ZLUruVxGTvomWhHmDfCyQxp28Zfufs1cw9k6Y
+6+6nrHOce7N46kUCBm1kqiS69qTaDeNflmKfoo0OOf8GKc9Px3nzt3j7qot13aeT
+OECp/ZyIY6F7xrWMbhsU5vgPuYAef1WHtCxlOV9Hocosq1fmFx703gyJAbwEGAEI
+ACYWIQSJM+soOhiZX0XWHawCHYl3G2gP+wUCYUf/6AIbDAUJA8JuWAAKCRACHYl3
+G2gP+5BkC/4tWknpSSBe0N+YYtdkxUDRtdVcohkEBCr0BSuwaDQAlx8jbhFJYgSY
+F4+Lrc97rcCoHXoxnaDrEhTeD/LcNoURoiqhxygZNkQhFjU7IMtpIp1HRfsGiNwI
+HBOaAgFW1zcaS7OOnhgra/LgLsyphGPRVOUf2fm0UdGrU9XLlDJS7d7gJM4mH3el
+wwppeGJ8WFjaf1L9P0vw00JVcpQrwDEjFJAa3enQccz3XgdvvQMWUpQGBnC2kxHX
+ocBpoQJqTVFQya2nEx6sqdp2fHFq7xkoe2EMkfnpS9cha2byoDVEUqlDqu/jIH2+
+QCaqPFvlEAV1YmCMDLxmA45tu7TV4HC0rCNb4ao7Bb/trrxuhf+xvyw6h5LS/WY8
+04HkFhVd52pzLYIr295//voLeqL1YgylyhNZfAOfNj+6d0TuB5xHQ3G6llHP9wl9
+J5AZNv/MjQVdMfGHWG9YcjYYNspThGsuv/M0GsduXqOweNlhJFzxs+GokAcqV16d
+T15m3mvre/E=
+=h5NI
+-----END PGP PRIVATE KEY BLOCK-----
diff --git a/third_party/CMakeLists.txt b/third_party/CMakeLists.txt
new file mode 100644
index 00000000..0a43857b
--- /dev/null
+++ b/third_party/CMakeLists.txt
@@ -0,0 +1,4 @@
+if(ESAY_LOGGING_PP)
+ message(STATUS "Build EsayLoggingPP")
+ add_subdirectory(easyloggingpp)
+endif() \ No newline at end of file
diff --git a/third_party/easyloggingpp/CMakeLists.txt b/third_party/easyloggingpp/CMakeLists.txt
new file mode 100644
index 00000000..9b96f9c4
--- /dev/null
+++ b/third_party/easyloggingpp/CMakeLists.txt
@@ -0,0 +1,4 @@
+aux_source_directory(. EASY_LOGGING_CPP_SOURCE)
+
+add_library(easy_logging_pp STATIC ${EASY_LOGGING_CPP_SOURCE})
+target_link_libraries(easy_logging_pp stdc++) \ No newline at end of file
diff --git a/third_party/easyloggingpp/easylogging++.cc b/third_party/easyloggingpp/easylogging++.cc
new file mode 100644
index 00000000..7451a3c1
--- /dev/null
+++ b/third_party/easyloggingpp/easylogging++.cc
@@ -0,0 +1,3526 @@
+//
+// Bismillah ar-Rahmaan ar-Raheem
+//
+// Easylogging++ v9.96.7
+// Cross-platform logging library for C++ applications
+//
+// Copyright (c) 2012-2018 Amrayn Web Services
+// Copyright (c) 2012-2018 @abumusamq
+//
+// This library is released under the MIT Licence.
+// https://github.com/amrayn/easyloggingpp/blob/master/LICENSE
+//
+// https://amrayn.com
+// http://muflihun.com
+//
+
+#include "easylogging++.h"
+
+#if defined(AUTO_INITIALIZE_EASYLOGGINGPP)
+INITIALIZE_EASYLOGGINGPP
+#endif
+
+namespace el {
+
+// el::base
+namespace base {
+// el::base::consts
+namespace consts {
+
+// Level log values - These are values that are replaced in place of %level
+// format specifier Extra spaces after format specifiers are only for
+// readability purposes in log files
+static const base::type::char_t *kInfoLevelLogValue = ELPP_LITERAL("INFO");
+static const base::type::char_t *kDebugLevelLogValue = ELPP_LITERAL("DEBUG");
+static const base::type::char_t *kWarningLevelLogValue =
+ ELPP_LITERAL("WARNING");
+static const base::type::char_t *kErrorLevelLogValue = ELPP_LITERAL("ERROR");
+static const base::type::char_t *kFatalLevelLogValue = ELPP_LITERAL("FATAL");
+static const base::type::char_t *kVerboseLevelLogValue =
+ ELPP_LITERAL("VERBOSE"); // will become VERBOSE-x where x = verbose level
+static const base::type::char_t *kTraceLevelLogValue = ELPP_LITERAL("TRACE");
+static const base::type::char_t *kInfoLevelShortLogValue = ELPP_LITERAL("I");
+static const base::type::char_t *kDebugLevelShortLogValue = ELPP_LITERAL("D");
+static const base::type::char_t *kWarningLevelShortLogValue = ELPP_LITERAL("W");
+static const base::type::char_t *kErrorLevelShortLogValue = ELPP_LITERAL("E");
+static const base::type::char_t *kFatalLevelShortLogValue = ELPP_LITERAL("F");
+static const base::type::char_t *kVerboseLevelShortLogValue = ELPP_LITERAL("V");
+static const base::type::char_t *kTraceLevelShortLogValue = ELPP_LITERAL("T");
+// Format specifiers - These are used to define log format
+static const base::type::char_t *kAppNameFormatSpecifier = ELPP_LITERAL("%app");
+static const base::type::char_t *kLoggerIdFormatSpecifier =
+ ELPP_LITERAL("%logger");
+static const base::type::char_t *kThreadIdFormatSpecifier =
+ ELPP_LITERAL("%thread");
+static const base::type::char_t *kSeverityLevelFormatSpecifier =
+ ELPP_LITERAL("%level");
+static const base::type::char_t *kSeverityLevelShortFormatSpecifier =
+ ELPP_LITERAL("%levshort");
+static const base::type::char_t *kDateTimeFormatSpecifier =
+ ELPP_LITERAL("%datetime");
+static const base::type::char_t *kLogFileFormatSpecifier =
+ ELPP_LITERAL("%file");
+static const base::type::char_t *kLogFileBaseFormatSpecifier =
+ ELPP_LITERAL("%fbase");
+static const base::type::char_t *kLogLineFormatSpecifier =
+ ELPP_LITERAL("%line");
+static const base::type::char_t *kLogLocationFormatSpecifier =
+ ELPP_LITERAL("%loc");
+static const base::type::char_t *kLogFunctionFormatSpecifier =
+ ELPP_LITERAL("%func");
+static const base::type::char_t *kCurrentUserFormatSpecifier =
+ ELPP_LITERAL("%user");
+static const base::type::char_t *kCurrentHostFormatSpecifier =
+ ELPP_LITERAL("%host");
+static const base::type::char_t *kMessageFormatSpecifier = ELPP_LITERAL("%msg");
+static const base::type::char_t *kVerboseLevelFormatSpecifier =
+ ELPP_LITERAL("%vlevel");
+static const char *kDateTimeFormatSpecifierForFilename = "%datetime";
+// Date/time
+static const char *kDays[7] = {"Sunday", "Monday", "Tuesday", "Wednesday",
+ "Thursday", "Friday", "Saturday"};
+static const char *kDaysAbbrev[7] = {"Sun", "Mon", "Tue", "Wed",
+ "Thu", "Fri", "Sat"};
+static const char *kMonths[12] = {
+ "January", "February", "March", "April", "May", "June",
+ "July", "August", "September", "October", "November", "December"};
+static const char *kMonthsAbbrev[12] = {"Jan", "Feb", "Mar", "Apr",
+ "May", "Jun", "Jul", "Aug",
+ "Sep", "Oct", "Nov", "Dec"};
+static const char *kDefaultDateTimeFormat = "%Y-%M-%d %H:%m:%s,%g";
+static const char *kDefaultDateTimeFormatInFilename = "%Y-%M-%d_%H-%m";
+static const int kYearBase = 1900;
+static const char *kAm = "AM";
+static const char *kPm = "PM";
+// Miscellaneous constants
+
+static const char *kNullPointer = "nullptr";
+#if ELPP_VARIADIC_TEMPLATES_SUPPORTED
+#endif // ELPP_VARIADIC_TEMPLATES_SUPPORTED
+static const base::type::VerboseLevel kMaxVerboseLevel = 9;
+static const char *kUnknownUser = "unknown-user";
+static const char *kUnknownHost = "unknown-host";
+
+//---------------- DEFAULT LOG FILE -----------------------
+
+#if defined(ELPP_NO_DEFAULT_LOG_FILE)
+#if ELPP_OS_UNIX
+static const char *kDefaultLogFile = "/dev/null";
+#elif ELPP_OS_WINDOWS
+static const char *kDefaultLogFile = "nul";
+#endif // ELPP_OS_UNIX
+#elif defined(ELPP_DEFAULT_LOG_FILE)
+static const char *kDefaultLogFile = ELPP_DEFAULT_LOG_FILE;
+#else
+static const char *kDefaultLogFile = "myeasylog.log";
+#endif // defined(ELPP_NO_DEFAULT_LOG_FILE)
+
+#if !defined(ELPP_DISABLE_LOG_FILE_FROM_ARG)
+static const char *kDefaultLogFileParam = "--default-log-file";
+#endif // !defined(ELPP_DISABLE_LOG_FILE_FROM_ARG)
+#if defined(ELPP_LOGGING_FLAGS_FROM_ARG)
+static const char *kLoggingFlagsParam = "--logging-flags";
+#endif // defined(ELPP_LOGGING_FLAGS_FROM_ARG)
+static const char *kValidLoggerIdSymbols =
+ "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-._";
+static const char *kConfigurationComment = "##";
+static const char *kConfigurationLevel = "*";
+static const char *kConfigurationLoggerId = "--";
+} // namespace consts
+// el::base::utils
+namespace utils {
+
+/// @brief Aborts application due with user-defined status
+static void abort(int status, const std::string &reason) {
+ // Both status and reason params are there for debugging with tools like gdb
+ // etc
+ ELPP_UNUSED(status);
+ ELPP_UNUSED(reason);
+#if defined(ELPP_COMPILER_MSVC) && defined(_M_IX86) && defined(_DEBUG)
+ // Ignore msvc critical error dialog - break instead (on debug mode)
+ _asm int 3
+#else
+ ::abort();
+#endif // defined(ELPP_COMPILER_MSVC) && defined(_M_IX86) && defined(_DEBUG)
+}
+
+} // namespace utils
+} // namespace base
+
+// el
+
+// LevelHelper
+
+const char *LevelHelper::convertToString(Level level) {
+ // Do not use switch over strongly typed enums because Intel C++ compilers
+ // dont support them yet.
+ if (level == Level::Global)
+ return "GLOBAL";
+ if (level == Level::Debug)
+ return "DEBUG";
+ if (level == Level::Info)
+ return "INFO";
+ if (level == Level::Warning)
+ return "WARNING";
+ if (level == Level::Error)
+ return "ERROR";
+ if (level == Level::Fatal)
+ return "FATAL";
+ if (level == Level::Verbose)
+ return "VERBOSE";
+ if (level == Level::Trace)
+ return "TRACE";
+ return "UNKNOWN";
+}
+
+struct StringToLevelItem {
+ const char *levelString;
+ Level level;
+};
+
+static struct StringToLevelItem stringToLevelMap[] = {
+ {"global", Level::Global}, {"debug", Level::Debug},
+ {"info", Level::Info}, {"warning", Level::Warning},
+ {"error", Level::Error}, {"fatal", Level::Fatal},
+ {"verbose", Level::Verbose}, {"trace", Level::Trace}};
+
+Level LevelHelper::convertFromString(const char *levelStr) {
+ for (auto &item : stringToLevelMap) {
+ if (base::utils::Str::cStringCaseEq(levelStr, item.levelString)) {
+ return item.level;
+ }
+ }
+ return Level::Unknown;
+}
+
+void LevelHelper::forEachLevel(base::type::EnumType *startIndex,
+ const std::function<bool(void)> &fn) {
+ base::type::EnumType lIndexMax = LevelHelper::kMaxValid;
+ do {
+ if (fn()) {
+ break;
+ }
+ *startIndex = static_cast<base::type::EnumType>(*startIndex << 1);
+ } while (*startIndex <= lIndexMax);
+}
+
+// ConfigurationTypeHelper
+
+const char *
+ConfigurationTypeHelper::convertToString(ConfigurationType configurationType) {
+ // Do not use switch over strongly typed enums because Intel C++ compilers
+ // dont support them yet.
+ if (configurationType == ConfigurationType::Enabled)
+ return "ENABLED";
+ if (configurationType == ConfigurationType::Filename)
+ return "FILENAME";
+ if (configurationType == ConfigurationType::Format)
+ return "FORMAT";
+ if (configurationType == ConfigurationType::ToFile)
+ return "TO_FILE";
+ if (configurationType == ConfigurationType::ToStandardOutput)
+ return "TO_STANDARD_OUTPUT";
+ if (configurationType == ConfigurationType::SubsecondPrecision)
+ return "SUBSECOND_PRECISION";
+ if (configurationType == ConfigurationType::PerformanceTracking)
+ return "PERFORMANCE_TRACKING";
+ if (configurationType == ConfigurationType::MaxLogFileSize)
+ return "MAX_LOG_FILE_SIZE";
+ if (configurationType == ConfigurationType::LogFlushThreshold)
+ return "LOG_FLUSH_THRESHOLD";
+ return "UNKNOWN";
+}
+
+struct ConfigurationStringToTypeItem {
+ const char *configString;
+ ConfigurationType configType;
+};
+
+static struct ConfigurationStringToTypeItem configStringToTypeMap[] = {
+ {"enabled", ConfigurationType::Enabled},
+ {"to_file", ConfigurationType::ToFile},
+ {"to_standard_output", ConfigurationType::ToStandardOutput},
+ {"format", ConfigurationType::Format},
+ {"filename", ConfigurationType::Filename},
+ {"subsecond_precision", ConfigurationType::SubsecondPrecision},
+ {"milliseconds_width", ConfigurationType::MillisecondsWidth},
+ {"performance_tracking", ConfigurationType::PerformanceTracking},
+ {"max_log_file_size", ConfigurationType::MaxLogFileSize},
+ {"log_flush_threshold", ConfigurationType::LogFlushThreshold},
+};
+
+ConfigurationType
+ConfigurationTypeHelper::convertFromString(const char *configStr) {
+ for (auto &item : configStringToTypeMap) {
+ if (base::utils::Str::cStringCaseEq(configStr, item.configString)) {
+ return item.configType;
+ }
+ }
+ return ConfigurationType::Unknown;
+}
+
+void ConfigurationTypeHelper::forEachConfigType(
+ base::type::EnumType *startIndex, const std::function<bool(void)> &fn) {
+ base::type::EnumType cIndexMax = ConfigurationTypeHelper::kMaxValid;
+ do {
+ if (fn()) {
+ break;
+ }
+ *startIndex = static_cast<base::type::EnumType>(*startIndex << 1);
+ } while (*startIndex <= cIndexMax);
+}
+
+// Configuration
+
+Configuration::Configuration(const Configuration &c)
+ : m_level(c.m_level), m_configurationType(c.m_configurationType),
+ m_value(c.m_value) {}
+
+Configuration &Configuration::operator=(const Configuration &c) {
+ if (&c != this) {
+ m_level = c.m_level;
+ m_configurationType = c.m_configurationType;
+ m_value = c.m_value;
+ }
+ return *this;
+}
+
+/// @brief Full constructor used to sets value of configuration
+Configuration::Configuration(Level level, ConfigurationType configurationType,
+ const std::string &value)
+ : m_level(level), m_configurationType(configurationType), m_value(value) {}
+
+void Configuration::log(el::base::type::ostream_t &os) const {
+ os << LevelHelper::convertToString(m_level) << ELPP_LITERAL(" ")
+ << ConfigurationTypeHelper::convertToString(m_configurationType)
+ << ELPP_LITERAL(" = ") << m_value.c_str();
+}
+
+/// @brief Used to find configuration from configuration (pointers) repository.
+/// Avoid using it.
+Configuration::Predicate::Predicate(Level level,
+ ConfigurationType configurationType)
+ : m_level(level), m_configurationType(configurationType) {}
+
+bool Configuration::Predicate::operator()(const Configuration *conf) const {
+ return ((conf != nullptr) && (conf->level() == m_level) &&
+ (conf->configurationType() == m_configurationType));
+}
+
+// Configurations
+
+Configurations::Configurations(void)
+ : m_configurationFile(std::string()), m_isFromFile(false) {}
+
+Configurations::Configurations(const std::string &configurationFile,
+ bool useDefaultsForRemaining,
+ Configurations *base)
+ : m_configurationFile(configurationFile), m_isFromFile(false) {
+ parseFromFile(configurationFile, base);
+ if (useDefaultsForRemaining) {
+ setRemainingToDefault();
+ }
+}
+
+bool Configurations::parseFromFile(const std::string &configurationFile,
+ Configurations *base) {
+ // We initial assertion with true because if we have assertion disabled, we
+ // want to pass this check and if assertion is enabled we will have values
+ // re-assigned any way.
+ bool assertionPassed = true;
+ ELPP_ASSERT((assertionPassed = base::utils::File::pathExists(
+ configurationFile.c_str(), true)) == true,
+ "Configuration file [" << configurationFile
+ << "] does not exist!");
+ if (!assertionPassed) {
+ return false;
+ }
+ bool success = Parser::parseFromFile(configurationFile, this, base);
+ m_isFromFile = success;
+ return success;
+}
+
+bool Configurations::parseFromText(const std::string &configurationsString,
+ Configurations *base) {
+ bool success = Parser::parseFromText(configurationsString, this, base);
+ if (success) {
+ m_isFromFile = false;
+ }
+ return success;
+}
+
+void Configurations::setFromBase(Configurations *base) {
+ if (base == nullptr || base == this) {
+ return;
+ }
+ base::threading::ScopedLock scopedLock(base->lock());
+ for (Configuration *&conf : base->list()) {
+ set(conf);
+ }
+}
+
+bool Configurations::hasConfiguration(ConfigurationType configurationType) {
+ base::type::EnumType lIndex = LevelHelper::kMinValid;
+ bool result = false;
+ LevelHelper::forEachLevel(&lIndex, [&](void) -> bool {
+ if (hasConfiguration(LevelHelper::castFromInt(lIndex), configurationType)) {
+ result = true;
+ }
+ return result;
+ });
+ return result;
+}
+
+bool Configurations::hasConfiguration(Level level,
+ ConfigurationType configurationType) {
+ base::threading::ScopedLock scopedLock(lock());
+#if ELPP_COMPILER_INTEL
+ // We cant specify template types here, Intel C++ throws compilation error
+ // "error: type name is not allowed"
+ return RegistryWithPred::get(level, configurationType) != nullptr;
+#else
+ return RegistryWithPred<Configuration, Configuration::Predicate>::get(
+ level, configurationType) != nullptr;
+#endif // ELPP_COMPILER_INTEL
+}
+
+void Configurations::set(Level level, ConfigurationType configurationType,
+ const std::string &value) {
+ base::threading::ScopedLock scopedLock(lock());
+ unsafeSet(level, configurationType,
+ value); // This is not unsafe anymore as we have locked mutex
+ if (level == Level::Global) {
+ unsafeSetGlobally(configurationType, value,
+ false); // Again this is not unsafe either
+ }
+}
+
+void Configurations::set(Configuration *conf) {
+ if (conf == nullptr) {
+ return;
+ }
+ set(conf->level(), conf->configurationType(), conf->value());
+}
+
+void Configurations::setToDefault(void) {
+ setGlobally(ConfigurationType::Enabled, std::string("true"), true);
+ setGlobally(ConfigurationType::Filename,
+ std::string(base::consts::kDefaultLogFile), true);
+#if defined(ELPP_NO_LOG_TO_FILE)
+ setGlobally(ConfigurationType::ToFile, std::string("false"), true);
+#else
+ setGlobally(ConfigurationType::ToFile, std::string("true"), true);
+#endif // defined(ELPP_NO_LOG_TO_FILE)
+ setGlobally(ConfigurationType::ToStandardOutput, std::string("true"), true);
+ setGlobally(ConfigurationType::SubsecondPrecision, std::string("3"), true);
+ setGlobally(ConfigurationType::PerformanceTracking, std::string("true"),
+ true);
+ setGlobally(ConfigurationType::MaxLogFileSize, std::string("0"), true);
+ setGlobally(ConfigurationType::LogFlushThreshold, std::string("0"), true);
+
+ setGlobally(ConfigurationType::Format,
+ std::string("%datetime %level [%logger] %msg"), true);
+ set(Level::Debug, ConfigurationType::Format,
+ std::string(
+ "%datetime %level [%logger] [%user@%host] [%func] [%loc] %msg"));
+ // INFO and WARNING are set to default by Level::Global
+ set(Level::Error, ConfigurationType::Format,
+ std::string("%datetime %level [%logger] %msg"));
+ set(Level::Fatal, ConfigurationType::Format,
+ std::string("%datetime %level [%logger] %msg"));
+ set(Level::Verbose, ConfigurationType::Format,
+ std::string("%datetime %level-%vlevel [%logger] %msg"));
+ set(Level::Trace, ConfigurationType::Format,
+ std::string("%datetime %level [%logger] [%func] [%loc] %msg"));
+}
+
+void Configurations::setRemainingToDefault(void) {
+ base::threading::ScopedLock scopedLock(lock());
+#if defined(ELPP_NO_LOG_TO_FILE)
+ unsafeSetIfNotExist(Level::Global, ConfigurationType::Enabled,
+ std::string("false"));
+#else
+ unsafeSetIfNotExist(Level::Global, ConfigurationType::Enabled,
+ std::string("true"));
+#endif // defined(ELPP_NO_LOG_TO_FILE)
+ unsafeSetIfNotExist(Level::Global, ConfigurationType::Filename,
+ std::string(base::consts::kDefaultLogFile));
+ unsafeSetIfNotExist(Level::Global, ConfigurationType::ToStandardOutput,
+ std::string("true"));
+ unsafeSetIfNotExist(Level::Global, ConfigurationType::SubsecondPrecision,
+ std::string("3"));
+ unsafeSetIfNotExist(Level::Global, ConfigurationType::PerformanceTracking,
+ std::string("true"));
+ unsafeSetIfNotExist(Level::Global, ConfigurationType::MaxLogFileSize,
+ std::string("0"));
+ unsafeSetIfNotExist(Level::Global, ConfigurationType::Format,
+ std::string("%datetime %level [%logger] %msg"));
+ unsafeSetIfNotExist(
+ Level::Debug, ConfigurationType::Format,
+ std::string(
+ "%datetime %level [%logger] [%user@%host] [%func] [%loc] %msg"));
+ // INFO and WARNING are set to default by Level::Global
+ unsafeSetIfNotExist(Level::Error, ConfigurationType::Format,
+ std::string("%datetime %level [%logger] %msg"));
+ unsafeSetIfNotExist(Level::Fatal, ConfigurationType::Format,
+ std::string("%datetime %level [%logger] %msg"));
+ unsafeSetIfNotExist(Level::Verbose, ConfigurationType::Format,
+ std::string("%datetime %level-%vlevel [%logger] %msg"));
+ unsafeSetIfNotExist(
+ Level::Trace, ConfigurationType::Format,
+ std::string("%datetime %level [%logger] [%func] [%loc] %msg"));
+}
+
+bool Configurations::Parser::parseFromFile(const std::string &configurationFile,
+ Configurations *sender,
+ Configurations *base) {
+ sender->setFromBase(base);
+ std::ifstream fileStream_(configurationFile.c_str(), std::ifstream::in);
+ ELPP_ASSERT(fileStream_.is_open(), "Unable to open configuration file ["
+ << configurationFile
+ << "] for parsing.");
+ bool parsedSuccessfully = false;
+ std::string line = std::string();
+ Level currLevel = Level::Unknown;
+ std::string currConfigStr = std::string();
+ std::string currLevelStr = std::string();
+ while (fileStream_.good()) {
+ std::getline(fileStream_, line);
+ parsedSuccessfully =
+ parseLine(&line, &currConfigStr, &currLevelStr, &currLevel, sender);
+ ELPP_ASSERT(parsedSuccessfully,
+ "Unable to parse configuration line: " << line);
+ }
+ return parsedSuccessfully;
+}
+
+bool Configurations::Parser::parseFromText(
+ const std::string &configurationsString, Configurations *sender,
+ Configurations *base) {
+ sender->setFromBase(base);
+ bool parsedSuccessfully = false;
+ std::stringstream ss(configurationsString);
+ std::string line = std::string();
+ Level currLevel = Level::Unknown;
+ std::string currConfigStr = std::string();
+ std::string currLevelStr = std::string();
+ while (std::getline(ss, line)) {
+ parsedSuccessfully =
+ parseLine(&line, &currConfigStr, &currLevelStr, &currLevel, sender);
+ ELPP_ASSERT(parsedSuccessfully,
+ "Unable to parse configuration line: " << line);
+ }
+ return parsedSuccessfully;
+}
+
+void Configurations::Parser::ignoreComments(std::string *line) {
+ std::size_t foundAt = 0;
+ std::size_t quotesStart = line->find("\"");
+ std::size_t quotesEnd = std::string::npos;
+ if (quotesStart != std::string::npos) {
+ quotesEnd = line->find("\"", quotesStart + 1);
+ while (quotesEnd != std::string::npos && line->at(quotesEnd - 1) == '\\') {
+ // Do not erase slash yet - we will erase it in parseLine(..) while loop
+ quotesEnd = line->find("\"", quotesEnd + 2);
+ }
+ }
+ if ((foundAt = line->find(base::consts::kConfigurationComment)) !=
+ std::string::npos) {
+ if (foundAt < quotesEnd) {
+ foundAt = line->find(base::consts::kConfigurationComment, quotesEnd + 1);
+ }
+ *line = line->substr(0, foundAt);
+ }
+}
+
+bool Configurations::Parser::isLevel(const std::string &line) {
+ return base::utils::Str::startsWith(
+ line, std::string(base::consts::kConfigurationLevel));
+}
+
+bool Configurations::Parser::isComment(const std::string &line) {
+ return base::utils::Str::startsWith(
+ line, std::string(base::consts::kConfigurationComment));
+}
+
+bool Configurations::Parser::isConfig(const std::string &line) {
+ std::size_t assignment = line.find('=');
+ return line != "" &&
+ ((line[0] >= 'A' && line[0] <= 'Z') ||
+ (line[0] >= 'a' && line[0] <= 'z')) &&
+ (assignment != std::string::npos) && (line.size() > assignment);
+}
+
+bool Configurations::Parser::parseLine(std::string *line,
+ std::string *currConfigStr,
+ std::string *currLevelStr,
+ Level *currLevel, Configurations *conf) {
+ ConfigurationType currConfig = ConfigurationType::Unknown;
+ std::string currValue = std::string();
+ *line = base::utils::Str::trim(*line);
+ if (isComment(*line))
+ return true;
+ ignoreComments(line);
+ *line = base::utils::Str::trim(*line);
+ if (line->empty()) {
+ // Comment ignored
+ return true;
+ }
+ if (isLevel(*line)) {
+ if (line->size() <= 2) {
+ return true;
+ }
+ *currLevelStr = line->substr(1, line->size() - 2);
+ *currLevelStr = base::utils::Str::toUpper(*currLevelStr);
+ *currLevelStr = base::utils::Str::trim(*currLevelStr);
+ *currLevel = LevelHelper::convertFromString(currLevelStr->c_str());
+ return true;
+ }
+ if (isConfig(*line)) {
+ std::size_t assignment = line->find('=');
+ *currConfigStr = line->substr(0, assignment);
+ *currConfigStr = base::utils::Str::toUpper(*currConfigStr);
+ *currConfigStr = base::utils::Str::trim(*currConfigStr);
+ currConfig =
+ ConfigurationTypeHelper::convertFromString(currConfigStr->c_str());
+ currValue = line->substr(assignment + 1);
+ currValue = base::utils::Str::trim(currValue);
+ std::size_t quotesStart = currValue.find("\"", 0);
+ std::size_t quotesEnd = std::string::npos;
+ if (quotesStart != std::string::npos) {
+ quotesEnd = currValue.find("\"", quotesStart + 1);
+ while (quotesEnd != std::string::npos &&
+ currValue.at(quotesEnd - 1) == '\\') {
+ currValue = currValue.erase(quotesEnd - 1, 1);
+ quotesEnd = currValue.find("\"", quotesEnd + 2);
+ }
+ }
+ if (quotesStart != std::string::npos && quotesEnd != std::string::npos) {
+ // Quote provided - check and strip if valid
+ ELPP_ASSERT((quotesStart < quotesEnd),
+ "Configuration error - No ending quote found in ["
+ << currConfigStr << "]");
+ ELPP_ASSERT((quotesStart + 1 != quotesEnd),
+ "Empty configuration value for [" << currConfigStr << "]");
+ if ((quotesStart != quotesEnd) && (quotesStart + 1 != quotesEnd)) {
+ // Explicit check in case if assertion is disabled
+ currValue = currValue.substr(quotesStart + 1, quotesEnd - 1);
+ }
+ }
+ }
+ ELPP_ASSERT(*currLevel != Level::Unknown,
+ "Unrecognized severity level [" << *currLevelStr << "]");
+ ELPP_ASSERT(currConfig != ConfigurationType::Unknown,
+ "Unrecognized configuration [" << *currConfigStr << "]");
+ if (*currLevel == Level::Unknown ||
+ currConfig == ConfigurationType::Unknown) {
+ return false; // unrecognizable level or config
+ }
+ conf->set(*currLevel, currConfig, currValue);
+ return true;
+}
+
+void Configurations::unsafeSetIfNotExist(Level level,
+ ConfigurationType configurationType,
+ const std::string &value) {
+ Configuration *conf =
+ RegistryWithPred<Configuration, Configuration::Predicate>::get(
+ level, configurationType);
+ if (conf == nullptr) {
+ unsafeSet(level, configurationType, value);
+ }
+}
+
+void Configurations::unsafeSet(Level level, ConfigurationType configurationType,
+ const std::string &value) {
+ Configuration *conf =
+ RegistryWithPred<Configuration, Configuration::Predicate>::get(
+ level, configurationType);
+ if (conf == nullptr) {
+ registerNew(new Configuration(level, configurationType, value));
+ } else {
+ conf->setValue(value);
+ }
+ if (level == Level::Global) {
+ unsafeSetGlobally(configurationType, value, false);
+ }
+}
+
+void Configurations::setGlobally(ConfigurationType configurationType,
+ const std::string &value,
+ bool includeGlobalLevel) {
+ if (includeGlobalLevel) {
+ set(Level::Global, configurationType, value);
+ }
+ base::type::EnumType lIndex = LevelHelper::kMinValid;
+ LevelHelper::forEachLevel(&lIndex, [&](void) -> bool {
+ set(LevelHelper::castFromInt(lIndex), configurationType, value);
+ return false; // Do not break lambda function yet as we need to set all
+ // levels regardless
+ });
+}
+
+void Configurations::unsafeSetGlobally(ConfigurationType configurationType,
+ const std::string &value,
+ bool includeGlobalLevel) {
+ if (includeGlobalLevel) {
+ unsafeSet(Level::Global, configurationType, value);
+ }
+ base::type::EnumType lIndex = LevelHelper::kMinValid;
+ LevelHelper::forEachLevel(&lIndex, [&](void) -> bool {
+ unsafeSet(LevelHelper::castFromInt(lIndex), configurationType, value);
+ return false; // Do not break lambda function yet as we need to set all
+ // levels regardless
+ });
+}
+
+// LogBuilder
+
+void LogBuilder::convertToColoredOutput(base::type::string_t *logLine,
+ Level level) {
+ if (!m_termSupportsColor)
+ return;
+ const base::type::char_t *resetColor = ELPP_LITERAL("\x1b[0m");
+ if (level == Level::Error || level == Level::Fatal)
+ *logLine = ELPP_LITERAL("\x1b[31m") + *logLine + resetColor;
+ else if (level == Level::Warning)
+ *logLine = ELPP_LITERAL("\x1b[33m") + *logLine + resetColor;
+ else if (level == Level::Debug)
+ *logLine = ELPP_LITERAL("\x1b[32m") + *logLine + resetColor;
+ else if (level == Level::Info)
+ *logLine = ELPP_LITERAL("\x1b[36m") + *logLine + resetColor;
+ else if (level == Level::Trace)
+ *logLine = ELPP_LITERAL("\x1b[35m") + *logLine + resetColor;
+}
+
+// Logger
+
+Logger::Logger(const std::string &id,
+ base::LogStreamsReferenceMapPtr logStreamsReference)
+ : m_id(id), m_typedConfigurations(nullptr),
+ m_parentApplicationName(std::string()), m_isConfigured(false),
+ m_logStreamsReference(logStreamsReference) {
+ initUnflushedCount();
+}
+
+Logger::Logger(const std::string &id, const Configurations &configurations,
+ base::LogStreamsReferenceMapPtr logStreamsReference)
+ : m_id(id), m_typedConfigurations(nullptr),
+ m_parentApplicationName(std::string()), m_isConfigured(false),
+ m_logStreamsReference(logStreamsReference) {
+ initUnflushedCount();
+ configure(configurations);
+}
+
+Logger::Logger(const Logger &logger) {
+ base::utils::safeDelete(m_typedConfigurations);
+ m_id = logger.m_id;
+ m_typedConfigurations = logger.m_typedConfigurations;
+ m_parentApplicationName = logger.m_parentApplicationName;
+ m_isConfigured = logger.m_isConfigured;
+ m_configurations = logger.m_configurations;
+ m_unflushedCount = logger.m_unflushedCount;
+ m_logStreamsReference = logger.m_logStreamsReference;
+}
+
+Logger &Logger::operator=(const Logger &logger) {
+ if (&logger != this) {
+ base::utils::safeDelete(m_typedConfigurations);
+ m_id = logger.m_id;
+ m_typedConfigurations = logger.m_typedConfigurations;
+ m_parentApplicationName = logger.m_parentApplicationName;
+ m_isConfigured = logger.m_isConfigured;
+ m_configurations = logger.m_configurations;
+ m_unflushedCount = logger.m_unflushedCount;
+ m_logStreamsReference = logger.m_logStreamsReference;
+ }
+ return *this;
+}
+
+void Logger::configure(const Configurations &configurations) {
+ m_isConfigured = false; // we set it to false in case if we fail
+ initUnflushedCount();
+ if (m_typedConfigurations != nullptr) {
+ Configurations *c =
+ const_cast<Configurations *>(m_typedConfigurations->configurations());
+ if (c->hasConfiguration(Level::Global, ConfigurationType::Filename)) {
+ flush();
+ }
+ }
+ base::threading::ScopedLock scopedLock(lock());
+ if (m_configurations != configurations) {
+ m_configurations.setFromBase(const_cast<Configurations *>(&configurations));
+ }
+ base::utils::safeDelete(m_typedConfigurations);
+ m_typedConfigurations =
+ new base::TypedConfigurations(&m_configurations, m_logStreamsReference);
+ resolveLoggerFormatSpec();
+ m_isConfigured = true;
+}
+
+void Logger::reconfigure(void) {
+ ELPP_INTERNAL_INFO(1, "Reconfiguring logger [" << m_id << "]");
+ configure(m_configurations);
+}
+
+bool Logger::isValidId(const std::string &id) {
+ for (std::string::const_iterator it = id.begin(); it != id.end(); ++it) {
+ if (!base::utils::Str::contains(base::consts::kValidLoggerIdSymbols, *it)) {
+ return false;
+ }
+ }
+ return true;
+}
+
+void Logger::flush(void) {
+ ELPP_INTERNAL_INFO(3, "Flushing logger [" << m_id << "] all levels");
+ base::threading::ScopedLock scopedLock(lock());
+ base::type::EnumType lIndex = LevelHelper::kMinValid;
+ LevelHelper::forEachLevel(&lIndex, [&](void) -> bool {
+ flush(LevelHelper::castFromInt(lIndex), nullptr);
+ return false;
+ });
+}
+
+void Logger::flush(Level level, base::type::fstream_t *fs) {
+ if (fs == nullptr && m_typedConfigurations->toFile(level)) {
+ fs = m_typedConfigurations->fileStream(level);
+ }
+ if (fs != nullptr) {
+ fs->flush();
+ std::unordered_map<Level, unsigned int>::iterator iter =
+ m_unflushedCount.find(level);
+ if (iter != m_unflushedCount.end()) {
+ iter->second = 0;
+ }
+ Helpers::validateFileRolling(this, level);
+ }
+}
+
+void Logger::initUnflushedCount(void) {
+ m_unflushedCount.clear();
+ base::type::EnumType lIndex = LevelHelper::kMinValid;
+ LevelHelper::forEachLevel(&lIndex, [&](void) -> bool {
+ m_unflushedCount.insert(
+ std::make_pair(LevelHelper::castFromInt(lIndex), 0));
+ return false;
+ });
+}
+
+void Logger::resolveLoggerFormatSpec(void) const {
+ base::type::EnumType lIndex = LevelHelper::kMinValid;
+ LevelHelper::forEachLevel(&lIndex, [&](void) -> bool {
+ base::LogFormat *logFormat = const_cast<base::LogFormat *>(
+ &m_typedConfigurations->logFormat(LevelHelper::castFromInt(lIndex)));
+ base::utils::Str::replaceFirstWithEscape(
+ logFormat->m_format, base::consts::kLoggerIdFormatSpecifier, m_id);
+ return false;
+ });
+}
+
+// el::base
+namespace base {
+
+// el::base::utils
+namespace utils {
+
+// File
+
+base::type::fstream_t *File::newFileStream(const std::string &filename) {
+ base::type::fstream_t *fs = new base::type::fstream_t(
+ filename.c_str(), base::type::fstream_t::out
+#if !defined(ELPP_FRESH_LOG_FILE)
+ | base::type::fstream_t::app
+#endif
+ );
+#if defined(ELPP_UNICODE)
+ std::locale elppUnicodeLocale("");
+#if ELPP_OS_WINDOWS
+ std::locale elppUnicodeLocaleWindows(elppUnicodeLocale,
+ new std::codecvt_utf8_utf16<wchar_t>);
+ elppUnicodeLocale = elppUnicodeLocaleWindows;
+#endif // ELPP_OS_WINDOWS
+ fs->imbue(elppUnicodeLocale);
+#endif // defined(ELPP_UNICODE)
+ if (fs->is_open()) {
+ fs->flush();
+ } else {
+ base::utils::safeDelete(fs);
+ ELPP_INTERNAL_ERROR("Bad file [" << filename << "]", true);
+ }
+ return fs;
+}
+
+std::size_t File::getSizeOfFile(base::type::fstream_t *fs) {
+ if (fs == nullptr) {
+ return 0;
+ }
+ // Since the file stream is appended to or truncated, the current
+ // offset is the file size.
+ std::size_t size = static_cast<std::size_t>(fs->tellg());
+ return size;
+}
+
+bool File::pathExists(const char *path, bool considerFile) {
+ if (path == nullptr) {
+ return false;
+ }
+#if ELPP_OS_UNIX
+ ELPP_UNUSED(considerFile);
+ struct stat st;
+ return (stat(path, &st) == 0);
+#elif ELPP_OS_WINDOWS
+ DWORD fileType = GetFileAttributesA(path);
+ if (fileType == INVALID_FILE_ATTRIBUTES) {
+ return false;
+ }
+ return considerFile
+ ? true
+ : ((fileType & FILE_ATTRIBUTE_DIRECTORY) == 0 ? false : true);
+#endif // ELPP_OS_UNIX
+}
+
+bool File::createPath(const std::string &path) {
+ if (path.empty()) {
+ return false;
+ }
+ if (base::utils::File::pathExists(path.c_str())) {
+ return true;
+ }
+ int status = -1;
+
+ char *currPath = const_cast<char *>(path.c_str());
+ std::string builtPath = std::string();
+#if ELPP_OS_UNIX
+ if (path[0] == '/') {
+ builtPath = "/";
+ }
+ currPath = STRTOK(currPath, base::consts::kFilePathSeparator, 0);
+#elif ELPP_OS_WINDOWS
+ // Use secure functions API
+ char *nextTok_ = nullptr;
+ currPath = STRTOK(currPath, base::consts::kFilePathSeparator, &nextTok_);
+ ELPP_UNUSED(nextTok_);
+#endif // ELPP_OS_UNIX
+ while (currPath != nullptr) {
+ builtPath.append(currPath);
+ builtPath.append(base::consts::kFilePathSeparator);
+#if ELPP_OS_UNIX
+ status = mkdir(builtPath.c_str(), ELPP_LOG_PERMS);
+ currPath = STRTOK(nullptr, base::consts::kFilePathSeparator, 0);
+#elif ELPP_OS_WINDOWS
+ status = _mkdir(builtPath.c_str());
+ currPath = STRTOK(nullptr, base::consts::kFilePathSeparator, &nextTok_);
+#endif // ELPP_OS_UNIX
+ }
+ if (status == -1) {
+ ELPP_INTERNAL_ERROR("Error while creating path [" << path << "]", true);
+ return false;
+ }
+ return true;
+}
+
+std::string File::extractPathFromFilename(const std::string &fullPath,
+ const char *separator) {
+ if ((fullPath == "") || (fullPath.find(separator) == std::string::npos)) {
+ return fullPath;
+ }
+ std::size_t lastSlashAt = fullPath.find_last_of(separator);
+ if (lastSlashAt == 0) {
+ return std::string(separator);
+ }
+ return fullPath.substr(0, lastSlashAt + 1);
+}
+
+void File::buildStrippedFilename(const char *filename, char buff[],
+ std::size_t limit) {
+ std::size_t sizeOfFilename = strlen(filename);
+ if (sizeOfFilename >= limit) {
+ filename += (sizeOfFilename - limit);
+ if (filename[0] != '.' && filename[1] != '.') { // prepend if not already
+ filename += 3; // 3 = '..'
+ STRCAT(buff, "..", limit);
+ }
+ }
+ STRCAT(buff, filename, limit);
+}
+
+void File::buildBaseFilename(const std::string &fullPath, char buff[],
+ std::size_t limit, const char *separator) {
+ const char *filename = fullPath.c_str();
+ std::size_t lastSlashAt = fullPath.find_last_of(separator);
+ filename += lastSlashAt ? lastSlashAt + 1 : 0;
+ std::size_t sizeOfFilename = strlen(filename);
+ if (sizeOfFilename >= limit) {
+ filename += (sizeOfFilename - limit);
+ if (filename[0] != '.' && filename[1] != '.') { // prepend if not already
+ filename += 3; // 3 = '..'
+ STRCAT(buff, "..", limit);
+ }
+ }
+ STRCAT(buff, filename, limit);
+}
+
+// Str
+
+bool Str::wildCardMatch(const char *str, const char *pattern) {
+ while (*pattern) {
+ switch (*pattern) {
+ case '?':
+ if (!*str)
+ return false;
+ ++str;
+ ++pattern;
+ break;
+ case '*':
+ if (wildCardMatch(str, pattern + 1))
+ return true;
+ if (*str && wildCardMatch(str + 1, pattern))
+ return true;
+ return false;
+ default:
+ if (*str++ != *pattern++)
+ return false;
+ break;
+ }
+ }
+ return !*str && !*pattern;
+}
+
+std::string &Str::ltrim(std::string &str) {
+ str.erase(str.begin(), std::find_if(str.begin(), str.end(),
+ [](char c) { return !std::isspace(c); }));
+ return str;
+}
+
+std::string &Str::rtrim(std::string &str) {
+ str.erase(std::find_if(str.rbegin(), str.rend(),
+ [](char c) { return !std::isspace(c); })
+ .base(),
+ str.end());
+ return str;
+}
+
+std::string &Str::trim(std::string &str) { return ltrim(rtrim(str)); }
+
+bool Str::startsWith(const std::string &str, const std::string &start) {
+ return (str.length() >= start.length()) &&
+ (str.compare(0, start.length(), start) == 0);
+}
+
+bool Str::endsWith(const std::string &str, const std::string &end) {
+ return (str.length() >= end.length()) &&
+ (str.compare(str.length() - end.length(), end.length(), end) == 0);
+}
+
+std::string &Str::replaceAll(std::string &str, char replaceWhat,
+ char replaceWith) {
+ std::replace(str.begin(), str.end(), replaceWhat, replaceWith);
+ return str;
+}
+
+std::string &Str::replaceAll(std::string &str, const std::string &replaceWhat,
+ const std::string &replaceWith) {
+ if (replaceWhat == replaceWith)
+ return str;
+ std::size_t foundAt = std::string::npos;
+ while ((foundAt = str.find(replaceWhat, foundAt + 1)) != std::string::npos) {
+ str.replace(foundAt, replaceWhat.length(), replaceWith);
+ }
+ return str;
+}
+
+void Str::replaceFirstWithEscape(base::type::string_t &str,
+ const base::type::string_t &replaceWhat,
+ const base::type::string_t &replaceWith) {
+ std::size_t foundAt = base::type::string_t::npos;
+ while ((foundAt = str.find(replaceWhat, foundAt + 1)) !=
+ base::type::string_t::npos) {
+ if (foundAt > 0 && str[foundAt - 1] == base::consts::kFormatSpecifierChar) {
+ str.erase(foundAt - 1, 1);
+ ++foundAt;
+ } else {
+ str.replace(foundAt, replaceWhat.length(), replaceWith);
+ return;
+ }
+ }
+}
+#if defined(ELPP_UNICODE)
+void Str::replaceFirstWithEscape(base::type::string_t &str,
+ const base::type::string_t &replaceWhat,
+ const std::string &replaceWith) {
+ replaceFirstWithEscape(
+ str, replaceWhat,
+ base::type::string_t(replaceWith.begin(), replaceWith.end()));
+}
+#endif // defined(ELPP_UNICODE)
+
+std::string &Str::toUpper(std::string &str) {
+ std::transform(str.begin(), str.end(), str.begin(),
+ [](char c) { return static_cast<char>(::toupper(c)); });
+ return str;
+}
+
+bool Str::cStringEq(const char *s1, const char *s2) {
+ if (s1 == nullptr && s2 == nullptr)
+ return true;
+ if (s1 == nullptr || s2 == nullptr)
+ return false;
+ return strcmp(s1, s2) == 0;
+}
+
+bool Str::cStringCaseEq(const char *s1, const char *s2) {
+ if (s1 == nullptr && s2 == nullptr)
+ return true;
+ if (s1 == nullptr || s2 == nullptr)
+ return false;
+
+ // With thanks to cygwin for this code
+ int d = 0;
+
+ while (true) {
+ const int c1 = toupper(*s1++);
+ const int c2 = toupper(*s2++);
+
+ if (((d = c1 - c2) != 0) || (c2 == '\0')) {
+ break;
+ }
+ }
+
+ return d == 0;
+}
+
+bool Str::contains(const char *str, char c) {
+ for (; *str; ++str) {
+ if (*str == c)
+ return true;
+ }
+ return false;
+}
+
+char *Str::convertAndAddToBuff(std::size_t n, int len, char *buf,
+ const char *bufLim, bool zeroPadded) {
+ char localBuff[10] = "";
+ char *p = localBuff + sizeof(localBuff) - 2;
+ if (n > 0) {
+ for (; n > 0 && p > localBuff && len > 0; n /= 10, --len)
+ *--p = static_cast<char>(n % 10 + '0');
+ } else {
+ *--p = '0';
+ --len;
+ }
+ if (zeroPadded)
+ while (p > localBuff && len-- > 0)
+ *--p = static_cast<char>('0');
+ return addToBuff(p, buf, bufLim);
+}
+
+char *Str::addToBuff(const char *str, char *buf, const char *bufLim) {
+ while ((buf < bufLim) && ((*buf = *str++) != '\0'))
+ ++buf;
+ return buf;
+}
+
+char *Str::clearBuff(char buff[], std::size_t lim) {
+ STRCPY(buff, "", lim);
+ ELPP_UNUSED(
+ lim); // For *nix we dont have anything using lim in above STRCPY macro
+ return buff;
+}
+
+/// @brief Converts wchar* to char*
+/// NOTE: Need to free return value after use!
+char *Str::wcharPtrToCharPtr(const wchar_t *line) {
+ std::size_t len_ = wcslen(line) + 1;
+ char *buff_ = static_cast<char *>(malloc(len_ + 1));
+#if ELPP_OS_UNIX || (ELPP_OS_WINDOWS && !ELPP_CRT_DBG_WARNINGS)
+ std::wcstombs(buff_, line, len_);
+#elif ELPP_OS_WINDOWS
+ std::size_t convCount_ = 0;
+ mbstate_t mbState_;
+ ::memset(static_cast<void *>(&mbState_), 0, sizeof(mbState_));
+ wcsrtombs_s(&convCount_, buff_, len_, &line, len_, &mbState_);
+#endif // ELPP_OS_UNIX || (ELPP_OS_WINDOWS && !ELPP_CRT_DBG_WARNINGS)
+ return buff_;
+}
+
+// OS
+
+#if ELPP_OS_WINDOWS
+/// @brief Gets environment variables for Windows based OS.
+/// We are not using <code>getenv(const char*)</code> because of CRT
+/// deprecation
+/// @param varname Variable name to get environment variable value for
+/// @return If variable exist the value of it otherwise nullptr
+const char *OS::getWindowsEnvironmentVariable(const char *varname) {
+ const DWORD bufferLen = 50;
+ static char buffer[bufferLen];
+ if (GetEnvironmentVariableA(varname, buffer, bufferLen)) {
+ return buffer;
+ }
+ return nullptr;
+}
+#endif // ELPP_OS_WINDOWS
+#if ELPP_OS_ANDROID
+std::string OS::getProperty(const char *prop) {
+ char propVal[PROP_VALUE_MAX + 1];
+ int ret = __system_property_get(prop, propVal);
+ return ret == 0 ? std::string() : std::string(propVal);
+}
+
+std::string OS::getDeviceName(void) {
+ std::stringstream ss;
+ std::string manufacturer = getProperty("ro.product.manufacturer");
+ std::string model = getProperty("ro.product.model");
+ if (manufacturer.empty() || model.empty()) {
+ return std::string();
+ }
+ ss << manufacturer << "-" << model;
+ return ss.str();
+}
+#endif // ELPP_OS_ANDROID
+
+const std::string OS::getBashOutput(const char *command) {
+#if (ELPP_OS_UNIX && !ELPP_OS_ANDROID && !ELPP_CYGWIN)
+ if (command == nullptr) {
+ return std::string();
+ }
+ FILE *proc = nullptr;
+ if ((proc = popen(command, "r")) == nullptr) {
+ ELPP_INTERNAL_ERROR("\nUnable to run command [" << command << "]", true);
+ return std::string();
+ }
+ char hBuff[4096];
+ if (fgets(hBuff, sizeof(hBuff), proc) != nullptr) {
+ pclose(proc);
+ const std::size_t buffLen = strlen(hBuff);
+ if (buffLen > 0 && hBuff[buffLen - 1] == '\n') {
+ hBuff[buffLen - 1] = '\0';
+ }
+ return std::string(hBuff);
+ } else {
+ pclose(proc);
+ }
+ return std::string();
+#else
+ ELPP_UNUSED(command);
+ return std::string();
+#endif // (ELPP_OS_UNIX && !ELPP_OS_ANDROID && !ELPP_CYGWIN)
+}
+
+std::string OS::getEnvironmentVariable(const char *variableName,
+ const char *defaultVal,
+ const char *alternativeBashCommand) {
+#if ELPP_OS_UNIX
+ const char *val = getenv(variableName);
+#elif ELPP_OS_WINDOWS
+ const char *val = getWindowsEnvironmentVariable(variableName);
+#endif // ELPP_OS_UNIX
+ if ((val == nullptr) || ((strcmp(val, "") == 0))) {
+#if ELPP_OS_UNIX && defined(ELPP_FORCE_ENV_VAR_FROM_BASH)
+ // Try harder on unix-based systems
+ std::string valBash =
+ base::utils::OS::getBashOutput(alternativeBashCommand);
+ if (valBash.empty()) {
+ return std::string(defaultVal);
+ } else {
+ return valBash;
+ }
+#elif ELPP_OS_WINDOWS || ELPP_OS_UNIX
+ ELPP_UNUSED(alternativeBashCommand);
+ return std::string(defaultVal);
+#endif // ELPP_OS_UNIX && defined(ELPP_FORCE_ENV_VAR_FROM_BASH)
+ }
+ return std::string(val);
+}
+
+std::string OS::currentUser(void) {
+#if ELPP_OS_UNIX && !ELPP_OS_ANDROID
+ return getEnvironmentVariable("USER", base::consts::kUnknownUser, "whoami");
+#elif ELPP_OS_WINDOWS
+ return getEnvironmentVariable("USERNAME", base::consts::kUnknownUser);
+#elif ELPP_OS_ANDROID
+ ELPP_UNUSED(base::consts::kUnknownUser);
+ return std::string("android");
+#else
+ return std::string();
+#endif // ELPP_OS_UNIX && !ELPP_OS_ANDROID
+}
+
+std::string OS::currentHost(void) {
+#if ELPP_OS_UNIX && !ELPP_OS_ANDROID
+ return getEnvironmentVariable("HOSTNAME", base::consts::kUnknownHost,
+ "hostname");
+#elif ELPP_OS_WINDOWS
+ return getEnvironmentVariable("COMPUTERNAME", base::consts::kUnknownHost);
+#elif ELPP_OS_ANDROID
+ ELPP_UNUSED(base::consts::kUnknownHost);
+ return getDeviceName();
+#else
+ return std::string();
+#endif // ELPP_OS_UNIX && !ELPP_OS_ANDROID
+}
+
+bool OS::termSupportsColor(void) {
+ std::string term = getEnvironmentVariable("TERM", "");
+ return term == "xterm" || term == "xterm-color" || term == "xterm-256color" ||
+ term == "screen" || term == "linux" || term == "cygwin" ||
+ term == "screen-256color";
+}
+
+// DateTime
+
+void DateTime::gettimeofday(struct timeval *tv) {
+#if ELPP_OS_WINDOWS
+ if (tv != nullptr) {
+#if ELPP_COMPILER_MSVC || defined(_MSC_EXTENSIONS)
+ const unsigned __int64 delta_ = 11644473600000000Ui64;
+#else
+ const unsigned __int64 delta_ = 11644473600000000ULL;
+#endif // ELPP_COMPILER_MSVC || defined(_MSC_EXTENSIONS)
+ const double secOffSet = 0.000001;
+ const unsigned long usecOffSet = 1000000;
+ FILETIME fileTime;
+ GetSystemTimeAsFileTime(&fileTime);
+ unsigned __int64 present = 0;
+ present |= fileTime.dwHighDateTime;
+ present = present << 32;
+ present |= fileTime.dwLowDateTime;
+ present /= 10; // mic-sec
+ // Subtract the difference
+ present -= delta_;
+ tv->tv_sec = static_cast<long>(present * secOffSet);
+ tv->tv_usec = static_cast<long>(present % usecOffSet);
+ }
+#else
+ ::gettimeofday(tv, nullptr);
+#endif // ELPP_OS_WINDOWS
+}
+
+std::string DateTime::getDateTime(const char *format,
+ const base::SubsecondPrecision *ssPrec) {
+ struct timeval currTime;
+ gettimeofday(&currTime);
+ return timevalToString(currTime, format, ssPrec);
+}
+
+std::string
+DateTime::timevalToString(struct timeval tval, const char *format,
+ const el::base::SubsecondPrecision *ssPrec) {
+ struct ::tm timeInfo;
+ buildTimeInfo(&tval, &timeInfo);
+ const int kBuffSize = 30;
+ char buff_[kBuffSize] = "";
+ parseFormat(buff_, kBuffSize, format, &timeInfo,
+ static_cast<std::size_t>(tval.tv_usec / ssPrec->m_offset),
+ ssPrec);
+ return std::string(buff_);
+}
+
+base::type::string_t DateTime::formatTime(unsigned long long time,
+ base::TimestampUnit timestampUnit) {
+ base::type::EnumType start = static_cast<base::type::EnumType>(timestampUnit);
+ const base::type::char_t *unit = base::consts::kTimeFormats[start].unit;
+ for (base::type::EnumType i = start; i < base::consts::kTimeFormatsCount - 1;
+ ++i) {
+ if (time <= base::consts::kTimeFormats[i].value) {
+ break;
+ }
+ if (base::consts::kTimeFormats[i].value == 1000.0f &&
+ time / 1000.0f < 1.9f) {
+ break;
+ }
+ time /= static_cast<decltype(time)>(base::consts::kTimeFormats[i].value);
+ unit = base::consts::kTimeFormats[i + 1].unit;
+ }
+ base::type::stringstream_t ss;
+ ss << time << " " << unit;
+ return ss.str();
+}
+
+unsigned long long
+DateTime::getTimeDifference(const struct timeval &endTime,
+ const struct timeval &startTime,
+ base::TimestampUnit timestampUnit) {
+ if (timestampUnit == base::TimestampUnit::Microsecond) {
+ return static_cast<unsigned long long>(
+ static_cast<unsigned long long>(1000000 * endTime.tv_sec +
+ endTime.tv_usec) -
+ static_cast<unsigned long long>(1000000 * startTime.tv_sec +
+ startTime.tv_usec));
+ }
+ // milliseconds
+ auto conv = [](const struct timeval &tim) {
+ return static_cast<unsigned long long>((tim.tv_sec * 1000) +
+ (tim.tv_usec / 1000));
+ };
+ return static_cast<unsigned long long>(conv(endTime) - conv(startTime));
+}
+
+struct ::tm *DateTime::buildTimeInfo(struct timeval *currTime,
+ struct ::tm *timeInfo) {
+#if ELPP_OS_UNIX
+ time_t rawTime = currTime->tv_sec;
+ ::elpptime_r(&rawTime, timeInfo);
+ return timeInfo;
+#else
+#if ELPP_COMPILER_MSVC
+ ELPP_UNUSED(currTime);
+ time_t t;
+#if defined(_USE_32BIT_TIME_T)
+ _time32(&t);
+#else
+ _time64(&t);
+#endif
+ elpptime_s(timeInfo, &t);
+ return timeInfo;
+#else
+ // For any other compilers that don't have CRT warnings issue e.g, MinGW or
+ // TDM GCC- we use different method
+ time_t rawTime = currTime->tv_sec;
+ struct tm *tmInf = elpptime(&rawTime);
+ *timeInfo = *tmInf;
+ return timeInfo;
+#endif // ELPP_COMPILER_MSVC
+#endif // ELPP_OS_UNIX
+}
+
+char *DateTime::parseFormat(char *buf, std::size_t bufSz, const char *format,
+ const struct tm *tInfo, std::size_t msec,
+ const base::SubsecondPrecision *ssPrec) {
+ const char *bufLim = buf + bufSz;
+ for (; *format; ++format) {
+ if (*format == base::consts::kFormatSpecifierChar) {
+ switch (*++format) {
+ case base::consts::kFormatSpecifierChar: // Escape
+ break;
+ case '\0': // End
+ --format;
+ break;
+ case 'd': // Day
+ buf = base::utils::Str::convertAndAddToBuff(tInfo->tm_mday, 2, buf,
+ bufLim);
+ continue;
+ case 'a': // Day of week (short)
+ buf = base::utils::Str::addToBuff(
+ base::consts::kDaysAbbrev[tInfo->tm_wday], buf, bufLim);
+ continue;
+ case 'A': // Day of week (long)
+ buf = base::utils::Str::addToBuff(base::consts::kDays[tInfo->tm_wday],
+ buf, bufLim);
+ continue;
+ case 'M': // month
+ buf = base::utils::Str::convertAndAddToBuff(tInfo->tm_mon + 1, 2, buf,
+ bufLim);
+ continue;
+ case 'b': // month (short)
+ buf = base::utils::Str::addToBuff(
+ base::consts::kMonthsAbbrev[tInfo->tm_mon], buf, bufLim);
+ continue;
+ case 'B': // month (long)
+ buf = base::utils::Str::addToBuff(base::consts::kMonths[tInfo->tm_mon],
+ buf, bufLim);
+ continue;
+ case 'y': // year (two digits)
+ buf = base::utils::Str::convertAndAddToBuff(
+ tInfo->tm_year + base::consts::kYearBase, 2, buf, bufLim);
+ continue;
+ case 'Y': // year (four digits)
+ buf = base::utils::Str::convertAndAddToBuff(
+ tInfo->tm_year + base::consts::kYearBase, 4, buf, bufLim);
+ continue;
+ case 'h': // hour (12-hour)
+ buf = base::utils::Str::convertAndAddToBuff(tInfo->tm_hour % 12, 2, buf,
+ bufLim);
+ continue;
+ case 'H': // hour (24-hour)
+ buf = base::utils::Str::convertAndAddToBuff(tInfo->tm_hour, 2, buf,
+ bufLim);
+ continue;
+ case 'm': // minute
+ buf = base::utils::Str::convertAndAddToBuff(tInfo->tm_min, 2, buf,
+ bufLim);
+ continue;
+ case 's': // second
+ buf = base::utils::Str::convertAndAddToBuff(tInfo->tm_sec, 2, buf,
+ bufLim);
+ continue;
+ case 'z': // subsecond part
+ case 'g':
+ buf = base::utils::Str::convertAndAddToBuff(msec, ssPrec->m_width, buf,
+ bufLim);
+ continue;
+ case 'F': // AM/PM
+ buf = base::utils::Str::addToBuff(
+ (tInfo->tm_hour >= 12) ? base::consts::kPm : base::consts::kAm, buf,
+ bufLim);
+ continue;
+ default:
+ continue;
+ }
+ }
+ if (buf == bufLim)
+ break;
+ *buf++ = *format;
+ }
+ return buf;
+}
+
+// CommandLineArgs
+
+void CommandLineArgs::setArgs(int argc, char **argv) {
+ m_params.clear();
+ m_paramsWithValue.clear();
+ if (argc == 0 || argv == nullptr) {
+ return;
+ }
+ m_argc = argc;
+ m_argv = argv;
+ for (int i = 1; i < m_argc; ++i) {
+ const char *v = (strstr(m_argv[i], "="));
+ if (v != nullptr && strlen(v) > 0) {
+ std::string key = std::string(m_argv[i]);
+ key = key.substr(0, key.find_first_of('='));
+ if (hasParamWithValue(key.c_str())) {
+ ELPP_INTERNAL_INFO(1, "Skipping ["
+ << key << "] arg since it already has value ["
+ << getParamValue(key.c_str()) << "]");
+ } else {
+ m_paramsWithValue.insert(std::make_pair(key, std::string(v + 1)));
+ }
+ }
+ if (v == nullptr) {
+ if (hasParam(m_argv[i])) {
+ ELPP_INTERNAL_INFO(1, "Skipping [" << m_argv[i]
+ << "] arg since it already exists");
+ } else {
+ m_params.push_back(std::string(m_argv[i]));
+ }
+ }
+ }
+}
+
+bool CommandLineArgs::hasParamWithValue(const char *paramKey) const {
+ return m_paramsWithValue.find(std::string(paramKey)) !=
+ m_paramsWithValue.end();
+}
+
+const char *CommandLineArgs::getParamValue(const char *paramKey) const {
+ std::unordered_map<std::string, std::string>::const_iterator iter =
+ m_paramsWithValue.find(std::string(paramKey));
+ return iter != m_paramsWithValue.end() ? iter->second.c_str() : "";
+}
+
+bool CommandLineArgs::hasParam(const char *paramKey) const {
+ return std::find(m_params.begin(), m_params.end(), std::string(paramKey)) !=
+ m_params.end();
+}
+
+bool CommandLineArgs::empty(void) const {
+ return m_params.empty() && m_paramsWithValue.empty();
+}
+
+std::size_t CommandLineArgs::size(void) const {
+ return m_params.size() + m_paramsWithValue.size();
+}
+
+base::type::ostream_t &operator<<(base::type::ostream_t &os,
+ const CommandLineArgs &c) {
+ for (int i = 1; i < c.m_argc; ++i) {
+ os << ELPP_LITERAL("[") << c.m_argv[i] << ELPP_LITERAL("]");
+ if (i < c.m_argc - 1) {
+ os << ELPP_LITERAL(" ");
+ }
+ }
+ return os;
+}
+
+} // namespace utils
+
+// el::base::threading
+namespace threading {
+
+#if ELPP_THREADING_ENABLED
+#if ELPP_USE_STD_THREADING
+#if ELPP_ASYNC_LOGGING
+static void msleep(int ms) {
+ // Only when async logging enabled - this is because async is strict on
+ // compiler
+#if defined(ELPP_NO_SLEEP_FOR)
+ usleep(ms * 1000);
+#else
+ std::this_thread::sleep_for(std::chrono::milliseconds(ms));
+#endif // defined(ELPP_NO_SLEEP_FOR)
+}
+#endif // ELPP_ASYNC_LOGGING
+#endif // !ELPP_USE_STD_THREADING
+#endif // ELPP_THREADING_ENABLED
+
+} // namespace threading
+
+// el::base
+
+// SubsecondPrecision
+
+void SubsecondPrecision::init(int width) {
+ if (width < 1 || width > 6) {
+ width = base::consts::kDefaultSubsecondPrecision;
+ }
+ m_width = width;
+ switch (m_width) {
+ case 3:
+ m_offset = 1000;
+ break;
+ case 4:
+ m_offset = 100;
+ break;
+ case 5:
+ m_offset = 10;
+ break;
+ case 6:
+ m_offset = 1;
+ break;
+ default:
+ m_offset = 1000;
+ break;
+ }
+}
+
+// LogFormat
+
+LogFormat::LogFormat(void)
+ : m_level(Level::Unknown), m_userFormat(base::type::string_t()),
+ m_format(base::type::string_t()), m_dateTimeFormat(std::string()),
+ m_flags(0x0), m_currentUser(base::utils::OS::currentUser()),
+ m_currentHost(base::utils::OS::currentHost()) {}
+
+LogFormat::LogFormat(Level level, const base::type::string_t &format)
+ : m_level(level), m_userFormat(format),
+ m_currentUser(base::utils::OS::currentUser()),
+ m_currentHost(base::utils::OS::currentHost()) {
+ parseFromFormat(m_userFormat);
+}
+
+LogFormat::LogFormat(const LogFormat &logFormat)
+ : m_level(logFormat.m_level), m_userFormat(logFormat.m_userFormat),
+ m_format(logFormat.m_format),
+ m_dateTimeFormat(logFormat.m_dateTimeFormat), m_flags(logFormat.m_flags),
+ m_currentUser(logFormat.m_currentUser),
+ m_currentHost(logFormat.m_currentHost) {}
+
+LogFormat::LogFormat(LogFormat &&logFormat) {
+ m_level = std::move(logFormat.m_level);
+ m_userFormat = std::move(logFormat.m_userFormat);
+ m_format = std::move(logFormat.m_format);
+ m_dateTimeFormat = std::move(logFormat.m_dateTimeFormat);
+ m_flags = std::move(logFormat.m_flags);
+ m_currentUser = std::move(logFormat.m_currentUser);
+ m_currentHost = std::move(logFormat.m_currentHost);
+}
+
+LogFormat &LogFormat::operator=(const LogFormat &logFormat) {
+ if (&logFormat != this) {
+ m_level = logFormat.m_level;
+ m_userFormat = logFormat.m_userFormat;
+ m_dateTimeFormat = logFormat.m_dateTimeFormat;
+ m_flags = logFormat.m_flags;
+ m_currentUser = logFormat.m_currentUser;
+ m_currentHost = logFormat.m_currentHost;
+ }
+ return *this;
+}
+
+bool LogFormat::operator==(const LogFormat &other) {
+ return m_level == other.m_level && m_userFormat == other.m_userFormat &&
+ m_format == other.m_format &&
+ m_dateTimeFormat == other.m_dateTimeFormat && m_flags == other.m_flags;
+}
+
+/// @brief Updates format to be used while logging.
+/// @param userFormat User provided format
+void LogFormat::parseFromFormat(const base::type::string_t &userFormat) {
+ // We make copy because we will be changing the format
+ // i.e, removing user provided date format from original format
+ // and then storing it.
+ base::type::string_t formatCopy = userFormat;
+ m_flags = 0x0;
+ auto conditionalAddFlag = [&](const base::type::char_t *specifier,
+ base::FormatFlags flag) {
+ std::size_t foundAt = base::type::string_t::npos;
+ while ((foundAt = formatCopy.find(specifier, foundAt + 1)) !=
+ base::type::string_t::npos) {
+ if (foundAt > 0 &&
+ formatCopy[foundAt - 1] == base::consts::kFormatSpecifierChar) {
+ if (hasFlag(flag)) {
+ // If we already have flag we remove the escape chars so that '%%' is
+ // turned to '%' even after specifier resolution - this is because we
+ // only replaceFirst specifier
+ formatCopy.erase(foundAt - 1, 1);
+ ++foundAt;
+ }
+ } else {
+ if (!hasFlag(flag))
+ addFlag(flag);
+ }
+ }
+ };
+ conditionalAddFlag(base::consts::kAppNameFormatSpecifier,
+ base::FormatFlags::AppName);
+ conditionalAddFlag(base::consts::kSeverityLevelFormatSpecifier,
+ base::FormatFlags::Level);
+ conditionalAddFlag(base::consts::kSeverityLevelShortFormatSpecifier,
+ base::FormatFlags::LevelShort);
+ conditionalAddFlag(base::consts::kLoggerIdFormatSpecifier,
+ base::FormatFlags::LoggerId);
+ conditionalAddFlag(base::consts::kThreadIdFormatSpecifier,
+ base::FormatFlags::ThreadId);
+ conditionalAddFlag(base::consts::kLogFileFormatSpecifier,
+ base::FormatFlags::File);
+ conditionalAddFlag(base::consts::kLogFileBaseFormatSpecifier,
+ base::FormatFlags::FileBase);
+ conditionalAddFlag(base::consts::kLogLineFormatSpecifier,
+ base::FormatFlags::Line);
+ conditionalAddFlag(base::consts::kLogLocationFormatSpecifier,
+ base::FormatFlags::Location);
+ conditionalAddFlag(base::consts::kLogFunctionFormatSpecifier,
+ base::FormatFlags::Function);
+ conditionalAddFlag(base::consts::kCurrentUserFormatSpecifier,
+ base::FormatFlags::User);
+ conditionalAddFlag(base::consts::kCurrentHostFormatSpecifier,
+ base::FormatFlags::Host);
+ conditionalAddFlag(base::consts::kMessageFormatSpecifier,
+ base::FormatFlags::LogMessage);
+ conditionalAddFlag(base::consts::kVerboseLevelFormatSpecifier,
+ base::FormatFlags::VerboseLevel);
+ // For date/time we need to extract user's date format first
+ std::size_t dateIndex = std::string::npos;
+ if ((dateIndex = formatCopy.find(base::consts::kDateTimeFormatSpecifier)) !=
+ std::string::npos) {
+ while (dateIndex != std::string::npos && dateIndex > 0 &&
+ formatCopy[dateIndex - 1] == base::consts::kFormatSpecifierChar) {
+ dateIndex = formatCopy.find(base::consts::kDateTimeFormatSpecifier,
+ dateIndex + 1);
+ }
+ if (dateIndex != std::string::npos) {
+ addFlag(base::FormatFlags::DateTime);
+ updateDateFormat(dateIndex, formatCopy);
+ }
+ }
+ m_format = formatCopy;
+ updateFormatSpec();
+}
+
+void LogFormat::updateDateFormat(std::size_t index,
+ base::type::string_t &currFormat) {
+ if (hasFlag(base::FormatFlags::DateTime)) {
+ index += ELPP_STRLEN(base::consts::kDateTimeFormatSpecifier);
+ }
+ const base::type::char_t *ptr = currFormat.c_str() + index;
+ if ((currFormat.size() > index) && (ptr[0] == '{')) {
+ // User has provided format for date/time
+ ++ptr;
+ int count = 1; // Start by 1 in order to remove starting brace
+ std::stringstream ss;
+ for (; *ptr; ++ptr, ++count) {
+ if (*ptr == '}') {
+ ++count; // In order to remove ending brace
+ break;
+ }
+ ss << static_cast<char>(*ptr);
+ }
+ currFormat.erase(index, count);
+ m_dateTimeFormat = ss.str();
+ } else {
+ // No format provided, use default
+ if (hasFlag(base::FormatFlags::DateTime)) {
+ m_dateTimeFormat = std::string(base::consts::kDefaultDateTimeFormat);
+ }
+ }
+}
+
+void LogFormat::updateFormatSpec(void) {
+ // Do not use switch over strongly typed enums because Intel C++ compilers
+ // dont support them yet.
+ if (m_level == Level::Debug) {
+ base::utils::Str::replaceFirstWithEscape(
+ m_format, base::consts::kSeverityLevelFormatSpecifier,
+ base::consts::kDebugLevelLogValue);
+ base::utils::Str::replaceFirstWithEscape(
+ m_format, base::consts::kSeverityLevelShortFormatSpecifier,
+ base::consts::kDebugLevelShortLogValue);
+ } else if (m_level == Level::Info) {
+ base::utils::Str::replaceFirstWithEscape(
+ m_format, base::consts::kSeverityLevelFormatSpecifier,
+ base::consts::kInfoLevelLogValue);
+ base::utils::Str::replaceFirstWithEscape(
+ m_format, base::consts::kSeverityLevelShortFormatSpecifier,
+ base::consts::kInfoLevelShortLogValue);
+ } else if (m_level == Level::Warning) {
+ base::utils::Str::replaceFirstWithEscape(
+ m_format, base::consts::kSeverityLevelFormatSpecifier,
+ base::consts::kWarningLevelLogValue);
+ base::utils::Str::replaceFirstWithEscape(
+ m_format, base::consts::kSeverityLevelShortFormatSpecifier,
+ base::consts::kWarningLevelShortLogValue);
+ } else if (m_level == Level::Error) {
+ base::utils::Str::replaceFirstWithEscape(
+ m_format, base::consts::kSeverityLevelFormatSpecifier,
+ base::consts::kErrorLevelLogValue);
+ base::utils::Str::replaceFirstWithEscape(
+ m_format, base::consts::kSeverityLevelShortFormatSpecifier,
+ base::consts::kErrorLevelShortLogValue);
+ } else if (m_level == Level::Fatal) {
+ base::utils::Str::replaceFirstWithEscape(
+ m_format, base::consts::kSeverityLevelFormatSpecifier,
+ base::consts::kFatalLevelLogValue);
+ base::utils::Str::replaceFirstWithEscape(
+ m_format, base::consts::kSeverityLevelShortFormatSpecifier,
+ base::consts::kFatalLevelShortLogValue);
+ } else if (m_level == Level::Verbose) {
+ base::utils::Str::replaceFirstWithEscape(
+ m_format, base::consts::kSeverityLevelFormatSpecifier,
+ base::consts::kVerboseLevelLogValue);
+ base::utils::Str::replaceFirstWithEscape(
+ m_format, base::consts::kSeverityLevelShortFormatSpecifier,
+ base::consts::kVerboseLevelShortLogValue);
+ } else if (m_level == Level::Trace) {
+ base::utils::Str::replaceFirstWithEscape(
+ m_format, base::consts::kSeverityLevelFormatSpecifier,
+ base::consts::kTraceLevelLogValue);
+ base::utils::Str::replaceFirstWithEscape(
+ m_format, base::consts::kSeverityLevelShortFormatSpecifier,
+ base::consts::kTraceLevelShortLogValue);
+ }
+ if (hasFlag(base::FormatFlags::User)) {
+ base::utils::Str::replaceFirstWithEscape(
+ m_format, base::consts::kCurrentUserFormatSpecifier, m_currentUser);
+ }
+ if (hasFlag(base::FormatFlags::Host)) {
+ base::utils::Str::replaceFirstWithEscape(
+ m_format, base::consts::kCurrentHostFormatSpecifier, m_currentHost);
+ }
+ // Ignore Level::Global and Level::Unknown
+}
+
+// TypedConfigurations
+
+TypedConfigurations::TypedConfigurations(
+ Configurations *configurations,
+ LogStreamsReferenceMapPtr logStreamsReference) {
+ m_configurations = configurations;
+ m_logStreamsReference = logStreamsReference;
+ build(m_configurations);
+}
+
+TypedConfigurations::TypedConfigurations(const TypedConfigurations &other) {
+ this->m_configurations = other.m_configurations;
+ this->m_logStreamsReference = other.m_logStreamsReference;
+ build(m_configurations);
+}
+
+bool TypedConfigurations::enabled(Level level) {
+ return getConfigByVal<bool>(level, &m_enabledMap, "enabled");
+}
+
+bool TypedConfigurations::toFile(Level level) {
+ return getConfigByVal<bool>(level, &m_toFileMap, "toFile");
+}
+
+const std::string &TypedConfigurations::filename(Level level) {
+ return getConfigByRef<std::string>(level, &m_filenameMap, "filename");
+}
+
+bool TypedConfigurations::toStandardOutput(Level level) {
+ return getConfigByVal<bool>(level, &m_toStandardOutputMap,
+ "toStandardOutput");
+}
+
+const base::LogFormat &TypedConfigurations::logFormat(Level level) {
+ return getConfigByRef<base::LogFormat>(level, &m_logFormatMap, "logFormat");
+}
+
+const base::SubsecondPrecision &
+TypedConfigurations::subsecondPrecision(Level level) {
+ return getConfigByRef<base::SubsecondPrecision>(
+ level, &m_subsecondPrecisionMap, "subsecondPrecision");
+}
+
+const base::MillisecondsWidth &
+TypedConfigurations::millisecondsWidth(Level level) {
+ return getConfigByRef<base::MillisecondsWidth>(
+ level, &m_subsecondPrecisionMap, "millisecondsWidth");
+}
+
+bool TypedConfigurations::performanceTracking(Level level) {
+ return getConfigByVal<bool>(level, &m_performanceTrackingMap,
+ "performanceTracking");
+}
+
+base::type::fstream_t *TypedConfigurations::fileStream(Level level) {
+ return getConfigByRef<base::FileStreamPtr>(level, &m_fileStreamMap,
+ "fileStream")
+ .get();
+}
+
+std::size_t TypedConfigurations::maxLogFileSize(Level level) {
+ return getConfigByVal<std::size_t>(level, &m_maxLogFileSizeMap,
+ "maxLogFileSize");
+}
+
+std::size_t TypedConfigurations::logFlushThreshold(Level level) {
+ return getConfigByVal<std::size_t>(level, &m_logFlushThresholdMap,
+ "logFlushThreshold");
+}
+
+void TypedConfigurations::build(Configurations *configurations) {
+ base::threading::ScopedLock scopedLock(lock());
+ auto getBool = [](std::string boolStr) -> bool { // Pass by value for trimming
+ base::utils::Str::trim(boolStr);
+ return (boolStr == "TRUE" || boolStr == "true" || boolStr == "1");
+ };
+ std::vector<Configuration *> withFileSizeLimit;
+ for (Configurations::const_iterator it = configurations->begin();
+ it != configurations->end(); ++it) {
+ Configuration *conf = *it;
+ // We cannot use switch on strong enums because Intel C++ dont support them
+ // yet
+ if (conf->configurationType() == ConfigurationType::Enabled) {
+ setValue(conf->level(), getBool(conf->value()), &m_enabledMap);
+ } else if (conf->configurationType() == ConfigurationType::ToFile) {
+ setValue(conf->level(), getBool(conf->value()), &m_toFileMap);
+ } else if (conf->configurationType() ==
+ ConfigurationType::ToStandardOutput) {
+ setValue(conf->level(), getBool(conf->value()), &m_toStandardOutputMap);
+ } else if (conf->configurationType() == ConfigurationType::Filename) {
+ // We do not yet configure filename but we will configure in another
+ // loop. This is because if file cannot be created, we will force ToFile
+ // to be false. Because configuring logger is not necessarily performance
+ // sensitive operation, we can live with another loop; (by the way this
+ // loop is not very heavy either)
+ } else if (conf->configurationType() == ConfigurationType::Format) {
+ setValue(conf->level(),
+ base::LogFormat(conf->level(),
+ base::type::string_t(conf->value().begin(),
+ conf->value().end())),
+ &m_logFormatMap);
+ } else if (conf->configurationType() ==
+ ConfigurationType::SubsecondPrecision) {
+ setValue(
+ Level::Global,
+ base::SubsecondPrecision(static_cast<int>(getULong(conf->value()))),
+ &m_subsecondPrecisionMap);
+ } else if (conf->configurationType() ==
+ ConfigurationType::PerformanceTracking) {
+ setValue(Level::Global, getBool(conf->value()),
+ &m_performanceTrackingMap);
+ } else if (conf->configurationType() == ConfigurationType::MaxLogFileSize) {
+ auto v = getULong(conf->value());
+ setValue(conf->level(), static_cast<std::size_t>(v),
+ &m_maxLogFileSizeMap);
+ if (v != 0) {
+ withFileSizeLimit.push_back(conf);
+ }
+ } else if (conf->configurationType() ==
+ ConfigurationType::LogFlushThreshold) {
+ setValue(conf->level(), static_cast<std::size_t>(getULong(conf->value())),
+ &m_logFlushThresholdMap);
+ }
+ }
+ // As mentioned earlier, we will now set filename configuration in separate
+ // loop to deal with non-existent files
+ for (Configurations::const_iterator it = configurations->begin();
+ it != configurations->end(); ++it) {
+ Configuration *conf = *it;
+ if (conf->configurationType() == ConfigurationType::Filename) {
+ insertFile(conf->level(), conf->value());
+ }
+ }
+ for (std::vector<Configuration *>::iterator conf = withFileSizeLimit.begin();
+ conf != withFileSizeLimit.end(); ++conf) {
+ // This is not unsafe as mutex is locked in currect scope
+ unsafeValidateFileRolling((*conf)->level(),
+ base::defaultPreRollOutCallback);
+ }
+}
+
+unsigned long TypedConfigurations::getULong(std::string confVal) {
+ bool valid = true;
+ base::utils::Str::trim(confVal);
+ valid = !confVal.empty() &&
+ std::find_if(confVal.begin(), confVal.end(), [](char c) {
+ return !base::utils::Str::isDigit(c);
+ }) == confVal.end();
+ if (!valid) {
+ valid = false;
+ ELPP_ASSERT(valid,
+ "Configuration value not a valid integer [" << confVal << "]");
+ return 0;
+ }
+ return atol(confVal.c_str());
+}
+
+std::string TypedConfigurations::resolveFilename(const std::string &filename) {
+ std::string resultingFilename = filename;
+ std::size_t dateIndex = std::string::npos;
+ std::string dateTimeFormatSpecifierStr =
+ std::string(base::consts::kDateTimeFormatSpecifierForFilename);
+ if ((dateIndex = resultingFilename.find(
+ dateTimeFormatSpecifierStr.c_str())) != std::string::npos) {
+ while (dateIndex > 0 && resultingFilename[dateIndex - 1] ==
+ base::consts::kFormatSpecifierChar) {
+ dateIndex = resultingFilename.find(dateTimeFormatSpecifierStr.c_str(),
+ dateIndex + 1);
+ }
+ if (dateIndex != std::string::npos) {
+ const char *ptr = resultingFilename.c_str() + dateIndex;
+ // Goto end of specifier
+ ptr += dateTimeFormatSpecifierStr.size();
+ std::string fmt;
+ if ((resultingFilename.size() > dateIndex) && (ptr[0] == '{')) {
+ // User has provided format for date/time
+ ++ptr;
+ int count = 1; // Start by 1 in order to remove starting brace
+ std::stringstream ss;
+ for (; *ptr; ++ptr, ++count) {
+ if (*ptr == '}') {
+ ++count; // In order to remove ending brace
+ break;
+ }
+ ss << *ptr;
+ }
+ resultingFilename.erase(dateIndex + dateTimeFormatSpecifierStr.size(),
+ count);
+ fmt = ss.str();
+ } else {
+ fmt = std::string(base::consts::kDefaultDateTimeFormatInFilename);
+ }
+ base::SubsecondPrecision ssPrec(3);
+ std::string now =
+ base::utils::DateTime::getDateTime(fmt.c_str(), &ssPrec);
+ base::utils::Str::replaceAll(
+ now, '/',
+ '-'); // Replace path element since we are dealing with filename
+ base::utils::Str::replaceAll(resultingFilename,
+ dateTimeFormatSpecifierStr, now);
+ }
+ }
+ return resultingFilename;
+}
+
+void TypedConfigurations::insertFile(Level level,
+ const std::string &fullFilename) {
+ std::string resolvedFilename = resolveFilename(fullFilename);
+ if (resolvedFilename.empty()) {
+ std::cerr << "Could not load empty file for logging, please re-check your "
+ "configurations for level ["
+ << LevelHelper::convertToString(level) << "]";
+ }
+ std::string filePath = base::utils::File::extractPathFromFilename(
+ resolvedFilename, base::consts::kFilePathSeparator);
+ if (filePath.size() < resolvedFilename.size()) {
+ base::utils::File::createPath(filePath);
+ }
+ auto create = [&](Level level) {
+ base::LogStreamsReferenceMap::iterator filestreamIter =
+ m_logStreamsReference->find(resolvedFilename);
+ base::type::fstream_t *fs = nullptr;
+ if (filestreamIter == m_logStreamsReference->end()) {
+ // We need a completely new stream, nothing to share with
+ fs = base::utils::File::newFileStream(resolvedFilename);
+ m_filenameMap.insert(std::make_pair(level, resolvedFilename));
+ m_fileStreamMap.insert(std::make_pair(level, base::FileStreamPtr(fs)));
+ m_logStreamsReference->insert(std::make_pair(
+ resolvedFilename, base::FileStreamPtr(m_fileStreamMap.at(level))));
+ } else {
+ // Woops! we have an existing one, share it!
+ m_filenameMap.insert(std::make_pair(level, filestreamIter->first));
+ m_fileStreamMap.insert(
+ std::make_pair(level, base::FileStreamPtr(filestreamIter->second)));
+ fs = filestreamIter->second.get();
+ }
+ if (fs == nullptr) {
+ // We display bad file error from newFileStream()
+ ELPP_INTERNAL_ERROR("Setting [TO_FILE] of ["
+ << LevelHelper::convertToString(level)
+ << "] to FALSE",
+ false);
+ setValue(level, false, &m_toFileMap);
+ }
+ };
+ // If we dont have file conf for any level, create it for Level::Global first
+ // otherwise create for specified level
+ create(m_filenameMap.empty() && m_fileStreamMap.empty() ? Level::Global
+ : level);
+}
+
+bool TypedConfigurations::unsafeValidateFileRolling(
+ Level level, const PreRollOutCallback &preRollOutCallback) {
+ base::type::fstream_t *fs =
+ unsafeGetConfigByRef(level, &m_fileStreamMap, "fileStream").get();
+ if (fs == nullptr) {
+ return true;
+ }
+ std::size_t maxLogFileSize =
+ unsafeGetConfigByVal(level, &m_maxLogFileSizeMap, "maxLogFileSize");
+ std::size_t currFileSize = base::utils::File::getSizeOfFile(fs);
+ if (maxLogFileSize != 0 && currFileSize >= maxLogFileSize) {
+ std::string fname = unsafeGetConfigByRef(level, &m_filenameMap, "filename");
+ ELPP_INTERNAL_INFO(1, "Truncating log file ["
+ << fname
+ << "] as a result of configurations for level ["
+ << LevelHelper::convertToString(level) << "]");
+ fs->close();
+ preRollOutCallback(fname.c_str(), currFileSize);
+ fs->open(fname, std::fstream::out | std::fstream::trunc);
+ return true;
+ }
+ return false;
+}
+
+// RegisteredHitCounters
+
+bool RegisteredHitCounters::validateEveryN(const char *filename,
+ base::type::LineNumber lineNumber,
+ std::size_t n) {
+ base::threading::ScopedLock scopedLock(lock());
+ base::HitCounter *counter = get(filename, lineNumber);
+ if (counter == nullptr) {
+ registerNew(counter = new base::HitCounter(filename, lineNumber));
+ }
+ counter->validateHitCounts(n);
+ bool result =
+ (n >= 1 && counter->hitCounts() != 0 && counter->hitCounts() % n == 0);
+ return result;
+}
+
+/// @brief Validates counter for hits >= N, i.e, registers new if does not exist
+/// otherwise updates original one
+/// @return True if validation resulted in triggering hit. Meaning logs should
+/// be written everytime true is returned
+bool RegisteredHitCounters::validateAfterN(const char *filename,
+ base::type::LineNumber lineNumber,
+ std::size_t n) {
+ base::threading::ScopedLock scopedLock(lock());
+ base::HitCounter *counter = get(filename, lineNumber);
+ if (counter == nullptr) {
+ registerNew(counter = new base::HitCounter(filename, lineNumber));
+ }
+ // Do not use validateHitCounts here since we do not want to reset counter
+ // here Note the >= instead of > because we are incrementing after this check
+ if (counter->hitCounts() >= n)
+ return true;
+ counter->increment();
+ return false;
+}
+
+/// @brief Validates counter for hits are <= n, i.e, registers new if does not
+/// exist otherwise updates original one
+/// @return True if validation resulted in triggering hit. Meaning logs should
+/// be written everytime true is returned
+bool RegisteredHitCounters::validateNTimes(const char *filename,
+ base::type::LineNumber lineNumber,
+ std::size_t n) {
+ base::threading::ScopedLock scopedLock(lock());
+ base::HitCounter *counter = get(filename, lineNumber);
+ if (counter == nullptr) {
+ registerNew(counter = new base::HitCounter(filename, lineNumber));
+ }
+ counter->increment();
+ // Do not use validateHitCounts here since we do not want to reset counter
+ // here
+ if (counter->hitCounts() <= n)
+ return true;
+ return false;
+}
+
+// RegisteredLoggers
+
+RegisteredLoggers::RegisteredLoggers(const LogBuilderPtr &defaultLogBuilder)
+ : m_defaultLogBuilder(defaultLogBuilder) {
+ m_defaultConfigurations.setToDefault();
+ m_logStreamsReference = std::make_shared<base::LogStreamsReferenceMap>();
+}
+
+Logger *RegisteredLoggers::get(const std::string &id, bool forceCreation) {
+ base::threading::ScopedLock scopedLock(lock());
+ Logger *logger_ = base::utils::Registry<Logger, std::string>::get(id);
+ if (logger_ == nullptr && forceCreation) {
+ bool validId = Logger::isValidId(id);
+ if (!validId) {
+ ELPP_ASSERT(validId, "Invalid logger ID ["
+ << id << "]. Not registering this logger.");
+ return nullptr;
+ }
+ logger_ = new Logger(id, m_defaultConfigurations, m_logStreamsReference);
+ logger_->m_logBuilder = m_defaultLogBuilder;
+ registerNew(id, logger_);
+ LoggerRegistrationCallback *callback = nullptr;
+ for (const std::pair<std::string, base::type::LoggerRegistrationCallbackPtr>
+ h : m_loggerRegistrationCallbacks) {
+ callback = h.second.get();
+ if (callback != nullptr && callback->enabled()) {
+ callback->handle(logger_);
+ }
+ }
+ }
+ return logger_;
+}
+
+bool RegisteredLoggers::remove(const std::string &id) {
+ if (id == base::consts::kDefaultLoggerId) {
+ return false;
+ }
+ // get has internal lock
+ Logger *logger = base::utils::Registry<Logger, std::string>::get(id);
+ if (logger != nullptr) {
+ // unregister has internal lock
+ unregister(logger);
+ }
+ return true;
+}
+
+void RegisteredLoggers::unsafeFlushAll(void) {
+ ELPP_INTERNAL_INFO(1, "Flushing all log files");
+ for (base::LogStreamsReferenceMap::iterator it =
+ m_logStreamsReference->begin();
+ it != m_logStreamsReference->end(); ++it) {
+ if (it->second.get() == nullptr)
+ continue;
+ it->second->flush();
+ }
+}
+
+// VRegistry
+
+VRegistry::VRegistry(base::type::VerboseLevel level,
+ base::type::EnumType *pFlags)
+ : m_level(level), m_pFlags(pFlags) {}
+
+/// @brief Sets verbose level. Accepted range is 0-9
+void VRegistry::setLevel(base::type::VerboseLevel level) {
+ base::threading::ScopedLock scopedLock(lock());
+ if (level > 9)
+ m_level = base::consts::kMaxVerboseLevel;
+ else
+ m_level = level;
+}
+
+void VRegistry::setModules(const char *modules) {
+ base::threading::ScopedLock scopedLock(lock());
+ auto addSuffix = [](std::stringstream &ss, const char *sfx,
+ const char *prev) {
+ if (prev != nullptr &&
+ base::utils::Str::endsWith(ss.str(), std::string(prev))) {
+ std::string chr(ss.str().substr(0, ss.str().size() - strlen(prev)));
+ ss.str(std::string(""));
+ ss << chr;
+ }
+ if (base::utils::Str::endsWith(ss.str(), std::string(sfx))) {
+ std::string chr(ss.str().substr(0, ss.str().size() - strlen(sfx)));
+ ss.str(std::string(""));
+ ss << chr;
+ }
+ ss << sfx;
+ };
+ auto insert = [&](std::stringstream &ss, base::type::VerboseLevel level) {
+ if (!base::utils::hasFlag(LoggingFlag::DisableVModulesExtensions,
+ *m_pFlags)) {
+ addSuffix(ss, ".h", nullptr);
+ m_modules.insert(std::make_pair(ss.str(), level));
+ addSuffix(ss, ".c", ".h");
+ m_modules.insert(std::make_pair(ss.str(), level));
+ addSuffix(ss, ".cpp", ".c");
+ m_modules.insert(std::make_pair(ss.str(), level));
+ addSuffix(ss, ".cc", ".cpp");
+ m_modules.insert(std::make_pair(ss.str(), level));
+ addSuffix(ss, ".cxx", ".cc");
+ m_modules.insert(std::make_pair(ss.str(), level));
+ addSuffix(ss, ".-inl.h", ".cxx");
+ m_modules.insert(std::make_pair(ss.str(), level));
+ addSuffix(ss, ".hxx", ".-inl.h");
+ m_modules.insert(std::make_pair(ss.str(), level));
+ addSuffix(ss, ".hpp", ".hxx");
+ m_modules.insert(std::make_pair(ss.str(), level));
+ addSuffix(ss, ".hh", ".hpp");
+ }
+ m_modules.insert(std::make_pair(ss.str(), level));
+ };
+ bool isMod = true;
+ bool isLevel = false;
+ std::stringstream ss;
+ int level = -1;
+ for (; *modules; ++modules) {
+ switch (*modules) {
+ case '=':
+ isLevel = true;
+ isMod = false;
+ break;
+ case ',':
+ isLevel = false;
+ isMod = true;
+ if (!ss.str().empty() && level != -1) {
+ insert(ss, static_cast<base::type::VerboseLevel>(level));
+ ss.str(std::string(""));
+ level = -1;
+ }
+ break;
+ default:
+ if (isMod) {
+ ss << *modules;
+ } else if (isLevel) {
+ if (isdigit(*modules)) {
+ level = static_cast<base::type::VerboseLevel>(*modules) - 48;
+ }
+ }
+ break;
+ }
+ }
+ if (!ss.str().empty() && level != -1) {
+ insert(ss, static_cast<base::type::VerboseLevel>(level));
+ }
+}
+
+bool VRegistry::allowed(base::type::VerboseLevel vlevel, const char *file) {
+ base::threading::ScopedLock scopedLock(lock());
+ if (m_modules.empty() || file == nullptr) {
+ return vlevel <= m_level;
+ } else {
+ char baseFilename[base::consts::kSourceFilenameMaxLength] = "";
+ base::utils::File::buildBaseFilename(file, baseFilename);
+ std::unordered_map<std::string, base::type::VerboseLevel>::iterator it =
+ m_modules.begin();
+ for (; it != m_modules.end(); ++it) {
+ if (base::utils::Str::wildCardMatch(baseFilename, it->first.c_str())) {
+ return vlevel <= it->second;
+ }
+ }
+ if (base::utils::hasFlag(LoggingFlag::AllowVerboseIfModuleNotSpecified,
+ *m_pFlags)) {
+ return true;
+ }
+ return false;
+ }
+}
+
+void VRegistry::setFromArgs(
+ const base::utils::CommandLineArgs *commandLineArgs) {
+ if (commandLineArgs->hasParam("-v") ||
+ commandLineArgs->hasParam("--verbose") ||
+ commandLineArgs->hasParam("-V") ||
+ commandLineArgs->hasParam("--VERBOSE")) {
+ setLevel(base::consts::kMaxVerboseLevel);
+ } else if (commandLineArgs->hasParamWithValue("--v")) {
+ setLevel(static_cast<base::type::VerboseLevel>(
+ atoi(commandLineArgs->getParamValue("--v"))));
+ } else if (commandLineArgs->hasParamWithValue("--V")) {
+ setLevel(static_cast<base::type::VerboseLevel>(
+ atoi(commandLineArgs->getParamValue("--V"))));
+ } else if ((commandLineArgs->hasParamWithValue("-vmodule")) &&
+ vModulesEnabled()) {
+ setModules(commandLineArgs->getParamValue("-vmodule"));
+ } else if (commandLineArgs->hasParamWithValue("-VMODULE") &&
+ vModulesEnabled()) {
+ setModules(commandLineArgs->getParamValue("-VMODULE"));
+ }
+}
+
+#if !defined(ELPP_DEFAULT_LOGGING_FLAGS)
+#define ELPP_DEFAULT_LOGGING_FLAGS 0x0
+#endif // !defined(ELPP_DEFAULT_LOGGING_FLAGS)
+// Storage
+#if ELPP_ASYNC_LOGGING
+Storage::Storage(const LogBuilderPtr &defaultLogBuilder,
+ base::IWorker *asyncDispatchWorker)
+ :
+#else
+Storage::Storage(const LogBuilderPtr &defaultLogBuilder)
+ :
+#endif // ELPP_ASYNC_LOGGING
+ m_registeredHitCounters(new base::RegisteredHitCounters()),
+ m_registeredLoggers(new base::RegisteredLoggers(defaultLogBuilder)),
+ m_flags(ELPP_DEFAULT_LOGGING_FLAGS),
+ m_vRegistry(new base::VRegistry(0, &m_flags)),
+
+#if ELPP_ASYNC_LOGGING
+ m_asyncLogQueue(new base::AsyncLogQueue()),
+ m_asyncDispatchWorker(asyncDispatchWorker),
+#endif // ELPP_ASYNC_LOGGING
+
+ m_preRollOutCallback(base::defaultPreRollOutCallback) {
+ // Register default logger
+ m_registeredLoggers->get(std::string(base::consts::kDefaultLoggerId));
+ // We register default logger anyway (worse case it's not going to register)
+ // just in case
+ m_registeredLoggers->get("default");
+
+#if defined(ELPP_FEATURE_ALL) || defined(ELPP_FEATURE_PERFORMANCE_TRACKING)
+ // Register performance logger and reconfigure format
+ Logger *performanceLogger =
+ m_registeredLoggers->get(std::string(base::consts::kPerformanceLoggerId));
+ m_registeredLoggers->get("performance");
+ performanceLogger->configurations()->setGlobally(
+ ConfigurationType::Format, std::string("%datetime %level %msg"));
+ performanceLogger->reconfigure();
+#endif // defined(ELPP_FEATURE_ALL) ||
+ // defined(ELPP_FEATURE_PERFORMANCE_TRACKING)
+
+#if defined(ELPP_SYSLOG)
+ // Register syslog logger and reconfigure format
+ Logger *sysLogLogger =
+ m_registeredLoggers->get(std::string(base::consts::kSysLogLoggerId));
+ sysLogLogger->configurations()->setGlobally(ConfigurationType::Format,
+ std::string("%level: %msg"));
+ sysLogLogger->reconfigure();
+#endif // defined(ELPP_SYSLOG)
+ addFlag(LoggingFlag::AllowVerboseIfModuleNotSpecified);
+#if ELPP_ASYNC_LOGGING
+ installLogDispatchCallback<base::AsyncLogDispatchCallback>(
+ std::string("AsyncLogDispatchCallback"));
+#else
+ installLogDispatchCallback<base::DefaultLogDispatchCallback>(
+ std::string("DefaultLogDispatchCallback"));
+#endif // ELPP_ASYNC_LOGGING
+#if defined(ELPP_FEATURE_ALL) || defined(ELPP_FEATURE_PERFORMANCE_TRACKING)
+ installPerformanceTrackingCallback<base::DefaultPerformanceTrackingCallback>(
+ std::string("DefaultPerformanceTrackingCallback"));
+#endif // defined(ELPP_FEATURE_ALL) ||
+ // defined(ELPP_FEATURE_PERFORMANCE_TRACKING)
+ ELPP_INTERNAL_INFO(1, "Easylogging++ has been initialized");
+#if ELPP_ASYNC_LOGGING
+ m_asyncDispatchWorker->start();
+#endif // ELPP_ASYNC_LOGGING
+}
+
+Storage::~Storage(void) {
+ ELPP_INTERNAL_INFO(4, "Destroying storage");
+#if ELPP_ASYNC_LOGGING
+ ELPP_INTERNAL_INFO(5, "Replacing log dispatch callback to synchronous");
+ uninstallLogDispatchCallback<base::AsyncLogDispatchCallback>(
+ std::string("AsyncLogDispatchCallback"));
+ installLogDispatchCallback<base::DefaultLogDispatchCallback>(
+ std::string("DefaultLogDispatchCallback"));
+ ELPP_INTERNAL_INFO(5, "Destroying asyncDispatchWorker");
+ base::utils::safeDelete(m_asyncDispatchWorker);
+ ELPP_INTERNAL_INFO(5, "Destroying asyncLogQueue");
+ base::utils::safeDelete(m_asyncLogQueue);
+#endif // ELPP_ASYNC_LOGGING
+ ELPP_INTERNAL_INFO(5, "Destroying registeredHitCounters");
+ base::utils::safeDelete(m_registeredHitCounters);
+ ELPP_INTERNAL_INFO(5, "Destroying registeredLoggers");
+ base::utils::safeDelete(m_registeredLoggers);
+ ELPP_INTERNAL_INFO(5, "Destroying vRegistry");
+ base::utils::safeDelete(m_vRegistry);
+}
+
+bool Storage::hasCustomFormatSpecifier(const char *formatSpecifier) {
+ base::threading::ScopedLock scopedLock(customFormatSpecifiersLock());
+ return std::find(m_customFormatSpecifiers.begin(),
+ m_customFormatSpecifiers.end(),
+ formatSpecifier) != m_customFormatSpecifiers.end();
+}
+
+void Storage::installCustomFormatSpecifier(
+ const CustomFormatSpecifier &customFormatSpecifier) {
+ if (hasCustomFormatSpecifier(customFormatSpecifier.formatSpecifier())) {
+ return;
+ }
+ base::threading::ScopedLock scopedLock(customFormatSpecifiersLock());
+ m_customFormatSpecifiers.push_back(customFormatSpecifier);
+}
+
+bool Storage::uninstallCustomFormatSpecifier(const char *formatSpecifier) {
+ base::threading::ScopedLock scopedLock(customFormatSpecifiersLock());
+ std::vector<CustomFormatSpecifier>::iterator it =
+ std::find(m_customFormatSpecifiers.begin(),
+ m_customFormatSpecifiers.end(), formatSpecifier);
+ if (it != m_customFormatSpecifiers.end() &&
+ strcmp(formatSpecifier, it->formatSpecifier()) == 0) {
+ m_customFormatSpecifiers.erase(it);
+ return true;
+ }
+ return false;
+}
+
+void Storage::setApplicationArguments(int argc, char **argv) {
+ m_commandLineArgs.setArgs(argc, argv);
+ m_vRegistry->setFromArgs(commandLineArgs());
+ // default log file
+#if !defined(ELPP_DISABLE_LOG_FILE_FROM_ARG)
+ if (m_commandLineArgs.hasParamWithValue(base::consts::kDefaultLogFileParam)) {
+ Configurations c;
+ c.setGlobally(ConfigurationType::Filename,
+ std::string(m_commandLineArgs.getParamValue(
+ base::consts::kDefaultLogFileParam)));
+ registeredLoggers()->setDefaultConfigurations(c);
+ for (base::RegisteredLoggers::iterator it = registeredLoggers()->begin();
+ it != registeredLoggers()->end(); ++it) {
+ it->second->configure(c);
+ }
+ }
+#endif // !defined(ELPP_DISABLE_LOG_FILE_FROM_ARG)
+#if defined(ELPP_LOGGING_FLAGS_FROM_ARG)
+ if (m_commandLineArgs.hasParamWithValue(base::consts::kLoggingFlagsParam)) {
+ int userInput =
+ atoi(m_commandLineArgs.getParamValue(base::consts::kLoggingFlagsParam));
+ if (ELPP_DEFAULT_LOGGING_FLAGS == 0x0) {
+ m_flags = userInput;
+ } else {
+ base::utils::addFlag<base::type::EnumType>(userInput, &m_flags);
+ }
+ }
+#endif // defined(ELPP_LOGGING_FLAGS_FROM_ARG)
+}
+
+} // namespace base
+
+// LogDispatchCallback
+#if defined(ELPP_THREAD_SAFE)
+void LogDispatchCallback::handle(const LogDispatchData *data) {
+ base::threading::ScopedLock scopedLock(m_fileLocksMapLock);
+ std::string filename =
+ data->logMessage()->logger()->typedConfigurations()->filename(
+ data->logMessage()->level());
+ auto lock = m_fileLocks.find(filename);
+ if (lock == m_fileLocks.end()) {
+ m_fileLocks.emplace(std::make_pair(
+ filename,
+ std::unique_ptr<base::threading::Mutex>(new base::threading::Mutex)));
+ }
+}
+#else
+void LogDispatchCallback::handle(const LogDispatchData * /*data*/) {}
+#endif
+
+base::threading::Mutex &
+LogDispatchCallback::fileHandle(const LogDispatchData *data) {
+ auto it = m_fileLocks.find(
+ data->logMessage()->logger()->typedConfigurations()->filename(
+ data->logMessage()->level()));
+ return *(it->second.get());
+}
+
+namespace base {
+// DefaultLogDispatchCallback
+
+void DefaultLogDispatchCallback::handle(const LogDispatchData *data) {
+#if defined(ELPP_THREAD_SAFE)
+ LogDispatchCallback::handle(data);
+ base::threading::ScopedLock scopedLock(fileHandle(data));
+#endif
+ m_data = data;
+ dispatch(m_data->logMessage()->logger()->logBuilder()->build(
+ m_data->logMessage(),
+ m_data->dispatchAction() == base::DispatchAction::NormalLog));
+}
+
+void DefaultLogDispatchCallback::dispatch(base::type::string_t &&logLine) {
+ if (m_data->dispatchAction() == base::DispatchAction::NormalLog) {
+ if (m_data->logMessage()->logger()->m_typedConfigurations->toFile(
+ m_data->logMessage()->level())) {
+ base::type::fstream_t *fs =
+ m_data->logMessage()->logger()->m_typedConfigurations->fileStream(
+ m_data->logMessage()->level());
+ if (fs != nullptr) {
+ fs->write(logLine.c_str(), logLine.size());
+ if (fs->fail()) {
+ ELPP_INTERNAL_ERROR(
+ "Unable to write log to file ["
+ << m_data->logMessage()
+ ->logger()
+ ->m_typedConfigurations->filename(
+ m_data->logMessage()->level())
+ << "].\n"
+ << "Few possible reasons (could be something else):\n"
+ << " * Permission denied\n"
+ << " * Disk full\n"
+ << " * Disk is not writable",
+ true);
+ } else {
+ if (ELPP->hasFlag(LoggingFlag::ImmediateFlush) ||
+ (m_data->logMessage()->logger()->isFlushNeeded(
+ m_data->logMessage()->level()))) {
+ m_data->logMessage()->logger()->flush(m_data->logMessage()->level(),
+ fs);
+ }
+ }
+ } else {
+ ELPP_INTERNAL_ERROR(
+ "Log file for ["
+ << LevelHelper::convertToString(m_data->logMessage()->level())
+ << "] "
+ << "has not been configured but [TO_FILE] is configured to "
+ "TRUE. [Logger ID: "
+ << m_data->logMessage()->logger()->id() << "]",
+ false);
+ }
+ }
+ if (m_data->logMessage()->logger()->m_typedConfigurations->toStandardOutput(
+ m_data->logMessage()->level())) {
+ if (ELPP->hasFlag(LoggingFlag::ColoredTerminalOutput))
+ m_data->logMessage()->logger()->logBuilder()->convertToColoredOutput(
+ &logLine, m_data->logMessage()->level());
+ ELPP_COUT << ELPP_COUT_LINE(logLine);
+ }
+ }
+#if defined(ELPP_SYSLOG)
+ else if (m_data->dispatchAction() == base::DispatchAction::SysLog) {
+ // Determine syslog priority
+ int sysLogPriority = 0;
+ if (m_data->logMessage()->level() == Level::Fatal)
+ sysLogPriority = LOG_EMERG;
+ else if (m_data->logMessage()->level() == Level::Error)
+ sysLogPriority = LOG_ERR;
+ else if (m_data->logMessage()->level() == Level::Warning)
+ sysLogPriority = LOG_WARNING;
+ else if (m_data->logMessage()->level() == Level::Info)
+ sysLogPriority = LOG_INFO;
+ else if (m_data->logMessage()->level() == Level::Debug)
+ sysLogPriority = LOG_DEBUG;
+ else
+ sysLogPriority = LOG_NOTICE;
+#if defined(ELPP_UNICODE)
+ char *line = base::utils::Str::wcharPtrToCharPtr(logLine.c_str());
+ syslog(sysLogPriority, "%s", line);
+ free(line);
+#else
+ syslog(sysLogPriority, "%s", logLine.c_str());
+#endif
+ }
+#endif // defined(ELPP_SYSLOG)
+}
+
+#if ELPP_ASYNC_LOGGING
+
+// AsyncLogDispatchCallback
+
+void AsyncLogDispatchCallback::handle(const LogDispatchData *data) {
+ base::type::string_t logLine =
+ data->logMessage()->logger()->logBuilder()->build(
+ data->logMessage(),
+ data->dispatchAction() == base::DispatchAction::NormalLog);
+ if (data->dispatchAction() == base::DispatchAction::NormalLog &&
+ data->logMessage()->logger()->typedConfigurations()->toStandardOutput(
+ data->logMessage()->level())) {
+ if (ELPP->hasFlag(LoggingFlag::ColoredTerminalOutput))
+ data->logMessage()->logger()->logBuilder()->convertToColoredOutput(
+ &logLine, data->logMessage()->level());
+ ELPP_COUT << ELPP_COUT_LINE(logLine);
+ }
+ // Save resources and only queue if we want to write to file otherwise just
+ // ignore handler
+ if (data->logMessage()->logger()->typedConfigurations()->toFile(
+ data->logMessage()->level())) {
+ ELPP->asyncLogQueue()->push(
+ AsyncLogItem(*(data->logMessage()), *data, logLine));
+ }
+}
+
+// AsyncDispatchWorker
+AsyncDispatchWorker::AsyncDispatchWorker() { setContinueRunning(false); }
+
+AsyncDispatchWorker::~AsyncDispatchWorker() {
+ setContinueRunning(false);
+ ELPP_INTERNAL_INFO(6, "Stopping dispatch worker - Cleaning log queue");
+ clean();
+ ELPP_INTERNAL_INFO(6, "Log queue cleaned");
+}
+
+bool AsyncDispatchWorker::clean(void) {
+ std::mutex m;
+ std::unique_lock<std::mutex> lk(m);
+ cv.wait(lk, [] { return !ELPP->asyncLogQueue()->empty(); });
+ emptyQueue();
+ lk.unlock();
+ cv.notify_one();
+ return ELPP->asyncLogQueue()->empty();
+}
+
+void AsyncDispatchWorker::emptyQueue(void) {
+ while (!ELPP->asyncLogQueue()->empty()) {
+ AsyncLogItem data = ELPP->asyncLogQueue()->next();
+ handle(&data);
+ base::threading::msleep(100);
+ }
+}
+
+void AsyncDispatchWorker::start(void) {
+ base::threading::msleep(5000); // 5s (why?)
+ setContinueRunning(true);
+ std::thread t1(&AsyncDispatchWorker::run, this);
+ t1.join();
+}
+
+void AsyncDispatchWorker::handle(AsyncLogItem *logItem) {
+ LogDispatchData *data = logItem->data();
+ LogMessage *logMessage = logItem->logMessage();
+ Logger *logger = logMessage->logger();
+ base::TypedConfigurations *conf = logger->typedConfigurations();
+ base::type::string_t logLine = logItem->logLine();
+ if (data->dispatchAction() == base::DispatchAction::NormalLog) {
+ if (conf->toFile(logMessage->level())) {
+ base::type::fstream_t *fs = conf->fileStream(logMessage->level());
+ if (fs != nullptr) {
+ fs->write(logLine.c_str(), logLine.size());
+ if (fs->fail()) {
+ ELPP_INTERNAL_ERROR(
+ "Unable to write log to file ["
+ << conf->filename(logMessage->level()) << "].\n"
+ << "Few possible reasons (could be something else):\n"
+ << " * Permission denied\n"
+ << " * Disk full\n"
+ << " * Disk is not writable",
+ true);
+ } else {
+ if (ELPP->hasFlag(LoggingFlag::ImmediateFlush) ||
+ (logger->isFlushNeeded(logMessage->level()))) {
+ logger->flush(logMessage->level(), fs);
+ }
+ }
+ } else {
+ ELPP_INTERNAL_ERROR(
+ "Log file for ["
+ << LevelHelper::convertToString(logMessage->level()) << "] "
+ << "has not been configured but [TO_FILE] is configured to "
+ "TRUE. [Logger ID: "
+ << logger->id() << "]",
+ false);
+ }
+ }
+ }
+#if defined(ELPP_SYSLOG)
+ else if (data->dispatchAction() == base::DispatchAction::SysLog) {
+ // Determine syslog priority
+ int sysLogPriority = 0;
+ if (logMessage->level() == Level::Fatal)
+ sysLogPriority = LOG_EMERG;
+ else if (logMessage->level() == Level::Error)
+ sysLogPriority = LOG_ERR;
+ else if (logMessage->level() == Level::Warning)
+ sysLogPriority = LOG_WARNING;
+ else if (logMessage->level() == Level::Info)
+ sysLogPriority = LOG_INFO;
+ else if (logMessage->level() == Level::Debug)
+ sysLogPriority = LOG_DEBUG;
+ else
+ sysLogPriority = LOG_NOTICE;
+#if defined(ELPP_UNICODE)
+ char *line = base::utils::Str::wcharPtrToCharPtr(logLine.c_str());
+ syslog(sysLogPriority, "%s", line);
+ free(line);
+#else
+ syslog(sysLogPriority, "%s", logLine.c_str());
+#endif
+ }
+#endif // defined(ELPP_SYSLOG)
+}
+
+void AsyncDispatchWorker::run(void) {
+ while (continueRunning()) {
+ emptyQueue();
+ base::threading::msleep(10); // 10ms
+ }
+}
+#endif // ELPP_ASYNC_LOGGING
+
+// DefaultLogBuilder
+
+base::type::string_t DefaultLogBuilder::build(const LogMessage *logMessage,
+ bool appendNewLine) const {
+ base::TypedConfigurations *tc = logMessage->logger()->typedConfigurations();
+ const base::LogFormat *logFormat = &tc->logFormat(logMessage->level());
+ base::type::string_t logLine = logFormat->format();
+ char buff[base::consts::kSourceFilenameMaxLength +
+ base::consts::kSourceLineMaxLength] = "";
+ const char *bufLim = buff + sizeof(buff);
+ if (logFormat->hasFlag(base::FormatFlags::AppName)) {
+ // App name
+ base::utils::Str::replaceFirstWithEscape(
+ logLine, base::consts::kAppNameFormatSpecifier,
+ logMessage->logger()->parentApplicationName());
+ }
+ if (logFormat->hasFlag(base::FormatFlags::ThreadId)) {
+ // Thread ID
+ base::utils::Str::replaceFirstWithEscape(
+ logLine, base::consts::kThreadIdFormatSpecifier,
+ ELPP->getThreadName(base::threading::getCurrentThreadId()));
+ }
+ if (logFormat->hasFlag(base::FormatFlags::DateTime)) {
+ // DateTime
+ base::utils::Str::replaceFirstWithEscape(
+ logLine, base::consts::kDateTimeFormatSpecifier,
+ base::utils::DateTime::getDateTime(
+ logFormat->dateTimeFormat().c_str(),
+ &tc->subsecondPrecision(logMessage->level())));
+ }
+ if (logFormat->hasFlag(base::FormatFlags::Function)) {
+ // Function
+ base::utils::Str::replaceFirstWithEscape(
+ logLine, base::consts::kLogFunctionFormatSpecifier, logMessage->func());
+ }
+ if (logFormat->hasFlag(base::FormatFlags::File)) {
+ // File
+ base::utils::Str::clearBuff(buff, base::consts::kSourceFilenameMaxLength);
+ base::utils::File::buildStrippedFilename(logMessage->file().c_str(), buff);
+ base::utils::Str::replaceFirstWithEscape(
+ logLine, base::consts::kLogFileFormatSpecifier, std::string(buff));
+ }
+ if (logFormat->hasFlag(base::FormatFlags::FileBase)) {
+ // FileBase
+ base::utils::Str::clearBuff(buff, base::consts::kSourceFilenameMaxLength);
+ base::utils::File::buildBaseFilename(logMessage->file(), buff);
+ base::utils::Str::replaceFirstWithEscape(
+ logLine, base::consts::kLogFileBaseFormatSpecifier, std::string(buff));
+ }
+ if (logFormat->hasFlag(base::FormatFlags::Line)) {
+ // Line
+ char *buf =
+ base::utils::Str::clearBuff(buff, base::consts::kSourceLineMaxLength);
+ buf = base::utils::Str::convertAndAddToBuff(
+ logMessage->line(), base::consts::kSourceLineMaxLength, buf, bufLim,
+ false);
+ base::utils::Str::replaceFirstWithEscape(
+ logLine, base::consts::kLogLineFormatSpecifier, std::string(buff));
+ }
+ if (logFormat->hasFlag(base::FormatFlags::Location)) {
+ // Location
+ char *buf = base::utils::Str::clearBuff(
+ buff, base::consts::kSourceFilenameMaxLength +
+ base::consts::kSourceLineMaxLength);
+ base::utils::File::buildStrippedFilename(logMessage->file().c_str(), buff);
+ buf = base::utils::Str::addToBuff(buff, buf, bufLim);
+ buf = base::utils::Str::addToBuff(":", buf, bufLim);
+ buf = base::utils::Str::convertAndAddToBuff(
+ logMessage->line(), base::consts::kSourceLineMaxLength, buf, bufLim,
+ false);
+ base::utils::Str::replaceFirstWithEscape(
+ logLine, base::consts::kLogLocationFormatSpecifier, std::string(buff));
+ }
+ if (logMessage->level() == Level::Verbose &&
+ logFormat->hasFlag(base::FormatFlags::VerboseLevel)) {
+ // Verbose level
+ char *buf = base::utils::Str::clearBuff(buff, 1);
+ buf = base::utils::Str::convertAndAddToBuff(logMessage->verboseLevel(), 1,
+ buf, bufLim, false);
+ base::utils::Str::replaceFirstWithEscape(
+ logLine, base::consts::kVerboseLevelFormatSpecifier, std::string(buff));
+ }
+ if (logFormat->hasFlag(base::FormatFlags::LogMessage)) {
+ // Log message
+ base::utils::Str::replaceFirstWithEscape(
+ logLine, base::consts::kMessageFormatSpecifier, logMessage->message());
+ }
+#if !defined(ELPP_DISABLE_CUSTOM_FORMAT_SPECIFIERS)
+ el::base::threading::ScopedLock lock_(ELPP->customFormatSpecifiersLock());
+ ELPP_UNUSED(lock_);
+ for (std::vector<CustomFormatSpecifier>::const_iterator it =
+ ELPP->customFormatSpecifiers()->begin();
+ it != ELPP->customFormatSpecifiers()->end(); ++it) {
+ std::string fs(it->formatSpecifier());
+ base::type::string_t wcsFormatSpecifier(fs.begin(), fs.end());
+ base::utils::Str::replaceFirstWithEscape(logLine, wcsFormatSpecifier,
+ it->resolver()(logMessage));
+ }
+#endif // !defined(ELPP_DISABLE_CUSTOM_FORMAT_SPECIFIERS)
+ if (appendNewLine)
+ logLine += ELPP_LITERAL("\n");
+ return logLine;
+}
+
+// LogDispatcher
+
+void LogDispatcher::dispatch(void) {
+ if (m_proceed && m_dispatchAction == base::DispatchAction::None) {
+ m_proceed = false;
+ }
+ if (!m_proceed) {
+ return;
+ }
+#ifndef ELPP_NO_GLOBAL_LOCK
+ // see https://github.com/muflihun/easyloggingpp/issues/580
+ // global lock is turned on by default unless
+ // ELPP_NO_GLOBAL_LOCK is defined
+ base::threading::ScopedLock scopedLock(ELPP->lock());
+#endif
+ base::TypedConfigurations *tc = m_logMessage->logger()->m_typedConfigurations;
+ if (ELPP->hasFlag(LoggingFlag::StrictLogFileSizeCheck)) {
+ tc->validateFileRolling(m_logMessage->level(), ELPP->preRollOutCallback());
+ }
+ LogDispatchCallback *callback = nullptr;
+ LogDispatchData data;
+ for (const std::pair<std::string, base::type::LogDispatchCallbackPtr> h :
+ ELPP->m_logDispatchCallbacks) {
+ callback = h.second.get();
+ if (callback != nullptr && callback->enabled()) {
+ data.setLogMessage(m_logMessage);
+ data.setDispatchAction(m_dispatchAction);
+ callback->handle(&data);
+ }
+ }
+}
+
+// MessageBuilder
+
+void MessageBuilder::initialize(Logger *logger) {
+ m_logger = logger;
+ m_containerLogSeparator = ELPP->hasFlag(LoggingFlag::NewLineForContainer)
+ ? ELPP_LITERAL("\n ")
+ : ELPP_LITERAL(", ");
+}
+
+MessageBuilder &MessageBuilder::operator<<(const wchar_t *msg) {
+ if (msg == nullptr) {
+ m_logger->stream() << base::consts::kNullPointer;
+ return *this;
+ }
+#if defined(ELPP_UNICODE)
+ m_logger->stream() << msg;
+#else
+ char *buff_ = base::utils::Str::wcharPtrToCharPtr(msg);
+ m_logger->stream() << buff_;
+ free(buff_);
+#endif
+ if (ELPP->hasFlag(LoggingFlag::AutoSpacing)) {
+ m_logger->stream() << " ";
+ }
+ return *this;
+}
+
+// Writer
+
+Writer &Writer::construct(Logger *logger, bool needLock) {
+ m_logger = logger;
+ initializeLogger(logger->id(), false, needLock);
+ m_messageBuilder.initialize(m_logger);
+ return *this;
+}
+
+Writer &Writer::construct(int count, const char *loggerIds, ...) {
+ if (ELPP->hasFlag(LoggingFlag::MultiLoggerSupport)) {
+ va_list loggersList;
+ va_start(loggersList, loggerIds);
+ const char *id = loggerIds;
+ m_loggerIds.reserve(count);
+ for (int i = 0; i < count; ++i) {
+ m_loggerIds.push_back(std::string(id));
+ id = va_arg(loggersList, const char *);
+ }
+ va_end(loggersList);
+ initializeLogger(m_loggerIds.at(0));
+ } else {
+ initializeLogger(std::string(loggerIds));
+ }
+ m_messageBuilder.initialize(m_logger);
+ return *this;
+}
+
+void Writer::initializeLogger(const std::string &loggerId, bool lookup,
+ bool needLock) {
+ if (lookup) {
+ m_logger = ELPP->registeredLoggers()->get(
+ loggerId, ELPP->hasFlag(LoggingFlag::CreateLoggerAutomatically));
+ }
+ if (m_logger == nullptr) {
+ {
+ if (!ELPP->registeredLoggers()->has(
+ std::string(base::consts::kDefaultLoggerId))) {
+ // Somehow default logger has been unregistered. Not good! Register
+ // again
+ ELPP->registeredLoggers()->get(
+ std::string(base::consts::kDefaultLoggerId));
+ }
+ }
+ Writer(Level::Debug, m_file, m_line, m_func)
+ .construct(1, base::consts::kDefaultLoggerId)
+ << "Logger [" << loggerId << "] is not registered yet!";
+ m_proceed = false;
+ } else {
+ if (needLock) {
+ m_logger->acquireLock(); // This should not be unlocked by checking
+ // m_proceed because
+ // m_proceed can be changed by lines below
+ }
+ if (ELPP->hasFlag(LoggingFlag::HierarchicalLogging)) {
+ m_proceed = m_level == Level::Verbose
+ ? m_logger->enabled(m_level)
+ : LevelHelper::castToInt(m_level) >=
+ LevelHelper::castToInt(ELPP->m_loggingLevel);
+ } else {
+ m_proceed = m_logger->enabled(m_level);
+ }
+ }
+}
+
+void Writer::processDispatch() {
+#if ELPP_LOGGING_ENABLED
+ if (ELPP->hasFlag(LoggingFlag::MultiLoggerSupport)) {
+ bool firstDispatched = false;
+ base::type::string_t logMessage;
+ std::size_t i = 0;
+ do {
+ if (m_proceed) {
+ if (firstDispatched) {
+ m_logger->stream() << logMessage;
+ } else {
+ firstDispatched = true;
+ if (m_loggerIds.size() > 1) {
+ logMessage = m_logger->stream().str();
+ }
+ }
+ triggerDispatch();
+ } else if (m_logger != nullptr) {
+ m_logger->stream().str(ELPP_LITERAL(""));
+ m_logger->releaseLock();
+ }
+ if (i + 1 < m_loggerIds.size()) {
+ initializeLogger(m_loggerIds.at(i + 1));
+ }
+ } while (++i < m_loggerIds.size());
+ } else {
+ if (m_proceed) {
+ triggerDispatch();
+ } else if (m_logger != nullptr) {
+ m_logger->stream().str(ELPP_LITERAL(""));
+ m_logger->releaseLock();
+ }
+ }
+#else
+ if (m_logger != nullptr) {
+ m_logger->stream().str(ELPP_LITERAL(""));
+ m_logger->releaseLock();
+ }
+#endif // ELPP_LOGGING_ENABLED
+}
+
+void Writer::triggerDispatch(void) {
+ try {
+ if (m_proceed) {
+ if (m_msg == nullptr) {
+ LogMessage msg(m_level, m_file, m_line, m_func, m_verboseLevel,
+ m_logger);
+ base::LogDispatcher(m_proceed, &msg, m_dispatchAction).dispatch();
+ } else {
+ base::LogDispatcher(m_proceed, m_msg, m_dispatchAction).dispatch();
+ }
+ }
+ if (m_logger != nullptr) {
+ m_logger->stream().str(ELPP_LITERAL(""));
+ m_logger->releaseLock();
+ }
+ if (m_proceed && m_level == Level::Fatal &&
+ !ELPP->hasFlag(LoggingFlag::DisableApplicationAbortOnFatalLog)) {
+ base::Writer(Level::Warning, m_file, m_line, m_func)
+ .construct(1, base::consts::kDefaultLoggerId)
+ << "Aborting application. Reason: Fatal log at [" << m_file << ":"
+ << m_line << "]";
+ std::stringstream reasonStream;
+ reasonStream << "Fatal log at [" << m_file << ":" << m_line << "]"
+ << " If you wish to disable 'abort on fatal log' please use "
+ << "el::Loggers::addFlag(el::LoggingFlag::"
+ "DisableApplicationAbortOnFatalLog)";
+ base::utils::abort(1, reasonStream.str());
+ }
+ m_proceed = false;
+ } catch (std::exception &ex) {
+ // Extremely low memory situation; don't let exception be unhandled.
+ }
+}
+
+// PErrorWriter
+
+PErrorWriter::~PErrorWriter(void) {
+ if (m_proceed) {
+#if ELPP_COMPILER_MSVC
+ char buff[256];
+ strerror_s(buff, 256, errno);
+ m_logger->stream() << ": " << buff << " [" << errno << "]";
+#else
+ m_logger->stream() << ": " << strerror(errno) << " [" << errno << "]";
+#endif
+ }
+}
+
+// PerformanceTracker
+
+#if defined(ELPP_FEATURE_ALL) || defined(ELPP_FEATURE_PERFORMANCE_TRACKING)
+
+PerformanceTracker::PerformanceTracker(const std::string &blockName,
+ base::TimestampUnit timestampUnit,
+ const std::string &loggerId,
+ bool scopedLog, Level level)
+ : m_blockName(blockName), m_timestampUnit(timestampUnit),
+ m_loggerId(loggerId), m_scopedLog(scopedLog), m_level(level),
+ m_hasChecked(false), m_lastCheckpointId(std::string()), m_enabled(false) {
+#if !defined(ELPP_DISABLE_PERFORMANCE_TRACKING) && ELPP_LOGGING_ENABLED
+ // We store it locally so that if user happen to change configuration by the
+ // end of scope or before calling checkpoint, we still depend on state of
+ // configuration at time of construction
+ el::Logger *loggerPtr = ELPP->registeredLoggers()->get(loggerId, false);
+ m_enabled = loggerPtr != nullptr &&
+ loggerPtr->m_typedConfigurations->performanceTracking(m_level);
+ if (m_enabled) {
+ base::utils::DateTime::gettimeofday(&m_startTime);
+ }
+#endif // !defined(ELPP_DISABLE_PERFORMANCE_TRACKING) && ELPP_LOGGING_ENABLED
+}
+
+PerformanceTracker::~PerformanceTracker(void) {
+#if !defined(ELPP_DISABLE_PERFORMANCE_TRACKING) && ELPP_LOGGING_ENABLED
+ if (m_enabled) {
+ base::threading::ScopedLock scopedLock(lock());
+ if (m_scopedLog) {
+ base::utils::DateTime::gettimeofday(&m_endTime);
+ base::type::string_t formattedTime = getFormattedTimeTaken();
+ PerformanceTrackingData data(PerformanceTrackingData::DataType::Complete);
+ data.init(this);
+ data.m_formattedTimeTaken = formattedTime;
+ PerformanceTrackingCallback *callback = nullptr;
+ for (const std::pair<std::string,
+ base::type::PerformanceTrackingCallbackPtr> &h :
+ ELPP->m_performanceTrackingCallbacks) {
+ callback = h.second.get();
+ if (callback != nullptr && callback->enabled()) {
+ callback->handle(&data);
+ }
+ }
+ }
+ }
+#endif // !defined(ELPP_DISABLE_PERFORMANCE_TRACKING)
+}
+
+void PerformanceTracker::checkpoint(const std::string &id, const char *file,
+ base::type::LineNumber line,
+ const char *func) {
+#if !defined(ELPP_DISABLE_PERFORMANCE_TRACKING) && ELPP_LOGGING_ENABLED
+ if (m_enabled) {
+ base::threading::ScopedLock scopedLock(lock());
+ base::utils::DateTime::gettimeofday(&m_endTime);
+ base::type::string_t formattedTime =
+ m_hasChecked ? getFormattedTimeTaken(m_lastCheckpointTime)
+ : ELPP_LITERAL("");
+ PerformanceTrackingData data(PerformanceTrackingData::DataType::Checkpoint);
+ data.init(this);
+ data.m_checkpointId = id;
+ data.m_file = file;
+ data.m_line = line;
+ data.m_func = func;
+ data.m_formattedTimeTaken = formattedTime;
+ PerformanceTrackingCallback *callback = nullptr;
+ for (const std::pair<std::string,
+ base::type::PerformanceTrackingCallbackPtr> &h :
+ ELPP->m_performanceTrackingCallbacks) {
+ callback = h.second.get();
+ if (callback != nullptr && callback->enabled()) {
+ callback->handle(&data);
+ }
+ }
+ base::utils::DateTime::gettimeofday(&m_lastCheckpointTime);
+ m_hasChecked = true;
+ m_lastCheckpointId = id;
+ }
+#endif // !defined(ELPP_DISABLE_PERFORMANCE_TRACKING) && ELPP_LOGGING_ENABLED
+ ELPP_UNUSED(id);
+ ELPP_UNUSED(file);
+ ELPP_UNUSED(line);
+ ELPP_UNUSED(func);
+}
+
+const base::type::string_t
+PerformanceTracker::getFormattedTimeTaken(struct timeval startTime) const {
+ if (ELPP->hasFlag(LoggingFlag::FixedTimeFormat)) {
+ base::type::stringstream_t ss;
+ ss << base::utils::DateTime::getTimeDifference(m_endTime, startTime,
+ m_timestampUnit)
+ << " "
+ << base::consts::kTimeFormats[static_cast<base::type::EnumType>(
+ m_timestampUnit)]
+ .unit;
+ return ss.str();
+ }
+ return base::utils::DateTime::formatTime(
+ base::utils::DateTime::getTimeDifference(m_endTime, startTime,
+ m_timestampUnit),
+ m_timestampUnit);
+}
+
+#endif // defined(ELPP_FEATURE_ALL) ||
+ // defined(ELPP_FEATURE_PERFORMANCE_TRACKING)
+
+namespace debug {
+#if defined(ELPP_FEATURE_ALL) || defined(ELPP_FEATURE_CRASH_LOG)
+
+// StackTrace
+
+StackTrace::StackTraceEntry::StackTraceEntry(std::size_t index,
+ const std::string &loc,
+ const std::string &demang,
+ const std::string &hex,
+ const std::string &addr)
+ : m_index(index), m_location(loc), m_demangled(demang), m_hex(hex),
+ m_addr(addr) {}
+
+std::ostream &operator<<(std::ostream &ss,
+ const StackTrace::StackTraceEntry &si) {
+ ss << "[" << si.m_index << "] " << si.m_location
+ << (si.m_hex.empty() ? "" : "+") << si.m_hex << " " << si.m_addr
+ << (si.m_demangled.empty() ? "" : ":") << si.m_demangled;
+ return ss;
+}
+
+std::ostream &operator<<(std::ostream &os, const StackTrace &st) {
+ std::vector<StackTrace::StackTraceEntry>::const_iterator it =
+ st.m_stack.begin();
+ while (it != st.m_stack.end()) {
+ os << " " << *it++ << "\n";
+ }
+ return os;
+}
+
+void StackTrace::generateNew(void) {
+#ifdef HAVE_EXECINFO
+ m_stack.clear();
+ void *stack[kMaxStack];
+ unsigned int size = backtrace(stack, kMaxStack);
+ char **strings = backtrace_symbols(stack, size);
+ if (size > kStackStart) { // Skip StackTrace c'tor and generateNew
+ for (std::size_t i = kStackStart; i < size; ++i) {
+ std::string mangName;
+ std::string location;
+ std::string hex;
+ std::string addr;
+
+ // entry: 2 crash.cpp.bin 0x0000000101552be5
+ // _ZN2el4base5debug10StackTraceC1Ev + 21
+ const std::string line(strings[i]);
+ auto p = line.find("_");
+ if (p != std::string::npos) {
+ mangName = line.substr(p);
+ mangName = mangName.substr(0, mangName.find(" +"));
+ }
+ p = line.find("0x");
+ if (p != std::string::npos) {
+ addr = line.substr(p);
+ addr = addr.substr(0, addr.find("_"));
+ }
+ // Perform demangling if parsed properly
+ if (!mangName.empty()) {
+ int status = 0;
+ char *demangName = abi::__cxa_demangle(mangName.data(), 0, 0, &status);
+ // if demangling is successful, output the demangled function name
+ if (status == 0) {
+ // Success (see
+ // http://gcc.gnu.org/onlinedocs/libstdc++/libstdc++-html-USERS-4.3/a01696.html)
+ StackTraceEntry entry(i - 1, location, demangName, hex, addr);
+ m_stack.push_back(entry);
+ } else {
+ // Not successful - we will use mangled name
+ StackTraceEntry entry(i - 1, location, mangName, hex, addr);
+ m_stack.push_back(entry);
+ }
+ free(demangName);
+ } else {
+ StackTraceEntry entry(i - 1, line);
+ m_stack.push_back(entry);
+ }
+ }
+ }
+ free(strings);
+#else
+ ELPP_INTERNAL_INFO(
+ 1, "Stacktrace generation not supported for selected compiler");
+#endif // ELPP_STACKTRACE
+}
+
+// Static helper functions
+
+static std::string crashReason(int sig) {
+ std::stringstream ss;
+ bool foundReason = false;
+ for (int i = 0; i < base::consts::kCrashSignalsCount; ++i) {
+ if (base::consts::kCrashSignals[i].numb == sig) {
+ ss << "Application has crashed due to ["
+ << base::consts::kCrashSignals[i].name << "] signal";
+ if (ELPP->hasFlag(el::LoggingFlag::LogDetailedCrashReason)) {
+ ss << std::endl
+ << " " << base::consts::kCrashSignals[i].brief << std::endl
+ << " " << base::consts::kCrashSignals[i].detail;
+ }
+ foundReason = true;
+ }
+ }
+ if (!foundReason) {
+ ss << "Application has crashed due to unknown signal [" << sig << "]";
+ }
+ return ss.str();
+}
+/// @brief Logs reason of crash from sig
+static void logCrashReason(int sig, bool stackTraceIfAvailable, Level level,
+ const char *logger) {
+ if (sig == SIGINT && ELPP->hasFlag(el::LoggingFlag::IgnoreSigInt)) {
+ return;
+ }
+ std::stringstream ss;
+ ss << "CRASH HANDLED; ";
+ ss << crashReason(sig);
+#if ELPP_STACKTRACE
+ if (stackTraceIfAvailable) {
+ ss << std::endl
+ << " ======= Backtrace: =========" << std::endl
+ << base::debug::StackTrace();
+ }
+#else
+ ELPP_UNUSED(stackTraceIfAvailable);
+#endif // ELPP_STACKTRACE
+ ELPP_WRITE_LOG(el::base::Writer, level, base::DispatchAction::NormalLog,
+ logger)
+ << ss.str();
+}
+
+static inline void crashAbort(int sig) {
+ base::utils::abort(sig, std::string());
+}
+
+/// @brief Default application crash handler
+///
+/// @detail This function writes log using 'default' logger, prints stack trace
+/// for GCC based compilers and aborts program.
+static inline void defaultCrashHandler(int sig) {
+ base::debug::logCrashReason(sig, true, Level::Fatal,
+ base::consts::kDefaultLoggerId);
+ base::debug::crashAbort(sig);
+}
+
+// CrashHandler
+
+CrashHandler::CrashHandler(bool useDefault) {
+ if (useDefault) {
+ setHandler(defaultCrashHandler);
+ }
+}
+
+void CrashHandler::setHandler(const Handler &cHandler) {
+ m_handler = cHandler;
+#if defined(ELPP_HANDLE_SIGABRT)
+ int i = 0; // SIGABRT is at base::consts::kCrashSignals[0]
+#else
+ int i = 1;
+#endif // defined(ELPP_HANDLE_SIGABRT)
+ for (; i < base::consts::kCrashSignalsCount; ++i) {
+ m_handler = signal(base::consts::kCrashSignals[i].numb, cHandler);
+ }
+}
+
+#endif // defined(ELPP_FEATURE_ALL) || defined(ELPP_FEATURE_CRASH_LOG)
+} // namespace debug
+} // namespace base
+
+// el
+
+// Helpers
+
+#if defined(ELPP_FEATURE_ALL) || defined(ELPP_FEATURE_CRASH_LOG)
+
+void Helpers::crashAbort(int sig, const char *sourceFile,
+ unsigned int long line) {
+ std::stringstream ss;
+ ss << base::debug::crashReason(sig).c_str();
+ ss << " - [Called el::Helpers::crashAbort(" << sig << ")]";
+ if (sourceFile != nullptr && strlen(sourceFile) > 0) {
+ ss << " - Source: " << sourceFile;
+ if (line > 0)
+ ss << ":" << line;
+ else
+ ss << " (line number not specified)";
+ }
+ base::utils::abort(sig, ss.str());
+}
+
+void Helpers::logCrashReason(int sig, bool stackTraceIfAvailable, Level level,
+ const char *logger) {
+ el::base::debug::logCrashReason(sig, stackTraceIfAvailable, level, logger);
+}
+
+#endif // defined(ELPP_FEATURE_ALL) || defined(ELPP_FEATURE_CRASH_LOG)
+
+// Loggers
+
+Logger *Loggers::getLogger(const std::string &identity,
+ bool registerIfNotAvailable) {
+ return ELPP->registeredLoggers()->get(identity, registerIfNotAvailable);
+}
+
+void Loggers::setDefaultLogBuilder(el::LogBuilderPtr &logBuilderPtr) {
+ ELPP->registeredLoggers()->setDefaultLogBuilder(logBuilderPtr);
+}
+
+bool Loggers::unregisterLogger(const std::string &identity) {
+ return ELPP->registeredLoggers()->remove(identity);
+}
+
+bool Loggers::hasLogger(const std::string &identity) {
+ return ELPP->registeredLoggers()->has(identity);
+}
+
+Logger *Loggers::reconfigureLogger(Logger *logger,
+ const Configurations &configurations) {
+ if (!logger)
+ return nullptr;
+ logger->configure(configurations);
+ return logger;
+}
+
+Logger *Loggers::reconfigureLogger(const std::string &identity,
+ const Configurations &configurations) {
+ return Loggers::reconfigureLogger(Loggers::getLogger(identity),
+ configurations);
+}
+
+Logger *Loggers::reconfigureLogger(const std::string &identity,
+ ConfigurationType configurationType,
+ const std::string &value) {
+ Logger *logger = Loggers::getLogger(identity);
+ if (logger == nullptr) {
+ return nullptr;
+ }
+ logger->configurations()->set(Level::Global, configurationType, value);
+ logger->reconfigure();
+ return logger;
+}
+
+void Loggers::reconfigureAllLoggers(const Configurations &configurations) {
+ for (base::RegisteredLoggers::iterator it =
+ ELPP->registeredLoggers()->begin();
+ it != ELPP->registeredLoggers()->end(); ++it) {
+ Loggers::reconfigureLogger(it->second, configurations);
+ }
+}
+
+void Loggers::reconfigureAllLoggers(Level level,
+ ConfigurationType configurationType,
+ const std::string &value) {
+ for (base::RegisteredLoggers::iterator it =
+ ELPP->registeredLoggers()->begin();
+ it != ELPP->registeredLoggers()->end(); ++it) {
+ Logger *logger = it->second;
+ logger->configurations()->set(level, configurationType, value);
+ logger->reconfigure();
+ }
+}
+
+void Loggers::setDefaultConfigurations(const Configurations &configurations,
+ bool reconfigureExistingLoggers) {
+ ELPP->registeredLoggers()->setDefaultConfigurations(configurations);
+ if (reconfigureExistingLoggers) {
+ Loggers::reconfigureAllLoggers(configurations);
+ }
+}
+
+const Configurations *Loggers::defaultConfigurations(void) {
+ return ELPP->registeredLoggers()->defaultConfigurations();
+}
+
+const base::LogStreamsReferenceMapPtr Loggers::logStreamsReference(void) {
+ return ELPP->registeredLoggers()->logStreamsReference();
+}
+
+base::TypedConfigurations Loggers::defaultTypedConfigurations(void) {
+ return base::TypedConfigurations(
+ ELPP->registeredLoggers()->defaultConfigurations(),
+ ELPP->registeredLoggers()->logStreamsReference());
+}
+
+std::vector<std::string> *
+Loggers::populateAllLoggerIds(std::vector<std::string> *targetList) {
+ targetList->clear();
+ for (base::RegisteredLoggers::iterator it =
+ ELPP->registeredLoggers()->list().begin();
+ it != ELPP->registeredLoggers()->list().end(); ++it) {
+ targetList->push_back(it->first);
+ }
+ return targetList;
+}
+
+void Loggers::configureFromGlobal(const char *globalConfigurationFilePath) {
+ std::ifstream gcfStream(globalConfigurationFilePath, std::ifstream::in);
+ ELPP_ASSERT(gcfStream.is_open(), "Unable to open global configuration file ["
+ << globalConfigurationFilePath
+ << "] for parsing.");
+ std::string line = std::string();
+ std::stringstream ss;
+ Logger *logger = nullptr;
+ auto configure = [&](void) {
+ ELPP_INTERNAL_INFO(8, "Configuring logger: '"
+ << logger->id() << "' with configurations \n"
+ << ss.str() << "\n--------------");
+ Configurations c;
+ c.parseFromText(ss.str());
+ logger->configure(c);
+ };
+ while (gcfStream.good()) {
+ std::getline(gcfStream, line);
+ ELPP_INTERNAL_INFO(1, "Parsing line: " << line);
+ base::utils::Str::trim(line);
+ if (Configurations::Parser::isComment(line))
+ continue;
+ Configurations::Parser::ignoreComments(&line);
+ base::utils::Str::trim(line);
+ if (line.size() > 2 &&
+ base::utils::Str::startsWith(
+ line, std::string(base::consts::kConfigurationLoggerId))) {
+ if (!ss.str().empty() && logger != nullptr) {
+ configure();
+ }
+ ss.str(std::string(""));
+ line = line.substr(2);
+ base::utils::Str::trim(line);
+ if (line.size() > 1) {
+ ELPP_INTERNAL_INFO(1, "Getting logger: '" << line << "'");
+ logger = getLogger(line);
+ }
+ } else {
+ ss << line << "\n";
+ }
+ }
+ if (!ss.str().empty() && logger != nullptr) {
+ configure();
+ }
+}
+
+bool Loggers::configureFromArg(const char *argKey) {
+#if defined(ELPP_DISABLE_CONFIGURATION_FROM_PROGRAM_ARGS)
+ ELPP_UNUSED(argKey);
+#else
+ if (!Helpers::commandLineArgs()->hasParamWithValue(argKey)) {
+ return false;
+ }
+ configureFromGlobal(Helpers::commandLineArgs()->getParamValue(argKey));
+#endif // defined(ELPP_DISABLE_CONFIGURATION_FROM_PROGRAM_ARGS)
+ return true;
+}
+
+void Loggers::flushAll(void) { ELPP->registeredLoggers()->flushAll(); }
+
+void Loggers::setVerboseLevel(base::type::VerboseLevel level) {
+ ELPP->vRegistry()->setLevel(level);
+}
+
+base::type::VerboseLevel Loggers::verboseLevel(void) {
+ return ELPP->vRegistry()->level();
+}
+
+void Loggers::setVModules(const char *modules) {
+ if (ELPP->vRegistry()->vModulesEnabled()) {
+ ELPP->vRegistry()->setModules(modules);
+ }
+}
+
+void Loggers::clearVModules(void) { ELPP->vRegistry()->clearModules(); }
+
+// VersionInfo
+
+const std::string VersionInfo::version(void) { return std::string("9.96.7"); }
+/// @brief Release date of current version
+const std::string VersionInfo::releaseDate(void) {
+ return std::string("24-11-2018 0728hrs");
+}
+
+} // namespace el
diff --git a/third_party/easyloggingpp/easylogging++.h b/third_party/easyloggingpp/easylogging++.h
new file mode 100644
index 00000000..6e81edfb
--- /dev/null
+++ b/third_party/easyloggingpp/easylogging++.h
@@ -0,0 +1,4576 @@
+//
+// Bismillah ar-Rahmaan ar-Raheem
+//
+// Easylogging++ v9.96.7
+// Single-header only, cross-platform logging library for C++ applications
+//
+// Copyright (c) 2012-2018 Amrayn Web Services
+// Copyright (c) 2012-2018 @abumusamq
+//
+// This library is released under the MIT Licence.
+// https://github.com/amrayn/easyloggingpp/blob/master/LICENSE
+//
+// https://amrayn.com
+// http://muflihun.com
+//
+
+#ifndef EASYLOGGINGPP_H
+#define EASYLOGGINGPP_H
+// Compilers and C++0x/C++11 Evaluation
+#if __cplusplus >= 201103L
+# define ELPP_CXX11 1
+#endif // __cplusplus >= 201103L
+#if (defined(__GNUC__))
+# define ELPP_COMPILER_GCC 1
+#else
+# define ELPP_COMPILER_GCC 0
+#endif
+#if ELPP_COMPILER_GCC
+# define ELPP_GCC_VERSION (__GNUC__ * 10000 \
++ __GNUC_MINOR__ * 100 \
++ __GNUC_PATCHLEVEL__)
+# if defined(__GXX_EXPERIMENTAL_CXX0X__)
+# define ELPP_CXX0X 1
+# endif
+#endif
+// Visual C++
+#if defined(_MSC_VER)
+# define ELPP_COMPILER_MSVC 1
+#else
+# define ELPP_COMPILER_MSVC 0
+#endif
+#define ELPP_CRT_DBG_WARNINGS ELPP_COMPILER_MSVC
+#if ELPP_COMPILER_MSVC
+# if (_MSC_VER == 1600)
+# define ELPP_CXX0X 1
+# elif(_MSC_VER >= 1700)
+# define ELPP_CXX11 1
+# endif
+#endif
+// Clang++
+#if (defined(__clang__) && (__clang__ == 1))
+# define ELPP_COMPILER_CLANG 1
+#else
+# define ELPP_COMPILER_CLANG 0
+#endif
+#if ELPP_COMPILER_CLANG
+# if __has_include(<thread>)
+# include <cstddef> // Make __GLIBCXX__ defined when using libstdc++
+# if !defined(__GLIBCXX__) || __GLIBCXX__ >= 20150426
+# define ELPP_CLANG_SUPPORTS_THREAD
+# endif // !defined(__GLIBCXX__) || __GLIBCXX__ >= 20150426
+# endif // __has_include(<thread>)
+#endif
+#if (defined(__MINGW32__) || defined(__MINGW64__))
+# define ELPP_MINGW 1
+#else
+# define ELPP_MINGW 0
+#endif
+#if (defined(__CYGWIN__) && (__CYGWIN__ == 1))
+# define ELPP_CYGWIN 1
+#else
+# define ELPP_CYGWIN 0
+#endif
+#if (defined(__INTEL_COMPILER))
+# define ELPP_COMPILER_INTEL 1
+#else
+# define ELPP_COMPILER_INTEL 0
+#endif
+// Operating System Evaluation
+// Windows
+#if (defined(_WIN32) || defined(_WIN64))
+# define ELPP_OS_WINDOWS 1
+#else
+# define ELPP_OS_WINDOWS 0
+#endif
+// Linux
+#if (defined(__linux) || defined(__linux__))
+# define ELPP_OS_LINUX 1
+#else
+# define ELPP_OS_LINUX 0
+#endif
+#if (defined(__APPLE__))
+# define ELPP_OS_MAC 1
+#else
+# define ELPP_OS_MAC 0
+#endif
+#if (defined(__FreeBSD__) || defined(__FreeBSD_kernel__))
+# define ELPP_OS_FREEBSD 1
+#else
+# define ELPP_OS_FREEBSD 0
+#endif
+#if (defined(__sun))
+# define ELPP_OS_SOLARIS 1
+#else
+# define ELPP_OS_SOLARIS 0
+#endif
+#if (defined(_AIX))
+# define ELPP_OS_AIX 1
+#else
+# define ELPP_OS_AIX 0
+#endif
+#if (defined(__NetBSD__))
+# define ELPP_OS_NETBSD 1
+#else
+# define ELPP_OS_NETBSD 0
+#endif
+#if defined(__EMSCRIPTEN__)
+# define ELPP_OS_EMSCRIPTEN 1
+#else
+# define ELPP_OS_EMSCRIPTEN 0
+#endif
+#if (defined(__QNX__) || defined(__QNXNTO__))
+# define ELPP_OS_QNX 1
+#else
+# define ELPP_OS_QNX 0
+#endif
+// Unix
+#if ((ELPP_OS_LINUX || ELPP_OS_MAC || ELPP_OS_FREEBSD || ELPP_OS_NETBSD || ELPP_OS_SOLARIS || ELPP_OS_AIX || ELPP_OS_EMSCRIPTEN || ELPP_OS_QNX) && (!ELPP_OS_WINDOWS))
+# define ELPP_OS_UNIX 1
+#else
+# define ELPP_OS_UNIX 0
+#endif
+#if (defined(__ANDROID__))
+# define ELPP_OS_ANDROID 1
+#else
+# define ELPP_OS_ANDROID 0
+#endif
+// Evaluating Cygwin as *nix OS
+#if !ELPP_OS_UNIX && !ELPP_OS_WINDOWS && ELPP_CYGWIN
+# undef ELPP_OS_UNIX
+# undef ELPP_OS_LINUX
+# define ELPP_OS_UNIX 1
+# define ELPP_OS_LINUX 1
+#endif // !ELPP_OS_UNIX && !ELPP_OS_WINDOWS && ELPP_CYGWIN
+#if !defined(ELPP_INTERNAL_DEBUGGING_OUT_INFO)
+# define ELPP_INTERNAL_DEBUGGING_OUT_INFO std::cout
+#endif // !defined(ELPP_INTERNAL_DEBUGGING_OUT)
+#if !defined(ELPP_INTERNAL_DEBUGGING_OUT_ERROR)
+# define ELPP_INTERNAL_DEBUGGING_OUT_ERROR std::cerr
+#endif // !defined(ELPP_INTERNAL_DEBUGGING_OUT)
+#if !defined(ELPP_INTERNAL_DEBUGGING_ENDL)
+# define ELPP_INTERNAL_DEBUGGING_ENDL std::endl
+#endif // !defined(ELPP_INTERNAL_DEBUGGING_OUT)
+#if !defined(ELPP_INTERNAL_DEBUGGING_MSG)
+# define ELPP_INTERNAL_DEBUGGING_MSG(msg) msg
+#endif // !defined(ELPP_INTERNAL_DEBUGGING_OUT)
+// Internal Assertions and errors
+#if !defined(ELPP_DISABLE_ASSERT)
+# if (defined(ELPP_DEBUG_ASSERT_FAILURE))
+# define ELPP_ASSERT(expr, msg) if (!(expr)) { \
+std::stringstream internalInfoStream; internalInfoStream << msg; \
+ELPP_INTERNAL_DEBUGGING_OUT_ERROR \
+<< "EASYLOGGING++ ASSERTION FAILED (LINE: " << __LINE__ << ") [" #expr << "] WITH MESSAGE \"" \
+<< ELPP_INTERNAL_DEBUGGING_MSG(internalInfoStream.str()) << "\"" << ELPP_INTERNAL_DEBUGGING_ENDL; base::utils::abort(1, \
+"ELPP Assertion failure, please define ELPP_DEBUG_ASSERT_FAILURE"); }
+# else
+# define ELPP_ASSERT(expr, msg) if (!(expr)) { \
+std::stringstream internalInfoStream; internalInfoStream << msg; \
+ELPP_INTERNAL_DEBUGGING_OUT_ERROR\
+<< "ASSERTION FAILURE FROM EASYLOGGING++ (LINE: " \
+<< __LINE__ << ") [" #expr << "] WITH MESSAGE \"" << ELPP_INTERNAL_DEBUGGING_MSG(internalInfoStream.str()) << "\"" \
+<< ELPP_INTERNAL_DEBUGGING_ENDL; }
+# endif // (defined(ELPP_DEBUG_ASSERT_FAILURE))
+#else
+# define ELPP_ASSERT(x, y)
+#endif //(!defined(ELPP_DISABLE_ASSERT)
+#if ELPP_COMPILER_MSVC
+# define ELPP_INTERNAL_DEBUGGING_WRITE_PERROR \
+{ char buff[256]; strerror_s(buff, 256, errno); \
+ELPP_INTERNAL_DEBUGGING_OUT_ERROR << ": " << buff << " [" << errno << "]";} (void)0
+#else
+# define ELPP_INTERNAL_DEBUGGING_WRITE_PERROR \
+ELPP_INTERNAL_DEBUGGING_OUT_ERROR << ": " << strerror(errno) << " [" << errno << "]"; (void)0
+#endif // ELPP_COMPILER_MSVC
+#if defined(ELPP_DEBUG_ERRORS)
+# if !defined(ELPP_INTERNAL_ERROR)
+# define ELPP_INTERNAL_ERROR(msg, pe) { \
+std::stringstream internalInfoStream; internalInfoStream << "<ERROR> " << msg; \
+ELPP_INTERNAL_DEBUGGING_OUT_ERROR \
+<< "ERROR FROM EASYLOGGING++ (LINE: " << __LINE__ << ") " \
+<< ELPP_INTERNAL_DEBUGGING_MSG(internalInfoStream.str()) << ELPP_INTERNAL_DEBUGGING_ENDL; \
+if (pe) { ELPP_INTERNAL_DEBUGGING_OUT_ERROR << " "; ELPP_INTERNAL_DEBUGGING_WRITE_PERROR; }} (void)0
+# endif
+#else
+# undef ELPP_INTERNAL_INFO
+# define ELPP_INTERNAL_ERROR(msg, pe)
+#endif // defined(ELPP_DEBUG_ERRORS)
+#if (defined(ELPP_DEBUG_INFO))
+# if !(defined(ELPP_INTERNAL_INFO_LEVEL))
+# define ELPP_INTERNAL_INFO_LEVEL 9
+# endif // !(defined(ELPP_INTERNAL_INFO_LEVEL))
+# if !defined(ELPP_INTERNAL_INFO)
+# define ELPP_INTERNAL_INFO(lvl, msg) { if (lvl <= ELPP_INTERNAL_INFO_LEVEL) { \
+std::stringstream internalInfoStream; internalInfoStream << "<INFO> " << msg; \
+ELPP_INTERNAL_DEBUGGING_OUT_INFO << ELPP_INTERNAL_DEBUGGING_MSG(internalInfoStream.str()) \
+<< ELPP_INTERNAL_DEBUGGING_ENDL; }}
+# endif
+#else
+# undef ELPP_INTERNAL_INFO
+# define ELPP_INTERNAL_INFO(lvl, msg)
+#endif // (defined(ELPP_DEBUG_INFO))
+#if (defined(ELPP_FEATURE_ALL)) || (defined(ELPP_FEATURE_CRASH_LOG))
+# if (ELPP_COMPILER_GCC && !ELPP_MINGW && !ELPP_CYGWIN && !ELPP_OS_ANDROID && !ELPP_OS_EMSCRIPTEN && !ELPP_OS_QNX)
+# define ELPP_STACKTRACE 1
+# else
+# if ELPP_COMPILER_MSVC
+# pragma message("Stack trace not available for this compiler")
+# else
+# warning "Stack trace not available for this compiler";
+# endif // ELPP_COMPILER_MSVC
+# define ELPP_STACKTRACE 0
+# endif // ELPP_COMPILER_GCC
+#else
+# define ELPP_STACKTRACE 0
+#endif // (defined(ELPP_FEATURE_ALL)) || (defined(ELPP_FEATURE_CRASH_LOG))
+// Miscellaneous macros
+#define ELPP_UNUSED(x) (void)x
+#if ELPP_OS_UNIX
+// Log file permissions for unix-based systems
+# define ELPP_LOG_PERMS S_IRUSR | S_IWUSR | S_IXUSR | S_IWGRP | S_IRGRP | S_IXGRP | S_IWOTH | S_IXOTH
+#endif // ELPP_OS_UNIX
+#if defined(ELPP_AS_DLL) && ELPP_COMPILER_MSVC
+# if defined(ELPP_EXPORT_SYMBOLS)
+# define ELPP_EXPORT __declspec(dllexport)
+# else
+# define ELPP_EXPORT __declspec(dllimport)
+# endif // defined(ELPP_EXPORT_SYMBOLS)
+#else
+# define ELPP_EXPORT
+#endif // defined(ELPP_AS_DLL) && ELPP_COMPILER_MSVC
+// Some special functions that are VC++ specific
+#undef STRTOK
+#undef STRERROR
+#undef STRCAT
+#undef STRCPY
+#if ELPP_CRT_DBG_WARNINGS
+# define STRTOK(a, b, c) strtok_s(a, b, c)
+# define STRERROR(a, b, c) strerror_s(a, b, c)
+# define STRCAT(a, b, len) strcat_s(a, len, b)
+# define STRCPY(a, b, len) strcpy_s(a, len, b)
+#else
+# define STRTOK(a, b, c) strtok(a, b)
+# define STRERROR(a, b, c) strerror(c)
+# define STRCAT(a, b, len) strcat(a, b)
+# define STRCPY(a, b, len) strcpy(a, b)
+#endif
+// Compiler specific support evaluations
+#if (ELPP_MINGW && !defined(ELPP_FORCE_USE_STD_THREAD))
+# define ELPP_USE_STD_THREADING 0
+#else
+# if ((ELPP_COMPILER_CLANG && defined(ELPP_CLANG_SUPPORTS_THREAD)) || \
+ (!ELPP_COMPILER_CLANG && defined(ELPP_CXX11)) || \
+ defined(ELPP_FORCE_USE_STD_THREAD))
+# define ELPP_USE_STD_THREADING 1
+# else
+# define ELPP_USE_STD_THREADING 0
+# endif
+#endif
+#undef ELPP_FINAL
+#if ELPP_COMPILER_INTEL || (ELPP_GCC_VERSION < 40702)
+# define ELPP_FINAL
+#else
+# define ELPP_FINAL final
+#endif // ELPP_COMPILER_INTEL || (ELPP_GCC_VERSION < 40702)
+#if defined(ELPP_EXPERIMENTAL_ASYNC)
+# define ELPP_ASYNC_LOGGING 1
+#else
+# define ELPP_ASYNC_LOGGING 0
+#endif // defined(ELPP_EXPERIMENTAL_ASYNC)
+#if defined(ELPP_THREAD_SAFE) || ELPP_ASYNC_LOGGING
+# define ELPP_THREADING_ENABLED 1
+#else
+# define ELPP_THREADING_ENABLED 0
+#endif // defined(ELPP_THREAD_SAFE) || ELPP_ASYNC_LOGGING
+// Function macro ELPP_FUNC
+#undef ELPP_FUNC
+#if ELPP_COMPILER_MSVC // Visual C++
+# define ELPP_FUNC __FUNCSIG__
+#elif ELPP_COMPILER_GCC // GCC
+# define ELPP_FUNC __PRETTY_FUNCTION__
+#elif ELPP_COMPILER_INTEL // Intel C++
+# define ELPP_FUNC __PRETTY_FUNCTION__
+#elif ELPP_COMPILER_CLANG // Clang++
+# define ELPP_FUNC __PRETTY_FUNCTION__
+#else
+# if defined(__func__)
+# define ELPP_FUNC __func__
+# else
+# define ELPP_FUNC ""
+# endif // defined(__func__)
+#endif // defined(_MSC_VER)
+#undef ELPP_VARIADIC_TEMPLATES_SUPPORTED
+// Keep following line commented until features are fixed
+#define ELPP_VARIADIC_TEMPLATES_SUPPORTED \
+(ELPP_COMPILER_GCC || ELPP_COMPILER_CLANG || ELPP_COMPILER_INTEL || (ELPP_COMPILER_MSVC && _MSC_VER >= 1800))
+// Logging Enable/Disable macros
+#if defined(ELPP_DISABLE_LOGS)
+#define ELPP_LOGGING_ENABLED 0
+#else
+#define ELPP_LOGGING_ENABLED 1
+#endif
+#if (!defined(ELPP_DISABLE_DEBUG_LOGS) && (ELPP_LOGGING_ENABLED))
+# define ELPP_DEBUG_LOG 1
+#else
+# define ELPP_DEBUG_LOG 0
+#endif // (!defined(ELPP_DISABLE_DEBUG_LOGS) && (ELPP_LOGGING_ENABLED))
+#if (!defined(ELPP_DISABLE_INFO_LOGS) && (ELPP_LOGGING_ENABLED))
+# define ELPP_INFO_LOG 1
+#else
+# define ELPP_INFO_LOG 0
+#endif // (!defined(ELPP_DISABLE_INFO_LOGS) && (ELPP_LOGGING_ENABLED))
+#if (!defined(ELPP_DISABLE_WARNING_LOGS) && (ELPP_LOGGING_ENABLED))
+# define ELPP_WARNING_LOG 1
+#else
+# define ELPP_WARNING_LOG 0
+#endif // (!defined(ELPP_DISABLE_WARNING_LOGS) && (ELPP_LOGGING_ENABLED))
+#if (!defined(ELPP_DISABLE_ERROR_LOGS) && (ELPP_LOGGING_ENABLED))
+# define ELPP_ERROR_LOG 1
+#else
+# define ELPP_ERROR_LOG 0
+#endif // (!defined(ELPP_DISABLE_ERROR_LOGS) && (ELPP_LOGGING_ENABLED))
+#if (!defined(ELPP_DISABLE_FATAL_LOGS) && (ELPP_LOGGING_ENABLED))
+# define ELPP_FATAL_LOG 1
+#else
+# define ELPP_FATAL_LOG 0
+#endif // (!defined(ELPP_DISABLE_FATAL_LOGS) && (ELPP_LOGGING_ENABLED))
+#if (!defined(ELPP_DISABLE_TRACE_LOGS) && (ELPP_LOGGING_ENABLED))
+# define ELPP_TRACE_LOG 1
+#else
+# define ELPP_TRACE_LOG 0
+#endif // (!defined(ELPP_DISABLE_TRACE_LOGS) && (ELPP_LOGGING_ENABLED))
+#if (!defined(ELPP_DISABLE_VERBOSE_LOGS) && (ELPP_LOGGING_ENABLED))
+# define ELPP_VERBOSE_LOG 1
+#else
+# define ELPP_VERBOSE_LOG 0
+#endif // (!defined(ELPP_DISABLE_VERBOSE_LOGS) && (ELPP_LOGGING_ENABLED))
+#if (!(ELPP_CXX0X || ELPP_CXX11))
+# error "C++0x (or higher) support not detected! (Is `-std=c++11' missing?)"
+#endif // (!(ELPP_CXX0X || ELPP_CXX11))
+// Headers
+#if defined(ELPP_SYSLOG)
+# include <syslog.h>
+#endif // defined(ELPP_SYSLOG)
+#include <ctime>
+#include <cstring>
+#include <cstdlib>
+#include <cctype>
+#include <cwchar>
+#include <csignal>
+#include <cerrno>
+#include <cstdarg>
+#if defined(ELPP_UNICODE)
+# include <locale>
+# if ELPP_OS_WINDOWS
+# include <codecvt>
+# endif // ELPP_OS_WINDOWS
+#endif // defined(ELPP_UNICODE)
+#ifdef HAVE_EXECINFO
+# include <cxxabi.h>
+# include <execinfo.h>
+#endif // ENABLE_EXECINFO
+#if ELPP_OS_ANDROID
+# include <sys/system_properties.h>
+#endif // ELPP_OS_ANDROID
+#if ELPP_OS_UNIX
+# include <sys/stat.h>
+# include <sys/time.h>
+#elif ELPP_OS_WINDOWS
+# include <direct.h>
+# include <windows.h>
+# if defined(WIN32_LEAN_AND_MEAN)
+# if defined(ELPP_WINSOCK2)
+# include <winsock2.h>
+# else
+# include <winsock.h>
+# endif // defined(ELPP_WINSOCK2)
+# endif // defined(WIN32_LEAN_AND_MEAN)
+#endif // ELPP_OS_UNIX
+#include <string>
+#include <vector>
+#include <map>
+#include <unordered_map>
+#include <utility>
+#include <functional>
+#include <algorithm>
+#include <fstream>
+#include <iostream>
+#include <sstream>
+#include <memory>
+#include <type_traits>
+#if ELPP_THREADING_ENABLED
+# if ELPP_USE_STD_THREADING
+# include <mutex>
+# include <thread>
+# else
+# if ELPP_OS_UNIX
+# include <pthread.h>
+# endif // ELPP_OS_UNIX
+# endif // ELPP_USE_STD_THREADING
+#endif // ELPP_THREADING_ENABLED
+#if ELPP_ASYNC_LOGGING
+# if defined(ELPP_NO_SLEEP_FOR)
+# include <unistd.h>
+# endif // defined(ELPP_NO_SLEEP_FOR)
+# include <thread>
+# include <queue>
+# include <condition_variable>
+#endif // ELPP_ASYNC_LOGGING
+#if defined(ELPP_STL_LOGGING)
+// For logging STL based templates
+# include <list>
+# include <queue>
+# include <deque>
+# include <set>
+# include <bitset>
+# include <stack>
+# if defined(ELPP_LOG_STD_ARRAY)
+# include <array>
+# endif // defined(ELPP_LOG_STD_ARRAY)
+# if defined(ELPP_LOG_UNORDERED_SET)
+# include <unordered_set>
+# endif // defined(ELPP_UNORDERED_SET)
+#endif // defined(ELPP_STL_LOGGING)
+#if defined(ELPP_QT_LOGGING)
+// For logging Qt based classes & templates
+# include <QString>
+# include <QByteArray>
+# include <QVector>
+# include <QList>
+# include <QPair>
+# include <QMap>
+# include <QQueue>
+# include <QSet>
+# include <QLinkedList>
+# include <QHash>
+# include <QMultiHash>
+# include <QStack>
+#endif // defined(ELPP_QT_LOGGING)
+#if defined(ELPP_BOOST_LOGGING)
+// For logging boost based classes & templates
+# include <boost/container/vector.hpp>
+# include <boost/container/stable_vector.hpp>
+# include <boost/container/list.hpp>
+# include <boost/container/deque.hpp>
+# include <boost/container/map.hpp>
+# include <boost/container/flat_map.hpp>
+# include <boost/container/set.hpp>
+# include <boost/container/flat_set.hpp>
+#endif // defined(ELPP_BOOST_LOGGING)
+#if defined(ELPP_WXWIDGETS_LOGGING)
+// For logging wxWidgets based classes & templates
+# include <wx/vector.h>
+#endif // defined(ELPP_WXWIDGETS_LOGGING)
+#if defined(ELPP_UTC_DATETIME)
+# define elpptime_r gmtime_r
+# define elpptime_s gmtime_s
+# define elpptime gmtime
+#else
+# define elpptime_r localtime_r
+# define elpptime_s localtime_s
+# define elpptime localtime
+#endif // defined(ELPP_UTC_DATETIME)
+// Forward declarations
+namespace el {
+class Logger;
+class LogMessage;
+class PerformanceTrackingData;
+class Loggers;
+class Helpers;
+template <typename T> class Callback;
+class LogDispatchCallback;
+class PerformanceTrackingCallback;
+class LoggerRegistrationCallback;
+class LogDispatchData;
+namespace base {
+class Storage;
+class RegisteredLoggers;
+class PerformanceTracker;
+class MessageBuilder;
+class Writer;
+class PErrorWriter;
+class LogDispatcher;
+class DefaultLogBuilder;
+class DefaultLogDispatchCallback;
+#if ELPP_ASYNC_LOGGING
+class AsyncLogDispatchCallback;
+class AsyncDispatchWorker;
+#endif // ELPP_ASYNC_LOGGING
+class DefaultPerformanceTrackingCallback;
+} // namespace base
+} // namespace el
+/// @brief Easylogging++ entry namespace
+namespace el {
+/// @brief Namespace containing base/internal functionality used by Easylogging++
+namespace base {
+/// @brief Data types used by Easylogging++
+namespace type {
+#undef ELPP_LITERAL
+#undef ELPP_STRLEN
+#undef ELPP_COUT
+#if defined(ELPP_UNICODE)
+# define ELPP_LITERAL(txt) L##txt
+# define ELPP_STRLEN wcslen
+# if defined ELPP_CUSTOM_COUT
+# define ELPP_COUT ELPP_CUSTOM_COUT
+# else
+# define ELPP_COUT std::wcout
+# endif // defined ELPP_CUSTOM_COUT
+typedef wchar_t char_t;
+typedef std::wstring string_t;
+typedef std::wstringstream stringstream_t;
+typedef std::wfstream fstream_t;
+typedef std::wostream ostream_t;
+#else
+# define ELPP_LITERAL(txt) txt
+# define ELPP_STRLEN strlen
+# if defined ELPP_CUSTOM_COUT
+# define ELPP_COUT ELPP_CUSTOM_COUT
+# else
+# define ELPP_COUT std::cout
+# endif // defined ELPP_CUSTOM_COUT
+typedef char char_t;
+typedef std::string string_t;
+typedef std::stringstream stringstream_t;
+typedef std::fstream fstream_t;
+typedef std::ostream ostream_t;
+#endif // defined(ELPP_UNICODE)
+#if defined(ELPP_CUSTOM_COUT_LINE)
+# define ELPP_COUT_LINE(logLine) ELPP_CUSTOM_COUT_LINE(logLine)
+#else
+# define ELPP_COUT_LINE(logLine) logLine << std::flush
+#endif // defined(ELPP_CUSTOM_COUT_LINE)
+typedef unsigned int EnumType;
+typedef unsigned short VerboseLevel;
+typedef unsigned long int LineNumber;
+typedef std::shared_ptr<base::Storage> StoragePointer;
+typedef std::shared_ptr<LogDispatchCallback> LogDispatchCallbackPtr;
+typedef std::shared_ptr<PerformanceTrackingCallback> PerformanceTrackingCallbackPtr;
+typedef std::shared_ptr<LoggerRegistrationCallback> LoggerRegistrationCallbackPtr;
+typedef std::unique_ptr<el::base::PerformanceTracker> PerformanceTrackerPtr;
+} // namespace type
+/// @brief Internal helper class that prevent copy constructor for class
+///
+/// @detail When using this class simply inherit it privately
+class NoCopy {
+ protected:
+ NoCopy(void) {}
+ private:
+ NoCopy(const NoCopy&);
+ NoCopy& operator=(const NoCopy&);
+};
+/// @brief Internal helper class that makes all default constructors private.
+///
+/// @detail This prevents initializing class making it static unless an explicit constructor is declared.
+/// When using this class simply inherit it privately
+class StaticClass {
+ private:
+ StaticClass(void);
+ StaticClass(const StaticClass&);
+ StaticClass& operator=(const StaticClass&);
+};
+} // namespace base
+/// @brief Represents enumeration for severity level used to determine level of logging
+///
+/// @detail With Easylogging++, developers may disable or enable any level regardless of
+/// what the severity is. Or they can choose to log using hierarchical logging flag
+enum class Level : base::type::EnumType {
+ /// @brief Generic level that represents all the levels. Useful when setting global configuration for all levels
+ Global = 1,
+ /// @brief Information that can be useful to back-trace certain events - mostly useful than debug logs.
+ Trace = 2,
+ /// @brief Informational events most useful for developers to debug application
+ Debug = 4,
+ /// @brief Severe error information that will presumably abort application
+ Fatal = 8,
+ /// @brief Information representing errors in application but application will keep running
+ Error = 16,
+ /// @brief Useful when application has potentially harmful situations
+ Warning = 32,
+ /// @brief Information that can be highly useful and vary with verbose logging level.
+ Verbose = 64,
+ /// @brief Mainly useful to represent current progress of application
+ Info = 128,
+ /// @brief Represents unknown level
+ Unknown = 1010
+};
+} // namespace el
+namespace std {
+template<> struct hash<el::Level> {
+ public:
+ std::size_t operator()(const el::Level& l) const {
+ return hash<el::base::type::EnumType> {}(static_cast<el::base::type::EnumType>(l));
+ }
+};
+}
+namespace el {
+/// @brief Static class that contains helper functions for el::Level
+class LevelHelper : base::StaticClass {
+ public:
+ /// @brief Represents minimum valid level. Useful when iterating through enum.
+ static const base::type::EnumType kMinValid = static_cast<base::type::EnumType>(Level::Trace);
+ /// @brief Represents maximum valid level. This is used internally and you should not need it.
+ static const base::type::EnumType kMaxValid = static_cast<base::type::EnumType>(Level::Info);
+ /// @brief Casts level to int, useful for iterating through enum.
+ static base::type::EnumType castToInt(Level level) {
+ return static_cast<base::type::EnumType>(level);
+ }
+ /// @brief Casts int(ushort) to level, useful for iterating through enum.
+ static Level castFromInt(base::type::EnumType l) {
+ return static_cast<Level>(l);
+ }
+ /// @brief Converts level to associated const char*
+ /// @return Upper case string based level.
+ static const char* convertToString(Level level);
+ /// @brief Converts from levelStr to Level
+ /// @param levelStr Upper case string based level.
+ /// Lower case is also valid but providing upper case is recommended.
+ static Level convertFromString(const char* levelStr);
+ /// @brief Applies specified function to each level starting from startIndex
+ /// @param startIndex initial value to start the iteration from. This is passed as pointer and
+ /// is left-shifted so this can be used inside function (fn) to represent current level.
+ /// @param fn function to apply with each level. This bool represent whether or not to stop iterating through levels.
+ static void forEachLevel(base::type::EnumType* startIndex, const std::function<bool(void)>& fn);
+};
+/// @brief Represents enumeration of ConfigurationType used to configure or access certain aspect
+/// of logging
+enum class ConfigurationType : base::type::EnumType {
+ /// @brief Determines whether or not corresponding level and logger of logging is enabled
+ /// You may disable all logs by using el::Level::Global
+ Enabled = 1,
+ /// @brief Whether or not to write corresponding log to log file
+ ToFile = 2,
+ /// @brief Whether or not to write corresponding level and logger log to standard output.
+ /// By standard output meaning termnal, command prompt etc
+ ToStandardOutput = 4,
+ /// @brief Determines format of logging corresponding level and logger.
+ Format = 8,
+ /// @brief Determines log file (full path) to write logs to for corresponding level and logger
+ Filename = 16,
+ /// @brief Specifies precision of the subsecond part. It should be within range (1-6).
+ SubsecondPrecision = 32,
+ /// @brief Alias of SubsecondPrecision (for backward compatibility)
+ MillisecondsWidth = SubsecondPrecision,
+ /// @brief Determines whether or not performance tracking is enabled.
+ ///
+ /// @detail This does not depend on logger or level. Performance tracking always uses 'performance' logger
+ PerformanceTracking = 64,
+ /// @brief Specifies log file max size.
+ ///
+ /// @detail If file size of corresponding log file (for corresponding level) is >= specified size, log file will
+ /// be truncated and re-initiated.
+ MaxLogFileSize = 128,
+ /// @brief Specifies number of log entries to hold until we flush pending log data
+ LogFlushThreshold = 256,
+ /// @brief Represents unknown configuration
+ Unknown = 1010
+};
+/// @brief Static class that contains helper functions for el::ConfigurationType
+class ConfigurationTypeHelper : base::StaticClass {
+ public:
+ /// @brief Represents minimum valid configuration type. Useful when iterating through enum.
+ static const base::type::EnumType kMinValid = static_cast<base::type::EnumType>(ConfigurationType::Enabled);
+ /// @brief Represents maximum valid configuration type. This is used internally and you should not need it.
+ static const base::type::EnumType kMaxValid = static_cast<base::type::EnumType>(ConfigurationType::MaxLogFileSize);
+ /// @brief Casts configuration type to int, useful for iterating through enum.
+ static base::type::EnumType castToInt(ConfigurationType configurationType) {
+ return static_cast<base::type::EnumType>(configurationType);
+ }
+ /// @brief Casts int(ushort) to configuration type, useful for iterating through enum.
+ static ConfigurationType castFromInt(base::type::EnumType c) {
+ return static_cast<ConfigurationType>(c);
+ }
+ /// @brief Converts configuration type to associated const char*
+ /// @returns Upper case string based configuration type.
+ static const char* convertToString(ConfigurationType configurationType);
+ /// @brief Converts from configStr to ConfigurationType
+ /// @param configStr Upper case string based configuration type.
+ /// Lower case is also valid but providing upper case is recommended.
+ static ConfigurationType convertFromString(const char* configStr);
+ /// @brief Applies specified function to each configuration type starting from startIndex
+ /// @param startIndex initial value to start the iteration from. This is passed by pointer and is left-shifted
+ /// so this can be used inside function (fn) to represent current configuration type.
+ /// @param fn function to apply with each configuration type.
+ /// This bool represent whether or not to stop iterating through configurations.
+ static inline void forEachConfigType(base::type::EnumType* startIndex, const std::function<bool(void)>& fn);
+};
+/// @brief Flags used while writing logs. This flags are set by user
+enum class LoggingFlag : base::type::EnumType {
+ /// @brief Makes sure we have new line for each container log entry
+ NewLineForContainer = 1,
+ /// @brief Makes sure if -vmodule is used and does not specifies a module, then verbose
+ /// logging is allowed via that module.
+ AllowVerboseIfModuleNotSpecified = 2,
+ /// @brief When handling crashes by default, detailed crash reason will be logged as well
+ LogDetailedCrashReason = 4,
+ /// @brief Allows to disable application abortion when logged using FATAL level
+ DisableApplicationAbortOnFatalLog = 8,
+ /// @brief Flushes log with every log-entry (performance sensitive) - Disabled by default
+ ImmediateFlush = 16,
+ /// @brief Enables strict file rolling
+ StrictLogFileSizeCheck = 32,
+ /// @brief Make terminal output colorful for supported terminals
+ ColoredTerminalOutput = 64,
+ /// @brief Supports use of multiple logging in same macro, e.g, CLOG(INFO, "default", "network")
+ MultiLoggerSupport = 128,
+ /// @brief Disables comparing performance tracker's checkpoints
+ DisablePerformanceTrackingCheckpointComparison = 256,
+ /// @brief Disable VModules
+ DisableVModules = 512,
+ /// @brief Disable VModules extensions
+ DisableVModulesExtensions = 1024,
+ /// @brief Enables hierarchical logging
+ HierarchicalLogging = 2048,
+ /// @brief Creates logger automatically when not available
+ CreateLoggerAutomatically = 4096,
+ /// @brief Adds spaces b/w logs that separated by left-shift operator
+ AutoSpacing = 8192,
+ /// @brief Preserves time format and does not convert it to sec, hour etc (performance tracking only)
+ FixedTimeFormat = 16384,
+ // @brief Ignore SIGINT or crash
+ IgnoreSigInt = 32768,
+};
+namespace base {
+/// @brief Namespace containing constants used internally.
+namespace consts {
+static const char kFormatSpecifierCharValue = 'v';
+static const char kFormatSpecifierChar = '%';
+static const unsigned int kMaxLogPerCounter = 100000;
+static const unsigned int kMaxLogPerContainer = 100;
+static const unsigned int kDefaultSubsecondPrecision = 3;
+
+#ifdef ELPP_DEFAULT_LOGGER
+static const char* kDefaultLoggerId = ELPP_DEFAULT_LOGGER;
+#else
+static const char* kDefaultLoggerId = "default";
+#endif
+
+#if defined(ELPP_FEATURE_ALL) || defined(ELPP_FEATURE_PERFORMANCE_TRACKING)
+#ifdef ELPP_DEFAULT_PERFORMANCE_LOGGER
+static const char* kPerformanceLoggerId = ELPP_DEFAULT_PERFORMANCE_LOGGER;
+#else
+static const char* kPerformanceLoggerId = "performance";
+#endif // ELPP_DEFAULT_PERFORMANCE_LOGGER
+#endif
+
+#if defined(ELPP_SYSLOG)
+static const char* kSysLogLoggerId = "syslog";
+#endif // defined(ELPP_SYSLOG)
+
+#if ELPP_OS_WINDOWS
+static const char* kFilePathSeparator = "\\";
+#else
+static const char* kFilePathSeparator = "/";
+#endif // ELPP_OS_WINDOWS
+
+static const std::size_t kSourceFilenameMaxLength = 100;
+static const std::size_t kSourceLineMaxLength = 10;
+static const Level kPerformanceTrackerDefaultLevel = Level::Info;
+const struct {
+ double value;
+ const base::type::char_t* unit;
+} kTimeFormats[] = {
+ { 1000.0f, ELPP_LITERAL("us") },
+ { 1000.0f, ELPP_LITERAL("ms") },
+ { 60.0f, ELPP_LITERAL("seconds") },
+ { 60.0f, ELPP_LITERAL("minutes") },
+ { 24.0f, ELPP_LITERAL("hours") },
+ { 7.0f, ELPP_LITERAL("days") }
+};
+static const int kTimeFormatsCount = sizeof(kTimeFormats) / sizeof(kTimeFormats[0]);
+const struct {
+ int numb;
+ const char* name;
+ const char* brief;
+ const char* detail;
+} kCrashSignals[] = {
+ // NOTE: Do not re-order, if you do please check CrashHandler(bool) constructor and CrashHandler::setHandler(..)
+ {
+ SIGABRT, "SIGABRT", "Abnormal termination",
+ "Program was abnormally terminated."
+ },
+ {
+ SIGFPE, "SIGFPE", "Erroneous arithmetic operation",
+ "Arithmetic operation issue such as division by zero or operation resulting in overflow."
+ },
+ {
+ SIGILL, "SIGILL", "Illegal instruction",
+ "Generally due to a corruption in the code or to an attempt to execute data."
+ },
+ {
+ SIGSEGV, "SIGSEGV", "Invalid access to memory",
+ "Program is trying to read an invalid (unallocated, deleted or corrupted) or inaccessible memory."
+ },
+ {
+ SIGINT, "SIGINT", "Interactive attention signal",
+ "Interruption generated (generally) by user or operating system."
+ },
+};
+static const int kCrashSignalsCount = sizeof(kCrashSignals) / sizeof(kCrashSignals[0]);
+} // namespace consts
+} // namespace base
+typedef std::function<void(const char*, std::size_t)> PreRollOutCallback;
+namespace base {
+static inline void defaultPreRollOutCallback(const char*, std::size_t) {}
+/// @brief Enum to represent timestamp unit
+enum class TimestampUnit : base::type::EnumType {
+ Microsecond = 0, Millisecond = 1, Second = 2, Minute = 3, Hour = 4, Day = 5
+};
+/// @brief Format flags used to determine specifiers that are active for performance improvements.
+enum class FormatFlags : base::type::EnumType {
+ DateTime = 1 << 1,
+ LoggerId = 1 << 2,
+ File = 1 << 3,
+ Line = 1 << 4,
+ Location = 1 << 5,
+ Function = 1 << 6,
+ User = 1 << 7,
+ Host = 1 << 8,
+ LogMessage = 1 << 9,
+ VerboseLevel = 1 << 10,
+ AppName = 1 << 11,
+ ThreadId = 1 << 12,
+ Level = 1 << 13,
+ FileBase = 1 << 14,
+ LevelShort = 1 << 15
+};
+/// @brief A subsecond precision class containing actual width and offset of the subsecond part
+class SubsecondPrecision {
+ public:
+ SubsecondPrecision(void) {
+ init(base::consts::kDefaultSubsecondPrecision);
+ }
+ explicit SubsecondPrecision(int width) {
+ init(width);
+ }
+ bool operator==(const SubsecondPrecision& ssPrec) {
+ return m_width == ssPrec.m_width && m_offset == ssPrec.m_offset;
+ }
+ int m_width;
+ unsigned int m_offset;
+ private:
+ void init(int width);
+};
+/// @brief Type alias of SubsecondPrecision
+typedef SubsecondPrecision MillisecondsWidth;
+/// @brief Namespace containing utility functions/static classes used internally
+namespace utils {
+/// @brief Deletes memory safely and points to null
+template <typename T>
+static
+typename std::enable_if<std::is_pointer<T*>::value, void>::type
+safeDelete(T*& pointer) {
+ if (pointer == nullptr)
+ return;
+ delete pointer;
+ pointer = nullptr;
+}
+/// @brief Bitwise operations for C++11 strong enum class. This casts e into Flag_T and returns value after bitwise operation
+/// Use these function as <pre>flag = bitwise::Or<MyEnum>(MyEnum::val1, flag);</pre>
+namespace bitwise {
+template <typename Enum>
+static inline base::type::EnumType And(Enum e, base::type::EnumType flag) {
+ return static_cast<base::type::EnumType>(flag) & static_cast<base::type::EnumType>(e);
+}
+template <typename Enum>
+static inline base::type::EnumType Not(Enum e, base::type::EnumType flag) {
+ return static_cast<base::type::EnumType>(flag) & ~(static_cast<base::type::EnumType>(e));
+}
+template <typename Enum>
+static inline base::type::EnumType Or(Enum e, base::type::EnumType flag) {
+ return static_cast<base::type::EnumType>(flag) | static_cast<base::type::EnumType>(e);
+}
+} // namespace bitwise
+template <typename Enum>
+static inline void addFlag(Enum e, base::type::EnumType* flag) {
+ *flag = base::utils::bitwise::Or<Enum>(e, *flag);
+}
+template <typename Enum>
+static inline void removeFlag(Enum e, base::type::EnumType* flag) {
+ *flag = base::utils::bitwise::Not<Enum>(e, *flag);
+}
+template <typename Enum>
+static inline bool hasFlag(Enum e, base::type::EnumType flag) {
+ return base::utils::bitwise::And<Enum>(e, flag) > 0x0;
+}
+} // namespace utils
+namespace threading {
+#if ELPP_THREADING_ENABLED
+# if !ELPP_USE_STD_THREADING
+namespace internal {
+/// @brief A mutex wrapper for compiler that dont yet support std::recursive_mutex
+class Mutex : base::NoCopy {
+ public:
+ Mutex(void) {
+# if ELPP_OS_UNIX
+ pthread_mutexattr_t attr;
+ pthread_mutexattr_init(&attr);
+ pthread_mutexattr_settype(&attr, PTHREAD_MUTEX_RECURSIVE);
+ pthread_mutex_init(&m_underlyingMutex, &attr);
+ pthread_mutexattr_destroy(&attr);
+# elif ELPP_OS_WINDOWS
+ InitializeCriticalSection(&m_underlyingMutex);
+# endif // ELPP_OS_UNIX
+ }
+
+ virtual ~Mutex(void) {
+# if ELPP_OS_UNIX
+ pthread_mutex_destroy(&m_underlyingMutex);
+# elif ELPP_OS_WINDOWS
+ DeleteCriticalSection(&m_underlyingMutex);
+# endif // ELPP_OS_UNIX
+ }
+
+ inline void lock(void) {
+# if ELPP_OS_UNIX
+ pthread_mutex_lock(&m_underlyingMutex);
+# elif ELPP_OS_WINDOWS
+ EnterCriticalSection(&m_underlyingMutex);
+# endif // ELPP_OS_UNIX
+ }
+
+ inline bool try_lock(void) {
+# if ELPP_OS_UNIX
+ return (pthread_mutex_trylock(&m_underlyingMutex) == 0);
+# elif ELPP_OS_WINDOWS
+ return TryEnterCriticalSection(&m_underlyingMutex);
+# endif // ELPP_OS_UNIX
+ }
+
+ inline void unlock(void) {
+# if ELPP_OS_UNIX
+ pthread_mutex_unlock(&m_underlyingMutex);
+# elif ELPP_OS_WINDOWS
+ LeaveCriticalSection(&m_underlyingMutex);
+# endif // ELPP_OS_UNIX
+ }
+
+ private:
+# if ELPP_OS_UNIX
+ pthread_mutex_t m_underlyingMutex;
+# elif ELPP_OS_WINDOWS
+ CRITICAL_SECTION m_underlyingMutex;
+# endif // ELPP_OS_UNIX
+};
+/// @brief Scoped lock for compiler that dont yet support std::lock_guard
+template <typename M>
+class ScopedLock : base::NoCopy {
+ public:
+ explicit ScopedLock(M& mutex) {
+ m_mutex = &mutex;
+ m_mutex->lock();
+ }
+
+ virtual ~ScopedLock(void) {
+ m_mutex->unlock();
+ }
+ private:
+ M* m_mutex;
+ ScopedLock(void);
+};
+} // namespace internal
+typedef base::threading::internal::Mutex Mutex;
+typedef base::threading::internal::ScopedLock<base::threading::Mutex> ScopedLock;
+# else
+typedef std::recursive_mutex Mutex;
+typedef std::lock_guard<base::threading::Mutex> ScopedLock;
+# endif // !ELPP_USE_STD_THREADING
+#else
+namespace internal {
+/// @brief Mutex wrapper used when multi-threading is disabled.
+class NoMutex : base::NoCopy {
+ public:
+ NoMutex(void) {}
+ inline void lock(void) {}
+ inline bool try_lock(void) {
+ return true;
+ }
+ inline void unlock(void) {}
+};
+/// @brief Lock guard wrapper used when multi-threading is disabled.
+template <typename Mutex>
+class NoScopedLock : base::NoCopy {
+ public:
+ explicit NoScopedLock(Mutex&) {
+ }
+ virtual ~NoScopedLock(void) {
+ }
+ private:
+ NoScopedLock(void);
+};
+} // namespace internal
+typedef base::threading::internal::NoMutex Mutex;
+typedef base::threading::internal::NoScopedLock<base::threading::Mutex> ScopedLock;
+#endif // ELPP_THREADING_ENABLED
+/// @brief Base of thread safe class, this class is inheritable-only
+class ThreadSafe {
+ public:
+ virtual inline void acquireLock(void) ELPP_FINAL { m_mutex.lock(); }
+ virtual inline void releaseLock(void) ELPP_FINAL { m_mutex.unlock(); }
+ virtual inline base::threading::Mutex& lock(void) ELPP_FINAL { return m_mutex; }
+ protected:
+ ThreadSafe(void) {}
+ virtual ~ThreadSafe(void) {}
+ private:
+ base::threading::Mutex m_mutex;
+};
+
+#if ELPP_THREADING_ENABLED
+# if !ELPP_USE_STD_THREADING
+/// @brief Gets ID of currently running threading in windows systems. On unix, nothing is returned.
+static std::string getCurrentThreadId(void) {
+ std::stringstream ss;
+# if (ELPP_OS_WINDOWS)
+ ss << GetCurrentThreadId();
+# endif // (ELPP_OS_WINDOWS)
+ return ss.str();
+}
+# else
+/// @brief Gets ID of currently running threading using std::this_thread::get_id()
+static std::string getCurrentThreadId(void) {
+ std::stringstream ss;
+ ss << std::this_thread::get_id();
+ return ss.str();
+}
+# endif // !ELPP_USE_STD_THREADING
+#else
+static inline std::string getCurrentThreadId(void) {
+ return std::string();
+}
+#endif // ELPP_THREADING_ENABLED
+} // namespace threading
+namespace utils {
+class File : base::StaticClass {
+ public:
+ /// @brief Creates new out file stream for specified filename.
+ /// @return Pointer to newly created fstream or nullptr
+ static base::type::fstream_t* newFileStream(const std::string& filename);
+
+ /// @brief Gets size of file provided in stream
+ static std::size_t getSizeOfFile(base::type::fstream_t* fs);
+
+ /// @brief Determines whether or not provided path exist in current file system
+ static bool pathExists(const char* path, bool considerFile = false);
+
+ /// @brief Creates specified path on file system
+ /// @param path Path to create.
+ static bool createPath(const std::string& path);
+ /// @brief Extracts path of filename with leading slash
+ static std::string extractPathFromFilename(const std::string& fullPath,
+ const char* separator = base::consts::kFilePathSeparator);
+ /// @brief builds stripped filename and puts it in buff
+ static void buildStrippedFilename(const char* filename, char buff[],
+ std::size_t limit = base::consts::kSourceFilenameMaxLength);
+ /// @brief builds base filename and puts it in buff
+ static void buildBaseFilename(const std::string& fullPath, char buff[],
+ std::size_t limit = base::consts::kSourceFilenameMaxLength,
+ const char* separator = base::consts::kFilePathSeparator);
+};
+/// @brief String utilities helper class used internally. You should not use it.
+class Str : base::StaticClass {
+ public:
+ /// @brief Checks if character is digit. Dont use libc implementation of it to prevent locale issues.
+ static inline bool isDigit(char c) {
+ return c >= '0' && c <= '9';
+ }
+
+ /// @brief Matches wildcards, '*' and '?' only supported.
+ static bool wildCardMatch(const char* str, const char* pattern);
+
+ static std::string& ltrim(std::string& str);
+ static std::string& rtrim(std::string& str);
+ static std::string& trim(std::string& str);
+
+ /// @brief Determines whether or not str starts with specified string
+ /// @param str String to check
+ /// @param start String to check against
+ /// @return Returns true if starts with specified string, false otherwise
+ static bool startsWith(const std::string& str, const std::string& start);
+
+ /// @brief Determines whether or not str ends with specified string
+ /// @param str String to check
+ /// @param end String to check against
+ /// @return Returns true if ends with specified string, false otherwise
+ static bool endsWith(const std::string& str, const std::string& end);
+
+ /// @brief Replaces all instances of replaceWhat with 'replaceWith'. Original variable is changed for performance.
+ /// @param [in,out] str String to replace from
+ /// @param replaceWhat Character to replace
+ /// @param replaceWith Character to replace with
+ /// @return Modified version of str
+ static std::string& replaceAll(std::string& str, char replaceWhat, char replaceWith);
+
+ /// @brief Replaces all instances of 'replaceWhat' with 'replaceWith'. (String version) Replaces in place
+ /// @param str String to replace from
+ /// @param replaceWhat Character to replace
+ /// @param replaceWith Character to replace with
+ /// @return Modified (original) str
+ static std::string& replaceAll(std::string& str, const std::string& replaceWhat,
+ const std::string& replaceWith);
+
+ static void replaceFirstWithEscape(base::type::string_t& str, const base::type::string_t& replaceWhat,
+ const base::type::string_t& replaceWith);
+#if defined(ELPP_UNICODE)
+ static void replaceFirstWithEscape(base::type::string_t& str, const base::type::string_t& replaceWhat,
+ const std::string& replaceWith);
+#endif // defined(ELPP_UNICODE)
+ /// @brief Converts string to uppercase
+ /// @param str String to convert
+ /// @return Uppercase string
+ static std::string& toUpper(std::string& str);
+
+ /// @brief Compares cstring equality - uses strcmp
+ static bool cStringEq(const char* s1, const char* s2);
+
+ /// @brief Compares cstring equality (case-insensitive) - uses toupper(char)
+ /// Dont use strcasecmp because of CRT (VC++)
+ static bool cStringCaseEq(const char* s1, const char* s2);
+
+ /// @brief Returns true if c exist in str
+ static bool contains(const char* str, char c);
+
+ static char* convertAndAddToBuff(std::size_t n, int len, char* buf, const char* bufLim, bool zeroPadded = true);
+ static char* addToBuff(const char* str, char* buf, const char* bufLim);
+ static char* clearBuff(char buff[], std::size_t lim);
+
+ /// @brief Converts wchar* to char*
+ /// NOTE: Need to free return value after use!
+ static char* wcharPtrToCharPtr(const wchar_t* line);
+};
+/// @brief Operating System helper static class used internally. You should not use it.
+class OS : base::StaticClass {
+ public:
+#if ELPP_OS_WINDOWS
+ /// @brief Gets environment variables for Windows based OS.
+ /// We are not using <code>getenv(const char*)</code> because of CRT deprecation
+ /// @param varname Variable name to get environment variable value for
+ /// @return If variable exist the value of it otherwise nullptr
+ static const char* getWindowsEnvironmentVariable(const char* varname);
+#endif // ELPP_OS_WINDOWS
+#if ELPP_OS_ANDROID
+ /// @brief Reads android property value
+ static std::string getProperty(const char* prop);
+
+ /// @brief Reads android device name
+ static std::string getDeviceName(void);
+#endif // ELPP_OS_ANDROID
+
+ /// @brief Runs command on terminal and returns the output.
+ ///
+ /// @detail This is applicable only on unix based systems, for all other OS, an empty string is returned.
+ /// @param command Bash command
+ /// @return Result of bash output or empty string if no result found.
+ static const std::string getBashOutput(const char* command);
+
+ /// @brief Gets environment variable. This is cross-platform and CRT safe (for VC++)
+ /// @param variableName Environment variable name
+ /// @param defaultVal If no environment variable or value found the value to return by default
+ /// @param alternativeBashCommand If environment variable not found what would be alternative bash command
+ /// in order to look for value user is looking for. E.g, for 'user' alternative command will 'whoami'
+ static std::string getEnvironmentVariable(const char* variableName, const char* defaultVal,
+ const char* alternativeBashCommand = nullptr);
+ /// @brief Gets current username.
+ static std::string currentUser(void);
+
+ /// @brief Gets current host name or computer name.
+ ///
+ /// @detail For android systems this is device name with its manufacturer and model separated by hyphen
+ static std::string currentHost(void);
+ /// @brief Whether or not terminal supports colors
+ static bool termSupportsColor(void);
+};
+/// @brief Contains utilities for cross-platform date/time. This class make use of el::base::utils::Str
+class DateTime : base::StaticClass {
+ public:
+ /// @brief Cross platform gettimeofday for Windows and unix platform. This can be used to determine current microsecond.
+ ///
+ /// @detail For unix system it uses gettimeofday(timeval*, timezone*) and for Windows, a separate implementation is provided
+ /// @param [in,out] tv Pointer that gets updated
+ static void gettimeofday(struct timeval* tv);
+
+ /// @brief Gets current date and time with a subsecond part.
+ /// @param format User provided date/time format
+ /// @param ssPrec A pointer to base::SubsecondPrecision from configuration (non-null)
+ /// @returns string based date time in specified format.
+ static std::string getDateTime(const char* format, const base::SubsecondPrecision* ssPrec);
+
+ /// @brief Converts timeval (struct from ctime) to string using specified format and subsecond precision
+ static std::string timevalToString(struct timeval tval, const char* format,
+ const el::base::SubsecondPrecision* ssPrec);
+
+ /// @brief Formats time to get unit accordingly, units like second if > 1000 or minutes if > 60000 etc
+ static base::type::string_t formatTime(unsigned long long time, base::TimestampUnit timestampUnit);
+
+ /// @brief Gets time difference in milli/micro second depending on timestampUnit
+ static unsigned long long getTimeDifference(const struct timeval& endTime, const struct timeval& startTime,
+ base::TimestampUnit timestampUnit);
+
+
+ static struct ::tm* buildTimeInfo(struct timeval* currTime, struct ::tm* timeInfo);
+ private:
+ static char* parseFormat(char* buf, std::size_t bufSz, const char* format, const struct tm* tInfo,
+ std::size_t msec, const base::SubsecondPrecision* ssPrec);
+};
+/// @brief Command line arguments for application if specified using el::Helpers::setArgs(..) or START_EASYLOGGINGPP(..)
+class CommandLineArgs {
+ public:
+ CommandLineArgs(void) {
+ setArgs(0, static_cast<char**>(nullptr));
+ }
+ CommandLineArgs(int argc, const char** argv) {
+ setArgs(argc, argv);
+ }
+ CommandLineArgs(int argc, char** argv) {
+ setArgs(argc, argv);
+ }
+ virtual ~CommandLineArgs(void) {}
+ /// @brief Sets arguments and parses them
+ inline void setArgs(int argc, const char** argv) {
+ setArgs(argc, const_cast<char**>(argv));
+ }
+ /// @brief Sets arguments and parses them
+ void setArgs(int argc, char** argv);
+ /// @brief Returns true if arguments contain paramKey with a value (separated by '=')
+ bool hasParamWithValue(const char* paramKey) const;
+ /// @brief Returns value of arguments
+ /// @see hasParamWithValue(const char*)
+ const char* getParamValue(const char* paramKey) const;
+ /// @brief Return true if arguments has a param (not having a value) i,e without '='
+ bool hasParam(const char* paramKey) const;
+ /// @brief Returns true if no params available. This exclude argv[0]
+ bool empty(void) const;
+ /// @brief Returns total number of arguments. This exclude argv[0]
+ std::size_t size(void) const;
+ friend base::type::ostream_t& operator<<(base::type::ostream_t& os, const CommandLineArgs& c);
+
+ private:
+ int m_argc;
+ char** m_argv;
+ std::unordered_map<std::string, std::string> m_paramsWithValue;
+ std::vector<std::string> m_params;
+};
+/// @brief Abstract registry (aka repository) that provides basic interface for pointer repository specified by T_Ptr type.
+///
+/// @detail Most of the functions are virtual final methods but anything implementing this abstract class should implement
+/// unregisterAll() and deepCopy(const AbstractRegistry<T_Ptr, Container>&) and write registerNew() method according to container
+/// and few more methods; get() to find element, unregister() to unregister single entry.
+/// Please note that this is thread-unsafe and should also implement thread-safety mechanisms in implementation.
+template <typename T_Ptr, typename Container>
+class AbstractRegistry : public base::threading::ThreadSafe {
+ public:
+ typedef typename Container::iterator iterator;
+ typedef typename Container::const_iterator const_iterator;
+
+ /// @brief Default constructor
+ AbstractRegistry(void) {}
+
+ /// @brief Move constructor that is useful for base classes
+ AbstractRegistry(AbstractRegistry&& sr) {
+ if (this == &sr) {
+ return;
+ }
+ unregisterAll();
+ m_list = std::move(sr.m_list);
+ }
+
+ bool operator==(const AbstractRegistry<T_Ptr, Container>& other) {
+ if (size() != other.size()) {
+ return false;
+ }
+ for (std::size_t i = 0; i < m_list.size(); ++i) {
+ if (m_list.at(i) != other.m_list.at(i)) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ bool operator!=(const AbstractRegistry<T_Ptr, Container>& other) {
+ if (size() != other.size()) {
+ return true;
+ }
+ for (std::size_t i = 0; i < m_list.size(); ++i) {
+ if (m_list.at(i) != other.m_list.at(i)) {
+ return true;
+ }
+ }
+ return false;
+ }
+
+ /// @brief Assignment move operator
+ AbstractRegistry& operator=(AbstractRegistry&& sr) {
+ if (this == &sr) {
+ return *this;
+ }
+ unregisterAll();
+ m_list = std::move(sr.m_list);
+ return *this;
+ }
+
+ virtual ~AbstractRegistry(void) {
+ }
+
+ /// @return Iterator pointer from start of repository
+ virtual inline iterator begin(void) ELPP_FINAL {
+ return m_list.begin();
+ }
+
+ /// @return Iterator pointer from end of repository
+ virtual inline iterator end(void) ELPP_FINAL {
+ return m_list.end();
+ }
+
+
+ /// @return Constant iterator pointer from start of repository
+ virtual inline const_iterator cbegin(void) const ELPP_FINAL {
+ return m_list.cbegin();
+ }
+
+ /// @return End of repository
+ virtual inline const_iterator cend(void) const ELPP_FINAL {
+ return m_list.cend();
+ }
+
+ /// @return Whether or not repository is empty
+ virtual inline bool empty(void) const ELPP_FINAL {
+ return m_list.empty();
+ }
+
+ /// @return Size of repository
+ virtual inline std::size_t size(void) const ELPP_FINAL {
+ return m_list.size();
+ }
+
+ /// @brief Returns underlying container by reference
+ virtual inline Container& list(void) ELPP_FINAL {
+ return m_list;
+ }
+
+ /// @brief Returns underlying container by constant reference.
+ virtual inline const Container& list(void) const ELPP_FINAL {
+ return m_list;
+ }
+
+ /// @brief Unregisters all the pointers from current repository.
+ virtual void unregisterAll(void) = 0;
+
+ protected:
+ virtual void deepCopy(const AbstractRegistry<T_Ptr, Container>&) = 0;
+ void reinitDeepCopy(const AbstractRegistry<T_Ptr, Container>& sr) {
+ unregisterAll();
+ deepCopy(sr);
+ }
+
+ private:
+ Container m_list;
+};
+
+/// @brief A pointer registry mechanism to manage memory and provide search functionalities. (non-predicate version)
+///
+/// @detail NOTE: This is thread-unsafe implementation (although it contains lock function, it does not use these functions)
+/// of AbstractRegistry<T_Ptr, Container>. Any implementation of this class should be
+/// explicitly (by using lock functions)
+template <typename T_Ptr, typename T_Key = const char*>
+class Registry : public AbstractRegistry<T_Ptr, std::unordered_map<T_Key, T_Ptr*>> {
+ public:
+ typedef typename Registry<T_Ptr, T_Key>::iterator iterator;
+ typedef typename Registry<T_Ptr, T_Key>::const_iterator const_iterator;
+
+ Registry(void) {}
+
+ /// @brief Copy constructor that is useful for base classes. Try to avoid this constructor, use move constructor.
+ Registry(const Registry& sr) : AbstractRegistry<T_Ptr, std::vector<T_Ptr*>>() {
+ if (this == &sr) {
+ return;
+ }
+ this->reinitDeepCopy(sr);
+ }
+
+ /// @brief Assignment operator that unregisters all the existing registries and deeply copies each of repo element
+ /// @see unregisterAll()
+ /// @see deepCopy(const AbstractRegistry&)
+ Registry& operator=(const Registry& sr) {
+ if (this == &sr) {
+ return *this;
+ }
+ this->reinitDeepCopy(sr);
+ return *this;
+ }
+
+ virtual ~Registry(void) {
+ unregisterAll();
+ }
+
+ protected:
+ virtual void unregisterAll(void) ELPP_FINAL {
+ if (!this->empty()) {
+ for (auto&& curr : this->list()) {
+ base::utils::safeDelete(curr.second);
+ }
+ this->list().clear();
+ }
+ }
+
+/// @brief Registers new registry to repository.
+ virtual void registerNew(const T_Key& uniqKey, T_Ptr* ptr) ELPP_FINAL {
+ unregister(uniqKey);
+ this->list().insert(std::make_pair(uniqKey, ptr));
+ }
+
+/// @brief Unregisters single entry mapped to specified unique key
+ void unregister(const T_Key& uniqKey) {
+ T_Ptr* existing = get(uniqKey);
+ if (existing != nullptr) {
+ this->list().erase(uniqKey);
+ base::utils::safeDelete(existing);
+ }
+ }
+
+/// @brief Gets pointer from repository. If none found, nullptr is returned.
+ T_Ptr* get(const T_Key& uniqKey) {
+ iterator it = this->list().find(uniqKey);
+ return it == this->list().end()
+ ? nullptr
+ : it->second;
+ }
+
+ private:
+ virtual void deepCopy(const AbstractRegistry<T_Ptr, std::unordered_map<T_Key, T_Ptr*>>& sr) ELPP_FINAL {
+ for (const_iterator it = sr.cbegin(); it != sr.cend(); ++it) {
+ registerNew(it->first, new T_Ptr(*it->second));
+ }
+ }
+};
+
+/// @brief A pointer registry mechanism to manage memory and provide search functionalities. (predicate version)
+///
+/// @detail NOTE: This is thread-unsafe implementation of AbstractRegistry<T_Ptr, Container>. Any implementation of this class
+/// should be made thread-safe explicitly
+template <typename T_Ptr, typename Pred>
+class RegistryWithPred : public AbstractRegistry<T_Ptr, std::vector<T_Ptr*>> {
+ public:
+ typedef typename RegistryWithPred<T_Ptr, Pred>::iterator iterator;
+ typedef typename RegistryWithPred<T_Ptr, Pred>::const_iterator const_iterator;
+
+ RegistryWithPred(void) {
+ }
+
+ virtual ~RegistryWithPred(void) {
+ unregisterAll();
+ }
+
+ /// @brief Copy constructor that is useful for base classes. Try to avoid this constructor, use move constructor.
+ RegistryWithPred(const RegistryWithPred& sr) : AbstractRegistry<T_Ptr, std::vector<T_Ptr*>>() {
+ if (this == &sr) {
+ return;
+ }
+ this->reinitDeepCopy(sr);
+ }
+
+ /// @brief Assignment operator that unregisters all the existing registries and deeply copies each of repo element
+ /// @see unregisterAll()
+ /// @see deepCopy(const AbstractRegistry&)
+ RegistryWithPred& operator=(const RegistryWithPred& sr) {
+ if (this == &sr) {
+ return *this;
+ }
+ this->reinitDeepCopy(sr);
+ return *this;
+ }
+
+ friend base::type::ostream_t& operator<<(base::type::ostream_t& os, const RegistryWithPred& sr) {
+ for (const_iterator it = sr.list().begin(); it != sr.list().end(); ++it) {
+ os << ELPP_LITERAL(" ") << **it << ELPP_LITERAL("\n");
+ }
+ return os;
+ }
+
+ protected:
+ virtual void unregisterAll(void) ELPP_FINAL {
+ if (!this->empty()) {
+ for (auto&& curr : this->list()) {
+ base::utils::safeDelete(curr);
+ }
+ this->list().clear();
+ }
+ }
+
+ virtual void unregister(T_Ptr*& ptr) ELPP_FINAL {
+ if (ptr) {
+ iterator iter = this->begin();
+ for (; iter != this->end(); ++iter) {
+ if (ptr == *iter) {
+ break;
+ }
+ }
+ if (iter != this->end() && *iter != nullptr) {
+ this->list().erase(iter);
+ base::utils::safeDelete(*iter);
+ }
+ }
+ }
+
+ virtual inline void registerNew(T_Ptr* ptr) ELPP_FINAL {
+ this->list().push_back(ptr);
+ }
+
+/// @brief Gets pointer from repository with specified arguments. Arguments are passed to predicate
+/// in order to validate pointer.
+ template <typename T, typename T2>
+ T_Ptr* get(const T& arg1, const T2 arg2) {
+ iterator iter = std::find_if(this->list().begin(), this->list().end(), Pred(arg1, arg2));
+ if (iter != this->list().end() && *iter != nullptr) {
+ return *iter;
+ }
+ return nullptr;
+ }
+
+ private:
+ virtual void deepCopy(const AbstractRegistry<T_Ptr, std::vector<T_Ptr*>>& sr) {
+ for (const_iterator it = sr.list().begin(); it != sr.list().end(); ++it) {
+ registerNew(new T_Ptr(**it));
+ }
+ }
+};
+class Utils {
+ public:
+ template <typename T, typename TPtr>
+ static bool installCallback(const std::string& id, std::unordered_map<std::string, TPtr>* mapT) {
+ if (mapT->find(id) == mapT->end()) {
+ mapT->insert(std::make_pair(id, TPtr(new T())));
+ return true;
+ }
+ return false;
+ }
+
+ template <typename T, typename TPtr>
+ static void uninstallCallback(const std::string& id, std::unordered_map<std::string, TPtr>* mapT) {
+ if (mapT->find(id) != mapT->end()) {
+ mapT->erase(id);
+ }
+ }
+
+ template <typename T, typename TPtr>
+ static T* callback(const std::string& id, std::unordered_map<std::string, TPtr>* mapT) {
+ typename std::unordered_map<std::string, TPtr>::iterator iter = mapT->find(id);
+ if (iter != mapT->end()) {
+ return static_cast<T*>(iter->second.get());
+ }
+ return nullptr;
+ }
+};
+} // namespace utils
+} // namespace base
+/// @brief Base of Easylogging++ friendly class
+///
+/// @detail After inheriting this class publicly, implement pure-virtual function `void log(std::ostream&) const`
+class Loggable {
+ public:
+ virtual ~Loggable(void) {}
+ virtual void log(el::base::type::ostream_t&) const = 0;
+ private:
+ friend inline el::base::type::ostream_t& operator<<(el::base::type::ostream_t& os, const Loggable& loggable) {
+ loggable.log(os);
+ return os;
+ }
+};
+namespace base {
+/// @brief Represents log format containing flags and date format. This is used internally to start initial log
+class LogFormat : public Loggable {
+ public:
+ LogFormat(void);
+ LogFormat(Level level, const base::type::string_t& format);
+ LogFormat(const LogFormat& logFormat);
+ LogFormat(LogFormat&& logFormat);
+ LogFormat& operator=(const LogFormat& logFormat);
+ virtual ~LogFormat(void) {}
+ bool operator==(const LogFormat& other);
+
+ /// @brief Updates format to be used while logging.
+ /// @param userFormat User provided format
+ void parseFromFormat(const base::type::string_t& userFormat);
+
+ inline Level level(void) const {
+ return m_level;
+ }
+
+ inline const base::type::string_t& userFormat(void) const {
+ return m_userFormat;
+ }
+
+ inline const base::type::string_t& format(void) const {
+ return m_format;
+ }
+
+ inline const std::string& dateTimeFormat(void) const {
+ return m_dateTimeFormat;
+ }
+
+ inline base::type::EnumType flags(void) const {
+ return m_flags;
+ }
+
+ inline bool hasFlag(base::FormatFlags flag) const {
+ return base::utils::hasFlag(flag, m_flags);
+ }
+
+ virtual void log(el::base::type::ostream_t& os) const {
+ os << m_format;
+ }
+
+ protected:
+ /// @brief Updates date time format if available in currFormat.
+ /// @param index Index where %datetime, %date or %time was found
+ /// @param [in,out] currFormat current format that is being used to format
+ virtual void updateDateFormat(std::size_t index, base::type::string_t& currFormat) ELPP_FINAL;
+
+ /// @brief Updates %level from format. This is so that we dont have to do it at log-writing-time. It uses m_format and m_level
+ virtual void updateFormatSpec(void) ELPP_FINAL;
+
+ inline void addFlag(base::FormatFlags flag) {
+ base::utils::addFlag(flag, &m_flags);
+ }
+
+ private:
+ Level m_level;
+ base::type::string_t m_userFormat;
+ base::type::string_t m_format;
+ std::string m_dateTimeFormat;
+ base::type::EnumType m_flags;
+ std::string m_currentUser;
+ std::string m_currentHost;
+ friend class el::Logger; // To resolve loggerId format specifier easily
+};
+} // namespace base
+/// @brief Resolving function for format specifier
+typedef std::function<std::string(const LogMessage*)> FormatSpecifierValueResolver;
+/// @brief User-provided custom format specifier
+/// @see el::Helpers::installCustomFormatSpecifier
+/// @see FormatSpecifierValueResolver
+class CustomFormatSpecifier {
+ public:
+ CustomFormatSpecifier(const char* formatSpecifier, const FormatSpecifierValueResolver& resolver) :
+ m_formatSpecifier(formatSpecifier), m_resolver(resolver) {}
+ inline const char* formatSpecifier(void) const {
+ return m_formatSpecifier;
+ }
+ inline const FormatSpecifierValueResolver& resolver(void) const {
+ return m_resolver;
+ }
+ inline bool operator==(const char* formatSpecifier) {
+ return strcmp(m_formatSpecifier, formatSpecifier) == 0;
+ }
+
+ private:
+ const char* m_formatSpecifier;
+ FormatSpecifierValueResolver m_resolver;
+};
+/// @brief Represents single configuration that has representing level, configuration type and a string based value.
+///
+/// @detail String based value means any value either its boolean, integer or string itself, it will be embedded inside quotes
+/// and will be parsed later.
+///
+/// Consider some examples below:
+/// * el::Configuration confEnabledInfo(el::Level::Info, el::ConfigurationType::Enabled, "true");
+/// * el::Configuration confMaxLogFileSizeInfo(el::Level::Info, el::ConfigurationType::MaxLogFileSize, "2048");
+/// * el::Configuration confFilenameInfo(el::Level::Info, el::ConfigurationType::Filename, "/var/log/my.log");
+class Configuration : public Loggable {
+ public:
+ Configuration(const Configuration& c);
+ Configuration& operator=(const Configuration& c);
+
+ virtual ~Configuration(void) {
+ }
+
+ /// @brief Full constructor used to sets value of configuration
+ Configuration(Level level, ConfigurationType configurationType, const std::string& value);
+
+ /// @brief Gets level of current configuration
+ inline Level level(void) const {
+ return m_level;
+ }
+
+ /// @brief Gets configuration type of current configuration
+ inline ConfigurationType configurationType(void) const {
+ return m_configurationType;
+ }
+
+ /// @brief Gets string based configuration value
+ inline const std::string& value(void) const {
+ return m_value;
+ }
+
+ /// @brief Set string based configuration value
+ /// @param value Value to set. Values have to be std::string; For boolean values use "true", "false", for any integral values
+ /// use them in quotes. They will be parsed when configuring
+ inline void setValue(const std::string& value) {
+ m_value = value;
+ }
+
+ virtual void log(el::base::type::ostream_t& os) const;
+
+ /// @brief Used to find configuration from configuration (pointers) repository. Avoid using it.
+ class Predicate {
+ public:
+ Predicate(Level level, ConfigurationType configurationType);
+
+ bool operator()(const Configuration* conf) const;
+
+ private:
+ Level m_level;
+ ConfigurationType m_configurationType;
+ };
+
+ private:
+ Level m_level;
+ ConfigurationType m_configurationType;
+ std::string m_value;
+};
+
+/// @brief Thread-safe Configuration repository
+///
+/// @detail This repository represents configurations for all the levels and configuration type mapped to a value.
+class Configurations : public base::utils::RegistryWithPred<Configuration, Configuration::Predicate> {
+ public:
+ /// @brief Default constructor with empty repository
+ Configurations(void);
+
+ /// @brief Constructor used to set configurations using configuration file.
+ /// @param configurationFile Full path to configuration file
+ /// @param useDefaultsForRemaining Lets you set the remaining configurations to default.
+ /// @param base If provided, this configuration will be based off existing repository that this argument is pointing to.
+ /// @see parseFromFile(const std::string&, Configurations* base)
+ /// @see setRemainingToDefault()
+ Configurations(const std::string& configurationFile, bool useDefaultsForRemaining = true,
+ Configurations* base = nullptr);
+
+ virtual ~Configurations(void) {
+ }
+
+ /// @brief Parses configuration from file.
+ /// @param configurationFile Full path to configuration file
+ /// @param base Configurations to base new configuration repository off. This value is used when you want to use
+ /// existing Configurations to base all the values and then set rest of configuration via configuration file.
+ /// @return True if successfully parsed, false otherwise. You may define 'ELPP_DEBUG_ASSERT_FAILURE' to make sure you
+ /// do not proceed without successful parse.
+ bool parseFromFile(const std::string& configurationFile, Configurations* base = nullptr);
+
+ /// @brief Parse configurations from configuration string.
+ ///
+ /// @detail This configuration string has same syntax as configuration file contents. Make sure all the necessary
+ /// new line characters are provided.
+ /// @param base Configurations to base new configuration repository off. This value is used when you want to use
+ /// existing Configurations to base all the values and then set rest of configuration via configuration text.
+ /// @return True if successfully parsed, false otherwise. You may define 'ELPP_DEBUG_ASSERT_FAILURE' to make sure you
+ /// do not proceed without successful parse.
+ bool parseFromText(const std::string& configurationsString, Configurations* base = nullptr);
+
+ /// @brief Sets configuration based-off an existing configurations.
+ /// @param base Pointer to existing configurations.
+ void setFromBase(Configurations* base);
+
+ /// @brief Determines whether or not specified configuration type exists in the repository.
+ ///
+ /// @detail Returns as soon as first level is found.
+ /// @param configurationType Type of configuration to check existence for.
+ bool hasConfiguration(ConfigurationType configurationType);
+
+ /// @brief Determines whether or not specified configuration type exists for specified level
+ /// @param level Level to check
+ /// @param configurationType Type of configuration to check existence for.
+ bool hasConfiguration(Level level, ConfigurationType configurationType);
+
+ /// @brief Sets value of configuration for specified level.
+ ///
+ /// @detail Any existing configuration for specified level will be replaced. Also note that configuration types
+ /// ConfigurationType::SubsecondPrecision and ConfigurationType::PerformanceTracking will be ignored if not set for
+ /// Level::Global because these configurations are not dependant on level.
+ /// @param level Level to set configuration for (el::Level).
+ /// @param configurationType Type of configuration (el::ConfigurationType)
+ /// @param value A string based value. Regardless of what the data type of configuration is, it will always be string
+ /// from users' point of view. This is then parsed later to be used internally.
+ /// @see Configuration::setValue(const std::string& value)
+ /// @see el::Level
+ /// @see el::ConfigurationType
+ void set(Level level, ConfigurationType configurationType, const std::string& value);
+
+ /// @brief Sets single configuration based on other single configuration.
+ /// @see set(Level level, ConfigurationType configurationType, const std::string& value)
+ void set(Configuration* conf);
+
+ inline Configuration* get(Level level, ConfigurationType configurationType) {
+ base::threading::ScopedLock scopedLock(lock());
+ return RegistryWithPred<Configuration, Configuration::Predicate>::get(level, configurationType);
+ }
+
+ /// @brief Sets configuration for all levels.
+ /// @param configurationType Type of configuration
+ /// @param value String based value
+ /// @see Configurations::set(Level level, ConfigurationType configurationType, const std::string& value)
+ inline void setGlobally(ConfigurationType configurationType, const std::string& value) {
+ setGlobally(configurationType, value, false);
+ }
+
+ /// @brief Clears repository so that all the configurations are unset
+ inline void clear(void) {
+ base::threading::ScopedLock scopedLock(lock());
+ unregisterAll();
+ }
+
+ /// @brief Gets configuration file used in parsing this configurations.
+ ///
+ /// @detail If this repository was set manually or by text this returns empty string.
+ inline const std::string& configurationFile(void) const {
+ return m_configurationFile;
+ }
+
+ /// @brief Sets configurations to "factory based" configurations.
+ void setToDefault(void);
+
+ /// @brief Lets you set the remaining configurations to default.
+ ///
+ /// @detail By remaining, it means that the level/type a configuration does not exist for.
+ /// This function is useful when you want to minimize chances of failures, e.g, if you have a configuration file that sets
+ /// configuration for all the configurations except for Enabled or not, we use this so that ENABLED is set to default i.e,
+ /// true. If you dont do this explicitly (either by calling this function or by using second param in Constructor
+ /// and try to access a value, an error is thrown
+ void setRemainingToDefault(void);
+
+ /// @brief Parser used internally to parse configurations from file or text.
+ ///
+ /// @detail This class makes use of base::utils::Str.
+ /// You should not need this unless you are working on some tool for Easylogging++
+ class Parser : base::StaticClass {
+ public:
+ /// @brief Parses configuration from file.
+ /// @param configurationFile Full path to configuration file
+ /// @param sender Sender configurations pointer. Usually 'this' is used from calling class
+ /// @param base Configurations to base new configuration repository off. This value is used when you want to use
+ /// existing Configurations to base all the values and then set rest of configuration via configuration file.
+ /// @return True if successfully parsed, false otherwise. You may define '_STOP_ON_FIRSTELPP_ASSERTION' to make sure you
+ /// do not proceed without successful parse.
+ static bool parseFromFile(const std::string& configurationFile, Configurations* sender,
+ Configurations* base = nullptr);
+
+ /// @brief Parse configurations from configuration string.
+ ///
+ /// @detail This configuration string has same syntax as configuration file contents. Make sure all the necessary
+ /// new line characters are provided. You may define '_STOP_ON_FIRSTELPP_ASSERTION' to make sure you
+ /// do not proceed without successful parse (This is recommended)
+ /// @param configurationsString the configuration in plain text format
+ /// @param sender Sender configurations pointer. Usually 'this' is used from calling class
+ /// @param base Configurations to base new configuration repository off. This value is used when you want to use
+ /// existing Configurations to base all the values and then set rest of configuration via configuration text.
+ /// @return True if successfully parsed, false otherwise.
+ static bool parseFromText(const std::string& configurationsString, Configurations* sender,
+ Configurations* base = nullptr);
+
+ private:
+ friend class el::Loggers;
+ static void ignoreComments(std::string* line);
+ static bool isLevel(const std::string& line);
+ static bool isComment(const std::string& line);
+ static inline bool isConfig(const std::string& line);
+ static bool parseLine(std::string* line, std::string* currConfigStr, std::string* currLevelStr, Level* currLevel,
+ Configurations* conf);
+ };
+
+ private:
+ std::string m_configurationFile;
+ bool m_isFromFile;
+ friend class el::Loggers;
+
+ /// @brief Unsafely sets configuration if does not already exist
+ void unsafeSetIfNotExist(Level level, ConfigurationType configurationType, const std::string& value);
+
+ /// @brief Thread unsafe set
+ void unsafeSet(Level level, ConfigurationType configurationType, const std::string& value);
+
+ /// @brief Sets configurations for all levels including Level::Global if includeGlobalLevel is true
+ /// @see Configurations::setGlobally(ConfigurationType configurationType, const std::string& value)
+ void setGlobally(ConfigurationType configurationType, const std::string& value, bool includeGlobalLevel);
+
+ /// @brief Sets configurations (Unsafely) for all levels including Level::Global if includeGlobalLevel is true
+ /// @see Configurations::setGlobally(ConfigurationType configurationType, const std::string& value)
+ void unsafeSetGlobally(ConfigurationType configurationType, const std::string& value, bool includeGlobalLevel);
+};
+
+namespace base {
+typedef std::shared_ptr<base::type::fstream_t> FileStreamPtr;
+typedef std::unordered_map<std::string, FileStreamPtr> LogStreamsReferenceMap;
+typedef std::shared_ptr<base::LogStreamsReferenceMap> LogStreamsReferenceMapPtr;
+/// @brief Configurations with data types.
+///
+/// @detail el::Configurations have string based values. This is whats used internally in order to read correct configurations.
+/// This is to perform faster while writing logs using correct configurations.
+///
+/// This is thread safe and final class containing non-virtual destructor (means nothing should inherit this class)
+class TypedConfigurations : public base::threading::ThreadSafe {
+ public:
+ /// @brief Constructor to initialize (construct) the object off el::Configurations
+ /// @param configurations Configurations pointer/reference to base this typed configurations off.
+ /// @param logStreamsReference Use ELPP->registeredLoggers()->logStreamsReference()
+ TypedConfigurations(Configurations* configurations, LogStreamsReferenceMapPtr logStreamsReference);
+
+ TypedConfigurations(const TypedConfigurations& other);
+
+ virtual ~TypedConfigurations(void) {
+ }
+
+ const Configurations* configurations(void) const {
+ return m_configurations;
+ }
+
+ bool enabled(Level level);
+ bool toFile(Level level);
+ const std::string& filename(Level level);
+ bool toStandardOutput(Level level);
+ const base::LogFormat& logFormat(Level level);
+ const base::SubsecondPrecision& subsecondPrecision(Level level = Level::Global);
+ const base::MillisecondsWidth& millisecondsWidth(Level level = Level::Global);
+ bool performanceTracking(Level level = Level::Global);
+ base::type::fstream_t* fileStream(Level level);
+ std::size_t maxLogFileSize(Level level);
+ std::size_t logFlushThreshold(Level level);
+
+ private:
+ Configurations* m_configurations;
+ std::unordered_map<Level, bool> m_enabledMap;
+ std::unordered_map<Level, bool> m_toFileMap;
+ std::unordered_map<Level, std::string> m_filenameMap;
+ std::unordered_map<Level, bool> m_toStandardOutputMap;
+ std::unordered_map<Level, base::LogFormat> m_logFormatMap;
+ std::unordered_map<Level, base::SubsecondPrecision> m_subsecondPrecisionMap;
+ std::unordered_map<Level, bool> m_performanceTrackingMap;
+ std::unordered_map<Level, base::FileStreamPtr> m_fileStreamMap;
+ std::unordered_map<Level, std::size_t> m_maxLogFileSizeMap;
+ std::unordered_map<Level, std::size_t> m_logFlushThresholdMap;
+ LogStreamsReferenceMapPtr m_logStreamsReference = nullptr;
+
+ friend class el::Helpers;
+ friend class el::base::MessageBuilder;
+ friend class el::base::Writer;
+ friend class el::base::DefaultLogDispatchCallback;
+ friend class el::base::LogDispatcher;
+
+ template <typename Conf_T>
+ inline Conf_T getConfigByVal(Level level, const std::unordered_map<Level, Conf_T>* confMap, const char* confName) {
+ base::threading::ScopedLock scopedLock(lock());
+ return unsafeGetConfigByVal(level, confMap, confName); // This is not unsafe anymore - mutex locked in scope
+ }
+
+ template <typename Conf_T>
+ inline Conf_T& getConfigByRef(Level level, std::unordered_map<Level, Conf_T>* confMap, const char* confName) {
+ base::threading::ScopedLock scopedLock(lock());
+ return unsafeGetConfigByRef(level, confMap, confName); // This is not unsafe anymore - mutex locked in scope
+ }
+
+ template <typename Conf_T>
+ Conf_T unsafeGetConfigByVal(Level level, const std::unordered_map<Level, Conf_T>* confMap, const char* confName) {
+ ELPP_UNUSED(confName);
+ typename std::unordered_map<Level, Conf_T>::const_iterator it = confMap->find(level);
+ if (it == confMap->end()) {
+ try {
+ return confMap->at(Level::Global);
+ } catch (...) {
+ ELPP_INTERNAL_ERROR("Unable to get configuration [" << confName << "] for level ["
+ << LevelHelper::convertToString(level) << "]"
+ << std::endl << "Please ensure you have properly configured logger.", false);
+ return Conf_T();
+ }
+ }
+ return it->second;
+ }
+
+ template <typename Conf_T>
+ Conf_T& unsafeGetConfigByRef(Level level, std::unordered_map<Level, Conf_T>* confMap, const char* confName) {
+ ELPP_UNUSED(confName);
+ typename std::unordered_map<Level, Conf_T>::iterator it = confMap->find(level);
+ if (it == confMap->end()) {
+ try {
+ return confMap->at(Level::Global);
+ } catch (...) {
+ ELPP_INTERNAL_ERROR("Unable to get configuration [" << confName << "] for level ["
+ << LevelHelper::convertToString(level) << "]"
+ << std::endl << "Please ensure you have properly configured logger.", false);
+ }
+ }
+ return it->second;
+ }
+
+ template <typename Conf_T>
+ void setValue(Level level, const Conf_T& value, std::unordered_map<Level, Conf_T>* confMap,
+ bool includeGlobalLevel = true) {
+ // If map is empty and we are allowed to add into generic level (Level::Global), do it!
+ if (confMap->empty() && includeGlobalLevel) {
+ confMap->insert(std::make_pair(Level::Global, value));
+ return;
+ }
+ // If same value exist in generic level already, dont add it to explicit level
+ typename std::unordered_map<Level, Conf_T>::iterator it = confMap->find(Level::Global);
+ if (it != confMap->end() && it->second == value) {
+ return;
+ }
+ // Now make sure we dont double up values if we really need to add it to explicit level
+ it = confMap->find(level);
+ if (it == confMap->end()) {
+ // Value not found for level, add new
+ confMap->insert(std::make_pair(level, value));
+ } else {
+ // Value found, just update value
+ confMap->at(level) = value;
+ }
+ }
+
+ void build(Configurations* configurations);
+ unsigned long getULong(std::string confVal);
+ std::string resolveFilename(const std::string& filename);
+ void insertFile(Level level, const std::string& fullFilename);
+ bool unsafeValidateFileRolling(Level level, const PreRollOutCallback& preRollOutCallback);
+
+ inline bool validateFileRolling(Level level, const PreRollOutCallback& preRollOutCallback) {
+ base::threading::ScopedLock scopedLock(lock());
+ return unsafeValidateFileRolling(level, preRollOutCallback);
+ }
+};
+/// @brief Class that keeps record of current line hit for occasional logging
+class HitCounter {
+ public:
+ HitCounter(void) :
+ m_filename(""),
+ m_lineNumber(0),
+ m_hitCounts(0) {
+ }
+
+ HitCounter(const char* filename, base::type::LineNumber lineNumber) :
+ m_filename(filename),
+ m_lineNumber(lineNumber),
+ m_hitCounts(0) {
+ }
+
+ HitCounter(const HitCounter& hitCounter) :
+ m_filename(hitCounter.m_filename),
+ m_lineNumber(hitCounter.m_lineNumber),
+ m_hitCounts(hitCounter.m_hitCounts) {
+ }
+
+ HitCounter& operator=(const HitCounter& hitCounter) {
+ if (&hitCounter != this) {
+ m_filename = hitCounter.m_filename;
+ m_lineNumber = hitCounter.m_lineNumber;
+ m_hitCounts = hitCounter.m_hitCounts;
+ }
+ return *this;
+ }
+
+ virtual ~HitCounter(void) {
+ }
+
+ /// @brief Resets location of current hit counter
+ inline void resetLocation(const char* filename, base::type::LineNumber lineNumber) {
+ m_filename = filename;
+ m_lineNumber = lineNumber;
+ }
+
+ /// @brief Validates hit counts and resets it if necessary
+ inline void validateHitCounts(std::size_t n) {
+ if (m_hitCounts >= base::consts::kMaxLogPerCounter) {
+ m_hitCounts = (n >= 1 ? base::consts::kMaxLogPerCounter % n : 0);
+ }
+ ++m_hitCounts;
+ }
+
+ inline const char* filename(void) const {
+ return m_filename;
+ }
+
+ inline base::type::LineNumber lineNumber(void) const {
+ return m_lineNumber;
+ }
+
+ inline std::size_t hitCounts(void) const {
+ return m_hitCounts;
+ }
+
+ inline void increment(void) {
+ ++m_hitCounts;
+ }
+
+ class Predicate {
+ public:
+ Predicate(const char* filename, base::type::LineNumber lineNumber)
+ : m_filename(filename),
+ m_lineNumber(lineNumber) {
+ }
+ inline bool operator()(const HitCounter* counter) {
+ return ((counter != nullptr) &&
+ (strcmp(counter->m_filename, m_filename) == 0) &&
+ (counter->m_lineNumber == m_lineNumber));
+ }
+
+ private:
+ const char* m_filename;
+ base::type::LineNumber m_lineNumber;
+ };
+
+ private:
+ const char* m_filename;
+ base::type::LineNumber m_lineNumber;
+ std::size_t m_hitCounts;
+};
+/// @brief Repository for hit counters used across the application
+class RegisteredHitCounters : public base::utils::RegistryWithPred<base::HitCounter, base::HitCounter::Predicate> {
+ public:
+ /// @brief Validates counter for every N, i.e, registers new if does not exist otherwise updates original one
+ /// @return True if validation resulted in triggering hit. Meaning logs should be written everytime true is returned
+ bool validateEveryN(const char* filename, base::type::LineNumber lineNumber, std::size_t n);
+
+ /// @brief Validates counter for hits >= N, i.e, registers new if does not exist otherwise updates original one
+ /// @return True if validation resulted in triggering hit. Meaning logs should be written everytime true is returned
+ bool validateAfterN(const char* filename, base::type::LineNumber lineNumber, std::size_t n);
+
+ /// @brief Validates counter for hits are <= n, i.e, registers new if does not exist otherwise updates original one
+ /// @return True if validation resulted in triggering hit. Meaning logs should be written everytime true is returned
+ bool validateNTimes(const char* filename, base::type::LineNumber lineNumber, std::size_t n);
+
+ /// @brief Gets hit counter registered at specified position
+ inline const base::HitCounter* getCounter(const char* filename, base::type::LineNumber lineNumber) {
+ base::threading::ScopedLock scopedLock(lock());
+ return get(filename, lineNumber);
+ }
+};
+/// @brief Action to be taken for dispatching
+enum class DispatchAction : base::type::EnumType {
+ None = 1, NormalLog = 2, SysLog = 4
+};
+} // namespace base
+template <typename T>
+class Callback : protected base::threading::ThreadSafe {
+ public:
+ Callback(void) : m_enabled(true) {}
+ inline bool enabled(void) const {
+ return m_enabled;
+ }
+ inline void setEnabled(bool enabled) {
+ base::threading::ScopedLock scopedLock(lock());
+ m_enabled = enabled;
+ }
+ protected:
+ virtual void handle(const T* handlePtr) = 0;
+ private:
+ bool m_enabled;
+};
+class LogDispatchData {
+ public:
+ LogDispatchData() : m_logMessage(nullptr), m_dispatchAction(base::DispatchAction::None) {}
+ inline const LogMessage* logMessage(void) const {
+ return m_logMessage;
+ }
+ inline base::DispatchAction dispatchAction(void) const {
+ return m_dispatchAction;
+ }
+ inline void setLogMessage(LogMessage* logMessage) {
+ m_logMessage = logMessage;
+ }
+ inline void setDispatchAction(base::DispatchAction dispatchAction) {
+ m_dispatchAction = dispatchAction;
+ }
+ private:
+ LogMessage* m_logMessage;
+ base::DispatchAction m_dispatchAction;
+ friend class base::LogDispatcher;
+
+};
+class LogDispatchCallback : public Callback<LogDispatchData> {
+ protected:
+ virtual void handle(const LogDispatchData* data);
+ base::threading::Mutex& fileHandle(const LogDispatchData* data);
+ private:
+ friend class base::LogDispatcher;
+ std::unordered_map<std::string, std::unique_ptr<base::threading::Mutex>> m_fileLocks;
+ base::threading::Mutex m_fileLocksMapLock;
+};
+class PerformanceTrackingCallback : public Callback<PerformanceTrackingData> {
+ private:
+ friend class base::PerformanceTracker;
+};
+class LoggerRegistrationCallback : public Callback<Logger> {
+ private:
+ friend class base::RegisteredLoggers;
+};
+class LogBuilder : base::NoCopy {
+ public:
+ LogBuilder() : m_termSupportsColor(base::utils::OS::termSupportsColor()) {}
+ virtual ~LogBuilder(void) {
+ ELPP_INTERNAL_INFO(3, "Destroying log builder...")
+ }
+ virtual base::type::string_t build(const LogMessage* logMessage, bool appendNewLine) const = 0;
+ void convertToColoredOutput(base::type::string_t* logLine, Level level);
+ private:
+ bool m_termSupportsColor;
+ friend class el::base::DefaultLogDispatchCallback;
+};
+typedef std::shared_ptr<LogBuilder> LogBuilderPtr;
+/// @brief Represents a logger holding ID and configurations we need to write logs
+///
+/// @detail This class does not write logs itself instead its used by writer to read configurations from.
+class Logger : public base::threading::ThreadSafe, public Loggable {
+ public:
+ Logger(const std::string& id, base::LogStreamsReferenceMapPtr logStreamsReference);
+ Logger(const std::string& id, const Configurations& configurations, base::LogStreamsReferenceMapPtr logStreamsReference);
+ Logger(const Logger& logger);
+ Logger& operator=(const Logger& logger);
+
+ virtual ~Logger(void) {
+ base::utils::safeDelete(m_typedConfigurations);
+ }
+
+ virtual inline void log(el::base::type::ostream_t& os) const {
+ os << m_id.c_str();
+ }
+
+ /// @brief Configures the logger using specified configurations.
+ void configure(const Configurations& configurations);
+
+ /// @brief Reconfigures logger using existing configurations
+ void reconfigure(void);
+
+ inline const std::string& id(void) const {
+ return m_id;
+ }
+
+ inline const std::string& parentApplicationName(void) const {
+ return m_parentApplicationName;
+ }
+
+ inline void setParentApplicationName(const std::string& parentApplicationName) {
+ m_parentApplicationName = parentApplicationName;
+ }
+
+ inline Configurations* configurations(void) {
+ return &m_configurations;
+ }
+
+ inline base::TypedConfigurations* typedConfigurations(void) {
+ return m_typedConfigurations;
+ }
+
+ static bool isValidId(const std::string& id);
+
+ /// @brief Flushes logger to sync all log files for all levels
+ void flush(void);
+
+ void flush(Level level, base::type::fstream_t* fs);
+
+ inline bool isFlushNeeded(Level level) {
+ return ++m_unflushedCount.find(level)->second >= m_typedConfigurations->logFlushThreshold(level);
+ }
+
+ inline LogBuilder* logBuilder(void) const {
+ return m_logBuilder.get();
+ }
+
+ inline void setLogBuilder(const LogBuilderPtr& logBuilder) {
+ m_logBuilder = logBuilder;
+ }
+
+ inline bool enabled(Level level) const {
+ return m_typedConfigurations->enabled(level);
+ }
+
+#if ELPP_VARIADIC_TEMPLATES_SUPPORTED
+# define LOGGER_LEVEL_WRITERS_SIGNATURES(FUNCTION_NAME)\
+template <typename T, typename... Args>\
+inline void FUNCTION_NAME(const char*, const T&, const Args&...);\
+template <typename T>\
+inline void FUNCTION_NAME(const T&);
+
+ template <typename T, typename... Args>
+ inline void verbose(int, const char*, const T&, const Args&...);
+
+ template <typename T>
+ inline void verbose(int, const T&);
+
+ LOGGER_LEVEL_WRITERS_SIGNATURES(info)
+ LOGGER_LEVEL_WRITERS_SIGNATURES(debug)
+ LOGGER_LEVEL_WRITERS_SIGNATURES(warn)
+ LOGGER_LEVEL_WRITERS_SIGNATURES(error)
+ LOGGER_LEVEL_WRITERS_SIGNATURES(fatal)
+ LOGGER_LEVEL_WRITERS_SIGNATURES(trace)
+# undef LOGGER_LEVEL_WRITERS_SIGNATURES
+#endif // ELPP_VARIADIC_TEMPLATES_SUPPORTED
+ private:
+ std::string m_id;
+ base::TypedConfigurations* m_typedConfigurations;
+ base::type::stringstream_t m_stream;
+ std::string m_parentApplicationName;
+ bool m_isConfigured;
+ Configurations m_configurations;
+ std::unordered_map<Level, unsigned int> m_unflushedCount;
+ base::LogStreamsReferenceMapPtr m_logStreamsReference = nullptr;
+ LogBuilderPtr m_logBuilder;
+
+ friend class el::LogMessage;
+ friend class el::Loggers;
+ friend class el::Helpers;
+ friend class el::base::RegisteredLoggers;
+ friend class el::base::DefaultLogDispatchCallback;
+ friend class el::base::MessageBuilder;
+ friend class el::base::Writer;
+ friend class el::base::PErrorWriter;
+ friend class el::base::Storage;
+ friend class el::base::PerformanceTracker;
+ friend class el::base::LogDispatcher;
+
+ Logger(void);
+
+#if ELPP_VARIADIC_TEMPLATES_SUPPORTED
+ template <typename T, typename... Args>
+ void log_(Level, int, const char*, const T&, const Args&...);
+
+ template <typename T>
+ inline void log_(Level, int, const T&);
+
+ template <typename T, typename... Args>
+ void log(Level, const char*, const T&, const Args&...);
+
+ template <typename T>
+ inline void log(Level, const T&);
+#endif // ELPP_VARIADIC_TEMPLATES_SUPPORTED
+
+ void initUnflushedCount(void);
+
+ inline base::type::stringstream_t& stream(void) {
+ return m_stream;
+ }
+
+ void resolveLoggerFormatSpec(void) const;
+};
+namespace base {
+/// @brief Loggers repository
+class RegisteredLoggers : public base::utils::Registry<Logger, std::string> {
+ public:
+ explicit RegisteredLoggers(const LogBuilderPtr& defaultLogBuilder);
+
+ virtual ~RegisteredLoggers(void) {
+ unsafeFlushAll();
+ }
+
+ inline void setDefaultConfigurations(const Configurations& configurations) {
+ base::threading::ScopedLock scopedLock(lock());
+ m_defaultConfigurations.setFromBase(const_cast<Configurations*>(&configurations));
+ }
+
+ inline Configurations* defaultConfigurations(void) {
+ return &m_defaultConfigurations;
+ }
+
+ Logger* get(const std::string& id, bool forceCreation = true);
+
+ template <typename T>
+ inline bool installLoggerRegistrationCallback(const std::string& id) {
+ return base::utils::Utils::installCallback<T, base::type::LoggerRegistrationCallbackPtr>(id,
+ &m_loggerRegistrationCallbacks);
+ }
+
+ template <typename T>
+ inline void uninstallLoggerRegistrationCallback(const std::string& id) {
+ base::utils::Utils::uninstallCallback<T, base::type::LoggerRegistrationCallbackPtr>(id, &m_loggerRegistrationCallbacks);
+ }
+
+ template <typename T>
+ inline T* loggerRegistrationCallback(const std::string& id) {
+ return base::utils::Utils::callback<T, base::type::LoggerRegistrationCallbackPtr>(id, &m_loggerRegistrationCallbacks);
+ }
+
+ bool remove(const std::string& id);
+
+ inline bool has(const std::string& id) {
+ return get(id, false) != nullptr;
+ }
+
+ inline void unregister(Logger*& logger) {
+ base::threading::ScopedLock scopedLock(lock());
+ base::utils::Registry<Logger, std::string>::unregister(logger->id());
+ }
+
+ inline LogStreamsReferenceMapPtr logStreamsReference(void) {
+ return m_logStreamsReference;
+ }
+
+ inline void flushAll(void) {
+ base::threading::ScopedLock scopedLock(lock());
+ unsafeFlushAll();
+ }
+
+ inline void setDefaultLogBuilder(LogBuilderPtr& logBuilderPtr) {
+ base::threading::ScopedLock scopedLock(lock());
+ m_defaultLogBuilder = logBuilderPtr;
+ }
+
+ private:
+ LogBuilderPtr m_defaultLogBuilder;
+ Configurations m_defaultConfigurations;
+ base::LogStreamsReferenceMapPtr m_logStreamsReference = nullptr;
+ std::unordered_map<std::string, base::type::LoggerRegistrationCallbackPtr> m_loggerRegistrationCallbacks;
+ friend class el::base::Storage;
+
+ void unsafeFlushAll(void);
+};
+/// @brief Represents registries for verbose logging
+class VRegistry : base::NoCopy, public base::threading::ThreadSafe {
+ public:
+ explicit VRegistry(base::type::VerboseLevel level, base::type::EnumType* pFlags);
+
+ /// @brief Sets verbose level. Accepted range is 0-9
+ void setLevel(base::type::VerboseLevel level);
+
+ inline base::type::VerboseLevel level(void) const {
+ return m_level;
+ }
+
+ inline void clearModules(void) {
+ base::threading::ScopedLock scopedLock(lock());
+ m_modules.clear();
+ }
+
+ void setModules(const char* modules);
+
+ bool allowed(base::type::VerboseLevel vlevel, const char* file);
+
+ inline const std::unordered_map<std::string, base::type::VerboseLevel>& modules(void) const {
+ return m_modules;
+ }
+
+ void setFromArgs(const base::utils::CommandLineArgs* commandLineArgs);
+
+ /// @brief Whether or not vModules enabled
+ inline bool vModulesEnabled(void) {
+ return !base::utils::hasFlag(LoggingFlag::DisableVModules, *m_pFlags);
+ }
+
+ private:
+ base::type::VerboseLevel m_level;
+ base::type::EnumType* m_pFlags;
+ std::unordered_map<std::string, base::type::VerboseLevel> m_modules;
+};
+} // namespace base
+class LogMessage {
+ public:
+ LogMessage(Level level, const std::string& file, base::type::LineNumber line, const std::string& func,
+ base::type::VerboseLevel verboseLevel, Logger* logger) :
+ m_level(level), m_file(file), m_line(line), m_func(func),
+ m_verboseLevel(verboseLevel), m_logger(logger), m_message(logger->stream().str()) {
+ }
+ inline Level level(void) const {
+ return m_level;
+ }
+ inline const std::string& file(void) const {
+ return m_file;
+ }
+ inline base::type::LineNumber line(void) const {
+ return m_line;
+ }
+ inline const std::string& func(void) const {
+ return m_func;
+ }
+ inline base::type::VerboseLevel verboseLevel(void) const {
+ return m_verboseLevel;
+ }
+ inline Logger* logger(void) const {
+ return m_logger;
+ }
+ inline const base::type::string_t& message(void) const {
+ return m_message;
+ }
+ private:
+ Level m_level;
+ std::string m_file;
+ base::type::LineNumber m_line;
+ std::string m_func;
+ base::type::VerboseLevel m_verboseLevel;
+ Logger* m_logger;
+ base::type::string_t m_message;
+};
+namespace base {
+#if ELPP_ASYNC_LOGGING
+class AsyncLogItem {
+ public:
+ explicit AsyncLogItem(const LogMessage& logMessage, const LogDispatchData& data, const base::type::string_t& logLine)
+ : m_logMessage(logMessage), m_dispatchData(data), m_logLine(logLine) {}
+ virtual ~AsyncLogItem() {}
+ inline LogMessage* logMessage(void) {
+ return &m_logMessage;
+ }
+ inline LogDispatchData* data(void) {
+ return &m_dispatchData;
+ }
+ inline base::type::string_t logLine(void) {
+ return m_logLine;
+ }
+ private:
+ LogMessage m_logMessage;
+ LogDispatchData m_dispatchData;
+ base::type::string_t m_logLine;
+};
+class AsyncLogQueue : public base::threading::ThreadSafe {
+ public:
+ virtual ~AsyncLogQueue() {
+ ELPP_INTERNAL_INFO(6, "~AsyncLogQueue");
+ }
+
+ inline AsyncLogItem next(void) {
+ base::threading::ScopedLock scopedLock(lock());
+ AsyncLogItem result = m_queue.front();
+ m_queue.pop();
+ return result;
+ }
+
+ inline void push(const AsyncLogItem& item) {
+ base::threading::ScopedLock scopedLock(lock());
+ m_queue.push(item);
+ }
+ inline void pop(void) {
+ base::threading::ScopedLock scopedLock(lock());
+ m_queue.pop();
+ }
+ inline AsyncLogItem front(void) {
+ base::threading::ScopedLock scopedLock(lock());
+ return m_queue.front();
+ }
+ inline bool empty(void) {
+ base::threading::ScopedLock scopedLock(lock());
+ return m_queue.empty();
+ }
+ private:
+ std::queue<AsyncLogItem> m_queue;
+};
+class IWorker {
+ public:
+ virtual ~IWorker() {}
+ virtual void start() = 0;
+};
+#endif // ELPP_ASYNC_LOGGING
+/// @brief Easylogging++ management storage
+class Storage : base::NoCopy, public base::threading::ThreadSafe {
+ public:
+#if ELPP_ASYNC_LOGGING
+ Storage(const LogBuilderPtr& defaultLogBuilder, base::IWorker* asyncDispatchWorker);
+#else
+ explicit Storage(const LogBuilderPtr& defaultLogBuilder);
+#endif // ELPP_ASYNC_LOGGING
+
+ virtual ~Storage(void);
+
+ inline bool validateEveryNCounter(const char* filename, base::type::LineNumber lineNumber, std::size_t occasion) {
+ return hitCounters()->validateEveryN(filename, lineNumber, occasion);
+ }
+
+ inline bool validateAfterNCounter(const char* filename, base::type::LineNumber lineNumber, std::size_t n) {
+ return hitCounters()->validateAfterN(filename, lineNumber, n);
+ }
+
+ inline bool validateNTimesCounter(const char* filename, base::type::LineNumber lineNumber, std::size_t n) {
+ return hitCounters()->validateNTimes(filename, lineNumber, n);
+ }
+
+ inline base::RegisteredHitCounters* hitCounters(void) const {
+ return m_registeredHitCounters;
+ }
+
+ inline base::RegisteredLoggers* registeredLoggers(void) const {
+ return m_registeredLoggers;
+ }
+
+ inline base::VRegistry* vRegistry(void) const {
+ return m_vRegistry;
+ }
+
+#if ELPP_ASYNC_LOGGING
+ inline base::AsyncLogQueue* asyncLogQueue(void) const {
+ return m_asyncLogQueue;
+ }
+#endif // ELPP_ASYNC_LOGGING
+
+ inline const base::utils::CommandLineArgs* commandLineArgs(void) const {
+ return &m_commandLineArgs;
+ }
+
+ inline void addFlag(LoggingFlag flag) {
+ base::utils::addFlag(flag, &m_flags);
+ }
+
+ inline void removeFlag(LoggingFlag flag) {
+ base::utils::removeFlag(flag, &m_flags);
+ }
+
+ inline bool hasFlag(LoggingFlag flag) const {
+ return base::utils::hasFlag(flag, m_flags);
+ }
+
+ inline base::type::EnumType flags(void) const {
+ return m_flags;
+ }
+
+ inline void setFlags(base::type::EnumType flags) {
+ m_flags = flags;
+ }
+
+ inline void setPreRollOutCallback(const PreRollOutCallback& callback) {
+ m_preRollOutCallback = callback;
+ }
+
+ inline void unsetPreRollOutCallback(void) {
+ m_preRollOutCallback = base::defaultPreRollOutCallback;
+ }
+
+ inline PreRollOutCallback& preRollOutCallback(void) {
+ return m_preRollOutCallback;
+ }
+
+ bool hasCustomFormatSpecifier(const char* formatSpecifier);
+ void installCustomFormatSpecifier(const CustomFormatSpecifier& customFormatSpecifier);
+ bool uninstallCustomFormatSpecifier(const char* formatSpecifier);
+
+ const std::vector<CustomFormatSpecifier>* customFormatSpecifiers(void) const {
+ return &m_customFormatSpecifiers;
+ }
+
+ base::threading::Mutex& customFormatSpecifiersLock() {
+ return m_customFormatSpecifiersLock;
+ }
+
+ inline void setLoggingLevel(Level level) {
+ m_loggingLevel = level;
+ }
+
+ template <typename T>
+ inline bool installLogDispatchCallback(const std::string& id) {
+ return base::utils::Utils::installCallback<T, base::type::LogDispatchCallbackPtr>(id, &m_logDispatchCallbacks);
+ }
+
+ template <typename T>
+ inline void uninstallLogDispatchCallback(const std::string& id) {
+ base::utils::Utils::uninstallCallback<T, base::type::LogDispatchCallbackPtr>(id, &m_logDispatchCallbacks);
+ }
+ template <typename T>
+ inline T* logDispatchCallback(const std::string& id) {
+ return base::utils::Utils::callback<T, base::type::LogDispatchCallbackPtr>(id, &m_logDispatchCallbacks);
+ }
+
+#if defined(ELPP_FEATURE_ALL) || defined(ELPP_FEATURE_PERFORMANCE_TRACKING)
+ template <typename T>
+ inline bool installPerformanceTrackingCallback(const std::string& id) {
+ return base::utils::Utils::installCallback<T, base::type::PerformanceTrackingCallbackPtr>(id,
+ &m_performanceTrackingCallbacks);
+ }
+
+ template <typename T>
+ inline void uninstallPerformanceTrackingCallback(const std::string& id) {
+ base::utils::Utils::uninstallCallback<T, base::type::PerformanceTrackingCallbackPtr>(id,
+ &m_performanceTrackingCallbacks);
+ }
+
+ template <typename T>
+ inline T* performanceTrackingCallback(const std::string& id) {
+ return base::utils::Utils::callback<T, base::type::PerformanceTrackingCallbackPtr>(id, &m_performanceTrackingCallbacks);
+ }
+#endif // defined(ELPP_FEATURE_ALL) || defined(ELPP_FEATURE_PERFORMANCE_TRACKING)
+
+ /// @brief Sets thread name for current thread. Requires std::thread
+ inline void setThreadName(const std::string& name) {
+ if (name.empty()) return;
+ base::threading::ScopedLock scopedLock(m_threadNamesLock);
+ m_threadNames[base::threading::getCurrentThreadId()] = name;
+ }
+
+ inline std::string getThreadName(const std::string& threadId) {
+ base::threading::ScopedLock scopedLock(m_threadNamesLock);
+ std::unordered_map<std::string, std::string>::const_iterator it = m_threadNames.find(threadId);
+ if (it == m_threadNames.end()) {
+ return threadId;
+ }
+ return it->second;
+ }
+ private:
+ base::RegisteredHitCounters* m_registeredHitCounters;
+ base::RegisteredLoggers* m_registeredLoggers;
+ base::type::EnumType m_flags;
+ base::VRegistry* m_vRegistry;
+#if ELPP_ASYNC_LOGGING
+ base::AsyncLogQueue* m_asyncLogQueue;
+ base::IWorker* m_asyncDispatchWorker;
+#endif // ELPP_ASYNC_LOGGING
+ base::utils::CommandLineArgs m_commandLineArgs;
+ PreRollOutCallback m_preRollOutCallback;
+ std::unordered_map<std::string, base::type::LogDispatchCallbackPtr> m_logDispatchCallbacks;
+ std::unordered_map<std::string, base::type::PerformanceTrackingCallbackPtr> m_performanceTrackingCallbacks;
+ std::unordered_map<std::string, std::string> m_threadNames;
+ std::vector<CustomFormatSpecifier> m_customFormatSpecifiers;
+ base::threading::Mutex m_customFormatSpecifiersLock;
+ base::threading::Mutex m_threadNamesLock;
+ Level m_loggingLevel;
+
+ friend class el::Helpers;
+ friend class el::base::DefaultLogDispatchCallback;
+ friend class el::LogBuilder;
+ friend class el::base::MessageBuilder;
+ friend class el::base::Writer;
+ friend class el::base::PerformanceTracker;
+ friend class el::base::LogDispatcher;
+
+ void setApplicationArguments(int argc, char** argv);
+
+ inline void setApplicationArguments(int argc, const char** argv) {
+ setApplicationArguments(argc, const_cast<char**>(argv));
+ }
+};
+extern ELPP_EXPORT base::type::StoragePointer elStorage;
+#define ELPP el::base::elStorage
+class DefaultLogDispatchCallback : public LogDispatchCallback {
+ protected:
+ void handle(const LogDispatchData* data);
+ private:
+ const LogDispatchData* m_data;
+ void dispatch(base::type::string_t&& logLine);
+};
+#if ELPP_ASYNC_LOGGING
+class AsyncLogDispatchCallback : public LogDispatchCallback {
+ protected:
+ void handle(const LogDispatchData* data);
+};
+class AsyncDispatchWorker : public base::IWorker, public base::threading::ThreadSafe {
+ public:
+ AsyncDispatchWorker();
+ virtual ~AsyncDispatchWorker();
+
+ bool clean(void);
+ void emptyQueue(void);
+ virtual void start(void);
+ void handle(AsyncLogItem* logItem);
+ void run(void);
+
+ void setContinueRunning(bool value) {
+ base::threading::ScopedLock scopedLock(m_continueRunningLock);
+ m_continueRunning = value;
+ }
+
+ bool continueRunning(void) const {
+ return m_continueRunning;
+ }
+ private:
+ std::condition_variable cv;
+ bool m_continueRunning;
+ base::threading::Mutex m_continueRunningLock;
+};
+#endif // ELPP_ASYNC_LOGGING
+} // namespace base
+namespace base {
+class DefaultLogBuilder : public LogBuilder {
+ public:
+ base::type::string_t build(const LogMessage* logMessage, bool appendNewLine) const;
+};
+/// @brief Dispatches log messages
+class LogDispatcher : base::NoCopy {
+ public:
+ LogDispatcher(bool proceed, LogMessage* logMessage, base::DispatchAction dispatchAction) :
+ m_proceed(proceed),
+ m_logMessage(logMessage),
+ m_dispatchAction(std::move(dispatchAction)) {
+ }
+
+ void dispatch(void);
+
+ private:
+ bool m_proceed;
+ LogMessage* m_logMessage;
+ base::DispatchAction m_dispatchAction;
+};
+#if defined(ELPP_STL_LOGGING)
+/// @brief Workarounds to write some STL logs
+///
+/// @detail There is workaround needed to loop through some stl containers. In order to do that, we need iterable containers
+/// of same type and provide iterator interface and pass it on to writeIterator().
+/// Remember, this is passed by value in constructor so that we dont change original containers.
+/// This operation is as expensive as Big-O(std::min(class_.size(), base::consts::kMaxLogPerContainer))
+namespace workarounds {
+/// @brief Abstract IterableContainer template that provides interface for iterable classes of type T
+template <typename T, typename Container>
+class IterableContainer {
+ public:
+ typedef typename Container::iterator iterator;
+ typedef typename Container::const_iterator const_iterator;
+ IterableContainer(void) {}
+ virtual ~IterableContainer(void) {}
+ iterator begin(void) {
+ return getContainer().begin();
+ }
+ iterator end(void) {
+ return getContainer().end();
+ }
+ private:
+ virtual Container& getContainer(void) = 0;
+};
+/// @brief Implements IterableContainer and provides iterable std::priority_queue class
+template<typename T, typename Container = std::vector<T>, typename Comparator = std::less<typename Container::value_type>>
+class IterablePriorityQueue : public IterableContainer<T, Container>,
+ public std::priority_queue<T, Container, Comparator> {
+ public:
+ IterablePriorityQueue(std::priority_queue<T, Container, Comparator> queue_) {
+ std::size_t count_ = 0;
+ while (++count_ < base::consts::kMaxLogPerContainer && !queue_.empty()) {
+ this->push(queue_.top());
+ queue_.pop();
+ }
+ }
+ private:
+ inline Container& getContainer(void) {
+ return this->c;
+ }
+};
+/// @brief Implements IterableContainer and provides iterable std::queue class
+template<typename T, typename Container = std::deque<T>>
+class IterableQueue : public IterableContainer<T, Container>, public std::queue<T, Container> {
+ public:
+ IterableQueue(std::queue<T, Container> queue_) {
+ std::size_t count_ = 0;
+ while (++count_ < base::consts::kMaxLogPerContainer && !queue_.empty()) {
+ this->push(queue_.front());
+ queue_.pop();
+ }
+ }
+ private:
+ inline Container& getContainer(void) {
+ return this->c;
+ }
+};
+/// @brief Implements IterableContainer and provides iterable std::stack class
+template<typename T, typename Container = std::deque<T>>
+class IterableStack : public IterableContainer<T, Container>, public std::stack<T, Container> {
+ public:
+ IterableStack(std::stack<T, Container> stack_) {
+ std::size_t count_ = 0;
+ while (++count_ < base::consts::kMaxLogPerContainer && !stack_.empty()) {
+ this->push(stack_.top());
+ stack_.pop();
+ }
+ }
+ private:
+ inline Container& getContainer(void) {
+ return this->c;
+ }
+};
+} // namespace workarounds
+#endif // defined(ELPP_STL_LOGGING)
+// Log message builder
+class MessageBuilder {
+ public:
+ MessageBuilder(void) : m_logger(nullptr), m_containerLogSeparator(ELPP_LITERAL("")) {}
+ void initialize(Logger* logger);
+
+# define ELPP_SIMPLE_LOG(LOG_TYPE)\
+MessageBuilder& operator<<(LOG_TYPE msg) {\
+m_logger->stream() << msg;\
+if (ELPP->hasFlag(LoggingFlag::AutoSpacing)) {\
+m_logger->stream() << " ";\
+}\
+return *this;\
+}
+
+ inline MessageBuilder& operator<<(const std::string& msg) {
+ return operator<<(msg.c_str());
+ }
+ ELPP_SIMPLE_LOG(char)
+ ELPP_SIMPLE_LOG(bool)
+ ELPP_SIMPLE_LOG(signed short)
+ ELPP_SIMPLE_LOG(unsigned short)
+ ELPP_SIMPLE_LOG(signed int)
+ ELPP_SIMPLE_LOG(unsigned int)
+ ELPP_SIMPLE_LOG(signed long)
+ ELPP_SIMPLE_LOG(unsigned long)
+ ELPP_SIMPLE_LOG(float)
+ ELPP_SIMPLE_LOG(double)
+ ELPP_SIMPLE_LOG(char*)
+ ELPP_SIMPLE_LOG(const char*)
+ ELPP_SIMPLE_LOG(const void*)
+ ELPP_SIMPLE_LOG(long double)
+ inline MessageBuilder& operator<<(const std::wstring& msg) {
+ return operator<<(msg.c_str());
+ }
+ MessageBuilder& operator<<(const wchar_t* msg);
+ // ostream manipulators
+ inline MessageBuilder& operator<<(std::ostream& (*OStreamMani)(std::ostream&)) {
+ m_logger->stream() << OStreamMani;
+ return *this;
+ }
+#define ELPP_ITERATOR_CONTAINER_LOG_ONE_ARG(temp) \
+template <typename T> \
+inline MessageBuilder& operator<<(const temp<T>& template_inst) { \
+return writeIterator(template_inst.begin(), template_inst.end(), template_inst.size()); \
+}
+#define ELPP_ITERATOR_CONTAINER_LOG_TWO_ARG(temp) \
+template <typename T1, typename T2> \
+inline MessageBuilder& operator<<(const temp<T1, T2>& template_inst) { \
+return writeIterator(template_inst.begin(), template_inst.end(), template_inst.size()); \
+}
+#define ELPP_ITERATOR_CONTAINER_LOG_THREE_ARG(temp) \
+template <typename T1, typename T2, typename T3> \
+inline MessageBuilder& operator<<(const temp<T1, T2, T3>& template_inst) { \
+return writeIterator(template_inst.begin(), template_inst.end(), template_inst.size()); \
+}
+#define ELPP_ITERATOR_CONTAINER_LOG_FOUR_ARG(temp) \
+template <typename T1, typename T2, typename T3, typename T4> \
+inline MessageBuilder& operator<<(const temp<T1, T2, T3, T4>& template_inst) { \
+return writeIterator(template_inst.begin(), template_inst.end(), template_inst.size()); \
+}
+#define ELPP_ITERATOR_CONTAINER_LOG_FIVE_ARG(temp) \
+template <typename T1, typename T2, typename T3, typename T4, typename T5> \
+inline MessageBuilder& operator<<(const temp<T1, T2, T3, T4, T5>& template_inst) { \
+return writeIterator(template_inst.begin(), template_inst.end(), template_inst.size()); \
+}
+
+#if defined(ELPP_STL_LOGGING)
+ ELPP_ITERATOR_CONTAINER_LOG_TWO_ARG(std::vector)
+ ELPP_ITERATOR_CONTAINER_LOG_TWO_ARG(std::list)
+ ELPP_ITERATOR_CONTAINER_LOG_TWO_ARG(std::deque)
+ ELPP_ITERATOR_CONTAINER_LOG_THREE_ARG(std::set)
+ ELPP_ITERATOR_CONTAINER_LOG_THREE_ARG(std::multiset)
+ ELPP_ITERATOR_CONTAINER_LOG_FOUR_ARG(std::map)
+ ELPP_ITERATOR_CONTAINER_LOG_FOUR_ARG(std::multimap)
+ template <class T, class Container>
+ inline MessageBuilder& operator<<(const std::queue<T, Container>& queue_) {
+ base::workarounds::IterableQueue<T, Container> iterableQueue_ =
+ static_cast<base::workarounds::IterableQueue<T, Container> >(queue_);
+ return writeIterator(iterableQueue_.begin(), iterableQueue_.end(), iterableQueue_.size());
+ }
+ template <class T, class Container>
+ inline MessageBuilder& operator<<(const std::stack<T, Container>& stack_) {
+ base::workarounds::IterableStack<T, Container> iterableStack_ =
+ static_cast<base::workarounds::IterableStack<T, Container> >(stack_);
+ return writeIterator(iterableStack_.begin(), iterableStack_.end(), iterableStack_.size());
+ }
+ template <class T, class Container, class Comparator>
+ inline MessageBuilder& operator<<(const std::priority_queue<T, Container, Comparator>& priorityQueue_) {
+ base::workarounds::IterablePriorityQueue<T, Container, Comparator> iterablePriorityQueue_ =
+ static_cast<base::workarounds::IterablePriorityQueue<T, Container, Comparator> >(priorityQueue_);
+ return writeIterator(iterablePriorityQueue_.begin(), iterablePriorityQueue_.end(), iterablePriorityQueue_.size());
+ }
+ template <class First, class Second>
+ MessageBuilder& operator<<(const std::pair<First, Second>& pair_) {
+ m_logger->stream() << ELPP_LITERAL("(");
+ operator << (static_cast<First>(pair_.first));
+ m_logger->stream() << ELPP_LITERAL(", ");
+ operator << (static_cast<Second>(pair_.second));
+ m_logger->stream() << ELPP_LITERAL(")");
+ return *this;
+ }
+ template <std::size_t Size>
+ MessageBuilder& operator<<(const std::bitset<Size>& bitset_) {
+ m_logger->stream() << ELPP_LITERAL("[");
+ operator << (bitset_.to_string());
+ m_logger->stream() << ELPP_LITERAL("]");
+ return *this;
+ }
+# if defined(ELPP_LOG_STD_ARRAY)
+ template <class T, std::size_t Size>
+ inline MessageBuilder& operator<<(const std::array<T, Size>& array) {
+ return writeIterator(array.begin(), array.end(), array.size());
+ }
+# endif // defined(ELPP_LOG_STD_ARRAY)
+# if defined(ELPP_LOG_UNORDERED_MAP)
+ ELPP_ITERATOR_CONTAINER_LOG_FIVE_ARG(std::unordered_map)
+ ELPP_ITERATOR_CONTAINER_LOG_FIVE_ARG(std::unordered_multimap)
+# endif // defined(ELPP_LOG_UNORDERED_MAP)
+# if defined(ELPP_LOG_UNORDERED_SET)
+ ELPP_ITERATOR_CONTAINER_LOG_FOUR_ARG(std::unordered_set)
+ ELPP_ITERATOR_CONTAINER_LOG_FOUR_ARG(std::unordered_multiset)
+# endif // defined(ELPP_LOG_UNORDERED_SET)
+#endif // defined(ELPP_STL_LOGGING)
+#if defined(ELPP_QT_LOGGING)
+ inline MessageBuilder& operator<<(const QString& msg) {
+# if defined(ELPP_UNICODE)
+ m_logger->stream() << msg.toStdWString();
+# else
+ m_logger->stream() << msg.toStdString();
+# endif // defined(ELPP_UNICODE)
+ return *this;
+ }
+ inline MessageBuilder& operator<<(const QByteArray& msg) {
+ return operator << (QString(msg));
+ }
+ inline MessageBuilder& operator<<(const QStringRef& msg) {
+ return operator<<(msg.toString());
+ }
+ inline MessageBuilder& operator<<(qint64 msg) {
+# if defined(ELPP_UNICODE)
+ m_logger->stream() << QString::number(msg).toStdWString();
+# else
+ m_logger->stream() << QString::number(msg).toStdString();
+# endif // defined(ELPP_UNICODE)
+ return *this;
+ }
+ inline MessageBuilder& operator<<(quint64 msg) {
+# if defined(ELPP_UNICODE)
+ m_logger->stream() << QString::number(msg).toStdWString();
+# else
+ m_logger->stream() << QString::number(msg).toStdString();
+# endif // defined(ELPP_UNICODE)
+ return *this;
+ }
+ inline MessageBuilder& operator<<(QChar msg) {
+ m_logger->stream() << msg.toLatin1();
+ return *this;
+ }
+ inline MessageBuilder& operator<<(const QLatin1String& msg) {
+ m_logger->stream() << msg.latin1();
+ return *this;
+ }
+ ELPP_ITERATOR_CONTAINER_LOG_ONE_ARG(QList)
+ ELPP_ITERATOR_CONTAINER_LOG_ONE_ARG(QVector)
+ ELPP_ITERATOR_CONTAINER_LOG_ONE_ARG(QQueue)
+ ELPP_ITERATOR_CONTAINER_LOG_ONE_ARG(QSet)
+ ELPP_ITERATOR_CONTAINER_LOG_ONE_ARG(QLinkedList)
+ ELPP_ITERATOR_CONTAINER_LOG_ONE_ARG(QStack)
+ template <typename First, typename Second>
+ MessageBuilder& operator<<(const QPair<First, Second>& pair_) {
+ m_logger->stream() << ELPP_LITERAL("(");
+ operator << (static_cast<First>(pair_.first));
+ m_logger->stream() << ELPP_LITERAL(", ");
+ operator << (static_cast<Second>(pair_.second));
+ m_logger->stream() << ELPP_LITERAL(")");
+ return *this;
+ }
+ template <typename K, typename V>
+ MessageBuilder& operator<<(const QMap<K, V>& map_) {
+ m_logger->stream() << ELPP_LITERAL("[");
+ QList<K> keys = map_.keys();
+ typename QList<K>::const_iterator begin = keys.begin();
+ typename QList<K>::const_iterator end = keys.end();
+ int max_ = static_cast<int>(base::consts::kMaxLogPerContainer); // to prevent warning
+ for (int index_ = 0; begin != end && index_ < max_; ++index_, ++begin) {
+ m_logger->stream() << ELPP_LITERAL("(");
+ operator << (static_cast<K>(*begin));
+ m_logger->stream() << ELPP_LITERAL(", ");
+ operator << (static_cast<V>(map_.value(*begin)));
+ m_logger->stream() << ELPP_LITERAL(")");
+ m_logger->stream() << ((index_ < keys.size() -1) ? m_containerLogSeparator : ELPP_LITERAL(""));
+ }
+ if (begin != end) {
+ m_logger->stream() << ELPP_LITERAL("...");
+ }
+ m_logger->stream() << ELPP_LITERAL("]");
+ return *this;
+ }
+ template <typename K, typename V>
+ inline MessageBuilder& operator<<(const QMultiMap<K, V>& map_) {
+ operator << (static_cast<QMap<K, V>>(map_));
+ return *this;
+ }
+ template <typename K, typename V>
+ MessageBuilder& operator<<(const QHash<K, V>& hash_) {
+ m_logger->stream() << ELPP_LITERAL("[");
+ QList<K> keys = hash_.keys();
+ typename QList<K>::const_iterator begin = keys.begin();
+ typename QList<K>::const_iterator end = keys.end();
+ int max_ = static_cast<int>(base::consts::kMaxLogPerContainer); // prevent type warning
+ for (int index_ = 0; begin != end && index_ < max_; ++index_, ++begin) {
+ m_logger->stream() << ELPP_LITERAL("(");
+ operator << (static_cast<K>(*begin));
+ m_logger->stream() << ELPP_LITERAL(", ");
+ operator << (static_cast<V>(hash_.value(*begin)));
+ m_logger->stream() << ELPP_LITERAL(")");
+ m_logger->stream() << ((index_ < keys.size() -1) ? m_containerLogSeparator : ELPP_LITERAL(""));
+ }
+ if (begin != end) {
+ m_logger->stream() << ELPP_LITERAL("...");
+ }
+ m_logger->stream() << ELPP_LITERAL("]");
+ return *this;
+ }
+ template <typename K, typename V>
+ inline MessageBuilder& operator<<(const QMultiHash<K, V>& multiHash_) {
+ operator << (static_cast<QHash<K, V>>(multiHash_));
+ return *this;
+ }
+#endif // defined(ELPP_QT_LOGGING)
+#if defined(ELPP_BOOST_LOGGING)
+ ELPP_ITERATOR_CONTAINER_LOG_TWO_ARG(boost::container::vector)
+ ELPP_ITERATOR_CONTAINER_LOG_TWO_ARG(boost::container::stable_vector)
+ ELPP_ITERATOR_CONTAINER_LOG_TWO_ARG(boost::container::list)
+ ELPP_ITERATOR_CONTAINER_LOG_TWO_ARG(boost::container::deque)
+ ELPP_ITERATOR_CONTAINER_LOG_FOUR_ARG(boost::container::map)
+ ELPP_ITERATOR_CONTAINER_LOG_FOUR_ARG(boost::container::flat_map)
+ ELPP_ITERATOR_CONTAINER_LOG_THREE_ARG(boost::container::set)
+ ELPP_ITERATOR_CONTAINER_LOG_THREE_ARG(boost::container::flat_set)
+#endif // defined(ELPP_BOOST_LOGGING)
+
+ /// @brief Macro used internally that can be used externally to make containers easylogging++ friendly
+ ///
+ /// @detail This macro expands to write an ostream& operator<< for container. This container is expected to
+ /// have begin() and end() methods that return respective iterators
+ /// @param ContainerType Type of container e.g, MyList from WX_DECLARE_LIST(int, MyList); in wxwidgets
+ /// @param SizeMethod Method used to get size of container.
+ /// @param ElementInstance Instance of element to be fed out. Instance name is "elem". See WXELPP_ENABLED macro
+ /// for an example usage
+#define MAKE_CONTAINERELPP_FRIENDLY(ContainerType, SizeMethod, ElementInstance) \
+el::base::type::ostream_t& operator<<(el::base::type::ostream_t& ss, const ContainerType& container) {\
+const el::base::type::char_t* sep = ELPP->hasFlag(el::LoggingFlag::NewLineForContainer) ? \
+ELPP_LITERAL("\n ") : ELPP_LITERAL(", ");\
+ContainerType::const_iterator elem = container.begin();\
+ContainerType::const_iterator endElem = container.end();\
+std::size_t size_ = container.SizeMethod; \
+ss << ELPP_LITERAL("[");\
+for (std::size_t i = 0; elem != endElem && i < el::base::consts::kMaxLogPerContainer; ++i, ++elem) { \
+ss << ElementInstance;\
+ss << ((i < size_ - 1) ? sep : ELPP_LITERAL(""));\
+}\
+if (elem != endElem) {\
+ss << ELPP_LITERAL("...");\
+}\
+ss << ELPP_LITERAL("]");\
+return ss;\
+}
+#if defined(ELPP_WXWIDGETS_LOGGING)
+ ELPP_ITERATOR_CONTAINER_LOG_ONE_ARG(wxVector)
+# define ELPP_WX_PTR_ENABLED(ContainerType) MAKE_CONTAINERELPP_FRIENDLY(ContainerType, size(), *(*elem))
+# define ELPP_WX_ENABLED(ContainerType) MAKE_CONTAINERELPP_FRIENDLY(ContainerType, size(), (*elem))
+# define ELPP_WX_HASH_MAP_ENABLED(ContainerType) MAKE_CONTAINERELPP_FRIENDLY(ContainerType, size(), \
+ELPP_LITERAL("(") << elem->first << ELPP_LITERAL(", ") << elem->second << ELPP_LITERAL(")")
+#else
+# define ELPP_WX_PTR_ENABLED(ContainerType)
+# define ELPP_WX_ENABLED(ContainerType)
+# define ELPP_WX_HASH_MAP_ENABLED(ContainerType)
+#endif // defined(ELPP_WXWIDGETS_LOGGING)
+ // Other classes
+ template <class Class>
+ ELPP_SIMPLE_LOG(const Class&)
+#undef ELPP_SIMPLE_LOG
+#undef ELPP_ITERATOR_CONTAINER_LOG_ONE_ARG
+#undef ELPP_ITERATOR_CONTAINER_LOG_TWO_ARG
+#undef ELPP_ITERATOR_CONTAINER_LOG_THREE_ARG
+#undef ELPP_ITERATOR_CONTAINER_LOG_FOUR_ARG
+#undef ELPP_ITERATOR_CONTAINER_LOG_FIVE_ARG
+ private:
+ Logger* m_logger;
+ const base::type::char_t* m_containerLogSeparator;
+
+ template<class Iterator>
+ MessageBuilder& writeIterator(Iterator begin_, Iterator end_, std::size_t size_) {
+ m_logger->stream() << ELPP_LITERAL("[");
+ for (std::size_t i = 0; begin_ != end_ && i < base::consts::kMaxLogPerContainer; ++i, ++begin_) {
+ operator << (*begin_);
+ m_logger->stream() << ((i < size_ - 1) ? m_containerLogSeparator : ELPP_LITERAL(""));
+ }
+ if (begin_ != end_) {
+ m_logger->stream() << ELPP_LITERAL("...");
+ }
+ m_logger->stream() << ELPP_LITERAL("]");
+ if (ELPP->hasFlag(LoggingFlag::AutoSpacing)) {
+ m_logger->stream() << " ";
+ }
+ return *this;
+ }
+};
+/// @brief Writes nothing - Used when certain log is disabled
+class NullWriter : base::NoCopy {
+ public:
+ NullWriter(void) {}
+
+ // Null manipulator
+ inline NullWriter& operator<<(std::ostream& (*)(std::ostream&)) {
+ return *this;
+ }
+
+ template <typename T>
+ inline NullWriter& operator<<(const T&) {
+ return *this;
+ }
+
+ inline operator bool() {
+ return true;
+ }
+};
+/// @brief Main entry point of each logging
+class Writer : base::NoCopy {
+ public:
+ Writer(Level level, const char* file, base::type::LineNumber line,
+ const char* func, base::DispatchAction dispatchAction = base::DispatchAction::NormalLog,
+ base::type::VerboseLevel verboseLevel = 0) :
+ m_msg(nullptr), m_level(level), m_file(file), m_line(line), m_func(func), m_verboseLevel(verboseLevel),
+ m_logger(nullptr), m_proceed(false), m_dispatchAction(dispatchAction) {
+ }
+
+ Writer(LogMessage* msg, base::DispatchAction dispatchAction = base::DispatchAction::NormalLog) :
+ m_msg(msg), m_level(msg != nullptr ? msg->level() : Level::Unknown),
+ m_line(0), m_logger(nullptr), m_proceed(false), m_dispatchAction(dispatchAction) {
+ }
+
+ virtual ~Writer(void) {
+ processDispatch();
+ }
+
+ template <typename T>
+ inline Writer& operator<<(const T& log) {
+#if ELPP_LOGGING_ENABLED
+ if (m_proceed) {
+ m_messageBuilder << log;
+ }
+#endif // ELPP_LOGGING_ENABLED
+ return *this;
+ }
+
+ inline Writer& operator<<(std::ostream& (*log)(std::ostream&)) {
+#if ELPP_LOGGING_ENABLED
+ if (m_proceed) {
+ m_messageBuilder << log;
+ }
+#endif // ELPP_LOGGING_ENABLED
+ return *this;
+ }
+
+ inline operator bool() {
+ return true;
+ }
+
+ Writer& construct(Logger* logger, bool needLock = true);
+ Writer& construct(int count, const char* loggerIds, ...);
+ protected:
+ LogMessage* m_msg;
+ Level m_level;
+ const char* m_file;
+ const base::type::LineNumber m_line;
+ const char* m_func;
+ base::type::VerboseLevel m_verboseLevel;
+ Logger* m_logger;
+ bool m_proceed;
+ base::MessageBuilder m_messageBuilder;
+ base::DispatchAction m_dispatchAction;
+ std::vector<std::string> m_loggerIds;
+ friend class el::Helpers;
+
+ void initializeLogger(const std::string& loggerId, bool lookup = true, bool needLock = true);
+ void processDispatch();
+ void triggerDispatch(void);
+};
+class PErrorWriter : public base::Writer {
+ public:
+ PErrorWriter(Level level, const char* file, base::type::LineNumber line,
+ const char* func, base::DispatchAction dispatchAction = base::DispatchAction::NormalLog,
+ base::type::VerboseLevel verboseLevel = 0) :
+ base::Writer(level, file, line, func, dispatchAction, verboseLevel) {
+ }
+
+ virtual ~PErrorWriter(void);
+};
+} // namespace base
+// Logging from Logger class. Why this is here? Because we have Storage and Writer class available
+#if ELPP_VARIADIC_TEMPLATES_SUPPORTED
+template <typename T, typename... Args>
+void Logger::log_(Level level, int vlevel, const char* s, const T& value, const Args&... args) {
+ base::MessageBuilder b;
+ b.initialize(this);
+ while (*s) {
+ if (*s == base::consts::kFormatSpecifierChar) {
+ if (*(s + 1) == base::consts::kFormatSpecifierChar) {
+ ++s;
+ } else {
+ if (*(s + 1) == base::consts::kFormatSpecifierCharValue) {
+ ++s;
+ b << value;
+ log_(level, vlevel, ++s, args...);
+ return;
+ }
+ }
+ }
+ b << *s++;
+ }
+ ELPP_INTERNAL_ERROR("Too many arguments provided. Unable to handle. Please provide more format specifiers", false);
+}
+template <typename T>
+void Logger::log_(Level level, int vlevel, const T& log) {
+ if (level == Level::Verbose) {
+ if (ELPP->vRegistry()->allowed(vlevel, __FILE__)) {
+ base::Writer(Level::Verbose, "FILE", 0, "FUNCTION",
+ base::DispatchAction::NormalLog, vlevel).construct(this, false) << log;
+ } else {
+ stream().str(ELPP_LITERAL(""));
+ releaseLock();
+ }
+ } else {
+ base::Writer(level, "FILE", 0, "FUNCTION").construct(this, false) << log;
+ }
+}
+template <typename T, typename... Args>
+inline void Logger::log(Level level, const char* s, const T& value, const Args&... args) {
+ acquireLock(); // released in Writer!
+ log_(level, 0, s, value, args...);
+}
+template <typename T>
+inline void Logger::log(Level level, const T& log) {
+ acquireLock(); // released in Writer!
+ log_(level, 0, log);
+}
+# if ELPP_VERBOSE_LOG
+template <typename T, typename... Args>
+inline void Logger::verbose(int vlevel, const char* s, const T& value, const Args&... args) {
+ acquireLock(); // released in Writer!
+ log_(el::Level::Verbose, vlevel, s, value, args...);
+}
+template <typename T>
+inline void Logger::verbose(int vlevel, const T& log) {
+ acquireLock(); // released in Writer!
+ log_(el::Level::Verbose, vlevel, log);
+}
+# else
+template <typename T, typename... Args>
+inline void Logger::verbose(int, const char*, const T&, const Args&...) {
+ return;
+}
+template <typename T>
+inline void Logger::verbose(int, const T&) {
+ return;
+}
+# endif // ELPP_VERBOSE_LOG
+# define LOGGER_LEVEL_WRITERS(FUNCTION_NAME, LOG_LEVEL)\
+template <typename T, typename... Args>\
+inline void Logger::FUNCTION_NAME(const char* s, const T& value, const Args&... args) {\
+log(LOG_LEVEL, s, value, args...);\
+}\
+template <typename T>\
+inline void Logger::FUNCTION_NAME(const T& value) {\
+log(LOG_LEVEL, value);\
+}
+# define LOGGER_LEVEL_WRITERS_DISABLED(FUNCTION_NAME, LOG_LEVEL)\
+template <typename T, typename... Args>\
+inline void Logger::FUNCTION_NAME(const char*, const T&, const Args&...) {\
+return;\
+}\
+template <typename T>\
+inline void Logger::FUNCTION_NAME(const T&) {\
+return;\
+}
+
+# if ELPP_INFO_LOG
+LOGGER_LEVEL_WRITERS(info, Level::Info)
+# else
+LOGGER_LEVEL_WRITERS_DISABLED(info, Level::Info)
+# endif // ELPP_INFO_LOG
+# if ELPP_DEBUG_LOG
+LOGGER_LEVEL_WRITERS(debug, Level::Debug)
+# else
+LOGGER_LEVEL_WRITERS_DISABLED(debug, Level::Debug)
+# endif // ELPP_DEBUG_LOG
+# if ELPP_WARNING_LOG
+LOGGER_LEVEL_WRITERS(warn, Level::Warning)
+# else
+LOGGER_LEVEL_WRITERS_DISABLED(warn, Level::Warning)
+# endif // ELPP_WARNING_LOG
+# if ELPP_ERROR_LOG
+LOGGER_LEVEL_WRITERS(error, Level::Error)
+# else
+LOGGER_LEVEL_WRITERS_DISABLED(error, Level::Error)
+# endif // ELPP_ERROR_LOG
+# if ELPP_FATAL_LOG
+LOGGER_LEVEL_WRITERS(fatal, Level::Fatal)
+# else
+LOGGER_LEVEL_WRITERS_DISABLED(fatal, Level::Fatal)
+# endif // ELPP_FATAL_LOG
+# if ELPP_TRACE_LOG
+LOGGER_LEVEL_WRITERS(trace, Level::Trace)
+# else
+LOGGER_LEVEL_WRITERS_DISABLED(trace, Level::Trace)
+# endif // ELPP_TRACE_LOG
+# undef LOGGER_LEVEL_WRITERS
+# undef LOGGER_LEVEL_WRITERS_DISABLED
+#endif // ELPP_VARIADIC_TEMPLATES_SUPPORTED
+#if ELPP_COMPILER_MSVC
+# define ELPP_VARIADIC_FUNC_MSVC(variadicFunction, variadicArgs) variadicFunction variadicArgs
+# define ELPP_VARIADIC_FUNC_MSVC_RUN(variadicFunction, ...) ELPP_VARIADIC_FUNC_MSVC(variadicFunction, (__VA_ARGS__))
+# define el_getVALength(...) ELPP_VARIADIC_FUNC_MSVC_RUN(el_resolveVALength, 0, ## __VA_ARGS__,\
+10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0)
+#else
+# if ELPP_COMPILER_CLANG
+# define el_getVALength(...) el_resolveVALength(0, __VA_ARGS__, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0)
+# else
+# define el_getVALength(...) el_resolveVALength(0, ## __VA_ARGS__, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0)
+# endif // ELPP_COMPILER_CLANG
+#endif // ELPP_COMPILER_MSVC
+#define el_resolveVALength(_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, N, ...) N
+#define ELPP_WRITE_LOG(writer, level, dispatchAction, ...) \
+writer(level, __FILE__, __LINE__, ELPP_FUNC, dispatchAction).construct(el_getVALength(__VA_ARGS__), __VA_ARGS__)
+#define ELPP_WRITE_LOG_IF(writer, condition, level, dispatchAction, ...) if (condition) \
+writer(level, __FILE__, __LINE__, ELPP_FUNC, dispatchAction).construct(el_getVALength(__VA_ARGS__), __VA_ARGS__)
+#define ELPP_WRITE_LOG_EVERY_N(writer, occasion, level, dispatchAction, ...) \
+ELPP->validateEveryNCounter(__FILE__, __LINE__, occasion) && \
+writer(level, __FILE__, __LINE__, ELPP_FUNC, dispatchAction).construct(el_getVALength(__VA_ARGS__), __VA_ARGS__)
+#define ELPP_WRITE_LOG_AFTER_N(writer, n, level, dispatchAction, ...) \
+ELPP->validateAfterNCounter(__FILE__, __LINE__, n) && \
+writer(level, __FILE__, __LINE__, ELPP_FUNC, dispatchAction).construct(el_getVALength(__VA_ARGS__), __VA_ARGS__)
+#define ELPP_WRITE_LOG_N_TIMES(writer, n, level, dispatchAction, ...) \
+ELPP->validateNTimesCounter(__FILE__, __LINE__, n) && \
+writer(level, __FILE__, __LINE__, ELPP_FUNC, dispatchAction).construct(el_getVALength(__VA_ARGS__), __VA_ARGS__)
+#if defined(ELPP_FEATURE_ALL) || defined(ELPP_FEATURE_PERFORMANCE_TRACKING)
+class PerformanceTrackingData {
+ public:
+ enum class DataType : base::type::EnumType {
+ Checkpoint = 1, Complete = 2
+ };
+ // Do not use constructor, will run into multiple definition error, use init(PerformanceTracker*)
+ explicit PerformanceTrackingData(DataType dataType) : m_performanceTracker(nullptr),
+ m_dataType(dataType), m_firstCheckpoint(false), m_file(""), m_line(0), m_func("") {}
+ inline const std::string* blockName(void) const;
+ inline const struct timeval* startTime(void) const;
+ inline const struct timeval* endTime(void) const;
+ inline const struct timeval* lastCheckpointTime(void) const;
+ inline const base::PerformanceTracker* performanceTracker(void) const {
+ return m_performanceTracker;
+ }
+ inline PerformanceTrackingData::DataType dataType(void) const {
+ return m_dataType;
+ }
+ inline bool firstCheckpoint(void) const {
+ return m_firstCheckpoint;
+ }
+ inline std::string checkpointId(void) const {
+ return m_checkpointId;
+ }
+ inline const char* file(void) const {
+ return m_file;
+ }
+ inline base::type::LineNumber line(void) const {
+ return m_line;
+ }
+ inline const char* func(void) const {
+ return m_func;
+ }
+ inline const base::type::string_t* formattedTimeTaken() const {
+ return &m_formattedTimeTaken;
+ }
+ inline const std::string& loggerId(void) const;
+ private:
+ base::PerformanceTracker* m_performanceTracker;
+ base::type::string_t m_formattedTimeTaken;
+ PerformanceTrackingData::DataType m_dataType;
+ bool m_firstCheckpoint;
+ std::string m_checkpointId;
+ const char* m_file;
+ base::type::LineNumber m_line;
+ const char* m_func;
+ inline void init(base::PerformanceTracker* performanceTracker, bool firstCheckpoint = false) {
+ m_performanceTracker = performanceTracker;
+ m_firstCheckpoint = firstCheckpoint;
+ }
+
+ friend class el::base::PerformanceTracker;
+};
+namespace base {
+/// @brief Represents performanceTracker block of code that conditionally adds performance status to log
+/// either when goes outside the scope of when checkpoint() is called
+class PerformanceTracker : public base::threading::ThreadSafe, public Loggable {
+ public:
+ PerformanceTracker(const std::string& blockName,
+ base::TimestampUnit timestampUnit = base::TimestampUnit::Millisecond,
+ const std::string& loggerId = std::string(el::base::consts::kPerformanceLoggerId),
+ bool scopedLog = true, Level level = base::consts::kPerformanceTrackerDefaultLevel);
+ /// @brief Copy constructor
+ PerformanceTracker(const PerformanceTracker& t) :
+ m_blockName(t.m_blockName), m_timestampUnit(t.m_timestampUnit), m_loggerId(t.m_loggerId), m_scopedLog(t.m_scopedLog),
+ m_level(t.m_level), m_hasChecked(t.m_hasChecked), m_lastCheckpointId(t.m_lastCheckpointId), m_enabled(t.m_enabled),
+ m_startTime(t.m_startTime), m_endTime(t.m_endTime), m_lastCheckpointTime(t.m_lastCheckpointTime) {
+ }
+ virtual ~PerformanceTracker(void);
+ /// @brief A checkpoint for current performanceTracker block.
+ void checkpoint(const std::string& id = std::string(), const char* file = __FILE__,
+ base::type::LineNumber line = __LINE__,
+ const char* func = "");
+ inline Level level(void) const {
+ return m_level;
+ }
+ private:
+ std::string m_blockName;
+ base::TimestampUnit m_timestampUnit;
+ std::string m_loggerId;
+ bool m_scopedLog;
+ Level m_level;
+ bool m_hasChecked;
+ std::string m_lastCheckpointId;
+ bool m_enabled;
+ struct timeval m_startTime, m_endTime, m_lastCheckpointTime;
+
+ PerformanceTracker(void);
+
+ friend class el::PerformanceTrackingData;
+ friend class base::DefaultPerformanceTrackingCallback;
+
+ const inline base::type::string_t getFormattedTimeTaken() const {
+ return getFormattedTimeTaken(m_startTime);
+ }
+
+ const base::type::string_t getFormattedTimeTaken(struct timeval startTime) const;
+
+ virtual inline void log(el::base::type::ostream_t& os) const {
+ os << getFormattedTimeTaken();
+ }
+};
+class DefaultPerformanceTrackingCallback : public PerformanceTrackingCallback {
+ protected:
+ void handle(const PerformanceTrackingData* data) {
+ m_data = data;
+ base::type::stringstream_t ss;
+ if (m_data->dataType() == PerformanceTrackingData::DataType::Complete) {
+ ss << ELPP_LITERAL("Executed [") << m_data->blockName()->c_str() << ELPP_LITERAL("] in [") <<
+ *m_data->formattedTimeTaken() << ELPP_LITERAL("]");
+ } else {
+ ss << ELPP_LITERAL("Performance checkpoint");
+ if (!m_data->checkpointId().empty()) {
+ ss << ELPP_LITERAL(" [") << m_data->checkpointId().c_str() << ELPP_LITERAL("]");
+ }
+ ss << ELPP_LITERAL(" for block [") << m_data->blockName()->c_str() << ELPP_LITERAL("] : [") <<
+ *m_data->performanceTracker();
+ if (!ELPP->hasFlag(LoggingFlag::DisablePerformanceTrackingCheckpointComparison)
+ && m_data->performanceTracker()->m_hasChecked) {
+ ss << ELPP_LITERAL(" ([") << *m_data->formattedTimeTaken() << ELPP_LITERAL("] from ");
+ if (m_data->performanceTracker()->m_lastCheckpointId.empty()) {
+ ss << ELPP_LITERAL("last checkpoint");
+ } else {
+ ss << ELPP_LITERAL("checkpoint '") << m_data->performanceTracker()->m_lastCheckpointId.c_str() << ELPP_LITERAL("'");
+ }
+ ss << ELPP_LITERAL(")]");
+ } else {
+ ss << ELPP_LITERAL("]");
+ }
+ }
+ el::base::Writer(m_data->performanceTracker()->level(), m_data->file(), m_data->line(), m_data->func()).construct(1,
+ m_data->loggerId().c_str()) << ss.str();
+ }
+ private:
+ const PerformanceTrackingData* m_data;
+};
+} // namespace base
+inline const std::string* PerformanceTrackingData::blockName() const {
+ return const_cast<const std::string*>(&m_performanceTracker->m_blockName);
+}
+inline const struct timeval* PerformanceTrackingData::startTime() const {
+ return const_cast<const struct timeval*>(&m_performanceTracker->m_startTime);
+}
+inline const struct timeval* PerformanceTrackingData::endTime() const {
+ return const_cast<const struct timeval*>(&m_performanceTracker->m_endTime);
+}
+inline const struct timeval* PerformanceTrackingData::lastCheckpointTime() const {
+ return const_cast<const struct timeval*>(&m_performanceTracker->m_lastCheckpointTime);
+}
+inline const std::string& PerformanceTrackingData::loggerId(void) const {
+ return m_performanceTracker->m_loggerId;
+}
+#endif // defined(ELPP_FEATURE_ALL) || defined(ELPP_FEATURE_PERFORMANCE_TRACKING)
+namespace base {
+/// @brief Contains some internal debugging tools like crash handler and stack tracer
+namespace debug {
+#if defined(ELPP_FEATURE_ALL) || defined(ELPP_FEATURE_CRASH_LOG)
+class StackTrace : base::NoCopy {
+ public:
+ static const unsigned int kMaxStack = 64;
+ static const unsigned int kStackStart = 2; // We want to skip c'tor and StackTrace::generateNew()
+ class StackTraceEntry {
+ public:
+ StackTraceEntry(std::size_t index, const std::string& loc, const std::string& demang, const std::string& hex,
+ const std::string& addr);
+ StackTraceEntry(std::size_t index, const std::string& loc) :
+ m_index(index),
+ m_location(loc) {
+ }
+ std::size_t m_index;
+ std::string m_location;
+ std::string m_demangled;
+ std::string m_hex;
+ std::string m_addr;
+ friend std::ostream& operator<<(std::ostream& ss, const StackTraceEntry& si);
+
+ private:
+ StackTraceEntry(void);
+ };
+
+ StackTrace(void) {
+ generateNew();
+ }
+
+ virtual ~StackTrace(void) {
+ }
+
+ inline std::vector<StackTraceEntry>& getLatestStack(void) {
+ return m_stack;
+ }
+
+ friend std::ostream& operator<<(std::ostream& os, const StackTrace& st);
+
+ private:
+ std::vector<StackTraceEntry> m_stack;
+
+ void generateNew(void);
+};
+/// @brief Handles unexpected crashes
+class CrashHandler : base::NoCopy {
+ public:
+ typedef void (*Handler)(int);
+
+ explicit CrashHandler(bool useDefault);
+ explicit CrashHandler(const Handler& cHandler) {
+ setHandler(cHandler);
+ }
+ void setHandler(const Handler& cHandler);
+
+ private:
+ Handler m_handler;
+};
+#else
+class CrashHandler {
+ public:
+ explicit CrashHandler(bool) {}
+};
+#endif // defined(ELPP_FEATURE_ALL) || defined(ELPP_FEATURE_CRASH_LOG)
+} // namespace debug
+} // namespace base
+extern base::debug::CrashHandler elCrashHandler;
+#define MAKE_LOGGABLE(ClassType, ClassInstance, OutputStreamInstance) \
+el::base::type::ostream_t& operator<<(el::base::type::ostream_t& OutputStreamInstance, const ClassType& ClassInstance)
+/// @brief Initializes syslog with process ID, options and facility. calls closelog() on d'tor
+class SysLogInitializer {
+ public:
+ SysLogInitializer(const char* processIdent, int options = 0, int facility = 0) {
+#if defined(ELPP_SYSLOG)
+ (void)base::consts::kSysLogLoggerId;
+ openlog(processIdent, options, facility);
+#else
+ ELPP_UNUSED(processIdent);
+ ELPP_UNUSED(options);
+ ELPP_UNUSED(facility);
+#endif // defined(ELPP_SYSLOG)
+ }
+ virtual ~SysLogInitializer(void) {
+#if defined(ELPP_SYSLOG)
+ closelog();
+#endif // defined(ELPP_SYSLOG)
+ }
+};
+#define ELPP_INITIALIZE_SYSLOG(id, opt, fac) el::SysLogInitializer elSyslogInit(id, opt, fac)
+/// @brief Static helpers for developers
+class Helpers : base::StaticClass {
+ public:
+ /// @brief Shares logging repository (base::Storage)
+ static inline void setStorage(base::type::StoragePointer storage) {
+ ELPP = storage;
+ }
+ /// @return Main storage repository
+ static inline base::type::StoragePointer storage() {
+ return ELPP;
+ }
+ /// @brief Sets application arguments and figures out whats active for logging and whats not.
+ static inline void setArgs(int argc, char** argv) {
+ ELPP->setApplicationArguments(argc, argv);
+ }
+ /// @copydoc setArgs(int argc, char** argv)
+ static inline void setArgs(int argc, const char** argv) {
+ ELPP->setApplicationArguments(argc, const_cast<char**>(argv));
+ }
+ /// @brief Sets thread name for current thread. Requires std::thread
+ static inline void setThreadName(const std::string& name) {
+ ELPP->setThreadName(name);
+ }
+ static inline std::string getThreadName() {
+ return ELPP->getThreadName(base::threading::getCurrentThreadId());
+ }
+#if defined(ELPP_FEATURE_ALL) || defined(ELPP_FEATURE_CRASH_LOG)
+ /// @brief Overrides default crash handler and installs custom handler.
+ /// @param crashHandler A functor with no return type that takes single int argument.
+ /// Handler is a typedef with specification: void (*Handler)(int)
+ static inline void setCrashHandler(const el::base::debug::CrashHandler::Handler& crashHandler) {
+ el::elCrashHandler.setHandler(crashHandler);
+ }
+ /// @brief Abort due to crash with signal in parameter
+ /// @param sig Crash signal
+ static void crashAbort(int sig, const char* sourceFile = "", unsigned int long line = 0);
+ /// @brief Logs reason of crash as per sig
+ /// @param sig Crash signal
+ /// @param stackTraceIfAvailable Includes stack trace if available
+ /// @param level Logging level
+ /// @param logger Logger to use for logging
+ static void logCrashReason(int sig, bool stackTraceIfAvailable = false,
+ Level level = Level::Fatal, const char* logger = base::consts::kDefaultLoggerId);
+#endif // defined(ELPP_FEATURE_ALL) || defined(ELPP_FEATURE_CRASH_LOG)
+ /// @brief Installs pre rollout callback, this callback is triggered when log file is about to be rolled out
+ /// (can be useful for backing up)
+ static inline void installPreRollOutCallback(const PreRollOutCallback& callback) {
+ ELPP->setPreRollOutCallback(callback);
+ }
+ /// @brief Uninstalls pre rollout callback
+ static inline void uninstallPreRollOutCallback(void) {
+ ELPP->unsetPreRollOutCallback();
+ }
+ /// @brief Installs post log dispatch callback, this callback is triggered when log is dispatched
+ template <typename T>
+ static inline bool installLogDispatchCallback(const std::string& id) {
+ return ELPP->installLogDispatchCallback<T>(id);
+ }
+ /// @brief Uninstalls log dispatch callback
+ template <typename T>
+ static inline void uninstallLogDispatchCallback(const std::string& id) {
+ ELPP->uninstallLogDispatchCallback<T>(id);
+ }
+ template <typename T>
+ static inline T* logDispatchCallback(const std::string& id) {
+ return ELPP->logDispatchCallback<T>(id);
+ }
+#if defined(ELPP_FEATURE_ALL) || defined(ELPP_FEATURE_PERFORMANCE_TRACKING)
+ /// @brief Installs post performance tracking callback, this callback is triggered when performance tracking is finished
+ template <typename T>
+ static inline bool installPerformanceTrackingCallback(const std::string& id) {
+ return ELPP->installPerformanceTrackingCallback<T>(id);
+ }
+ /// @brief Uninstalls post performance tracking handler
+ template <typename T>
+ static inline void uninstallPerformanceTrackingCallback(const std::string& id) {
+ ELPP->uninstallPerformanceTrackingCallback<T>(id);
+ }
+ template <typename T>
+ static inline T* performanceTrackingCallback(const std::string& id) {
+ return ELPP->performanceTrackingCallback<T>(id);
+ }
+#endif // defined(ELPP_FEATURE_ALL) || defined(ELPP_FEATURE_PERFORMANCE_TRACKING)
+ /// @brief Converts template to std::string - useful for loggable classes to log containers within log(std::ostream&) const
+ template <typename T>
+ static std::string convertTemplateToStdString(const T& templ) {
+ el::Logger* logger =
+ ELPP->registeredLoggers()->get(el::base::consts::kDefaultLoggerId);
+ if (logger == nullptr) {
+ return std::string();
+ }
+ base::MessageBuilder b;
+ b.initialize(logger);
+ logger->acquireLock();
+ b << templ;
+#if defined(ELPP_UNICODE)
+ std::string s = std::string(logger->stream().str().begin(), logger->stream().str().end());
+#else
+ std::string s = logger->stream().str();
+#endif // defined(ELPP_UNICODE)
+ logger->stream().str(ELPP_LITERAL(""));
+ logger->releaseLock();
+ return s;
+ }
+ /// @brief Returns command line arguments (pointer) provided to easylogging++
+ static inline const el::base::utils::CommandLineArgs* commandLineArgs(void) {
+ return ELPP->commandLineArgs();
+ }
+ /// @brief Reserve space for custom format specifiers for performance
+ /// @see std::vector::reserve
+ static inline void reserveCustomFormatSpecifiers(std::size_t size) {
+ ELPP->m_customFormatSpecifiers.reserve(size);
+ }
+ /// @brief Installs user defined format specifier and handler
+ static inline void installCustomFormatSpecifier(const CustomFormatSpecifier& customFormatSpecifier) {
+ ELPP->installCustomFormatSpecifier(customFormatSpecifier);
+ }
+ /// @brief Uninstalls user defined format specifier and handler
+ static inline bool uninstallCustomFormatSpecifier(const char* formatSpecifier) {
+ return ELPP->uninstallCustomFormatSpecifier(formatSpecifier);
+ }
+ /// @brief Returns true if custom format specifier is installed
+ static inline bool hasCustomFormatSpecifier(const char* formatSpecifier) {
+ return ELPP->hasCustomFormatSpecifier(formatSpecifier);
+ }
+ static inline void validateFileRolling(Logger* logger, Level level) {
+ if (ELPP == nullptr || logger == nullptr) return;
+ logger->m_typedConfigurations->validateFileRolling(level, ELPP->preRollOutCallback());
+ }
+};
+/// @brief Static helpers to deal with loggers and their configurations
+class Loggers : base::StaticClass {
+ public:
+ /// @brief Gets existing or registers new logger
+ static Logger* getLogger(const std::string& identity, bool registerIfNotAvailable = true);
+ /// @brief Changes default log builder for future loggers
+ static void setDefaultLogBuilder(el::LogBuilderPtr& logBuilderPtr);
+ /// @brief Installs logger registration callback, this callback is triggered when new logger is registered
+ template <typename T>
+ static inline bool installLoggerRegistrationCallback(const std::string& id) {
+ return ELPP->registeredLoggers()->installLoggerRegistrationCallback<T>(id);
+ }
+ /// @brief Uninstalls log dispatch callback
+ template <typename T>
+ static inline void uninstallLoggerRegistrationCallback(const std::string& id) {
+ ELPP->registeredLoggers()->uninstallLoggerRegistrationCallback<T>(id);
+ }
+ template <typename T>
+ static inline T* loggerRegistrationCallback(const std::string& id) {
+ return ELPP->registeredLoggers()->loggerRegistrationCallback<T>(id);
+ }
+ /// @brief Unregisters logger - use it only when you know what you are doing, you may unregister
+ /// loggers initialized / used by third-party libs.
+ static bool unregisterLogger(const std::string& identity);
+ /// @brief Whether or not logger with id is registered
+ static bool hasLogger(const std::string& identity);
+ /// @brief Reconfigures specified logger with new configurations
+ static Logger* reconfigureLogger(Logger* logger, const Configurations& configurations);
+ /// @brief Reconfigures logger with new configurations after looking it up using identity
+ static Logger* reconfigureLogger(const std::string& identity, const Configurations& configurations);
+ /// @brief Reconfigures logger's single configuration
+ static Logger* reconfigureLogger(const std::string& identity, ConfigurationType configurationType,
+ const std::string& value);
+ /// @brief Reconfigures all the existing loggers with new configurations
+ static void reconfigureAllLoggers(const Configurations& configurations);
+ /// @brief Reconfigures single configuration for all the loggers
+ static inline void reconfigureAllLoggers(ConfigurationType configurationType, const std::string& value) {
+ reconfigureAllLoggers(Level::Global, configurationType, value);
+ }
+ /// @brief Reconfigures single configuration for all the loggers for specified level
+ static void reconfigureAllLoggers(Level level, ConfigurationType configurationType,
+ const std::string& value);
+ /// @brief Sets default configurations. This configuration is used for future (and conditionally for existing) loggers
+ static void setDefaultConfigurations(const Configurations& configurations,
+ bool reconfigureExistingLoggers = false);
+ /// @brief Returns current default
+ static const Configurations* defaultConfigurations(void);
+ /// @brief Returns log stream reference pointer if needed by user
+ static const base::LogStreamsReferenceMapPtr logStreamsReference(void);
+ /// @brief Default typed configuration based on existing defaultConf
+ static base::TypedConfigurations defaultTypedConfigurations(void);
+ /// @brief Populates all logger IDs in current repository.
+ /// @param [out] targetList List of fill up.
+ static std::vector<std::string>* populateAllLoggerIds(std::vector<std::string>* targetList);
+ /// @brief Sets configurations from global configuration file.
+ static void configureFromGlobal(const char* globalConfigurationFilePath);
+ /// @brief Configures loggers using command line arg. Ensure you have already set command line args,
+ /// @return False if invalid argument or argument with no value provided, true if attempted to configure logger.
+ /// If true is returned that does not mean it has been configured successfully, it only means that it
+ /// has attempted to configure logger using configuration file provided in argument
+ static bool configureFromArg(const char* argKey);
+ /// @brief Flushes all loggers for all levels - Be careful if you dont know how many loggers are registered
+ static void flushAll(void);
+ /// @brief Adds logging flag used internally.
+ static inline void addFlag(LoggingFlag flag) {
+ ELPP->addFlag(flag);
+ }
+ /// @brief Removes logging flag used internally.
+ static inline void removeFlag(LoggingFlag flag) {
+ ELPP->removeFlag(flag);
+ }
+ /// @brief Determines whether or not certain flag is active
+ static inline bool hasFlag(LoggingFlag flag) {
+ return ELPP->hasFlag(flag);
+ }
+ /// @brief Adds flag and removes it when scope goes out
+ class ScopedAddFlag {
+ public:
+ ScopedAddFlag(LoggingFlag flag) : m_flag(flag) {
+ Loggers::addFlag(m_flag);
+ }
+ ~ScopedAddFlag(void) {
+ Loggers::removeFlag(m_flag);
+ }
+ private:
+ LoggingFlag m_flag;
+ };
+ /// @brief Removes flag and add it when scope goes out
+ class ScopedRemoveFlag {
+ public:
+ ScopedRemoveFlag(LoggingFlag flag) : m_flag(flag) {
+ Loggers::removeFlag(m_flag);
+ }
+ ~ScopedRemoveFlag(void) {
+ Loggers::addFlag(m_flag);
+ }
+ private:
+ LoggingFlag m_flag;
+ };
+ /// @brief Sets hierarchy for logging. Needs to enable logging flag (HierarchicalLogging)
+ static void setLoggingLevel(Level level) {
+ ELPP->setLoggingLevel(level);
+ }
+ /// @brief Sets verbose level on the fly
+ static void setVerboseLevel(base::type::VerboseLevel level);
+ /// @brief Gets current verbose level
+ static base::type::VerboseLevel verboseLevel(void);
+ /// @brief Sets vmodules as specified (on the fly)
+ static void setVModules(const char* modules);
+ /// @brief Clears vmodules
+ static void clearVModules(void);
+};
+class VersionInfo : base::StaticClass {
+ public:
+ /// @brief Current version number
+ static const std::string version(void);
+
+ /// @brief Release date of current version
+ static const std::string releaseDate(void);
+};
+} // namespace el
+#undef VLOG_IS_ON
+/// @brief Determines whether verbose logging is on for specified level current file.
+#define VLOG_IS_ON(verboseLevel) (ELPP->vRegistry()->allowed(verboseLevel, __FILE__))
+#undef TIMED_BLOCK
+#undef TIMED_SCOPE
+#undef TIMED_SCOPE_IF
+#undef TIMED_FUNC
+#undef TIMED_FUNC_IF
+#undef ELPP_MIN_UNIT
+#if defined(ELPP_PERFORMANCE_MICROSECONDS)
+# define ELPP_MIN_UNIT el::base::TimestampUnit::Microsecond
+#else
+# define ELPP_MIN_UNIT el::base::TimestampUnit::Millisecond
+#endif // (defined(ELPP_PERFORMANCE_MICROSECONDS))
+/// @brief Performance tracked scope. Performance gets written when goes out of scope using
+/// 'performance' logger.
+///
+/// @detail Please note in order to check the performance at a certain time you can use obj->checkpoint();
+/// @see el::base::PerformanceTracker
+/// @see el::base::PerformanceTracker::checkpoint
+// Note: Do not surround this definition with null macro because of obj instance
+#define TIMED_SCOPE_IF(obj, blockname, condition) el::base::type::PerformanceTrackerPtr obj( condition ? \
+ new el::base::PerformanceTracker(blockname, ELPP_MIN_UNIT) : nullptr )
+#define TIMED_SCOPE(obj, blockname) TIMED_SCOPE_IF(obj, blockname, true)
+#define TIMED_BLOCK(obj, blockName) for (struct { int i; el::base::type::PerformanceTrackerPtr timer; } obj = { 0, \
+ el::base::type::PerformanceTrackerPtr(new el::base::PerformanceTracker(blockName, ELPP_MIN_UNIT)) }; obj.i < 1; ++obj.i)
+/// @brief Performance tracked function. Performance gets written when goes out of scope using
+/// 'performance' logger.
+///
+/// @detail Please note in order to check the performance at a certain time you can use obj->checkpoint();
+/// @see el::base::PerformanceTracker
+/// @see el::base::PerformanceTracker::checkpoint
+#define TIMED_FUNC_IF(obj,condition) TIMED_SCOPE_IF(obj, ELPP_FUNC, condition)
+#define TIMED_FUNC(obj) TIMED_SCOPE(obj, ELPP_FUNC)
+#undef PERFORMANCE_CHECKPOINT
+#undef PERFORMANCE_CHECKPOINT_WITH_ID
+#define PERFORMANCE_CHECKPOINT(obj) obj->checkpoint(std::string(), __FILE__, __LINE__, ELPP_FUNC)
+#define PERFORMANCE_CHECKPOINT_WITH_ID(obj, id) obj->checkpoint(id, __FILE__, __LINE__, ELPP_FUNC)
+#undef ELPP_COUNTER
+#undef ELPP_COUNTER_POS
+/// @brief Gets hit counter for file/line
+#define ELPP_COUNTER (ELPP->hitCounters()->getCounter(__FILE__, __LINE__))
+/// @brief Gets hit counter position for file/line, -1 if not registered yet
+#define ELPP_COUNTER_POS (ELPP_COUNTER == nullptr ? -1 : ELPP_COUNTER->hitCounts())
+// Undef levels to support LOG(LEVEL)
+#undef INFO
+#undef WARNING
+#undef DEBUG
+#undef ERROR
+#undef FATAL
+#undef TRACE
+#undef VERBOSE
+// Undef existing
+#undef CINFO
+#undef CWARNING
+#undef CDEBUG
+#undef CFATAL
+#undef CERROR
+#undef CTRACE
+#undef CVERBOSE
+#undef CINFO_IF
+#undef CWARNING_IF
+#undef CDEBUG_IF
+#undef CERROR_IF
+#undef CFATAL_IF
+#undef CTRACE_IF
+#undef CVERBOSE_IF
+#undef CINFO_EVERY_N
+#undef CWARNING_EVERY_N
+#undef CDEBUG_EVERY_N
+#undef CERROR_EVERY_N
+#undef CFATAL_EVERY_N
+#undef CTRACE_EVERY_N
+#undef CVERBOSE_EVERY_N
+#undef CINFO_AFTER_N
+#undef CWARNING_AFTER_N
+#undef CDEBUG_AFTER_N
+#undef CERROR_AFTER_N
+#undef CFATAL_AFTER_N
+#undef CTRACE_AFTER_N
+#undef CVERBOSE_AFTER_N
+#undef CINFO_N_TIMES
+#undef CWARNING_N_TIMES
+#undef CDEBUG_N_TIMES
+#undef CERROR_N_TIMES
+#undef CFATAL_N_TIMES
+#undef CTRACE_N_TIMES
+#undef CVERBOSE_N_TIMES
+// Normal logs
+#if ELPP_INFO_LOG
+# define CINFO(writer, dispatchAction, ...) ELPP_WRITE_LOG(writer, el::Level::Info, dispatchAction, __VA_ARGS__)
+#else
+# define CINFO(writer, dispatchAction, ...) el::base::NullWriter()
+#endif // ELPP_INFO_LOG
+#if ELPP_WARNING_LOG
+# define CWARNING(writer, dispatchAction, ...) ELPP_WRITE_LOG(writer, el::Level::Warning, dispatchAction, __VA_ARGS__)
+#else
+# define CWARNING(writer, dispatchAction, ...) el::base::NullWriter()
+#endif // ELPP_WARNING_LOG
+#if ELPP_DEBUG_LOG
+# define CDEBUG(writer, dispatchAction, ...) ELPP_WRITE_LOG(writer, el::Level::Debug, dispatchAction, __VA_ARGS__)
+#else
+# define CDEBUG(writer, dispatchAction, ...) el::base::NullWriter()
+#endif // ELPP_DEBUG_LOG
+#if ELPP_ERROR_LOG
+# define CERROR(writer, dispatchAction, ...) ELPP_WRITE_LOG(writer, el::Level::Error, dispatchAction, __VA_ARGS__)
+#else
+# define CERROR(writer, dispatchAction, ...) el::base::NullWriter()
+#endif // ELPP_ERROR_LOG
+#if ELPP_FATAL_LOG
+# define CFATAL(writer, dispatchAction, ...) ELPP_WRITE_LOG(writer, el::Level::Fatal, dispatchAction, __VA_ARGS__)
+#else
+# define CFATAL(writer, dispatchAction, ...) el::base::NullWriter()
+#endif // ELPP_FATAL_LOG
+#if ELPP_TRACE_LOG
+# define CTRACE(writer, dispatchAction, ...) ELPP_WRITE_LOG(writer, el::Level::Trace, dispatchAction, __VA_ARGS__)
+#else
+# define CTRACE(writer, dispatchAction, ...) el::base::NullWriter()
+#endif // ELPP_TRACE_LOG
+#if ELPP_VERBOSE_LOG
+# define CVERBOSE(writer, vlevel, dispatchAction, ...) if (VLOG_IS_ON(vlevel)) writer(\
+el::Level::Verbose, __FILE__, __LINE__, ELPP_FUNC, dispatchAction, vlevel).construct(el_getVALength(__VA_ARGS__), __VA_ARGS__)
+#else
+# define CVERBOSE(writer, vlevel, dispatchAction, ...) el::base::NullWriter()
+#endif // ELPP_VERBOSE_LOG
+// Conditional logs
+#if ELPP_INFO_LOG
+# define CINFO_IF(writer, condition_, dispatchAction, ...) \
+ELPP_WRITE_LOG_IF(writer, (condition_), el::Level::Info, dispatchAction, __VA_ARGS__)
+#else
+# define CINFO_IF(writer, condition_, dispatchAction, ...) el::base::NullWriter()
+#endif // ELPP_INFO_LOG
+#if ELPP_WARNING_LOG
+# define CWARNING_IF(writer, condition_, dispatchAction, ...)\
+ELPP_WRITE_LOG_IF(writer, (condition_), el::Level::Warning, dispatchAction, __VA_ARGS__)
+#else
+# define CWARNING_IF(writer, condition_, dispatchAction, ...) el::base::NullWriter()
+#endif // ELPP_WARNING_LOG
+#if ELPP_DEBUG_LOG
+# define CDEBUG_IF(writer, condition_, dispatchAction, ...)\
+ELPP_WRITE_LOG_IF(writer, (condition_), el::Level::Debug, dispatchAction, __VA_ARGS__)
+#else
+# define CDEBUG_IF(writer, condition_, dispatchAction, ...) el::base::NullWriter()
+#endif // ELPP_DEBUG_LOG
+#if ELPP_ERROR_LOG
+# define CERROR_IF(writer, condition_, dispatchAction, ...)\
+ELPP_WRITE_LOG_IF(writer, (condition_), el::Level::Error, dispatchAction, __VA_ARGS__)
+#else
+# define CERROR_IF(writer, condition_, dispatchAction, ...) el::base::NullWriter()
+#endif // ELPP_ERROR_LOG
+#if ELPP_FATAL_LOG
+# define CFATAL_IF(writer, condition_, dispatchAction, ...)\
+ELPP_WRITE_LOG_IF(writer, (condition_), el::Level::Fatal, dispatchAction, __VA_ARGS__)
+#else
+# define CFATAL_IF(writer, condition_, dispatchAction, ...) el::base::NullWriter()
+#endif // ELPP_FATAL_LOG
+#if ELPP_TRACE_LOG
+# define CTRACE_IF(writer, condition_, dispatchAction, ...)\
+ELPP_WRITE_LOG_IF(writer, (condition_), el::Level::Trace, dispatchAction, __VA_ARGS__)
+#else
+# define CTRACE_IF(writer, condition_, dispatchAction, ...) el::base::NullWriter()
+#endif // ELPP_TRACE_LOG
+#if ELPP_VERBOSE_LOG
+# define CVERBOSE_IF(writer, condition_, vlevel, dispatchAction, ...) if (VLOG_IS_ON(vlevel) && (condition_)) writer( \
+el::Level::Verbose, __FILE__, __LINE__, ELPP_FUNC, dispatchAction, vlevel).construct(el_getVALength(__VA_ARGS__), __VA_ARGS__)
+#else
+# define CVERBOSE_IF(writer, condition_, vlevel, dispatchAction, ...) el::base::NullWriter()
+#endif // ELPP_VERBOSE_LOG
+// Occasional logs
+#if ELPP_INFO_LOG
+# define CINFO_EVERY_N(writer, occasion, dispatchAction, ...)\
+ELPP_WRITE_LOG_EVERY_N(writer, occasion, el::Level::Info, dispatchAction, __VA_ARGS__)
+#else
+# define CINFO_EVERY_N(writer, occasion, dispatchAction, ...) el::base::NullWriter()
+#endif // ELPP_INFO_LOG
+#if ELPP_WARNING_LOG
+# define CWARNING_EVERY_N(writer, occasion, dispatchAction, ...)\
+ELPP_WRITE_LOG_EVERY_N(writer, occasion, el::Level::Warning, dispatchAction, __VA_ARGS__)
+#else
+# define CWARNING_EVERY_N(writer, occasion, dispatchAction, ...) el::base::NullWriter()
+#endif // ELPP_WARNING_LOG
+#if ELPP_DEBUG_LOG
+# define CDEBUG_EVERY_N(writer, occasion, dispatchAction, ...)\
+ELPP_WRITE_LOG_EVERY_N(writer, occasion, el::Level::Debug, dispatchAction, __VA_ARGS__)
+#else
+# define CDEBUG_EVERY_N(writer, occasion, dispatchAction, ...) el::base::NullWriter()
+#endif // ELPP_DEBUG_LOG
+#if ELPP_ERROR_LOG
+# define CERROR_EVERY_N(writer, occasion, dispatchAction, ...)\
+ELPP_WRITE_LOG_EVERY_N(writer, occasion, el::Level::Error, dispatchAction, __VA_ARGS__)
+#else
+# define CERROR_EVERY_N(writer, occasion, dispatchAction, ...) el::base::NullWriter()
+#endif // ELPP_ERROR_LOG
+#if ELPP_FATAL_LOG
+# define CFATAL_EVERY_N(writer, occasion, dispatchAction, ...)\
+ELPP_WRITE_LOG_EVERY_N(writer, occasion, el::Level::Fatal, dispatchAction, __VA_ARGS__)
+#else
+# define CFATAL_EVERY_N(writer, occasion, dispatchAction, ...) el::base::NullWriter()
+#endif // ELPP_FATAL_LOG
+#if ELPP_TRACE_LOG
+# define CTRACE_EVERY_N(writer, occasion, dispatchAction, ...)\
+ELPP_WRITE_LOG_EVERY_N(writer, occasion, el::Level::Trace, dispatchAction, __VA_ARGS__)
+#else
+# define CTRACE_EVERY_N(writer, occasion, dispatchAction, ...) el::base::NullWriter()
+#endif // ELPP_TRACE_LOG
+#if ELPP_VERBOSE_LOG
+# define CVERBOSE_EVERY_N(writer, occasion, vlevel, dispatchAction, ...)\
+CVERBOSE_IF(writer, ELPP->validateEveryNCounter(__FILE__, __LINE__, occasion), vlevel, dispatchAction, __VA_ARGS__)
+#else
+# define CVERBOSE_EVERY_N(writer, occasion, vlevel, dispatchAction, ...) el::base::NullWriter()
+#endif // ELPP_VERBOSE_LOG
+// After N logs
+#if ELPP_INFO_LOG
+# define CINFO_AFTER_N(writer, n, dispatchAction, ...)\
+ELPP_WRITE_LOG_AFTER_N(writer, n, el::Level::Info, dispatchAction, __VA_ARGS__)
+#else
+# define CINFO_AFTER_N(writer, n, dispatchAction, ...) el::base::NullWriter()
+#endif // ELPP_INFO_LOG
+#if ELPP_WARNING_LOG
+# define CWARNING_AFTER_N(writer, n, dispatchAction, ...)\
+ELPP_WRITE_LOG_AFTER_N(writer, n, el::Level::Warning, dispatchAction, __VA_ARGS__)
+#else
+# define CWARNING_AFTER_N(writer, n, dispatchAction, ...) el::base::NullWriter()
+#endif // ELPP_WARNING_LOG
+#if ELPP_DEBUG_LOG
+# define CDEBUG_AFTER_N(writer, n, dispatchAction, ...)\
+ELPP_WRITE_LOG_AFTER_N(writer, n, el::Level::Debug, dispatchAction, __VA_ARGS__)
+#else
+# define CDEBUG_AFTER_N(writer, n, dispatchAction, ...) el::base::NullWriter()
+#endif // ELPP_DEBUG_LOG
+#if ELPP_ERROR_LOG
+# define CERROR_AFTER_N(writer, n, dispatchAction, ...)\
+ELPP_WRITE_LOG_AFTER_N(writer, n, el::Level::Error, dispatchAction, __VA_ARGS__)
+#else
+# define CERROR_AFTER_N(writer, n, dispatchAction, ...) el::base::NullWriter()
+#endif // ELPP_ERROR_LOG
+#if ELPP_FATAL_LOG
+# define CFATAL_AFTER_N(writer, n, dispatchAction, ...)\
+ELPP_WRITE_LOG_AFTER_N(writer, n, el::Level::Fatal, dispatchAction, __VA_ARGS__)
+#else
+# define CFATAL_AFTER_N(writer, n, dispatchAction, ...) el::base::NullWriter()
+#endif // ELPP_FATAL_LOG
+#if ELPP_TRACE_LOG
+# define CTRACE_AFTER_N(writer, n, dispatchAction, ...)\
+ELPP_WRITE_LOG_AFTER_N(writer, n, el::Level::Trace, dispatchAction, __VA_ARGS__)
+#else
+# define CTRACE_AFTER_N(writer, n, dispatchAction, ...) el::base::NullWriter()
+#endif // ELPP_TRACE_LOG
+#if ELPP_VERBOSE_LOG
+# define CVERBOSE_AFTER_N(writer, n, vlevel, dispatchAction, ...)\
+CVERBOSE_IF(writer, ELPP->validateAfterNCounter(__FILE__, __LINE__, n), vlevel, dispatchAction, __VA_ARGS__)
+#else
+# define CVERBOSE_AFTER_N(writer, n, vlevel, dispatchAction, ...) el::base::NullWriter()
+#endif // ELPP_VERBOSE_LOG
+// N Times logs
+#if ELPP_INFO_LOG
+# define CINFO_N_TIMES(writer, n, dispatchAction, ...)\
+ELPP_WRITE_LOG_N_TIMES(writer, n, el::Level::Info, dispatchAction, __VA_ARGS__)
+#else
+# define CINFO_N_TIMES(writer, n, dispatchAction, ...) el::base::NullWriter()
+#endif // ELPP_INFO_LOG
+#if ELPP_WARNING_LOG
+# define CWARNING_N_TIMES(writer, n, dispatchAction, ...)\
+ELPP_WRITE_LOG_N_TIMES(writer, n, el::Level::Warning, dispatchAction, __VA_ARGS__)
+#else
+# define CWARNING_N_TIMES(writer, n, dispatchAction, ...) el::base::NullWriter()
+#endif // ELPP_WARNING_LOG
+#if ELPP_DEBUG_LOG
+# define CDEBUG_N_TIMES(writer, n, dispatchAction, ...)\
+ELPP_WRITE_LOG_N_TIMES(writer, n, el::Level::Debug, dispatchAction, __VA_ARGS__)
+#else
+# define CDEBUG_N_TIMES(writer, n, dispatchAction, ...) el::base::NullWriter()
+#endif // ELPP_DEBUG_LOG
+#if ELPP_ERROR_LOG
+# define CERROR_N_TIMES(writer, n, dispatchAction, ...)\
+ELPP_WRITE_LOG_N_TIMES(writer, n, el::Level::Error, dispatchAction, __VA_ARGS__)
+#else
+# define CERROR_N_TIMES(writer, n, dispatchAction, ...) el::base::NullWriter()
+#endif // ELPP_ERROR_LOG
+#if ELPP_FATAL_LOG
+# define CFATAL_N_TIMES(writer, n, dispatchAction, ...)\
+ELPP_WRITE_LOG_N_TIMES(writer, n, el::Level::Fatal, dispatchAction, __VA_ARGS__)
+#else
+# define CFATAL_N_TIMES(writer, n, dispatchAction, ...) el::base::NullWriter()
+#endif // ELPP_FATAL_LOG
+#if ELPP_TRACE_LOG
+# define CTRACE_N_TIMES(writer, n, dispatchAction, ...)\
+ELPP_WRITE_LOG_N_TIMES(writer, n, el::Level::Trace, dispatchAction, __VA_ARGS__)
+#else
+# define CTRACE_N_TIMES(writer, n, dispatchAction, ...) el::base::NullWriter()
+#endif // ELPP_TRACE_LOG
+#if ELPP_VERBOSE_LOG
+# define CVERBOSE_N_TIMES(writer, n, vlevel, dispatchAction, ...)\
+CVERBOSE_IF(writer, ELPP->validateNTimesCounter(__FILE__, __LINE__, n), vlevel, dispatchAction, __VA_ARGS__)
+#else
+# define CVERBOSE_N_TIMES(writer, n, vlevel, dispatchAction, ...) el::base::NullWriter()
+#endif // ELPP_VERBOSE_LOG
+//
+// Custom Loggers - Requires (level, dispatchAction, loggerId/s)
+//
+// undef existing
+#undef CLOG
+#undef CLOG_VERBOSE
+#undef CVLOG
+#undef CLOG_IF
+#undef CLOG_VERBOSE_IF
+#undef CVLOG_IF
+#undef CLOG_EVERY_N
+#undef CVLOG_EVERY_N
+#undef CLOG_AFTER_N
+#undef CVLOG_AFTER_N
+#undef CLOG_N_TIMES
+#undef CVLOG_N_TIMES
+// Normal logs
+#define CLOG(LEVEL, ...)\
+C##LEVEL(el::base::Writer, el::base::DispatchAction::NormalLog, __VA_ARGS__)
+#define CVLOG(vlevel, ...) CVERBOSE(el::base::Writer, vlevel, el::base::DispatchAction::NormalLog, __VA_ARGS__)
+// Conditional logs
+#define CLOG_IF(condition, LEVEL, ...)\
+C##LEVEL##_IF(el::base::Writer, condition, el::base::DispatchAction::NormalLog, __VA_ARGS__)
+#define CVLOG_IF(condition, vlevel, ...)\
+CVERBOSE_IF(el::base::Writer, condition, vlevel, el::base::DispatchAction::NormalLog, __VA_ARGS__)
+// Hit counts based logs
+#define CLOG_EVERY_N(n, LEVEL, ...)\
+C##LEVEL##_EVERY_N(el::base::Writer, n, el::base::DispatchAction::NormalLog, __VA_ARGS__)
+#define CVLOG_EVERY_N(n, vlevel, ...)\
+CVERBOSE_EVERY_N(el::base::Writer, n, vlevel, el::base::DispatchAction::NormalLog, __VA_ARGS__)
+#define CLOG_AFTER_N(n, LEVEL, ...)\
+C##LEVEL##_AFTER_N(el::base::Writer, n, el::base::DispatchAction::NormalLog, __VA_ARGS__)
+#define CVLOG_AFTER_N(n, vlevel, ...)\
+CVERBOSE_AFTER_N(el::base::Writer, n, vlevel, el::base::DispatchAction::NormalLog, __VA_ARGS__)
+#define CLOG_N_TIMES(n, LEVEL, ...)\
+C##LEVEL##_N_TIMES(el::base::Writer, n, el::base::DispatchAction::NormalLog, __VA_ARGS__)
+#define CVLOG_N_TIMES(n, vlevel, ...)\
+CVERBOSE_N_TIMES(el::base::Writer, n, vlevel, el::base::DispatchAction::NormalLog, __VA_ARGS__)
+//
+// Default Loggers macro using CLOG(), CLOG_VERBOSE() and CVLOG() macros
+//
+// undef existing
+#undef LOG
+#undef VLOG
+#undef LOG_IF
+#undef VLOG_IF
+#undef LOG_EVERY_N
+#undef VLOG_EVERY_N
+#undef LOG_AFTER_N
+#undef VLOG_AFTER_N
+#undef LOG_N_TIMES
+#undef VLOG_N_TIMES
+#undef ELPP_CURR_FILE_LOGGER_ID
+#if defined(ELPP_DEFAULT_LOGGER)
+# define ELPP_CURR_FILE_LOGGER_ID ELPP_DEFAULT_LOGGER
+#else
+# define ELPP_CURR_FILE_LOGGER_ID el::base::consts::kDefaultLoggerId
+#endif
+#undef ELPP_TRACE
+#define ELPP_TRACE CLOG(TRACE, ELPP_CURR_FILE_LOGGER_ID)
+// Normal logs
+#define LOG(LEVEL) CLOG(LEVEL, ELPP_CURR_FILE_LOGGER_ID)
+#define VLOG(vlevel) CVLOG(vlevel, ELPP_CURR_FILE_LOGGER_ID)
+// Conditional logs
+#define LOG_IF(condition, LEVEL) CLOG_IF(condition, LEVEL, ELPP_CURR_FILE_LOGGER_ID)
+#define VLOG_IF(condition, vlevel) CVLOG_IF(condition, vlevel, ELPP_CURR_FILE_LOGGER_ID)
+// Hit counts based logs
+#define LOG_EVERY_N(n, LEVEL) CLOG_EVERY_N(n, LEVEL, ELPP_CURR_FILE_LOGGER_ID)
+#define VLOG_EVERY_N(n, vlevel) CVLOG_EVERY_N(n, vlevel, ELPP_CURR_FILE_LOGGER_ID)
+#define LOG_AFTER_N(n, LEVEL) CLOG_AFTER_N(n, LEVEL, ELPP_CURR_FILE_LOGGER_ID)
+#define VLOG_AFTER_N(n, vlevel) CVLOG_AFTER_N(n, vlevel, ELPP_CURR_FILE_LOGGER_ID)
+#define LOG_N_TIMES(n, LEVEL) CLOG_N_TIMES(n, LEVEL, ELPP_CURR_FILE_LOGGER_ID)
+#define VLOG_N_TIMES(n, vlevel) CVLOG_N_TIMES(n, vlevel, ELPP_CURR_FILE_LOGGER_ID)
+// Generic PLOG()
+#undef CPLOG
+#undef CPLOG_IF
+#undef PLOG
+#undef PLOG_IF
+#undef DCPLOG
+#undef DCPLOG_IF
+#undef DPLOG
+#undef DPLOG_IF
+#define CPLOG(LEVEL, ...)\
+C##LEVEL(el::base::PErrorWriter, el::base::DispatchAction::NormalLog, __VA_ARGS__)
+#define CPLOG_IF(condition, LEVEL, ...)\
+C##LEVEL##_IF(el::base::PErrorWriter, condition, el::base::DispatchAction::NormalLog, __VA_ARGS__)
+#define DCPLOG(LEVEL, ...)\
+if (ELPP_DEBUG_LOG) C##LEVEL(el::base::PErrorWriter, el::base::DispatchAction::NormalLog, __VA_ARGS__)
+#define DCPLOG_IF(condition, LEVEL, ...)\
+C##LEVEL##_IF(el::base::PErrorWriter, (ELPP_DEBUG_LOG) && (condition), el::base::DispatchAction::NormalLog, __VA_ARGS__)
+#define PLOG(LEVEL) CPLOG(LEVEL, ELPP_CURR_FILE_LOGGER_ID)
+#define PLOG_IF(condition, LEVEL) CPLOG_IF(condition, LEVEL, ELPP_CURR_FILE_LOGGER_ID)
+#define DPLOG(LEVEL) DCPLOG(LEVEL, ELPP_CURR_FILE_LOGGER_ID)
+#define DPLOG_IF(condition, LEVEL) DCPLOG_IF(condition, LEVEL, ELPP_CURR_FILE_LOGGER_ID)
+// Generic SYSLOG()
+#undef CSYSLOG
+#undef CSYSLOG_IF
+#undef CSYSLOG_EVERY_N
+#undef CSYSLOG_AFTER_N
+#undef CSYSLOG_N_TIMES
+#undef SYSLOG
+#undef SYSLOG_IF
+#undef SYSLOG_EVERY_N
+#undef SYSLOG_AFTER_N
+#undef SYSLOG_N_TIMES
+#undef DCSYSLOG
+#undef DCSYSLOG_IF
+#undef DCSYSLOG_EVERY_N
+#undef DCSYSLOG_AFTER_N
+#undef DCSYSLOG_N_TIMES
+#undef DSYSLOG
+#undef DSYSLOG_IF
+#undef DSYSLOG_EVERY_N
+#undef DSYSLOG_AFTER_N
+#undef DSYSLOG_N_TIMES
+#if defined(ELPP_SYSLOG)
+# define CSYSLOG(LEVEL, ...)\
+C##LEVEL(el::base::Writer, el::base::DispatchAction::SysLog, __VA_ARGS__)
+# define CSYSLOG_IF(condition, LEVEL, ...)\
+C##LEVEL##_IF(el::base::Writer, condition, el::base::DispatchAction::SysLog, __VA_ARGS__)
+# define CSYSLOG_EVERY_N(n, LEVEL, ...) C##LEVEL##_EVERY_N(el::base::Writer, n, el::base::DispatchAction::SysLog, __VA_ARGS__)
+# define CSYSLOG_AFTER_N(n, LEVEL, ...) C##LEVEL##_AFTER_N(el::base::Writer, n, el::base::DispatchAction::SysLog, __VA_ARGS__)
+# define CSYSLOG_N_TIMES(n, LEVEL, ...) C##LEVEL##_N_TIMES(el::base::Writer, n, el::base::DispatchAction::SysLog, __VA_ARGS__)
+# define SYSLOG(LEVEL) CSYSLOG(LEVEL, el::base::consts::kSysLogLoggerId)
+# define SYSLOG_IF(condition, LEVEL) CSYSLOG_IF(condition, LEVEL, el::base::consts::kSysLogLoggerId)
+# define SYSLOG_EVERY_N(n, LEVEL) CSYSLOG_EVERY_N(n, LEVEL, el::base::consts::kSysLogLoggerId)
+# define SYSLOG_AFTER_N(n, LEVEL) CSYSLOG_AFTER_N(n, LEVEL, el::base::consts::kSysLogLoggerId)
+# define SYSLOG_N_TIMES(n, LEVEL) CSYSLOG_N_TIMES(n, LEVEL, el::base::consts::kSysLogLoggerId)
+# define DCSYSLOG(LEVEL, ...) if (ELPP_DEBUG_LOG) C##LEVEL(el::base::Writer, el::base::DispatchAction::SysLog, __VA_ARGS__)
+# define DCSYSLOG_IF(condition, LEVEL, ...)\
+C##LEVEL##_IF(el::base::Writer, (ELPP_DEBUG_LOG) && (condition), el::base::DispatchAction::SysLog, __VA_ARGS__)
+# define DCSYSLOG_EVERY_N(n, LEVEL, ...)\
+if (ELPP_DEBUG_LOG) C##LEVEL##_EVERY_N(el::base::Writer, n, el::base::DispatchAction::SysLog, __VA_ARGS__)
+# define DCSYSLOG_AFTER_N(n, LEVEL, ...)\
+if (ELPP_DEBUG_LOG) C##LEVEL##_AFTER_N(el::base::Writer, n, el::base::DispatchAction::SysLog, __VA_ARGS__)
+# define DCSYSLOG_N_TIMES(n, LEVEL, ...)\
+if (ELPP_DEBUG_LOG) C##LEVEL##_EVERY_N(el::base::Writer, n, el::base::DispatchAction::SysLog, __VA_ARGS__)
+# define DSYSLOG(LEVEL) DCSYSLOG(LEVEL, el::base::consts::kSysLogLoggerId)
+# define DSYSLOG_IF(condition, LEVEL) DCSYSLOG_IF(condition, LEVEL, el::base::consts::kSysLogLoggerId)
+# define DSYSLOG_EVERY_N(n, LEVEL) DCSYSLOG_EVERY_N(n, LEVEL, el::base::consts::kSysLogLoggerId)
+# define DSYSLOG_AFTER_N(n, LEVEL) DCSYSLOG_AFTER_N(n, LEVEL, el::base::consts::kSysLogLoggerId)
+# define DSYSLOG_N_TIMES(n, LEVEL) DCSYSLOG_N_TIMES(n, LEVEL, el::base::consts::kSysLogLoggerId)
+#else
+# define CSYSLOG(LEVEL, ...) el::base::NullWriter()
+# define CSYSLOG_IF(condition, LEVEL, ...) el::base::NullWriter()
+# define CSYSLOG_EVERY_N(n, LEVEL, ...) el::base::NullWriter()
+# define CSYSLOG_AFTER_N(n, LEVEL, ...) el::base::NullWriter()
+# define CSYSLOG_N_TIMES(n, LEVEL, ...) el::base::NullWriter()
+# define SYSLOG(LEVEL) el::base::NullWriter()
+# define SYSLOG_IF(condition, LEVEL) el::base::NullWriter()
+# define SYSLOG_EVERY_N(n, LEVEL) el::base::NullWriter()
+# define SYSLOG_AFTER_N(n, LEVEL) el::base::NullWriter()
+# define SYSLOG_N_TIMES(n, LEVEL) el::base::NullWriter()
+# define DCSYSLOG(LEVEL, ...) el::base::NullWriter()
+# define DCSYSLOG_IF(condition, LEVEL, ...) el::base::NullWriter()
+# define DCSYSLOG_EVERY_N(n, LEVEL, ...) el::base::NullWriter()
+# define DCSYSLOG_AFTER_N(n, LEVEL, ...) el::base::NullWriter()
+# define DCSYSLOG_N_TIMES(n, LEVEL, ...) el::base::NullWriter()
+# define DSYSLOG(LEVEL) el::base::NullWriter()
+# define DSYSLOG_IF(condition, LEVEL) el::base::NullWriter()
+# define DSYSLOG_EVERY_N(n, LEVEL) el::base::NullWriter()
+# define DSYSLOG_AFTER_N(n, LEVEL) el::base::NullWriter()
+# define DSYSLOG_N_TIMES(n, LEVEL) el::base::NullWriter()
+#endif // defined(ELPP_SYSLOG)
+//
+// Custom Debug Only Loggers - Requires (level, loggerId/s)
+//
+// undef existing
+#undef DCLOG
+#undef DCVLOG
+#undef DCLOG_IF
+#undef DCVLOG_IF
+#undef DCLOG_EVERY_N
+#undef DCVLOG_EVERY_N
+#undef DCLOG_AFTER_N
+#undef DCVLOG_AFTER_N
+#undef DCLOG_N_TIMES
+#undef DCVLOG_N_TIMES
+// Normal logs
+#define DCLOG(LEVEL, ...) if (ELPP_DEBUG_LOG) CLOG(LEVEL, __VA_ARGS__)
+#define DCLOG_VERBOSE(vlevel, ...) if (ELPP_DEBUG_LOG) CLOG_VERBOSE(vlevel, __VA_ARGS__)
+#define DCVLOG(vlevel, ...) if (ELPP_DEBUG_LOG) CVLOG(vlevel, __VA_ARGS__)
+// Conditional logs
+#define DCLOG_IF(condition, LEVEL, ...) if (ELPP_DEBUG_LOG) CLOG_IF(condition, LEVEL, __VA_ARGS__)
+#define DCVLOG_IF(condition, vlevel, ...) if (ELPP_DEBUG_LOG) CVLOG_IF(condition, vlevel, __VA_ARGS__)
+// Hit counts based logs
+#define DCLOG_EVERY_N(n, LEVEL, ...) if (ELPP_DEBUG_LOG) CLOG_EVERY_N(n, LEVEL, __VA_ARGS__)
+#define DCVLOG_EVERY_N(n, vlevel, ...) if (ELPP_DEBUG_LOG) CVLOG_EVERY_N(n, vlevel, __VA_ARGS__)
+#define DCLOG_AFTER_N(n, LEVEL, ...) if (ELPP_DEBUG_LOG) CLOG_AFTER_N(n, LEVEL, __VA_ARGS__)
+#define DCVLOG_AFTER_N(n, vlevel, ...) if (ELPP_DEBUG_LOG) CVLOG_AFTER_N(n, vlevel, __VA_ARGS__)
+#define DCLOG_N_TIMES(n, LEVEL, ...) if (ELPP_DEBUG_LOG) CLOG_N_TIMES(n, LEVEL, __VA_ARGS__)
+#define DCVLOG_N_TIMES(n, vlevel, ...) if (ELPP_DEBUG_LOG) CVLOG_N_TIMES(n, vlevel, __VA_ARGS__)
+//
+// Default Debug Only Loggers macro using CLOG(), CLOG_VERBOSE() and CVLOG() macros
+//
+#if !defined(ELPP_NO_DEBUG_MACROS)
+// undef existing
+#undef DLOG
+#undef DVLOG
+#undef DLOG_IF
+#undef DVLOG_IF
+#undef DLOG_EVERY_N
+#undef DVLOG_EVERY_N
+#undef DLOG_AFTER_N
+#undef DVLOG_AFTER_N
+#undef DLOG_N_TIMES
+#undef DVLOG_N_TIMES
+// Normal logs
+#define DLOG(LEVEL) DCLOG(LEVEL, ELPP_CURR_FILE_LOGGER_ID)
+#define DVLOG(vlevel) DCVLOG(vlevel, ELPP_CURR_FILE_LOGGER_ID)
+// Conditional logs
+#define DLOG_IF(condition, LEVEL) DCLOG_IF(condition, LEVEL, ELPP_CURR_FILE_LOGGER_ID)
+#define DVLOG_IF(condition, vlevel) DCVLOG_IF(condition, vlevel, ELPP_CURR_FILE_LOGGER_ID)
+// Hit counts based logs
+#define DLOG_EVERY_N(n, LEVEL) DCLOG_EVERY_N(n, LEVEL, ELPP_CURR_FILE_LOGGER_ID)
+#define DVLOG_EVERY_N(n, vlevel) DCVLOG_EVERY_N(n, vlevel, ELPP_CURR_FILE_LOGGER_ID)
+#define DLOG_AFTER_N(n, LEVEL) DCLOG_AFTER_N(n, LEVEL, ELPP_CURR_FILE_LOGGER_ID)
+#define DVLOG_AFTER_N(n, vlevel) DCVLOG_AFTER_N(n, vlevel, ELPP_CURR_FILE_LOGGER_ID)
+#define DLOG_N_TIMES(n, LEVEL) DCLOG_N_TIMES(n, LEVEL, ELPP_CURR_FILE_LOGGER_ID)
+#define DVLOG_N_TIMES(n, vlevel) DCVLOG_N_TIMES(n, vlevel, ELPP_CURR_FILE_LOGGER_ID)
+#endif // defined(ELPP_NO_DEBUG_MACROS)
+#if !defined(ELPP_NO_CHECK_MACROS)
+// Check macros
+#undef CCHECK
+#undef CPCHECK
+#undef CCHECK_EQ
+#undef CCHECK_NE
+#undef CCHECK_LT
+#undef CCHECK_GT
+#undef CCHECK_LE
+#undef CCHECK_GE
+#undef CCHECK_BOUNDS
+#undef CCHECK_NOTNULL
+#undef CCHECK_STRCASEEQ
+#undef CCHECK_STRCASENE
+#undef CHECK
+#undef PCHECK
+#undef CHECK_EQ
+#undef CHECK_NE
+#undef CHECK_LT
+#undef CHECK_GT
+#undef CHECK_LE
+#undef CHECK_GE
+#undef CHECK_BOUNDS
+#undef CHECK_NOTNULL
+#undef CHECK_STRCASEEQ
+#undef CHECK_STRCASENE
+#define CCHECK(condition, ...) CLOG_IF(!(condition), FATAL, __VA_ARGS__) << "Check failed: [" << #condition << "] "
+#define CPCHECK(condition, ...) CPLOG_IF(!(condition), FATAL, __VA_ARGS__) << "Check failed: [" << #condition << "] "
+#define CHECK(condition) CCHECK(condition, ELPP_CURR_FILE_LOGGER_ID)
+#define PCHECK(condition) CPCHECK(condition, ELPP_CURR_FILE_LOGGER_ID)
+#define CCHECK_EQ(a, b, ...) CCHECK(a == b, __VA_ARGS__)
+#define CCHECK_NE(a, b, ...) CCHECK(a != b, __VA_ARGS__)
+#define CCHECK_LT(a, b, ...) CCHECK(a < b, __VA_ARGS__)
+#define CCHECK_GT(a, b, ...) CCHECK(a > b, __VA_ARGS__)
+#define CCHECK_LE(a, b, ...) CCHECK(a <= b, __VA_ARGS__)
+#define CCHECK_GE(a, b, ...) CCHECK(a >= b, __VA_ARGS__)
+#define CCHECK_BOUNDS(val, min, max, ...) CCHECK(val >= min && val <= max, __VA_ARGS__)
+#define CHECK_EQ(a, b) CCHECK_EQ(a, b, ELPP_CURR_FILE_LOGGER_ID)
+#define CHECK_NE(a, b) CCHECK_NE(a, b, ELPP_CURR_FILE_LOGGER_ID)
+#define CHECK_LT(a, b) CCHECK_LT(a, b, ELPP_CURR_FILE_LOGGER_ID)
+#define CHECK_GT(a, b) CCHECK_GT(a, b, ELPP_CURR_FILE_LOGGER_ID)
+#define CHECK_LE(a, b) CCHECK_LE(a, b, ELPP_CURR_FILE_LOGGER_ID)
+#define CHECK_GE(a, b) CCHECK_GE(a, b, ELPP_CURR_FILE_LOGGER_ID)
+#define CHECK_BOUNDS(val, min, max) CCHECK_BOUNDS(val, min, max, ELPP_CURR_FILE_LOGGER_ID)
+#define CCHECK_NOTNULL(ptr, ...) CCHECK((ptr) != nullptr, __VA_ARGS__)
+#define CCHECK_STREQ(str1, str2, ...) CLOG_IF(!el::base::utils::Str::cStringEq(str1, str2), FATAL, __VA_ARGS__) \
+<< "Check failed: [" << #str1 << " == " << #str2 << "] "
+#define CCHECK_STRNE(str1, str2, ...) CLOG_IF(el::base::utils::Str::cStringEq(str1, str2), FATAL, __VA_ARGS__) \
+<< "Check failed: [" << #str1 << " != " << #str2 << "] "
+#define CCHECK_STRCASEEQ(str1, str2, ...) CLOG_IF(!el::base::utils::Str::cStringCaseEq(str1, str2), FATAL, __VA_ARGS__) \
+<< "Check failed: [" << #str1 << " == " << #str2 << "] "
+#define CCHECK_STRCASENE(str1, str2, ...) CLOG_IF(el::base::utils::Str::cStringCaseEq(str1, str2), FATAL, __VA_ARGS__) \
+<< "Check failed: [" << #str1 << " != " << #str2 << "] "
+#define CHECK_NOTNULL(ptr) CCHECK_NOTNULL((ptr), ELPP_CURR_FILE_LOGGER_ID)
+#define CHECK_STREQ(str1, str2) CCHECK_STREQ(str1, str2, ELPP_CURR_FILE_LOGGER_ID)
+#define CHECK_STRNE(str1, str2) CCHECK_STRNE(str1, str2, ELPP_CURR_FILE_LOGGER_ID)
+#define CHECK_STRCASEEQ(str1, str2) CCHECK_STRCASEEQ(str1, str2, ELPP_CURR_FILE_LOGGER_ID)
+#define CHECK_STRCASENE(str1, str2) CCHECK_STRCASENE(str1, str2, ELPP_CURR_FILE_LOGGER_ID)
+#undef DCCHECK
+#undef DCCHECK_EQ
+#undef DCCHECK_NE
+#undef DCCHECK_LT
+#undef DCCHECK_GT
+#undef DCCHECK_LE
+#undef DCCHECK_GE
+#undef DCCHECK_BOUNDS
+#undef DCCHECK_NOTNULL
+#undef DCCHECK_STRCASEEQ
+#undef DCCHECK_STRCASENE
+#undef DCPCHECK
+#undef DCHECK
+#undef DCHECK_EQ
+#undef DCHECK_NE
+#undef DCHECK_LT
+#undef DCHECK_GT
+#undef DCHECK_LE
+#undef DCHECK_GE
+#undef DCHECK_BOUNDS_
+#undef DCHECK_NOTNULL
+#undef DCHECK_STRCASEEQ
+#undef DCHECK_STRCASENE
+#undef DPCHECK
+#define DCCHECK(condition, ...) if (ELPP_DEBUG_LOG) CCHECK(condition, __VA_ARGS__)
+#define DCCHECK_EQ(a, b, ...) if (ELPP_DEBUG_LOG) CCHECK_EQ(a, b, __VA_ARGS__)
+#define DCCHECK_NE(a, b, ...) if (ELPP_DEBUG_LOG) CCHECK_NE(a, b, __VA_ARGS__)
+#define DCCHECK_LT(a, b, ...) if (ELPP_DEBUG_LOG) CCHECK_LT(a, b, __VA_ARGS__)
+#define DCCHECK_GT(a, b, ...) if (ELPP_DEBUG_LOG) CCHECK_GT(a, b, __VA_ARGS__)
+#define DCCHECK_LE(a, b, ...) if (ELPP_DEBUG_LOG) CCHECK_LE(a, b, __VA_ARGS__)
+#define DCCHECK_GE(a, b, ...) if (ELPP_DEBUG_LOG) CCHECK_GE(a, b, __VA_ARGS__)
+#define DCCHECK_BOUNDS(val, min, max, ...) if (ELPP_DEBUG_LOG) CCHECK_BOUNDS(val, min, max, __VA_ARGS__)
+#define DCCHECK_NOTNULL(ptr, ...) if (ELPP_DEBUG_LOG) CCHECK_NOTNULL((ptr), __VA_ARGS__)
+#define DCCHECK_STREQ(str1, str2, ...) if (ELPP_DEBUG_LOG) CCHECK_STREQ(str1, str2, __VA_ARGS__)
+#define DCCHECK_STRNE(str1, str2, ...) if (ELPP_DEBUG_LOG) CCHECK_STRNE(str1, str2, __VA_ARGS__)
+#define DCCHECK_STRCASEEQ(str1, str2, ...) if (ELPP_DEBUG_LOG) CCHECK_STRCASEEQ(str1, str2, __VA_ARGS__)
+#define DCCHECK_STRCASENE(str1, str2, ...) if (ELPP_DEBUG_LOG) CCHECK_STRCASENE(str1, str2, __VA_ARGS__)
+#define DCPCHECK(condition, ...) if (ELPP_DEBUG_LOG) CPCHECK(condition, __VA_ARGS__)
+#define DCHECK(condition) DCCHECK(condition, ELPP_CURR_FILE_LOGGER_ID)
+#define DCHECK_EQ(a, b) DCCHECK_EQ(a, b, ELPP_CURR_FILE_LOGGER_ID)
+#define DCHECK_NE(a, b) DCCHECK_NE(a, b, ELPP_CURR_FILE_LOGGER_ID)
+#define DCHECK_LT(a, b) DCCHECK_LT(a, b, ELPP_CURR_FILE_LOGGER_ID)
+#define DCHECK_GT(a, b) DCCHECK_GT(a, b, ELPP_CURR_FILE_LOGGER_ID)
+#define DCHECK_LE(a, b) DCCHECK_LE(a, b, ELPP_CURR_FILE_LOGGER_ID)
+#define DCHECK_GE(a, b) DCCHECK_GE(a, b, ELPP_CURR_FILE_LOGGER_ID)
+#define DCHECK_BOUNDS(val, min, max) DCCHECK_BOUNDS(val, min, max, ELPP_CURR_FILE_LOGGER_ID)
+#define DCHECK_NOTNULL(ptr) DCCHECK_NOTNULL((ptr), ELPP_CURR_FILE_LOGGER_ID)
+#define DCHECK_STREQ(str1, str2) DCCHECK_STREQ(str1, str2, ELPP_CURR_FILE_LOGGER_ID)
+#define DCHECK_STRNE(str1, str2) DCCHECK_STRNE(str1, str2, ELPP_CURR_FILE_LOGGER_ID)
+#define DCHECK_STRCASEEQ(str1, str2) DCCHECK_STRCASEEQ(str1, str2, ELPP_CURR_FILE_LOGGER_ID)
+#define DCHECK_STRCASENE(str1, str2) DCCHECK_STRCASENE(str1, str2, ELPP_CURR_FILE_LOGGER_ID)
+#define DPCHECK(condition) DCPCHECK(condition, ELPP_CURR_FILE_LOGGER_ID)
+#endif // defined(ELPP_NO_CHECK_MACROS)
+#if defined(ELPP_DISABLE_DEFAULT_CRASH_HANDLING)
+# define ELPP_USE_DEF_CRASH_HANDLER false
+#else
+# define ELPP_USE_DEF_CRASH_HANDLER true
+#endif // defined(ELPP_DISABLE_DEFAULT_CRASH_HANDLING)
+#define ELPP_CRASH_HANDLER_INIT
+#define ELPP_INIT_EASYLOGGINGPP(val) \
+namespace el { \
+namespace base { \
+el::base::type::StoragePointer elStorage(val); \
+} \
+el::base::debug::CrashHandler elCrashHandler(ELPP_USE_DEF_CRASH_HANDLER); \
+}
+
+#if ELPP_ASYNC_LOGGING
+# define INITIALIZE_EASYLOGGINGPP ELPP_INIT_EASYLOGGINGPP(new el::base::Storage(el::LogBuilderPtr(new el::base::DefaultLogBuilder()),\
+new el::base::AsyncDispatchWorker()))
+#else
+# define INITIALIZE_EASYLOGGINGPP ELPP_INIT_EASYLOGGINGPP(new el::base::Storage(el::LogBuilderPtr(new el::base::DefaultLogBuilder())))
+#endif // ELPP_ASYNC_LOGGING
+#define INITIALIZE_NULL_EASYLOGGINGPP \
+namespace el {\
+namespace base {\
+el::base::type::StoragePointer elStorage;\
+}\
+el::base::debug::CrashHandler elCrashHandler(ELPP_USE_DEF_CRASH_HANDLER);\
+}
+#define SHARE_EASYLOGGINGPP(initializedStorage)\
+namespace el {\
+namespace base {\
+el::base::type::StoragePointer elStorage(initializedStorage);\
+}\
+el::base::debug::CrashHandler elCrashHandler(ELPP_USE_DEF_CRASH_HANDLER);\
+}
+
+#if defined(ELPP_UNICODE)
+# define START_EASYLOGGINGPP(argc, argv) el::Helpers::setArgs(argc, argv); std::locale::global(std::locale(""))
+#else
+# define START_EASYLOGGINGPP(argc, argv) el::Helpers::setArgs(argc, argv)
+#endif // defined(ELPP_UNICODE)
+#endif // EASYLOGGINGPP_H
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_