diff options
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 @@ -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 ¤tVersion, 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(¬_, 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 Binary files differnew file mode 100644 index 00000000..5c24791f --- /dev/null +++ b/resource/gpgfrontend/usr/share/icons/hicolor/128x128/apps/GpgFrontend.png 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 Binary files differdeleted file mode 100755 index 7366dc97..00000000 --- a/resource/gpgfrontend/usr/share/icons/hicolor/200x200/apps/gpgfrontend-appimage-icon.png +++ /dev/null diff --git a/resource/gpgfrontend/usr/share/icons/hicolor/256x256/apps/GpgFrontend.png b/resource/gpgfrontend/usr/share/icons/hicolor/256x256/apps/GpgFrontend.png Binary files differnew file mode 100644 index 00000000..b3268b01 --- /dev/null +++ b/resource/gpgfrontend/usr/share/icons/hicolor/256x256/apps/GpgFrontend.png 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'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 & 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 & 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 & Sign File</source> - <translation type="unfinished"></translation> - </message> - <message> - <location filename="../../src/ui/Wizard.cpp" line="152"/> - <source>Sign & 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.<br><br></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.<br></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'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'n'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><b>NOTE: </b> 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><none></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><b>NOTE: </b> 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><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>.</source> - <translation type="unfinished"></translation> - </message> - <message> - <location filename="../../src/ui/help/AboutDialog.cpp" line="84"/> - <source><br><br> 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><br>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.<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):</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'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'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>&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>&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>&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>&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>&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 &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 &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>&Key</source> - <translation type="unfinished"></translation> - </message> - <message> - <location filename="../../src/ui/KeyMgmt.cpp" line="156"/> - <source>&Generate Key</source> - <translation type="unfinished"></translation> - </message> - <message> - <location filename="../../src/ui/KeyMgmt.cpp" line="160"/> - <source>&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'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'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'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>&Close</source> - <translation type="unfinished"></translation> - </message> - <message> - <location filename="../../src/ui/KeyServerImportDialog.cpp" line="41"/> - <source>&Import ALL</source> - <translation type="unfinished"></translation> - </message> - <message> - <location filename="../../src/ui/KeyServerImportDialog.cpp" line="42"/> - <source>&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><h4>%1 keys found. Double click a key to import it.</h4></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><h4>Key Updated</h4></source> - <translation type="unfinished"></translation> - </message> - <message> - <location filename="../../src/ui/KeyServerImportDialog.cpp" line="412"/> - <source><h4>Key Imported</h4></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'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.<br/></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><br/>For example the Following Key: <br/></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.<br/></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 & 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.<br/></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 & 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.<br/></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.<br/></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. <br/></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>&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>&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>&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>&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 &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>&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>&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>&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>&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>&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>&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&t</source> - <translation type="unfinished"></translation> - </message> - <message> - <location filename="../../src/ui/main_window/MainWindowUI.cpp" line="108"/> - <source>Cut the current selection's contents to the clipboard</source> - <translation type="unfinished"></translation> - </message> - <message> - <location filename="../../src/ui/main_window/MainWindowUI.cpp" line="112"/> - <source>&Copy</source> - <translation type="unfinished"></translation> - </message> - <message> - <location filename="../../src/ui/main_window/MainWindowUI.cpp" line="115"/> - <source>Copy the current selection's contents to the clipboard</source> - <translation type="unfinished"></translation> - </message> - <message> - <location filename="../../src/ui/main_window/MainWindowUI.cpp" line="119"/> - <source>&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 &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>&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 &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&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>&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>&Encrypt &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>&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>&Decrypt &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>&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>&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>&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>&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>&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>&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>&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 &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>&About</source> - <translation type="unfinished"></translation> - </message> - <message> - <location filename="../../src/ui/main_window/MainWindowUI.cpp" line="222"/> - <source>Show the application's About box</source> - <translation type="unfinished"></translation> - </message> - <message> - <location filename="../../src/ui/main_window/MainWindowUI.cpp" line="228"/> - <source>&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 &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>&File</source> - <translation type="unfinished"></translation> - </message> - <message> - <location filename="../../src/ui/main_window/MainWindowUI.cpp" line="293"/> - <source>&Edit</source> - <translation type="unfinished"></translation> - </message> - <message> - <location filename="../../src/ui/main_window/MainWindowUI.cpp" line="311"/> - <source>&File...</source> - <translation type="unfinished"></translation> - </message> - <message> - <location filename="../../src/ui/main_window/MainWindowUI.cpp" line="317"/> - <source>&Crypt</source> - <translation type="unfinished"></translation> - </message> - <message> - <location filename="../../src/ui/main_window/MainWindowUI.cpp" line="328"/> - <source>&Keys</source> - <translation type="unfinished"></translation> - </message> - <message> - <location filename="../../src/ui/main_window/MainWindowUI.cpp" line="329"/> - <source>&Import Key</source> - <translation type="unfinished"></translation> - </message> - <message> - <location filename="../../src/ui/main_window/MainWindowUI.cpp" line="338"/> - <source>&Steganography</source> - <translation type="unfinished"></translation> - </message> - <message> - <location filename="../../src/ui/main_window/MainWindowUI.cpp" line="347"/> - <source>&View</source> - <translation type="unfinished"></translation> - </message> - <message> - <location filename="../../src/ui/main_window/MainWindowUI.cpp" line="349"/> - <source>&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> {>} 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's </source> - <translation type="unfinished"></translation> - </message> - <message> - <location filename="../../src/gpg/result_analyse/VerifyResultAnalyse.cpp" line="82"/> - <source>Revoked Key's </source> - <translation type="unfinished"></translation> - </message> - <message> - <location filename="../../src/gpg/result_analyse/VerifyResultAnalyse.cpp" line="85"/> - <source>Expired Key's </source> - <translation type="unfinished"></translation> - </message> - <message> - <location filename="../../src/gpg/result_analyse/VerifyResultAnalyse.cpp" line="88"/> - <source>Missing CRL'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.<br/>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><b>Note:</b> If you don't save these files, all changes are lost.<br/></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'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'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>[>] 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><unknown></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 & 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>[>] 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 "%1" has been modified. Do you want to save your changes?<br/></source> - <translation type="unfinished"></translation> - </message> - <message> - <location filename="../../src/ui/widgets/TextEdit.cpp" line="337"/> - <source><b>Note:</b> If you don't save these files, all changes are lost.<br/></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 <a href="https://github.com/saturneric/GpgFrontend/releases">here</a> 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 <br/> It Contains:<br/><br/></source> - <translation type="unfinished"></translation> - </message> - <message> - <location filename="../../src/ui/VerifyDetailsDialog.cpp" line="72"/> - <source>Signed on %1 <br/> It Contains:<br /><br/></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'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><unknown></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 & 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'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 & 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 & 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 & Sign File</source> - <translation type="unfinished"></translation> - </message> - <message> - <location filename="../../src/ui/Wizard.cpp" line="152"/> - <source>Sign & 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.<br><br></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.<br></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'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'n'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><b>NOTE: </b> 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><none></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><b>NOTE: </b> 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><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>.</source> - <translation type="unfinished"></translation> - </message> - <message> - <location filename="../../src/ui/help/AboutDialog.cpp" line="84"/> - <source><br><br> 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><br>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.<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):</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'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'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>&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>&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>&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>&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>&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 &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 &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>&Key</source> - <translation type="unfinished"></translation> - </message> - <message> - <location filename="../../src/ui/KeyMgmt.cpp" line="156"/> - <source>&Generate Key</source> - <translation type="unfinished"></translation> - </message> - <message> - <location filename="../../src/ui/KeyMgmt.cpp" line="160"/> - <source>&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'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'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'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>&Close</source> - <translation type="unfinished"></translation> - </message> - <message> - <location filename="../../src/ui/KeyServerImportDialog.cpp" line="41"/> - <source>&Import ALL</source> - <translation type="unfinished"></translation> - </message> - <message> - <location filename="../../src/ui/KeyServerImportDialog.cpp" line="42"/> - <source>&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><h4>%1 keys found. Double click a key to import it.</h4></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><h4>Key Updated</h4></source> - <translation type="unfinished"></translation> - </message> - <message> - <location filename="../../src/ui/KeyServerImportDialog.cpp" line="412"/> - <source><h4>Key Imported</h4></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'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.<br/></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><br/>For example the Following Key: <br/></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.<br/></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 & 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.<br/></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 & 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.<br/></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.<br/></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. <br/></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>&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>&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>&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>&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 &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>&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>&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>&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>&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>&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>&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&t</source> - <translation type="unfinished"></translation> - </message> - <message> - <location filename="../../src/ui/main_window/MainWindowUI.cpp" line="108"/> - <source>Cut the current selection's contents to the clipboard</source> - <translation type="unfinished"></translation> - </message> - <message> - <location filename="../../src/ui/main_window/MainWindowUI.cpp" line="112"/> - <source>&Copy</source> - <translation type="unfinished"></translation> - </message> - <message> - <location filename="../../src/ui/main_window/MainWindowUI.cpp" line="115"/> - <source>Copy the current selection's contents to the clipboard</source> - <translation type="unfinished"></translation> - </message> - <message> - <location filename="../../src/ui/main_window/MainWindowUI.cpp" line="119"/> - <source>&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 &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>&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 &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&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>&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>&Encrypt &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>&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>&Decrypt &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>&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>&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>&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>&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>&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>&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>&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 &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>&About</source> - <translation type="unfinished"></translation> - </message> - <message> - <location filename="../../src/ui/main_window/MainWindowUI.cpp" line="222"/> - <source>Show the application's About box</source> - <translation type="unfinished"></translation> - </message> - <message> - <location filename="../../src/ui/main_window/MainWindowUI.cpp" line="228"/> - <source>&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 &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>&File</source> - <translation type="unfinished"></translation> - </message> - <message> - <location filename="../../src/ui/main_window/MainWindowUI.cpp" line="293"/> - <source>&Edit</source> - <translation type="unfinished"></translation> - </message> - <message> - <location filename="../../src/ui/main_window/MainWindowUI.cpp" line="311"/> - <source>&File...</source> - <translation type="unfinished"></translation> - </message> - <message> - <location filename="../../src/ui/main_window/MainWindowUI.cpp" line="317"/> - <source>&Crypt</source> - <translation type="unfinished"></translation> - </message> - <message> - <location filename="../../src/ui/main_window/MainWindowUI.cpp" line="328"/> - <source>&Keys</source> - <translation type="unfinished"></translation> - </message> - <message> - <location filename="../../src/ui/main_window/MainWindowUI.cpp" line="329"/> - <source>&Import Key</source> - <translation type="unfinished"></translation> - </message> - <message> - <location filename="../../src/ui/main_window/MainWindowUI.cpp" line="338"/> - <source>&Steganography</source> - <translation type="unfinished"></translation> - </message> - <message> - <location filename="../../src/ui/main_window/MainWindowUI.cpp" line="347"/> - <source>&View</source> - <translation type="unfinished"></translation> - </message> - <message> - <location filename="../../src/ui/main_window/MainWindowUI.cpp" line="349"/> - <source>&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> {>} 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's </source> - <translation type="unfinished"></translation> - </message> - <message> - <location filename="../../src/gpg/result_analyse/VerifyResultAnalyse.cpp" line="82"/> - <source>Revoked Key's </source> - <translation type="unfinished"></translation> - </message> - <message> - <location filename="../../src/gpg/result_analyse/VerifyResultAnalyse.cpp" line="85"/> - <source>Expired Key's </source> - <translation type="unfinished"></translation> - </message> - <message> - <location filename="../../src/gpg/result_analyse/VerifyResultAnalyse.cpp" line="88"/> - <source>Missing CRL'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.<br/>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><b>Note:</b> If you don't save these files, all changes are lost.<br/></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'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'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>[>] 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><unknown></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 & 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>[>] 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 "%1" has been modified. Do you want to save your changes?<br/></source> - <translation type="unfinished"></translation> - </message> - <message> - <location filename="../../src/ui/widgets/TextEdit.cpp" line="337"/> - <source><b>Note:</b> If you don't save these files, all changes are lost.<br/></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 <a href="https://github.com/saturneric/GpgFrontend/releases">here</a> 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 <br/> It Contains:<br/><br/></source> - <translation type="unfinished"></translation> - </message> - <message> - <location filename="../../src/ui/VerifyDetailsDialog.cpp" line="72"/> - <source>Signed on %1 <br/> It Contains:<br /><br/></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'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><unknown></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 & 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'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 & 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 & 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 & Sign File</source> - <translation type="unfinished"></translation> - </message> - <message> - <location filename="../../src/ui/Wizard.cpp" line="152"/> - <source>Sign & 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.<br><br></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.<br></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'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'n'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><b>NOTE: </b> 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><none></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><b>NOTE: </b> 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><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>.</source> - <translation type="unfinished"></translation> - </message> - <message> - <location filename="../../src/ui/help/AboutDialog.cpp" line="84"/> - <source><br><br> 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><br>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.<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):</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'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'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>&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>&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>&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>&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>&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 &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 &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>&Key</source> - <translation type="unfinished"></translation> - </message> - <message> - <location filename="../../src/ui/KeyMgmt.cpp" line="156"/> - <source>&Generate Key</source> - <translation type="unfinished"></translation> - </message> - <message> - <location filename="../../src/ui/KeyMgmt.cpp" line="160"/> - <source>&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'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'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'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>&Close</source> - <translation type="unfinished"></translation> - </message> - <message> - <location filename="../../src/ui/KeyServerImportDialog.cpp" line="41"/> - <source>&Import ALL</source> - <translation type="unfinished"></translation> - </message> - <message> - <location filename="../../src/ui/KeyServerImportDialog.cpp" line="42"/> - <source>&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><h4>%1 keys found. Double click a key to import it.</h4></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><h4>Key Updated</h4></source> - <translation type="unfinished"></translation> - </message> - <message> - <location filename="../../src/ui/KeyServerImportDialog.cpp" line="412"/> - <source><h4>Key Imported</h4></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'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.<br/></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><br/>For example the Following Key: <br/></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.<br/></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 & 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.<br/></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 & 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.<br/></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.<br/></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. <br/></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>&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>&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>&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>&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 &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>&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>&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>&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>&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>&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>&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&t</source> - <translation type="unfinished"></translation> - </message> - <message> - <location filename="../../src/ui/main_window/MainWindowUI.cpp" line="108"/> - <source>Cut the current selection's contents to the clipboard</source> - <translation type="unfinished"></translation> - </message> - <message> - <location filename="../../src/ui/main_window/MainWindowUI.cpp" line="112"/> - <source>&Copy</source> - <translation type="unfinished"></translation> - </message> - <message> - <location filename="../../src/ui/main_window/MainWindowUI.cpp" line="115"/> - <source>Copy the current selection's contents to the clipboard</source> - <translation type="unfinished"></translation> - </message> - <message> - <location filename="../../src/ui/main_window/MainWindowUI.cpp" line="119"/> - <source>&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 &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>&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 &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&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>&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>&Encrypt &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>&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>&Decrypt &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>&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>&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>&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>&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>&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>&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>&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 &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>&About</source> - <translation type="unfinished"></translation> - </message> - <message> - <location filename="../../src/ui/main_window/MainWindowUI.cpp" line="222"/> - <source>Show the application's About box</source> - <translation type="unfinished"></translation> - </message> - <message> - <location filename="../../src/ui/main_window/MainWindowUI.cpp" line="228"/> - <source>&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 &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>&File</source> - <translation type="unfinished"></translation> - </message> - <message> - <location filename="../../src/ui/main_window/MainWindowUI.cpp" line="293"/> - <source>&Edit</source> - <translation type="unfinished"></translation> - </message> - <message> - <location filename="../../src/ui/main_window/MainWindowUI.cpp" line="311"/> - <source>&File...</source> - <translation type="unfinished"></translation> - </message> - <message> - <location filename="../../src/ui/main_window/MainWindowUI.cpp" line="317"/> - <source>&Crypt</source> - <translation type="unfinished"></translation> - </message> - <message> - <location filename="../../src/ui/main_window/MainWindowUI.cpp" line="328"/> - <source>&Keys</source> - <translation type="unfinished"></translation> - </message> - <message> - <location filename="../../src/ui/main_window/MainWindowUI.cpp" line="329"/> - <source>&Import Key</source> - <translation type="unfinished"></translation> - </message> - <message> - <location filename="../../src/ui/main_window/MainWindowUI.cpp" line="338"/> - <source>&Steganography</source> - <translation type="unfinished"></translation> - </message> - <message> - <location filename="../../src/ui/main_window/MainWindowUI.cpp" line="347"/> - <source>&View</source> - <translation type="unfinished"></translation> - </message> - <message> - <location filename="../../src/ui/main_window/MainWindowUI.cpp" line="349"/> - <source>&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> {>} 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's </source> - <translation type="unfinished"></translation> - </message> - <message> - <location filename="../../src/gpg/result_analyse/VerifyResultAnalyse.cpp" line="82"/> - <source>Revoked Key's </source> - <translation type="unfinished"></translation> - </message> - <message> - <location filename="../../src/gpg/result_analyse/VerifyResultAnalyse.cpp" line="85"/> - <source>Expired Key's </source> - <translation type="unfinished"></translation> - </message> - <message> - <location filename="../../src/gpg/result_analyse/VerifyResultAnalyse.cpp" line="88"/> - <source>Missing CRL'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.<br/>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><b>Note:</b> If you don't save these files, all changes are lost.<br/></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'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'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>[>] 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><unknown></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 & 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>[>] 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 "%1" has been modified. Do you want to save your changes?<br/></source> - <translation type="unfinished"></translation> - </message> - <message> - <location filename="../../src/ui/widgets/TextEdit.cpp" line="337"/> - <source><b>Note:</b> If you don't save these files, all changes are lost.<br/></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 <a href="https://github.com/saturneric/GpgFrontend/releases">here</a> 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 <br/> It Contains:<br/><br/></source> - <translation type="unfinished"></translation> - </message> - <message> - <location filename="../../src/ui/VerifyDetailsDialog.cpp" line="72"/> - <source>Signed on %1 <br/> It Contains:<br /><br/></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'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><unknown></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 & 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'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 & 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 & 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 & Sign File</source> - <translation type="unfinished"></translation> - </message> - <message> - <location filename="../../src/ui/Wizard.cpp" line="152"/> - <source>Sign & 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.<br><br></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.<br></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'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'n'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><b>NOTE: </b> 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><none></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><b>NOTE: </b> 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><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>.</source> - <translation type="unfinished"></translation> - </message> - <message> - <location filename="../../src/ui/help/AboutDialog.cpp" line="84"/> - <source><br><br> 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><br>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.<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):</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'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'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>&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>&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>&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>&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>&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 &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 &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>&Key</source> - <translation type="unfinished"></translation> - </message> - <message> - <location filename="../../src/ui/KeyMgmt.cpp" line="156"/> - <source>&Generate Key</source> - <translation type="unfinished"></translation> - </message> - <message> - <location filename="../../src/ui/KeyMgmt.cpp" line="160"/> - <source>&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'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'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'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>&Close</source> - <translation type="unfinished"></translation> - </message> - <message> - <location filename="../../src/ui/KeyServerImportDialog.cpp" line="41"/> - <source>&Import ALL</source> - <translation type="unfinished"></translation> - </message> - <message> - <location filename="../../src/ui/KeyServerImportDialog.cpp" line="42"/> - <source>&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><h4>%1 keys found. Double click a key to import it.</h4></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><h4>Key Updated</h4></source> - <translation type="unfinished"></translation> - </message> - <message> - <location filename="../../src/ui/KeyServerImportDialog.cpp" line="412"/> - <source><h4>Key Imported</h4></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'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.<br/></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><br/>For example the Following Key: <br/></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.<br/></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 & 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.<br/></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 & 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.<br/></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.<br/></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. <br/></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>&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>&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>&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>&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 &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>&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>&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>&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>&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>&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>&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&t</source> - <translation type="unfinished"></translation> - </message> - <message> - <location filename="../../src/ui/main_window/MainWindowUI.cpp" line="108"/> - <source>Cut the current selection's contents to the clipboard</source> - <translation type="unfinished"></translation> - </message> - <message> - <location filename="../../src/ui/main_window/MainWindowUI.cpp" line="112"/> - <source>&Copy</source> - <translation type="unfinished"></translation> - </message> - <message> - <location filename="../../src/ui/main_window/MainWindowUI.cpp" line="115"/> - <source>Copy the current selection's contents to the clipboard</source> - <translation type="unfinished"></translation> - </message> - <message> - <location filename="../../src/ui/main_window/MainWindowUI.cpp" line="119"/> - <source>&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 &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>&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 &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&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>&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>&Encrypt &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>&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>&Decrypt &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>&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>&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>&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>&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>&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>&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>&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 &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>&About</source> - <translation type="unfinished"></translation> - </message> - <message> - <location filename="../../src/ui/main_window/MainWindowUI.cpp" line="222"/> - <source>Show the application's About box</source> - <translation type="unfinished"></translation> - </message> - <message> - <location filename="../../src/ui/main_window/MainWindowUI.cpp" line="228"/> - <source>&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 &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>&File</source> - <translation type="unfinished"></translation> - </message> - <message> - <location filename="../../src/ui/main_window/MainWindowUI.cpp" line="293"/> - <source>&Edit</source> - <translation type="unfinished"></translation> - </message> - <message> - <location filename="../../src/ui/main_window/MainWindowUI.cpp" line="311"/> - <source>&File...</source> - <translation type="unfinished"></translation> - </message> - <message> - <location filename="../../src/ui/main_window/MainWindowUI.cpp" line="317"/> - <source>&Crypt</source> - <translation type="unfinished"></translation> - </message> - <message> - <location filename="../../src/ui/main_window/MainWindowUI.cpp" line="328"/> - <source>&Keys</source> - <translation type="unfinished"></translation> - </message> - <message> - <location filename="../../src/ui/main_window/MainWindowUI.cpp" line="329"/> - <source>&Import Key</source> - <translation type="unfinished"></translation> - </message> - <message> - <location filename="../../src/ui/main_window/MainWindowUI.cpp" line="338"/> - <source>&Steganography</source> - <translation type="unfinished"></translation> - </message> - <message> - <location filename="../../src/ui/main_window/MainWindowUI.cpp" line="347"/> - <source>&View</source> - <translation type="unfinished"></translation> - </message> - <message> - <location filename="../../src/ui/main_window/MainWindowUI.cpp" line="349"/> - <source>&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> {>} 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's </source> - <translation type="unfinished"></translation> - </message> - <message> - <location filename="../../src/gpg/result_analyse/VerifyResultAnalyse.cpp" line="82"/> - <source>Revoked Key's </source> - <translation type="unfinished"></translation> - </message> - <message> - <location filename="../../src/gpg/result_analyse/VerifyResultAnalyse.cpp" line="85"/> - <source>Expired Key's </source> - <translation type="unfinished"></translation> - </message> - <message> - <location filename="../../src/gpg/result_analyse/VerifyResultAnalyse.cpp" line="88"/> - <source>Missing CRL'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.<br/>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><b>Note:</b> If you don't save these files, all changes are lost.<br/></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'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'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>[>] 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><unknown></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 & 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>[>] 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 "%1" has been modified. Do you want to save your changes?<br/></source> - <translation type="unfinished"></translation> - </message> - <message> - <location filename="../../src/ui/widgets/TextEdit.cpp" line="337"/> - <source><b>Note:</b> If you don't save these files, all changes are lost.<br/></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 <a href="https://github.com/saturneric/GpgFrontend/releases">here</a> 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 <br/> It Contains:<br/><br/></source> - <translation type="unfinished"></translation> - </message> - <message> - <location filename="../../src/ui/VerifyDetailsDialog.cpp" line="72"/> - <source>Signed on %1 <br/> It Contains:<br /><br/></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'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><unknown></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 & 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'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 & 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 & 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 & Sign File</source> - <translation type="unfinished"></translation> - </message> - <message> - <location filename="../../src/ui/Wizard.cpp" line="152"/> - <source>Sign & 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.<br><br></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.<br></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'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'n'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><b>NOTE: </b> 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><none></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><b>NOTE: </b> 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><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>.</source> - <translation type="unfinished"></translation> - </message> - <message> - <location filename="../../src/ui/help/AboutDialog.cpp" line="84"/> - <source><br><br> 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><br>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.<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):</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'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'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>&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>&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>&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>&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>&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 &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 &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>&Key</source> - <translation type="unfinished"></translation> - </message> - <message> - <location filename="../../src/ui/KeyMgmt.cpp" line="156"/> - <source>&Generate Key</source> - <translation type="unfinished"></translation> - </message> - <message> - <location filename="../../src/ui/KeyMgmt.cpp" line="160"/> - <source>&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'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'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'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>&Close</source> - <translation type="unfinished"></translation> - </message> - <message> - <location filename="../../src/ui/KeyServerImportDialog.cpp" line="41"/> - <source>&Import ALL</source> - <translation type="unfinished"></translation> - </message> - <message> - <location filename="../../src/ui/KeyServerImportDialog.cpp" line="42"/> - <source>&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><h4>%1 keys found. Double click a key to import it.</h4></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><h4>Key Updated</h4></source> - <translation type="unfinished"></translation> - </message> - <message> - <location filename="../../src/ui/KeyServerImportDialog.cpp" line="412"/> - <source><h4>Key Imported</h4></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'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.<br/></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><br/>For example the Following Key: <br/></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.<br/></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 & 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.<br/></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 & 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.<br/></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.<br/></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. <br/></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>&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>&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>&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>&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 &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>&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>&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>&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>&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>&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>&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&t</source> - <translation type="unfinished"></translation> - </message> - <message> - <location filename="../../src/ui/main_window/MainWindowUI.cpp" line="108"/> - <source>Cut the current selection's contents to the clipboard</source> - <translation type="unfinished"></translation> - </message> - <message> - <location filename="../../src/ui/main_window/MainWindowUI.cpp" line="112"/> - <source>&Copy</source> - <translation type="unfinished"></translation> - </message> - <message> - <location filename="../../src/ui/main_window/MainWindowUI.cpp" line="115"/> - <source>Copy the current selection's contents to the clipboard</source> - <translation type="unfinished"></translation> - </message> - <message> - <location filename="../../src/ui/main_window/MainWindowUI.cpp" line="119"/> - <source>&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 &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>&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 &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&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>&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>&Encrypt &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>&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>&Decrypt &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>&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>&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>&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>&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>&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>&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>&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 &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>&About</source> - <translation type="unfinished"></translation> - </message> - <message> - <location filename="../../src/ui/main_window/MainWindowUI.cpp" line="222"/> - <source>Show the application's About box</source> - <translation type="unfinished"></translation> - </message> - <message> - <location filename="../../src/ui/main_window/MainWindowUI.cpp" line="228"/> - <source>&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 &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>&File</source> - <translation type="unfinished"></translation> - </message> - <message> - <location filename="../../src/ui/main_window/MainWindowUI.cpp" line="293"/> - <source>&Edit</source> - <translation type="unfinished"></translation> - </message> - <message> - <location filename="../../src/ui/main_window/MainWindowUI.cpp" line="311"/> - <source>&File...</source> - <translation type="unfinished"></translation> - </message> - <message> - <location filename="../../src/ui/main_window/MainWindowUI.cpp" line="317"/> - <source>&Crypt</source> - <translation type="unfinished"></translation> - </message> - <message> - <location filename="../../src/ui/main_window/MainWindowUI.cpp" line="328"/> - <source>&Keys</source> - <translation type="unfinished"></translation> - </message> - <message> - <location filename="../../src/ui/main_window/MainWindowUI.cpp" line="329"/> - <source>&Import Key</source> - <translation type="unfinished"></translation> - </message> - <message> - <location filename="../../src/ui/main_window/MainWindowUI.cpp" line="338"/> - <source>&Steganography</source> - <translation type="unfinished"></translation> - </message> - <message> - <location filename="../../src/ui/main_window/MainWindowUI.cpp" line="347"/> - <source>&View</source> - <translation type="unfinished"></translation> - </message> - <message> - <location filename="../../src/ui/main_window/MainWindowUI.cpp" line="349"/> - <source>&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> {>} 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's </source> - <translation type="unfinished"></translation> - </message> - <message> - <location filename="../../src/gpg/result_analyse/VerifyResultAnalyse.cpp" line="82"/> - <source>Revoked Key's </source> - <translation type="unfinished"></translation> - </message> - <message> - <location filename="../../src/gpg/result_analyse/VerifyResultAnalyse.cpp" line="85"/> - <source>Expired Key's </source> - <translation type="unfinished"></translation> - </message> - <message> - <location filename="../../src/gpg/result_analyse/VerifyResultAnalyse.cpp" line="88"/> - <source>Missing CRL'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.<br/>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><b>Note:</b> If you don't save these files, all changes are lost.<br/></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'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'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>[>] 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><unknown></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 & 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>[>] 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 "%1" has been modified. Do you want to save your changes?<br/></source> - <translation type="unfinished"></translation> - </message> - <message> - <location filename="../../src/ui/widgets/TextEdit.cpp" line="337"/> - <source><b>Note:</b> If you don't save these files, all changes are lost.<br/></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 <a href="https://github.com/saturneric/GpgFrontend/releases">here</a> 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 <br/> It Contains:<br/><br/></source> - <translation type="unfinished"></translation> - </message> - <message> - <location filename="../../src/ui/VerifyDetailsDialog.cpp" line="72"/> - <source>Signed on %1 <br/> It Contains:<br /><br/></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'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><unknown></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 & 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> <"); - keynames.append(key.email); - keynames.append("> </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> <"); + keynames.append(QString::fromStdString(key.email())); + keynames.append("> </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 ¤tVersion, 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> <"); - keynames.append(uid.email); - keynames.append("> </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> <"); - keynames.append(selected_uid.email); - keynames.append("> </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> <"); - keynames.append(selected_uid.email); - keynames.append("> </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> <"); - keynames.append(selected_sign.email); - keynames.append("> </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 ¤tVersion, 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 ¤t) -> 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(¬_, 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_ |