pax_global_header00006660000000000000000000000064144462745240014526gustar00rootroot0000000000000052 comment=e265f6370dd750b4f23ffbfcbb477514f7c2a517 sexpp-0.8.7/000077500000000000000000000000001444627452400127015ustar00rootroot00000000000000sexpp-0.8.7/.clang-format000066400000000000000000000035361444627452400152630ustar00rootroot00000000000000--- Language: Cpp # BasedOnStyle: Mozilla AlignAfterOpenBracket: Align AlignConsecutiveAssignments: false AlignConsecutiveDeclarations: true AlignEscapedNewlinesLeft: true AlignOperands: true AlignTrailingComments: true AllowAllParametersOfDeclarationOnNextLine: true AllowShortBlocksOnASingleLine: false AllowShortCaseLabelsOnASingleLine: false AllowShortFunctionsOnASingleLine: Inline AllowShortIfStatementsOnASingleLine: false AllowShortLoopsOnASingleLine: false AlwaysBreakAfterDefinitionReturnType: None AlwaysBreakAfterReturnType: None AlwaysBreakBeforeMultilineStrings: false BinPackArguments: false BinPackParameters: false BraceWrapping: AfterControlStatement: false AfterEnum: false AfterFunction: true AfterStruct: false AfterUnion: false BeforeElse: false IndentBraces: false BreakBeforeBinaryOperators: None BreakBeforeBraces: Custom BreakBeforeTernaryOperators: false BreakStringLiterals: true ColumnLimit: 95 ContinuationIndentWidth: 2 DerivePointerAlignment: false DisableFormat: false ExperimentalAutoDetectBinPacking: false IncludeIsMainRegex: '$' IndentCaseLabels: false IndentWidth: 4 IndentWrappedFunctionNames: false KeepEmptyLinesAtTheStartOfBlocks: false MacroBlockBegin: '' MacroBlockEnd: '' MaxEmptyLinesToKeep: 1 PenaltyBreakBeforeFirstCallParameter: 19 PenaltyBreakComment: 300 PenaltyBreakString: 1000 PenaltyExcessCharacter: 1000000 PenaltyReturnTypeOnItsOwnLine: 200 PointerAlignment: Right ReflowComments: true SortIncludes: false SpaceAfterCStyleCast: true SpaceBeforeAssignmentOperators: true SpaceBeforeParens: ControlStatements SpaceInEmptyParentheses: false SpacesBeforeTrailingComments: 1 SpacesInContainerLiterals: true SpacesInCStyleCastParentheses: false SpacesInParentheses: false SpacesInSquareBrackets: false Standard: Auto TabWidth: 8 UseTab: Never ... sexpp-0.8.7/.gitattributes000066400000000000000000000000541444627452400155730ustar00rootroot00000000000000*.giattributes text eol=lf samples/** -text sexpp-0.8.7/.github/000077500000000000000000000000001444627452400142415ustar00rootroot00000000000000sexpp-0.8.7/.github/workflows/000077500000000000000000000000001444627452400162765ustar00rootroot00000000000000sexpp-0.8.7/.github/workflows/build-and-test-deb.yml000066400000000000000000000105671444627452400223760ustar00rootroot00000000000000# # Copyright 2021-2023 Ribose Inc. (https://www.ribose.com) # # Permission is hereby granted, free of charge, to any person obtaining a copy of # this software and associated documentation files (the "Software"), to deal in # the Software without restriction, including without limitation the rights to # use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of # the Software, and to permit persons to whom the Software is furnished to do so, # subject to the following conditions: # # The above copyright notice and this permission notice shall be included in all # copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS # FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR # COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER # IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN # CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # name: build-and-test-deb on: push: branches: [ main ] pull_request: workflow_dispatch: concurrency: group: '${{ github.workflow }}-${{ github.job }}-${{ github.head_ref || github.ref_name }}' cancel-in-progress: true env: # Looks like the last version that supports i386 CMAKE_VERSION: '3.20.6-2' MAKEFLAGS: j4 jobs: build-and-test: name: ${{ matrix.image }}-${{ matrix.env.CC }} shared lib ${{ matrix.shared }} runs-on: ubuntu-latest strategy: fail-fast: false matrix: image: [ 'i386/debian:10', 'i386/debian:11', 'amd64/debian:11' ] env: [ {CC: gcc, CXX: g++}, {CC: clang, CXX: clang++} ] shared: [on, off] container: ${{ matrix.image }} env: ${{ matrix.env }} steps: - name: Install packages run: | apt-get update apt-get -y install sudo git wget build-essential libssl-dev software-properties-common - name: Checkout # Because i386 support v1 only (no node run-time) uses: actions/checkout@v1 with: fetch-depth: 1 - name: Install cmake/i386 if: startsWith(matrix.image, 'i386') run: | wget -nv https://github.com/xpack-dev-tools/cmake-xpack/releases/download/v${{ env.CMAKE_VERSION }}/xpack-cmake-${{ env.CMAKE_VERSION }}-linux-ia32.tar.gz tar -zxf xpack-cmake-${{ env.CMAKE_VERSION }}-linux-ia32.tar.gz --directory /usr/local --strip-components=1 --skip-old-files - name: Install cmake/amd64 if: startsWith(matrix.image, 'amd64') run: | wget -nv https://github.com/xpack-dev-tools/cmake-xpack/releases/download/v${{ env.CMAKE_VERSION }}/xpack-cmake-${{ env.CMAKE_VERSION }}-linux-x64.tar.gz tar -zxf xpack-cmake-${{ env.CMAKE_VERSION }}-linux-x64.tar.gz --directory /usr/local --strip-components=1 --skip-old-files - name: Install clang if: matrix.env.CC == 'clang' run: | wget -O - https://apt.llvm.org/llvm-snapshot.gpg.key|sudo apt-key add - apt-add-repository "deb http://apt.llvm.org/stretch/ llvm-toolchain-stretch main" apt-get install -y clang - name: Adjust environment run: | echo "SEXP_INSTALL_PATH=$PWD/install" >> $GITHUB_ENV echo "SHARED_LIB=${{ matrix.shared }}" >> $GITHUB_ENV - name: Configure run: cmake . -Bbuild -DCMAKE_INSTALL_PREFIX=${{ env.SEXP_INSTALL_PATH }} -DCMAKE_BUILD_TYPE=Release -DBUILD_SHARED_LIBS=${{ matrix.shared }} - name: Build run: cmake --build build --config Release - name: Run tests run: ctest --test-dir build --output-on-failure - name: Checkout shell test framework/amd64 only # i386 supports actions/checkout@v1 only (no Node.js 32-bit binary) # and and actions/checkout@v1 has some issues with nested repositories if: startsWith(matrix.image, 'amd64') uses: actions/checkout@v3 with: repository: kward/shunit2 path: ${{github.workspace}}/tests/shunit2 fetch-depth: 1 - name: Install run: cmake --install build - name: Run additional tests # See above, just assume that in i386 config it was installed correctly if: startsWith(matrix.image, 'amd64') shell: bash run: tests/scripts/tests.sh sexpp-0.8.7/.github/workflows/build-and-test-msys.yml000066400000000000000000000054431444627452400226340ustar00rootroot00000000000000# # Copyright 2021-2023 Ribose Inc. (https://www.ribose.com) # # Permission is hereby granted, free of charge, to any person obtaining a copy of # this software and associated documentation files (the "Software"), to deal in # the Software without restriction, including without limitation the rights to # use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of # the Software, and to permit persons to whom the Software is furnished to do so, # subject to the following conditions: # # The above copyright notice and this permission notice shall be included in all # copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS # FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR # COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER # IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN # CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # name: build-and-test-msys on: push: branches: [ main ] pull_request: workflow_dispatch: concurrency: group: '${{ github.workflow }}-${{ github.job }}-${{ github.head_ref || github.ref_name }}' cancel-in-progress: true env: MAKEFLAGS: j4 defaults: run: shell: msys2 {0} jobs: build-and-test: name: MSys-${{ matrix.msystem }} shared lib ${{ matrix.shared }} runs-on: windows-latest strategy: fail-fast: false matrix: msystem: [ ucrt64, mingw64, clang64 ] shared: [on, off] steps: - name: Checkout uses: actions/checkout@v3 with: fetch-depth: 1 - name: Install MSys uses: msys2/setup-msys2@v2 with: msystem: ${{ matrix.msystem }} pacboy: >- toolchain:p cmake:p path-type: minimal - name: Adjust environment shell: bash run: | echo "SEXP_INSTALL_PATH=$(cygpath -u $PWD/install)" >> $GITHUB_ENV echo "SHARED_LIB=${{ matrix.shared }}" >> $GITHUB_ENV - name: Configure run: cmake -Bbuild -DCMAKE_INSTALL_PREFIX=${{ env.SEXP_INSTALL_PATH }} -DCMAKE_BUILD_TYPE=Release -DBUILD_SHARED_LIBS=${{ matrix.shared }} - name: Build run: cmake --build build --config Release - name: Run tests run: ctest --test-dir build --output-on-failure - name: Checkout shell test framework uses: actions/checkout@v3 with: repository: kward/shunit2 path: ${{ github.workspace }}/tests/shunit2 fetch-depth: 1 - name: Install run: cmake --install build - name: Run additional tests run: tests/scripts/tests.sh sexpp-0.8.7/.github/workflows/build-and-test-rh.yml000066400000000000000000000067661444627452400222630ustar00rootroot00000000000000# # Copyright 2021-2023 Ribose Inc. (https://www.ribose.com) # # Permission is hereby granted, free of charge, to any person obtaining a copy of # this software and associated documentation files (the "Software"), to deal in # the Software without restriction, including without limitation the rights to # use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of # the Software, and to permit persons to whom the Software is furnished to do so, # subject to the following conditions: # # The above copyright notice and this permission notice shall be included in all # copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS # FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR # COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER # IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN # CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # name: build-and-test-rh on: push: branches: [ main ] pull_request: workflow_dispatch: concurrency: group: '${{ github.workflow }}-${{ github.job }}-${{ github.head_ref || github.ref_name }}' cancel-in-progress: true env: MAKEFLAGS: j4 jobs: build-and-test: name: ${{ matrix.image }}-${{ matrix.env.CC }} shared lib ${{ matrix.shared }} runs-on: ubuntu-latest strategy: fail-fast: false matrix: image: [ 'centos:7', 'tgagor/centos:stream8', 'quay.io/centos/centos:stream9', 'fedora:35', 'fedora:36' ] env: [ {CC: gcc, CXX: g++}, {CC: clang, CXX: clang++} ] shared: [ on, off ] container: ${{ matrix.image }} env: ${{ matrix.env }} steps: - name: Install packages CentOS 7 if: matrix.image == 'centos:7' run: | yum -y install http://opensource.wandisco.com/centos/7/git/x86_64/wandisco-git-release-7-2.noarch.rpm yum -y install sudo git make wget gcc gcc-c++ clang wget -nv https://github.com/Kitware/CMake/releases/download/v3.24.3/cmake-3.24.3-linux-x86_64.sh chmod a+x cmake-3.24.3-linux-x86_64.sh ./cmake-3.24.3-linux-x86_64.sh --skip-license --exclude-subdir --prefix=/usr/local - name: Install packages not CentOS 7 if: matrix.image != 'centos:7' run: yum -y install sudo git gcc gcc-c++ make cmake clang - name: Checkout uses: actions/checkout@v3 with: fetch-depth: 1 - name: Adjust environment run: | echo "SEXP_INSTALL_PATH=$PWD/install" >> $GITHUB_ENV echo "SHARED_LIB=${{ matrix.shared }}" >> $GITHUB_ENV - name: Configure run: cmake . -Bbuild -DCMAKE_INSTALL_PREFIX=${{ env.SEXP_INSTALL_PATH }} -DCMAKE_BUILD_TYPE=Release -DBUILD_SHARED_LIBS=${{ matrix.shared }} - name: Build run: cmake --build build --config Release - name: Run tests run: ctest --test-dir build --output-on-failure - name: Install run: cmake --install build - name: Install xargs if: matrix.image == 'fedora:35' run: sudo yum -y install findutils - name: Checkout shell test framework uses: actions/checkout@v3 with: repository: kward/shunit2 path: ${{github.workspace}}/tests/shunit2 fetch-depth: 1 - name: Run additional tests shell: bash run: tests/scripts/tests.sh sexpp-0.8.7/.github/workflows/build-and-test.yml000066400000000000000000000107161444627452400216420ustar00rootroot00000000000000# # Copyright 2021-2023 Ribose Inc. (https://www.ribose.com) # # Permission is hereby granted, free of charge, to any person obtaining a copy of # this software and associated documentation files (the "Software"), to deal in # the Software without restriction, including without limitation the rights to # use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of # the Software, and to permit persons to whom the Software is furnished to do so, # subject to the following conditions: # # The above copyright notice and this permission notice shall be included in all # copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS # FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR # COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER # IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN # CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # name: build-and-test on: push: branches: [ main ] pull_request: workflow_dispatch: concurrency: group: '${{ github.workflow }}-${{ github.job }}-${{ github.head_ref || github.ref_name }}' cancel-in-progress: true env: MAKEFLAGS: j4 jobs: build-and-test: runs-on: ${{ matrix.os }} name: ${{ matrix.os }}-${{ matrix.env.CC }} shared lib ${{ matrix.shared }} strategy: fail-fast: false matrix: os: [ ubuntu-20.04, macos-11, windows-2019 ] env: [ { } ] shared: [on, off] # on macos gcc is an alias to clang by default, so there is no real value in macos clang run include: - { os: ubuntu-20.04, env: { CC: clang, CXX: clang++ }, shared: on } - { os: ubuntu-20.04, env: { CC: clang, CXX: clang++ }, shared: off } # Builds sexp dll with MSVC is not supported exclude: - { os: windows-2019, env: { }, shared: on } env: ${{ matrix.env }} steps: - name: Checkout uses: actions/checkout@v3 with: fetch-depth: 1 - name: Adjust environment for Windows build if: runner.os == 'Windows' shell: bash run: echo "OSTYPE=windows" >> $GITHUB_ENV - name: Adjust environment run: echo "SHARED_LIB=${{ matrix.shared }}" >> $GITHUB_ENV - name: Configure run: cmake -Bbuild -DCMAKE_INSTALL_PREFIX=${{ github.workspace }}/install -DCMAKE_BUILD_TYPE=Release -DBUILD_SHARED_LIBS=${{ matrix.shared }} - name: Build run: cmake --build build --config Release - name: Run tests run: ctest --test-dir build --output-on-failure - name: Checkout shell test framework uses: actions/checkout@v3 with: repository: kward/shunit2 path: ${{github.workspace}}/tests/shunit2 fetch-depth: 1 - name: Install run: cmake --install build - name: Run additional tests shell: bash run: tests/scripts/tests.sh offline-gtest: runs-on: ubuntu-latest steps: - name: Checkout uses: actions/checkout@v3 with: fetch-depth: 1 - name: Install googletest run: | sudo apt-get -y install googletest sudo cmake -B/usr/src/googletest/build /usr/src/googletest sudo cmake --build /usr/src/googletest/build sudo cmake --install /usr/src/googletest/build - name: Configure run: | cmake -Bbuild \ -DCMAKE_INSTALL_PREFIX=${{ github.workspace }}/install \ -DCMAKE_BUILD_TYPE=Release \ -DDOWNLOAD_GTEST=OFF - name: Build run: cmake --build build - name: Run tests run: ctest --test-dir build --output-on-failure sanitizers: runs-on: ubuntu-latest env: CC: clang CXX: clang++ steps: - name: Checkout uses: actions/checkout@v3 with: fetch-depth: 1 - name: Configure run: | cmake -Bbuild \ -DCMAKE_INSTALL_PREFIX=${{ github.workspace }}/install \ -DWITH_SANITIZERS=ON - name: Build run: cmake --build build - name: Run tests run: ctest --test-dir build --output-on-failure sexpp-0.8.7/.github/workflows/codeql.yml000066400000000000000000000067211444627452400202760ustar00rootroot00000000000000# # Copyright 2021-2023 Ribose Inc. (https://www.ribose.com) # # Permission is hereby granted, free of charge, to any person obtaining a copy of # this software and associated documentation files (the "Software"), to deal in # the Software without restriction, including without limitation the rights to # use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of # the Software, and to permit persons to whom the Software is furnished to do so, # subject to the following conditions: # # The above copyright notice and this permission notice shall be included in all # copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS # FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR # COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER # IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN # CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # name: "CodeQL" on: push: branches: [ "main" ] pull_request: # The branches below must be a subset of the branches above branches: [ "main" ] concurrency: group: '${{ github.workflow }}-${{ github.job }}-${{ github.head_ref || github.ref_name }}' cancel-in-progress: true jobs: analyze: name: Analyze runs-on: ubuntu-latest permissions: actions: read contents: read security-events: write strategy: fail-fast: false matrix: language: [ 'cpp' ] # CodeQL supports [ 'cpp', 'csharp', 'go', 'java', 'javascript', 'python', 'ruby' ] # Learn more about CodeQL language support at https://aka.ms/codeql-docs/language-support steps: - name: Checkout repository uses: actions/checkout@v3 # Initializes the CodeQL tools for scanning. - name: Initialize CodeQL uses: github/codeql-action/init@v2 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. # Details on CodeQL's query packs refer to : https://docs.github.com/en/code-security/code-scanning/automatically-scanning-your-code-for-vulnerabilities-and-errors/configuring-code-scanning#using-queries-in-ql-packs # queries: security-extended,security-and-quality # Autobuild attempts to build any compiled languages (C/C++, C#, Go, or Java). # If this step fails, then you should remove it and run the build manually (see below) - name: Autobuild uses: github/codeql-action/autobuild@v2 # ℹ️ Command-line programs to run using the OS shell. # 📚 See https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#jobsjob_idstepsrun # If the Autobuild fails above, remove it and uncomment the following three lines. # modify them (or add more) to build your code if your project, please refer to the EXAMPLE below for guidance. # - run: | # echo "Run, Build Application using script" # ./location_of_script_within_repo/buildscript.sh - name: Perform CodeQL Analysis uses: github/codeql-action/analyze@v2 with: category: "/language:${{matrix.language}}" sexpp-0.8.7/.github/workflows/coverage.yml000066400000000000000000000051721444627452400206210ustar00rootroot00000000000000# # Copyright 2021-2023 Ribose Inc. (https://www.ribose.com) # # Permission is hereby granted, free of charge, to any person obtaining a copy of # this software and associated documentation files (the "Software"), to deal in # the Software without restriction, including without limitation the rights to # use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of # the Software, and to permit persons to whom the Software is furnished to do so, # subject to the following conditions: # # The above copyright notice and this permission notice shall be included in all # copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS # FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR # COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER # IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN # CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # name: coverage on: push: branches: [ main ] pull_request: workflow_dispatch: concurrency: group: '${{ github.workflow }}-${{ github.job }}-${{ github.head_ref || github.ref_name }}' cancel-in-progress: true jobs: coverage: runs-on: ubuntu-latest env: CC: gcc CXX: g++ CODECOV_TOKEN: dbb06ac6-97ef-4d04-a0c6-24f7e3d8e1d6 MAKEFLAGS: j4 steps: - name: Checkout uses: actions/checkout@v3 with: fetch-depth: 1 - name: Configure run: | cmake -Bbuild \ -DCMAKE_INSTALL_PREFIX=${{ github.workspace }}/install \ -DWITH_COVERAGE=ON - name: Build run: cmake --build build - name: Run tests run: ctest --test-dir build --output-on-failure - name: Upload to codecov.io run: | curl -Os https://uploader.codecov.io/latest/linux/codecov curl https://uploader.codecov.io/verification.gpg | gpg --no-default-keyring --keyring trustedkeys.gpg --import curl -Os https://uploader.codecov.io/latest/linux/codecov curl -Os https://uploader.codecov.io/latest/linux/codecov.SHA256SUM curl -Os https://uploader.codecov.io/latest/linux/codecov.SHA256SUM.sig gpgv codecov.SHA256SUM.sig codecov.SHA256SUM shasum -a 256 -c codecov.SHA256SUM find "build" -type f -name '*.gcno' -exec gcov -p {} + chmod +x codecov ./codecov -t ${{ env.CODECOV_TOKEN }} sexpp-0.8.7/.github/workflows/coverity.yml000066400000000000000000000041611444627452400206670ustar00rootroot00000000000000# # Copyright 2021-2023 Ribose Inc. (https://www.ribose.com) # # Permission is hereby granted, free of charge, to any person obtaining a copy of # this software and associated documentation files (the "Software"), to deal in # the Software without restriction, including without limitation the rights to # use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of # the Software, and to permit persons to whom the Software is furnished to do so, # subject to the following conditions: # # The above copyright notice and this permission notice shall be included in all # copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS # FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR # COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER # IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN # CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # name: coverity on: push: branches: [ main ] pull_request: workflow_dispatch: concurrency: group: '${{ github.workflow }}-${{ github.job }}-${{ github.head_ref || github.ref_name }}' cancel-in-progress: true jobs: coverity: runs-on: ubuntu-latest env: CC: gcc CXX: g++ MAKEFLAGS: j4 COVERITY_TOKEN: qjcM1CWLcq9PJB3yL0ZXIw steps: - name: Checkout uses: actions/checkout@v3 with: fetch-depth: 1 - name: Install googletest run: | sudo apt-get -y install googletest sudo cmake -B/usr/src/googletest/build /usr/src/googletest sudo cmake --build /usr/src/googletest/build sudo cmake --install /usr/src/googletest/build - name: Configure run: cmake -Bbuild -DDOWNLOAD_GTEST=OFF - name: Coverity Scan uses: vapier/coverity-scan-action@v1 with: email: maxirmx@sw.consulting token: ${{ env.COVERITY_TOKEN }} command: cmake --build build sexpp-0.8.7/.github/workflows/lint.yml000066400000000000000000000036431444627452400177750ustar00rootroot00000000000000# # Copyright 2021-2023 Ribose Inc. (https://www.ribose.com) # # Permission is hereby granted, free of charge, to any person obtaining a copy of # this software and associated documentation files (the "Software"), to deal in # the Software without restriction, including without limitation the rights to # use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of # the Software, and to permit persons to whom the Software is furnished to do so, # subject to the following conditions: # # The above copyright notice and this permission notice shall be included in all # copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS # FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR # COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER # IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN # CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # name: lint on: workflow_dispatch: pull_request: paths-ignore: - '/.*' - '!.clang-format' - '**.adoc' - '**.md' jobs: clang-format: runs-on: ubuntu-latest steps: - uses: actions/checkout@v3 - uses: DoozyX/clang-format-lint-action@v0.11 with: source: '.' extensions: 'h,cpp,c' clangFormatVersion: 11 # inplace: True # - uses: EndBug/add-and-commit@v9 # with: # author_name: A robot on behalf of Maxim Samsonov # author_email: m.samsonov@computer.org # message: 'Committing clang-format changes' # env: # GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} shellcheck: runs-on: ubuntu-latest steps: - uses: actions/checkout@v3 - uses: ludeeus/action-shellcheck@master sexpp-0.8.7/.github/workflows/nix.yml000066400000000000000000000040041444627452400176150ustar00rootroot00000000000000# # Copyright 2021-2023 Ribose Inc. (https://www.ribose.com) # # Permission is hereby granted, free of charge, to any person obtaining a copy of # this software and associated documentation files (the "Software"), to deal in # the Software without restriction, including without limitation the rights to # use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of # the Software, and to permit persons to whom the Software is furnished to do so, # subject to the following conditions: # # The above copyright notice and this permission notice shall be included in all # copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS # FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR # COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER # IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN # CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # name: nix on: push: branches: [ main ] pull_request: workflow_dispatch: concurrency: group: '${{ github.workflow }}-${{ github.job }}-${{ github.head_ref || github.ref_name }}' cancel-in-progress: true jobs: build: runs-on: ${{ matrix.os }} strategy: fail-fast: false matrix: os: [ubuntu-latest, macos-latest] steps: - name: Checkout uses: actions/checkout@v3 with: fetch-depth: 1 - name: nix setup uses: cachix/install-nix-action@v22 with: nix_path: nixpkgs=channel:nixos-unstable - name: nix build run: nix build - name: Checkout shell test framework uses: actions/checkout@v3 with: repository: kward/shunit2 path: ${{github.workspace}}/tests/shunit2 fetch-depth: 1 - name: Run tests run: DIR_INSTALL=result tests/scripts/tests.sh sexpp-0.8.7/.gitignore000066400000000000000000000001701444627452400146670ustar00rootroot00000000000000### CMake and build artifacts ### /build /baseline /tests/include/sexp-samples-folder.h /.vscode /result /tests/shunit2 sexpp-0.8.7/CMakeLists.txt000066400000000000000000000212731444627452400154460ustar00rootroot00000000000000# # Copyright 2021-2023 Ribose Inc. (https://www.ribose.com) # # Permission is hereby granted, free of charge, to any person obtaining a copy of # this software and associated documentation files (the "Software"), to deal in # the Software without restriction, including without limitation the rights to # use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of # the Software, and to permit persons to whom the Software is furnished to do so, # subject to the following conditions: # # The above copyright notice and this permission notice shall be included in all # copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS # FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR # COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER # IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN # CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # # 3.14 -- FetchContent cmake_minimum_required(VERSION 3.14) include(cmake/version.cmake) determine_version("${CMAKE_CURRENT_SOURCE_DIR}" SEXPP) # project name, etc project(sexpp VERSION "${SEXPP_VERSION}" LANGUAGES C CXX DESCRIPTION "S-expressions parser and generator C++ library, fully compliant to [https://people.csail.mit.edu/rivest/Sexp.txt]" ) option(WITH_SEXP_TESTS "Build tests" ON) option(WITH_SEXP_CLI "Build sexp console application" ON) option(WITH_SANITIZERS "Enable ASAN and other sanitizers" OFF) option(WITH_COVERAGE "Enable coverage report" OFF) option(DOWNLOAD_GTEST "Download googletest" ON) option(BUILD_SHARED_LIBS "Build shared library" OFF) include(GNUInstallDirs) include(CheckCXXSourceCompiles) if (BUILD_SHARED_LIBS) set(TYPE "SHARED") else (BUILD_SHARED_LIBS) set(TYPE "STATIC") endif (BUILD_SHARED_LIBS) if (BUILD_SHARED_LIBS AND MSVC) message(FATAL_ERROR "Building sexp shared library with MSVC is not supported") endif(BUILD_SHARED_LIBS AND MSVC) message(STATUS "Building ${TYPE} library") if (WITH_SANITIZERS) if (NOT CMAKE_CXX_COMPILER_ID MATCHES "Clang") message(FATAL_ERROR "Sanitizers work with clang compiler only.") endif() if(NOT CMAKE_BUILD_TYPE MATCHES "Debug") message(STATUS "Forcing build type to Debug for sanitizers") set(CMAKE_BUILD_TYPE Debug CACHE STRING "Build type. Forced to Debug" FORCE) set(WITH_TESTS ON CACHE STRING "Forced to ON" FORCE) endif() endif() if (WITH_COVERAGE) if (NOT CMAKE_CXX_COMPILER_ID MATCHES "GNU") message(FATAL_ERROR "Coverage works with GNU compiler only.") endif() if(NOT CMAKE_BUILD_TYPE MATCHES "Debug") message(STATUS "Forcing build type to Debug for coverage") set(CMAKE_BUILD_TYPE Debug CACHE STRING "Build type. Forced to Debug" FORCE) set(WITH_TESTS ON CACHE STRING "Forced to ON" FORCE) endif() endif() if(NOT CMAKE_BUILD_TYPE) message(STATUS "Defaulting build type to Debug") set(CMAKE_BUILD_TYPE Debug) endif(NOT CMAKE_BUILD_TYPE) message(STATUS "Building ${CMAKE_BUILD_TYPE} configuration") if (WITH_SANITIZERS) add_compile_options(-fsanitize=leak,address,undefined -fno-omit-frame-pointer -fno-common -O1) link_libraries(-fsanitize=leak,address,undefined) endif(WITH_SANITIZERS) if (WITH_COVERAGE) add_compile_options(--coverage -O0) link_libraries(--coverage) endif(WITH_COVERAGE) # set warning flags at the top level if(NOT MSVC) add_compile_options( -Wall -Wextra -Wunreachable-code -Wpointer-arith -Wmissing-declarations ) # relax some warnings a bit add_compile_options( -Wno-pedantic -Wno-ignored-qualifiers -Wno-unused-parameter -Wno-missing-field-initializers ) endif(NOT MSVC) add_library(sexpp ${TYPE} "src/sexp-input.cpp" "src/sexp-output.cpp" "src/sexp-object.cpp" "src/sexp-simple-string.cpp" "src/sexp-char-defs.cpp" "src/sexp-error.cpp" "src/sexp-depth-manager.cpp" "src/ext-key-format.cpp" "include/sexpp/sexp.h" "include/sexpp/sexp-error.h" "include/sexpp/ext-key-format.h" ) target_compile_features(sexpp PUBLIC cxx_std_11) target_include_directories(sexpp PUBLIC $ $ ) if (BUILD_SHARED_LIBS) target_compile_definitions(sexpp PUBLIC BUILD_SHARED_LIBS) set_target_properties(sexpp PROPERTIES CXX_VISIBILITY_PRESET "hidden") endif (BUILD_SHARED_LIBS) set_target_properties(sexpp PROPERTIES POSITION_INDEPENDENT_CODE ON RUNTIME_OUTPUT_DIRECTORY "${CMAKE_BINARY_DIR}/bin" VERSION "${SEXPP_VERSION}" SOVERSION "${SEXPP_MAJOR_VERSION}" OUTPUT_NAME "sexpp" ) if (WITH_SEXP_CLI) add_executable (sexpp-cli src/sexp-main.cpp include/sexpp/sexp.h include/sexpp/sexp-error.h ) target_include_directories (sexpp-cli PUBLIC include) target_link_libraries(sexpp-cli PRIVATE sexpp) target_compile_features(sexpp-cli PUBLIC cxx_std_11) set_target_properties(sexpp-cli PROPERTIES RUNTIME_OUTPUT_NAME sexpp RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin ) endif (WITH_SEXP_CLI) if(WITH_SEXP_TESTS) CHECK_CXX_SOURCE_COMPILES( "#include #include struct test_struct { std::string str; }; int main() { bool b = std::is_copy_constructible::value; return b ? 0 : -1 ; }" CAN_USE_NEW_GTEST ) if(CAN_USE_NEW_GTEST) set(GTEST_TAG "release-1.12.1") else(CAN_USE_NEW_GTEST) if(WITH_COVERAGE) message(FATAL_ERROR "Coverage requires newer version of GTest that won't compile with your toolset") endif(WITH_COVERAGE) set(GTEST_TAG "release-1.8.1") endif(CAN_USE_NEW_GTEST) include(CTest) enable_testing() include(GoogleTest) set(SEXP_SAMPLES_FOLDER "${CMAKE_CURRENT_SOURCE_DIR}/samples") configure_file( "${CMAKE_CURRENT_SOURCE_DIR}/cmake/sexp-samples-folder.h.in" "${CMAKE_CURRENT_SOURCE_DIR}/tests/include/sexp-samples-folder.h" @ONLY ) add_executable(sexpp-tests "tests/src/baseline-tests.cpp" "tests/src/exception-tests.cpp" "tests/src/primitives-tests.cpp" "tests/src/g10-compat-tests.cpp" "tests/src/g23-compat-tests.cpp" "tests/src/g23-exception-tests.cpp" "tests/src/compare-files.cpp" "tests/include/sexp-tests.h" ) if(DOWNLOAD_GTEST) message(STATUS "Fetching googletest") include(FetchContent) FetchContent_Declare( googletest GIT_REPOSITORY https://github.com/google/googletest.git GIT_TAG ${GTEST_TAG} ) # maintain compiler/linker settings on Windows set(gtest_force_shared_crt ON CACHE BOOL "" FORCE) # do not install gtest set(INSTALL_GTEST OFF CACHE BOOL "" FORCE) # explicitely disable unneeded gmock build set(BUILD_GMOCK OFF CACHE BOOL "" FORCE) FetchContent_MakeAvailable(googletest) set(GTestMain gtest_main) set(GTest gtest) else(DOWNLOAD_GTEST) find_package(GTest REQUIRED) set(GTestMain GTest::Main) set(GTest GTest::GTest) if(NOT MSVC) target_link_libraries(sexpp-tests PRIVATE pthread) endif(NOT MSVC) endif(DOWNLOAD_GTEST) target_link_libraries(sexpp-tests PRIVATE sexpp ${GTestMain} ${GTest} ) target_include_directories(sexpp-tests PRIVATE tests/include include "${GTEST_INCLUDE_DIRS}" ) target_compile_features(sexpp-tests PUBLIC cxx_std_11) set_target_properties(sexpp-tests PROPERTIES RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin) gtest_discover_tests(sexpp-tests) endif(WITH_SEXP_TESTS) set(CONFIGURED_PC "${CMAKE_CURRENT_BINARY_DIR}/sexpp.pc") configure_file( "${CMAKE_CURRENT_SOURCE_DIR}/cmake/sexpp.pc.in" "${CONFIGURED_PC}" @ONLY ) if (WIN32 AND BUILD_SHARED_LIBS) install(TARGETS sexpp RUNTIME DESTINATION "${CMAKE_INSTALL_BINDIR}") install(TARGETS sexpp ARCHIVE DESTINATION "${CMAKE_INSTALL_LIBDIR}") else(WIN32 AND BUILD_SHARED_LIBS) install(TARGETS sexpp DESTINATION "${CMAKE_INSTALL_LIBDIR}") endif(WIN32 AND BUILD_SHARED_LIBS) install(DIRECTORY include/ DESTINATION "${CMAKE_INSTALL_INCLUDEDIR}") install(FILES "${CONFIGURED_PC}" DESTINATION "${CMAKE_INSTALL_LIBDIR}/pkgconfig") if(WITH_SEXP_CLI) install(TARGETS sexpp-cli DESTINATION "${CMAKE_INSTALL_BINDIR}") install(FILES man/sexpp.1 DESTINATION "${CMAKE_INSTALL_MANDIR}/man1") endif(WITH_SEXP_CLI) sexpp-0.8.7/LICENSE.md000066400000000000000000000025301444627452400143050ustar00rootroot00000000000000Original MIT License ==================== Copyright 1997 Ronald L. Rivest, Butler Lampson Copyright 1997 MIT Laboratory for Computer Science The code is available under the "MIT License" (open source). License text available at: https://opensource.org/licenses/MIT Ribose MIT License ==================== Copyright 2021-2022 Ribose Inc. Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. sexpp-0.8.7/README.adoc000066400000000000000000000155471444627452400145020ustar00rootroot00000000000000= S-Expressions parser and generator library in C\++ (SEXP in C++) image:https://github.com/rnpgp/sexp/workflows/build-and-test/badge.svg["Build status Ubuntu/macOS/Windows", link="https://github.com/rnpgp/sexp/actions?workflow=build-and-test"] image:https://github.com/rnpgp/sexp/workflows/build-and-test-rh/badge.svg["Build status CentOS/Fedora", link="https://github.com/rnpgp/sexp/actions?workflow=build-and-test-rh"] image:https://github.com/rnpgp/sexp/workflows/build-and-test-deb/badge.svg["Build status Debian", link="https://github.com/rnpgp/sexp/actions?workflow=build-and-test-deb"] image:https://github.com/rnpgp/sexp/workflows/build-and-test-msys/badge.svg["Build status MSys", link="https://github.com/rnpgp/sexp/actions?workflow=build-and-test-msys"] image:https://codecov.io/gh/rnpgp/sexpp/branch/main/graph/badge.svg["Code coverage", link="https://codecov.io/gh/rnpgp/sexpp"] image:https://github.com/rnpgp/sexpp/workflows/CodeQL/badge.svg["CodeQL analysis", link="https://github.com/rnpgp/sexpp/actions?workflow=CodeQL"] image:https://scan.coverity.com/projects/28717/badge.svg["Coverity Scan Build Status", link="https://scan.coverity.com/projects/rnpgp-sexpp"] == Purpose This is a C++ library for working with S-Expressions. This implementation is derived from the reference SEXP C library developed by Prof. Ronald Rivest and Prof. Butler Lampson of MIT LCS (now CSAIL). This library differs from the original C implementation in the following ways: * It aims to be reuseable in C++ implementations and is importable via CMake. * It includes a test suite for correctness testing and tests against malformed S-Expressions. * It supports, and is tested against, all major platforms, including: ** Ubuntu, Debian, Fedora, CentOS ** macOS ** Windows ** msys * It implements additional interface to work with S-Expressions wrapped by GnuPG 2.3+ extended format (https://github.com/gpg/gnupg/blob/master/agent/keyformat.txt[specification]). The original C library was available at (but no longer accessible): * http://people.csail.mit.edu/rivest/sexp.html == Background S-Expressions are a data structure for representing complex data as a variation on https://en.wikipedia.org/wiki/Lisp_(programming_language)[LISP] S-Expressions. S-Expressions were originally adopted for use in http://theory.lcs.mit.edu/~cis/sdsi.html[SDSI] and http://world.std.com/~cme/html/spki.html[SPKI]. SDSI has been developed by Prof. https://people.csail.mit.edu/rivest/index.html[Ronald L. Rivest] and Prof. Butler Lampson of http://www.lcs.mit.edu/[MIT's Laboratory for Computer Science], members of http://theory.lcs.mit.edu/~cis[LCS's Cryptography and Information Security] research group. NOTE: SDSI research has been supported by DARPA contract DABT63-96-C-0018, "Security for Distributed Computer Systems". NOTE: SPKI has been developed by http://www.clark.net/pub/cme/home.html[Carl Ellison] and others in the IETF SPKI working group. == S-Expressions specification * https://datatracker.ietf.org/doc/draft-rivest-sexp/ NOTE: The "SEXP 1.0 guide" used to be at https://people.csail.mit.edu/rivest/Sexp.txt. == Code The library is a deep rework to C++ of the original https://people.csail.mit.edu/rivest/sexp.html[SEXP library] that maintains full support of original specification. While most applications will not need anything but the simple canonical and transport formats; however, the code here is considerably more complex because it also supports the advanced format, both for input and for output. == Building and installation [source,sh] ---- $ mkdir build $ cd build $ cmake .. $ cmake --build . $ ctest $ cmake --install . ---- == CMake script options `BUILD_SHARED_LIBS:BOOL`:: (default: `OFF`) build shared library `WITH_SEXP_TESTS:BOOL`:: (default: `ON`) build tests `DOWNLOAD_GTEST`:: (default: `ON`) if tests are built, automatically download googletest from GitHub; when set to `OFF`, the googletest binary package needs to be available for SEXP tests. `WITH_SEXP_CLI:BOOL`:: (default: `ON`) build the `sexp` command-line utility `WITH_SANITIZERS:BOOL`:: (default: `OFF`) build with address and other sanitizers (requires clang compiler) == SEXPP command-line utility The `sexpp` command-line utility is reference parser and generator of S-Expressions. It can read, parse and print out SEXP in all defined formats. === Switches .`sexpp` switches [options="header"] |=== | Switch | Description | Default 3+| Input | `-i ` | input file name | read input from console (stdin) | `-p` | prompt input if reading from console | disabled | `-s` | treat input as a single SEXP string | disabled, input is treated as an S-Expression 3+| Output | `-o ` | output file name: | write output to console (stdout) | `-a` | generate advanced transport format | enabled if no format is specified | `-b` | generate base-64 transport format | disabled | `-c` | generate canonical format | disabled | `-l` | suppress linefeeds after output | disabled | `-w ` | set output line width (0 implies no constraint)| 75 3+| Miscellaneous | `-x` | execute repeatedly until EOF | process single S-Expression then exit | `-h` | print help message and exit | |=== Running without switches implies: `-p -a -b -c -x`. === Usage examples Prompt for S-Expressions input from console, parse and output it to `certificate.dat` in base64 transport format. [source] ---- $ sexpp -o certificate.dat -p -b > Input: > (aa bb (cc dd)) > > Writing base64 (of canonical) output to 'certificate.dat' ---- Parse all S-Expressions from `certificate.dat`, output them to console in advanced transport format with no prompts: [source,sh] ---- $ sexpp -i certificate.dat -x > (2:aa2:bb(2:cc2:dd)) ---- Parse S-Expressions from `certificate.dat`, output it to console in canonical, base64 and advanced format with prompts and no width limitation: [source,sh] ---- $ sexpp -i certificate.dat -a -b -c -p -w 0 > Reading input from certificate.dat > > Canonical output: > (2:aa2:bb(2:cc2:dd)) > Base64 (of canonical) output: > {KDI6YWEyOmJiKDI6Y2MyOmRkKSk=} > Advanced transport output: > (aa bb (cc dd)) ---- Repeatedly prompt for S-Expressions input from console, parse and output it console in advanced, base64 and canonical formats: [source,sh] ---- $ sexpp -p -a -b -c -x ---- or just [source,sh] ---- $ sexpp > Input: > (abc def (ghi jkl)) > > Canonical output: > (3:abc3:def(3:ghi3:jkl)) > Base64 (of canonical) output: > {KDM6YWJjMzpkZWYoMzpnaGkzOmprbCkp} > Advanced transport output: > (abc def (ghi jkl)) > > Input: > ^C ---- == License Copyright Ribose. The code is made available as open-source software under the MIT License. sexpp-0.8.7/cmake/000077500000000000000000000000001444627452400137615ustar00rootroot00000000000000sexpp-0.8.7/cmake/sexp-samples-folder.h.in000066400000000000000000000022741444627452400204360ustar00rootroot00000000000000/** * * Copyright 2021-2023 Ribose Inc. (https://www.ribose.com) * * Permission is hereby granted, free of charge, to any person obtaining a copy of * this software and associated documentation files (the "Software"), to deal in * the Software without restriction, including without limitation the rights to * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of * the Software, and to permit persons to whom the Software is furnished to do so, * subject to the following conditions: * * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * */ const std::string sexp_samples_folder = "@SEXP_SAMPLES_FOLDER@"; sexpp-0.8.7/cmake/sexpp.pc.in000066400000000000000000000004021444627452400160450ustar00rootroot00000000000000libdir=@CMAKE_INSTALL_FULL_LIBDIR@ includedir=@CMAKE_INSTALL_FULL_INCLUDEDIR@ Name: sexp Description: C++ library for working with S-Expressions Version: @PROJECT_VERSION@ URL: https://github.com/rnpgp/sexp Libs: -L${libdir} -lsexpp Cflags: -I${includedir} sexpp-0.8.7/cmake/version.cmake000066400000000000000000000161531444627452400164560ustar00rootroot00000000000000# # Copyright 2018-2023 Ribose Inc. (https://www.ribose.com) # # Permission is hereby granted, free of charge, to any person obtaining a copy of # this software and associated documentation files (the "Software"), to deal in # the Software without restriction, including without limitation the rights to # use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of # the Software, and to permit persons to whom the Software is furnished to do so, # subject to the following conditions: # # The above copyright notice and this permission notice shall be included in all # copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS # FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR # COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER # IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN # CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # # desired length of commit hash set(GIT_REV_LEN 7) # call git, store output in var (can fail) macro(_git var) execute_process( COMMAND "${GIT_EXECUTABLE}" ${ARGN} WORKING_DIRECTORY "${source_dir}" RESULT_VARIABLE _git_ec OUTPUT_VARIABLE ${var} OUTPUT_STRIP_TRAILING_WHITESPACE ERROR_QUIET ) endmacro() function(extract_version_info version var_prefix) # extract the main components # v1.9.0-3-g5b92266+1546836556 # v1.9.0-3-g5b92266-dirty+1546836556 string(REGEX MATCH "^v?(([0-9]+)\\.[0-9]+\\.[0-9]+)(-([0-9]+)-g([0-9a-f]+)(-dirty)?)?(\\+([0-9]+))?$" matches "${version}") if (NOT matches) message(FATAL_ERROR "Failed to extract version components from ${version}.") endif() set(${var_prefix}_VERSION "${CMAKE_MATCH_1}" PARENT_SCOPE) # 1.9.0 set(${var_prefix}_MAJOR_VERSION "${CMAKE_MATCH_2}" PARENT_SCOPE) # 1 if (NOT CMAKE_MATCH_4) set(CMAKE_MATCH_4 "0") endif() set(${var_prefix}_VERSION_NCOMMITS "${CMAKE_MATCH_4}" PARENT_SCOPE) # 3 if (NOT CMAKE_MATCH_5) set(CMAKE_MATCH_5 "0") endif() set(${var_prefix}_VERSION_GIT_REV "${CMAKE_MATCH_5}" PARENT_SCOPE) # 5b92266 if (CMAKE_MATCH_6 STREQUAL "-dirty") set(${var_prefix}_VERSION_IS_DIRTY TRUE PARENT_SCOPE) else() set(${var_prefix}_VERSION_IS_DIRTY FALSE PARENT_SCOPE) endif() # timestamp is optional, default to 0 if (NOT CMAKE_MATCH_8) set(CMAKE_MATCH_8 "0") endif() set(${var_prefix}_VERSION_COMMIT_TIMESTAMP "${CMAKE_MATCH_8}" PARENT_SCOPE) # 1546836556 endfunction() function(determine_version source_dir var_prefix) set(has_release_tag NO) set(has_version_txt NO) set(local_prefix "_determine_ver") # find out base version via version.txt set(base_version "0.0.0") if (EXISTS "${source_dir}/version.txt") set(has_version_txt YES) file(STRINGS "${source_dir}/version.txt" version_file) extract_version_info("${version_file}" "${local_prefix}") set(base_version "${${local_prefix}_VERSION}") message(STATUS "Found version.txt with ${version_file}") else() message(STATUS "Found no version.txt.") endif() # for GIT_EXECUTABLE find_package(Git) # get a description of the version, something like: # v1.9.1-0-g38ffe82 (a tagged release) # v1.9.1-0-g38ffe82-dirty (a tagged release with local modifications) # v1.9.0-3-g5b92266 (post-release snapshot) # v1.9.0-3-g5b92266-dirty (post-release snapshot with local modifications) _git(version describe --abbrev=${GIT_REV_LEN} --match "v[0-9]*" --long --dirty) if (NOT _git_ec EQUAL 0) # no annotated tags, fake one message(STATUS "Found no annotated tags.") _git(revision rev-parse --short=${GIT_REV_LEN} --verify HEAD) if (_git_ec EQUAL 0) set(version "v${base_version}-0-g${revision}") # check if dirty (this won't detect untracked files, but should be ok) _git(changes diff-index --quiet HEAD --) if (NOT _git_ec EQUAL 0) string(APPEND version "-dirty") endif() # append the commit timestamp of the most recent commit (only # in non-release branches -- typically master) _git(commit_timestamp show -s --format=%ct) if (_git_ec EQUAL 0) string(APPEND version "+${commit_timestamp}") endif() elseif(has_version_txt) # Nothing to get from git - so use version.txt completely set(version "${version_file}") else() # Sad case - no git, no version.txt set(version "v${base_version}") endif() else() set(has_release_tag YES) message(STATUS "Found annotated tag ${version}") endif() extract_version_info("${version}" "${local_prefix}") if ("${has_version_txt}" AND NOT ${base_version} STREQUAL ${local_prefix}_VERSION) message(WARNING "Tagged version ${${local_prefix}_VERSION} doesn't match one from the version.txt: ${base_version}") if (${base_version} VERSION_GREATER ${local_prefix}_VERSION) set(${local_prefix}_VERSION ${base_version}) endif() endif() foreach(suffix VERSION VERSION_NCOMMITS VERSION_GIT_REV VERSION_IS_DIRTY VERSION_COMMIT_TIMESTAMP) if (NOT DEFINED ${local_prefix}_${suffix}) message(FATAL_ERROR "Unable to determine version.") endif() set(${var_prefix}_${suffix} "${${local_prefix}_${suffix}}" PARENT_SCOPE) message(STATUS "${var_prefix}_${suffix}: ${${local_prefix}_${suffix}}") endforeach() # Set VERSION_SUFFIX and VERSION_FULL. When making changes, be aware that # this is used in packaging as well and will affect ordering. # | state | version_full | # |-----------------------------------------------------| # | exact tag | 0.9.0 | # | exact tag, dirty | 0.9.0+git20180604 | # | after tag | 0.9.0+git20180604.1.085039f | # | no tag, version.txt | 0.9.0+git20180604.2ee02af | # | no tag, no version.txt| 0.0.0+git20180604.2ee02af | string(TIMESTAMP date "%Y%m%d" UTC) set(version_suffix "") if (NOT ${local_prefix}_VERSION_NCOMMITS EQUAL 0) # 0.9.0+git20150604.4.289818b string(APPEND version_suffix "+git${date}.${${local_prefix}_VERSION_NCOMMITS}.${${local_prefix}_VERSION_GIT_REV}") elseif ((NOT has_release_tag) AND ((NOT has_version_txt) OR ("${base_version}" STREQUAL "0.0.0") OR (NOT "${revision}" STREQUAL ""))) # 0.9.0+git20150604.289818b string(APPEND version_suffix "+git${date}.${${local_prefix}_VERSION_GIT_REV}") elseif(${local_prefix}_VERSION_IS_DIRTY) # 0.9.0+git20150604 string(APPEND version_suffix "+git${date}") endif() set(version_full "${${local_prefix}_VERSION}${version_suffix}") # set the results set(${var_prefix}_VERSION_SUFFIX "${version_suffix}" PARENT_SCOPE) set(${var_prefix}_VERSION_FULL "${version_full}" PARENT_SCOPE) set(${var_prefix}_MAJOR_VERSION "${${local_prefix}_MAJOR_VERSION}" PARENT_SCOPE) # 1 # for informational purposes message(STATUS "${var_prefix}_MAJOR_VERSION: ${${local_prefix}_MAJOR_VERSION}") message(STATUS "${var_prefix}_VERSION_SUFFIX: ${version_suffix}") message(STATUS "${var_prefix}_VERSION_FULL: ${version_full}") endfunction() sexpp-0.8.7/codecov.yml000066400000000000000000000022131444627452400150440ustar00rootroot00000000000000# # Copyright 2021-2023 Ribose Inc. (https://www.ribose.com) # # Permission is hereby granted, free of charge, to any person obtaining a copy of # this software and associated documentation files (the "Software"), to deal in # the Software without restriction, including without limitation the rights to # use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of # the Software, and to permit persons to whom the Software is furnished to do so, # subject to the following conditions: # # The above copyright notice and this permission notice shall be included in all # copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS # FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR # COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER # IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN # CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # ignore: - "tests" - "src/sexp-main.cpp" sexpp-0.8.7/default.nix000066400000000000000000000034331444627452400150500ustar00rootroot00000000000000# # Copyright 2021-2023 Ribose Inc. (https://www.ribose.com) # # Permission is hereby granted, free of charge, to any person obtaining a copy of # this software and associated documentation files (the "Software"), to deal in # the Software without restriction, including without limitation the rights to # use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of # the Software, and to permit persons to whom the Software is furnished to do so, # subject to the following conditions: # # The above copyright notice and this permission notice shall be included in all # copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS # FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR # COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER # IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN # CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # { pkgs ? import { } , lib ? pkgs.lib , stdenv ? pkgs.stdenv }: stdenv.mkDerivation rec { pname = "sexp"; version = "unstable"; src = ./.; cmakeFlags = [ "-DCMAKE_INSTALL_PREFIX=${placeholder "out"}" "-DWITH_SEXP_TESTS=on" "-DWITH_SEXP_CLI=on" "-DDOWNLOAD_GTEST=off" ]; nativeBuildInputs = with pkgs; [ cmake gtest pkg-config ]; meta = with lib; { homepage = "https://github.com/rnpgp/sexp"; description = "S-expressions parser and generator C++ library, fully compliant to [https://people.csail.mit.edu/rivest/Sexp.txt]"; license = licenses.bsd2; platforms = platforms.all; maintainers = with maintainers; [ ribose-jeffreylau ]; }; }sexpp-0.8.7/flake.lock000066400000000000000000000017401444627452400146370ustar00rootroot00000000000000{ "nodes": { "flake-utils": { "locked": { "lastModified": 1667395993, "narHash": "sha256-nuEHfE/LcWyuSWnS8t12N1wc105Qtau+/OdUAjtQ0rA=", "owner": "numtide", "repo": "flake-utils", "rev": "5aed5285a952e0b949eb3ba02c12fa4fcfef535f", "type": "github" }, "original": { "owner": "numtide", "repo": "flake-utils", "type": "github" } }, "nixpkgs": { "locked": { "lastModified": 1669023499, "narHash": "sha256-iXvCW2VaH4LJD1AElk82/FaR7yepj/BqLYOJ3GAhdKQ=", "owner": "nixos", "repo": "nixpkgs", "rev": "c107fb66da7c150110fe301c38932eeccf5f9824", "type": "github" }, "original": { "owner": "nixos", "repo": "nixpkgs", "type": "github" } }, "root": { "inputs": { "flake-utils": "flake-utils", "nixpkgs": "nixpkgs" } } }, "root": "root", "version": 7 } sexpp-0.8.7/flake.nix000066400000000000000000000034601444627452400145060ustar00rootroot00000000000000# # Copyright 2021-2023 Ribose Inc. (https://www.ribose.com) # # Permission is hereby granted, free of charge, to any person obtaining a copy of # this software and associated documentation files (the "Software"), to deal in # the Software without restriction, including without limitation the rights to # use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of # the Software, and to permit persons to whom the Software is furnished to do so, # subject to the following conditions: # # The above copyright notice and this permission notice shall be included in all # copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS # FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR # COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER # IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN # CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # { description = "S-expressions parser and generator C++ library, fully compliant to [https://people.csail.mit.edu/rivest/Sexp.txt]"; inputs = { nixpkgs.url = "github:nixos/nixpkgs"; flake-utils.url = "github:numtide/flake-utils"; }; outputs = { self, nixpkgs, flake-utils }: flake-utils.lib.eachDefaultSystem (system: let pkgs = nixpkgs.legacyPackages.${system}; thePackage = pkgs.callPackage ./default.nix { }; in rec { defaultApp = flake-utils.lib.mkApp { drv = defaultPackage; }; defaultPackage = thePackage; devShell = pkgs.mkShell { buildInputs = [ thePackage ]; }; }); } sexpp-0.8.7/include/000077500000000000000000000000001444627452400143245ustar00rootroot00000000000000sexpp-0.8.7/include/sexpp/000077500000000000000000000000001444627452400154635ustar00rootroot00000000000000sexpp-0.8.7/include/sexpp/ext-key-format.h000066400000000000000000000063061444627452400205150ustar00rootroot00000000000000/** * * Copyright 2021-2023 Ribose Inc. (https://www.ribose.com) * * Permission is hereby granted, free of charge, to any person obtaining a copy of * this software and associated documentation files (the "Software"), to deal in * the Software without restriction, including without limitation the rights to * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of * the Software, and to permit persons to whom the Software is furnished to do so, * subject to the following conditions: * * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * */ #pragma once #include #include "sexp-public.h" #include "sexp.h" namespace ext_key_format { void SEXP_PUBLIC_SYMBOL ext_key_error( sexp::sexp_exception_t::severity level, const char *msg, size_t c1, size_t c2, int pos); class ext_key_input_stream_t; class SEXP_PUBLIC_SYMBOL extended_private_key_t { public: // Comparison of names is done case insensitively !!! struct ci_less { // case-independent (ci) compare_less binary function bool operator()(const std::string &s1, const std::string &s2) const { return std::lexicographical_compare( s1.begin(), s1.end(), s2.begin(), s2.end(), [](char a, char b) { return std::tolower(a) < std::tolower(b); }); } }; // C++ 11 compatible version (no std::equals) static bool iequals(const std::string &a, const std::string &b) { size_t sz = a.size(); if (b.size() != sz) return false; for (size_t i = 0; i < sz; ++i) if (tolower(a[i]) != tolower(b[i])) return false; return true; } typedef std::multimap fields_map_t; sexp::sexp_list_t key; fields_map_t fields; void parse(ext_key_input_stream_t &is); }; class SEXP_PUBLIC_SYMBOL ext_key_input_stream_t : public sexp::sexp_input_stream_t { private: static const bool namechar[256]; /* true if allowed in the name field */ static bool is_newline_char(int c) { return c == '\r' || c == '\n'; }; static bool is_namechar(int c) { return ((c >= 0 && c <= 255) && namechar[c]); } bool is_scanning_value; bool has_key; int skip_line(void); virtual int read_char(void); std::string scan_name(int c); std::string scan_value(void); public: ext_key_input_stream_t(std::istream *i, size_t md = 0) : sexp_input_stream_t(i, md), is_scanning_value(false), has_key(false) { } virtual ~ext_key_input_stream_t() = default; void scan(extended_private_key_t &extended_key); }; } // namespace ext_key_format sexpp-0.8.7/include/sexpp/sexp-error.h000066400000000000000000000055351444627452400177520ustar00rootroot00000000000000/** * * Copyright 2021-2023 Ribose Inc. (https://www.ribose.com) * * Permission is hereby granted, free of charge, to any person obtaining a copy of * this software and associated documentation files (the "Software"), to deal in * the Software without restriction, including without limitation the rights to * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of * the Software, and to permit persons to whom the Software is furnished to do so, * subject to the following conditions: * * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * */ #pragma once #include #include #include #include #include "sexp-public.h" namespace sexp { class SEXP_PUBLIC_SYMBOL sexp_exception_t : public std::exception { public: enum severity { error = 0, warning = 1 }; protected: static severity verbosity; static bool interactive; int position; // May be EOF aka -1 severity level; std::string message; public: sexp_exception_t(std::string error_message, severity error_level, int error_position, const char *prefix = "SEXP") : position{error_position}, level{error_level}, message{format(prefix, std::move(error_message), error_level, error_position)} {}; static std::string format(std::string prf, std::string message, severity level, int position); static bool shall_throw(severity level) { return level == error || verbosity != error; }; virtual const char *what(void) const throw() { return message.c_str(); }; severity get_level(void) const { return level; }; uint32_t get_position(void) const { return position; }; static severity get_verbosity(void) { return verbosity; }; static bool is_interactive(void) { return interactive; }; static void set_verbosity(severity new_verbosity) { verbosity = new_verbosity; }; static void set_interactive(bool new_interactive) { interactive = new_interactive; }; }; void SEXP_PUBLIC_SYMBOL sexp_error(sexp_exception_t::severity level, const char *msg, size_t c1, size_t c2, int pos); } // namespace sexp sexpp-0.8.7/include/sexpp/sexp-public.h000066400000000000000000000024071444627452400200720ustar00rootroot00000000000000/** * * Copyright 2023 Ribose Inc. (https://www.ribose.com) * * Permission is hereby granted, free of charge, to any person obtaining a copy of * this software and associated documentation files (the "Software"), to deal in * the Software without restriction, including without limitation the rights to * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of * the Software, and to permit persons to whom the Software is furnished to do so, * subject to the following conditions: * * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * */ #pragma once #ifdef BUILD_SHARED_LIBS #define SEXP_PUBLIC_SYMBOL __attribute__((visibility("default"))) #else #define SEXP_PUBLIC_SYMBOL #endif sexpp-0.8.7/include/sexpp/sexp.h000066400000000000000000000422711444627452400166210ustar00rootroot00000000000000/** * * Copyright 2021-2023 Ribose Inc. (https://www.ribose.com) * * Permission is hereby granted, free of charge, to any person obtaining a copy of * this software and associated documentation files (the "Software"), to deal in * the Software without restriction, including without limitation the rights to * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of * the Software, and to permit persons to whom the Software is furnished to do so, * subject to the following conditions: * * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * * Original copyright * * SEXP standard header file: sexp.h * Ronald L. Rivest * 6/29/1997 */ #pragma once #include #include #include #include #include #include #include #include #include #include #include #include #include "sexp-public.h" #include "sexp-error.h" namespace sexp { /* * SEXP octet_t definitions * We maintain some presumable redundancy with ctype * However, we do enforce 'C' locale this way */ class SEXP_PUBLIC_SYMBOL sexp_char_defs_t { protected: static const bool base64digit[256]; /* true if c is base64 digit */ static const bool tokenchar[256]; /* true if c can be in a token */ static const unsigned char values[256][3]; /* values of c as { dec. hex, base64 } digit */ static std::locale c_locale; static bool is_white_space(int c) { return c >= 0 && c <= 255 && std::isspace((char) c, c_locale); }; static bool is_dec_digit(int c) { return c >= 0 && c <= 255 && std::isdigit((char) c, c_locale); }; static bool is_hex_digit(int c) { return c >= 0 && c <= 255 && std::isxdigit((char) c, c_locale); }; static bool is_base64_digit(int c) { return c >= 0 && c <= 255 && base64digit[c]; }; static bool is_token_char(int c) { return c >= 0 && c <= 255 && tokenchar[c]; }; static bool is_alpha(int c) { return c >= 0 && c <= 255 && std::isalpha((char) c, c_locale); }; /* decvalue(c) is value of c as dec digit */ static unsigned char decvalue(int c) { return (c >= 0 && c <= 255) ? values[c][0] : 0; }; /* hexvalue(c) is value of c as a hex digit */ static unsigned char hexvalue(int c) { return (c >= 0 && c <= 255) ? values[c][1] : 0; }; /* base64value(c) is value of c as base64 digit */ static unsigned char base64value(int c) { return (c >= 0 && c <= 255) ? values[c][2] : 0; }; }; class sexp_string_t; class sexp_list_t; class sexp_output_stream_t; class sexp_input_stream_t; /* * SEXP simple string */ typedef uint8_t octet_t; class SEXP_PUBLIC_SYMBOL sexp_simple_string_t : public std::basic_string, private sexp_char_defs_t { public: sexp_simple_string_t(void) = default; sexp_simple_string_t(const octet_t *dt) : std::basic_string{dt} {} sexp_simple_string_t(const octet_t *bt, size_t ln) : std::basic_string{bt, ln} {} sexp_simple_string_t &append(int c) { (*this) += (octet_t)(c & 0xFF); return *this; } // Returns length for printing simple string as a token size_t advanced_length_token(void) const { return length(); } // Returns length for printing simple string as a base64 string size_t advanced_length_base64(void) const { return (2 + 4 * ((length() + 2) / 3)); } // Returns length for printing simple string ss in quoted-string mode size_t advanced_length_quoted(void) const { return (1 + length() + 1); } // Returns length for printing simple string ss in hexadecimal mode size_t advanced_length_hexadecimal(void) const { return (1 + 2 * length() + 1); } size_t advanced_length(sexp_output_stream_t *os) const; sexp_output_stream_t *print_canonical_verbatim(sexp_output_stream_t *os) const; sexp_output_stream_t *print_advanced(sexp_output_stream_t *os) const; sexp_output_stream_t *print_token(sexp_output_stream_t *os) const; sexp_output_stream_t *print_quoted(sexp_output_stream_t *os) const; sexp_output_stream_t *print_hexadecimal(sexp_output_stream_t *os) const; sexp_output_stream_t *print_base64(sexp_output_stream_t *os) const; bool can_print_as_quoted_string(void) const; bool can_print_as_token(const sexp_output_stream_t *os) const; bool operator==(const char *right) const noexcept { return length() == std::strlen(right) && std::memcmp(data(), right, length()) == 0; } bool operator!=(const char *right) const noexcept { return length() != std::strlen(right) || std::memcmp(data(), right, length()) != 0; } unsigned as_unsigned() const noexcept { return empty() ? std::numeric_limits::max() : (unsigned) atoi(reinterpret_cast(c_str())); } }; inline bool operator==(const sexp_simple_string_t *left, const std::string &right) noexcept { return *left == right.c_str(); } inline bool operator!=(const sexp_simple_string_t *left, const std::string &right) noexcept { return *left != right.c_str(); } /* * SEXP object */ class SEXP_PUBLIC_SYMBOL sexp_object_t { public: virtual ~sexp_object_t(){}; virtual sexp_output_stream_t *print_canonical(sexp_output_stream_t *os) const = 0; virtual sexp_output_stream_t *print_advanced(sexp_output_stream_t *os) const; virtual size_t advanced_length(sexp_output_stream_t *os) const = 0; virtual sexp_list_t * sexp_list_view(void) noexcept { return nullptr; } virtual sexp_string_t *sexp_string_view(void) noexcept { return nullptr; } virtual bool is_sexp_list(void) const noexcept { return false; } virtual bool is_sexp_string(void) const noexcept { return false; } virtual const sexp_list_t *sexp_list_at( std::vector>::size_type pos) const noexcept { return nullptr; } virtual const sexp_string_t *sexp_string_at( std::vector>::size_type pos) const noexcept { return nullptr; } virtual const sexp_simple_string_t *sexp_simple_string_at( std::vector>::size_type pos) const noexcept { return nullptr; } virtual bool operator==(const char *right) const noexcept { return false; } virtual bool operator!=(const char *right) const noexcept { return true; } virtual unsigned as_unsigned() const noexcept { return std::numeric_limits::max(); } }; /* * SEXP string */ class SEXP_PUBLIC_SYMBOL sexp_string_t : public sexp_object_t { protected: bool with_presentation_hint; sexp_simple_string_t presentation_hint; sexp_simple_string_t data_string; public: sexp_string_t(const octet_t *dt) : with_presentation_hint(false), data_string(dt) {} sexp_string_t(const octet_t *bt, size_t ln) : with_presentation_hint(false), data_string(bt, ln) { } sexp_string_t(const std::string &str) : with_presentation_hint(false), data_string(reinterpret_cast(str.data())) { } sexp_string_t(void) : with_presentation_hint(false) {} sexp_string_t(sexp_input_stream_t *sis) { parse(sis); }; const bool has_presentation_hint(void) const noexcept { return with_presentation_hint; } const sexp_simple_string_t &get_string(void) const noexcept { return data_string; } const sexp_simple_string_t &set_string(const sexp_simple_string_t &ss) { return data_string = ss; } const sexp_simple_string_t &get_presentation_hint(void) const noexcept { return presentation_hint; } const sexp_simple_string_t &set_presentation_hint(const sexp_simple_string_t &ph) { with_presentation_hint = true; return presentation_hint = ph; } virtual sexp_output_stream_t *print_canonical(sexp_output_stream_t *os) const; virtual sexp_output_stream_t *print_advanced(sexp_output_stream_t *os) const; virtual size_t advanced_length(sexp_output_stream_t *os) const; virtual sexp_string_t *sexp_string_view(void) noexcept { return this; } virtual bool is_sexp_string(void) const noexcept { return true; } virtual bool operator==(const char *right) const noexcept { return data_string == right; } virtual bool operator!=(const char *right) const noexcept { return data_string != right; } void parse(sexp_input_stream_t *sis); virtual unsigned as_unsigned() const noexcept { return data_string.as_unsigned(); } }; inline bool operator==(const sexp_string_t *left, const std::string &right) noexcept { return *left == right.c_str(); } inline bool operator!=(const sexp_string_t *left, const std::string &right) noexcept { return *left != right.c_str(); } /* * SEXP list */ class SEXP_PUBLIC_SYMBOL sexp_list_t : public sexp_object_t, public std::vector> { public: virtual ~sexp_list_t() {} virtual sexp_output_stream_t *print_canonical(sexp_output_stream_t *os) const; virtual sexp_output_stream_t *print_advanced(sexp_output_stream_t *os) const; virtual size_t advanced_length(sexp_output_stream_t *os) const; virtual sexp_list_t *sexp_list_view(void) noexcept { return this; } virtual bool is_sexp_list(void) const noexcept { return true; } virtual const sexp_list_t *sexp_list_at(size_type pos) const noexcept { return pos < size() ? (*at(pos)).sexp_list_view() : nullptr; } virtual const sexp_string_t *sexp_string_at(size_type pos) const noexcept { return pos < size() ? (*at(pos)).sexp_string_view() : nullptr; } const sexp_simple_string_t *sexp_simple_string_at(size_type pos) const noexcept { auto s = sexp_string_at(pos); return s != nullptr ? &s->get_string() : nullptr; } void parse(sexp_input_stream_t *sis); }; /* sexp_depth_manager controls maximum allowed nesting of sexp lists for sexp_input_stream, sexp_output_stream processing One still can create an object with deeper nesting manually */ class SEXP_PUBLIC_SYMBOL sexp_depth_manager { public: static const size_t DEFAULT_MAX_DEPTH = 1024; private: size_t depth; /* current depth of nested SEXP lists */ size_t max_depth; /* maximum allowed depth of nested SEXP lists, 0 if no limit */ protected: sexp_depth_manager(size_t m_depth = DEFAULT_MAX_DEPTH); void reset_depth(size_t m_depth); void increase_depth(int count = -1); void decrease_depth(void); }; /* * SEXP input stream */ class SEXP_PUBLIC_SYMBOL sexp_input_stream_t : public sexp_char_defs_t, sexp_depth_manager { protected: std::istream *input_file; uint32_t byte_size; /* 4 or 6 or 8 == currently scanning mode */ int next_char; /* character currently being scanned */ uint32_t bits; /* Bits waiting to be used */ uint32_t n_bits; /* number of such bits waiting to be used */ int count; /* number of 8-bit characters output by get_char */ virtual int read_char(void); public: sexp_input_stream_t(std::istream *i, size_t max_depth = sexp_depth_manager::DEFAULT_MAX_DEPTH); virtual ~sexp_input_stream_t() = default; sexp_input_stream_t * set_input(std::istream *i, size_t max_depth = sexp_depth_manager::DEFAULT_MAX_DEPTH); sexp_input_stream_t * set_byte_size(uint32_t new_byte_size); uint32_t get_byte_size(void) { return byte_size; } sexp_input_stream_t * get_char(void); sexp_input_stream_t * skip_white_space(void); sexp_input_stream_t * skip_char(int c); std::shared_ptr scan_to_eof(); std::shared_ptr scan_object(void); std::shared_ptr scan_string(void); std::shared_ptr scan_list(void); sexp_simple_string_t scan_simple_string(void); void scan_token(sexp_simple_string_t &ss); void scan_verbatim_string(sexp_simple_string_t &ss, uint32_t length); void scan_quoted_string(sexp_simple_string_t &ss, uint32_t length); void scan_hexadecimal_string(sexp_simple_string_t &ss, uint32_t length); void scan_base64_string(sexp_simple_string_t &ss, uint32_t length); uint32_t scan_decimal_string(void); int get_next_char(void) const { return next_char; } int set_next_char(int c) { return next_char = c; } sexp_input_stream_t *open_list(void); sexp_input_stream_t *close_list(void); }; /* * SEXP output stream */ class SEXP_PUBLIC_SYMBOL sexp_output_stream_t : sexp_depth_manager { public: const uint32_t default_line_length = 75; enum sexp_print_mode { /* PRINTING MODES */ canonical = 1, /* standard for hashing and tranmission */ base64 = 2, /* base64 version of canonical */ advanced = 3 /* pretty-printed */ }; protected: std::ostream * output_file; uint32_t base64_count; /* number of hex or base64 chars printed this region */ uint32_t byte_size; /* 4 or 6 or 8 depending on output mode */ uint32_t bits; /* bits waiting to go out */ uint32_t n_bits; /* number of bits waiting to go out */ sexp_print_mode mode; /* base64, advanced, or canonical */ uint32_t column; /* column where next character will go */ uint32_t max_column; /* max usable column, or 0 if no maximum */ uint32_t indent; /* current indentation level (starts at 0) */ public: sexp_output_stream_t(std::ostream *o, size_t max_depth = sexp_depth_manager::DEFAULT_MAX_DEPTH); sexp_output_stream_t *set_output(std::ostream *o, size_t max_depth = sexp_depth_manager::DEFAULT_MAX_DEPTH); sexp_output_stream_t *put_char(int c); /* output a character */ sexp_output_stream_t *new_line(sexp_print_mode mode); /* go to next line (and indent) */ sexp_output_stream_t *var_put_char(int c); sexp_output_stream_t *flush(void); sexp_output_stream_t *print_decimal(uint64_t n); sexp_output_stream_t *change_output_byte_size(int newByteSize, sexp_print_mode mode); sexp_output_stream_t *print_canonical(const std::shared_ptr &obj) { return obj->print_canonical(this); } sexp_output_stream_t *print_advanced(const std::shared_ptr &obj) { return obj->print_advanced(this); }; sexp_output_stream_t *print_base64(const std::shared_ptr &obj); sexp_output_stream_t *print_canonical(const sexp_simple_string_t *ss) { return ss->print_canonical_verbatim(this); } sexp_output_stream_t *print_advanced(const sexp_simple_string_t *ss) { return ss->print_advanced(this); }; uint32_t get_byte_size(void) const { return byte_size; } uint32_t get_column(void) const { return column; } sexp_output_stream_t *reset_column(void) { column = 0; return this; } uint32_t get_max_column(void) const { return max_column; } sexp_output_stream_t *set_max_column(uint32_t mc) { max_column = mc; return this; } sexp_output_stream_t *inc_indent(void) { ++indent; return this; } sexp_output_stream_t *dec_indent(void) { --indent; return this; } sexp_output_stream_t *open_list(void) { put_char('('); increase_depth(); return this; } sexp_output_stream_t *close_list(void) { put_char(')')->decrease_depth(); return this; } sexp_output_stream_t *var_open_list(void) { var_put_char('(')->increase_depth(); return this; } sexp_output_stream_t *var_close_list(void) { var_put_char(')')->decrease_depth(); return this; } }; } // namespace sexp sexpp-0.8.7/man/000077500000000000000000000000001444627452400134545ustar00rootroot00000000000000sexpp-0.8.7/man/sexpp.1000066400000000000000000000027561444627452400147070ustar00rootroot00000000000000.TH SEXPP "1" "June 2023" "sexpp" "User Commands" .SH NAME sexpp - Read, parse, and print out S-expressions .SH SYNOPSIS .B cat certificate-file | sexpp -a -x .SH DESCRIPTION \fBsexpp\fP typically reads an S-expression from standard input and rewrites it to standard output. Running without switches implies: -p -a -b -c -x .SH INPUT OPTIONS .B -i filename Takes input from file instead of stdin. .TP .B -p Prompts user for console input. .TP .B -s Treat input up to EOF as a single string, instead of parsing. .SH CONTROL LOOP The main routine typically reads one S-expression, prints it out again, and stops. This may be modified: .TP .B -x Execute main loop repeatedly until end of file. .SH OUTPUT OPTIONS The output format is normally canonical, but this can be changed. More than one output format can be requested at once. .TP .B -o filename Write output to file instead of stdout. .TP .B -a Write output in advanced transport format. .TP .B -b Write output in base-64 output format. .TP .B -c Write output in canonical format. .TP .B -l Suppress linefeeds after output. .TP .B -w width Changes line width to specified width (0 implies no line-width constraint). Default: 75 .SH AUTHOR The \fBsexpp\fP project is maintained by Maxim Samsonov on behalf of Ribose, Inc. It is based on code from Ron Rivest and Butler Lampson. This manual page was written by Daniel Kahn Gillmor for the Debian project, but may be used by others. .SH SEE ALSO https://datatracker.ietf.org/doc/draft-rivest-sexp/ sexpp-0.8.7/samples/000077500000000000000000000000001444627452400143455ustar00rootroot00000000000000sexpp-0.8.7/samples/baseline/000077500000000000000000000000001444627452400161275ustar00rootroot00000000000000sexpp-0.8.7/samples/baseline/sexp-sample-a000066400000000000000000000007751444627452400205370ustar00rootroot00000000000000(certificate (issuer (name (public-key rsa-with-md5 (e |NFGq/E3wh9f4rJIQVXhS|) (n |d738/4ghP9rFZ0gAIYZ5q9y6iskDJwASi5rEQpEQq8ZyMZeIZzIAR2I5iGE=|)) aid-committee)) (subject (ref (public-key rsa-with-md5 (e |NFGq/E3wh9f4rJIQVXhS|) (n |d738/4ghP9rFZ0gAIYZ5q9y6iskDJwASi5rEQpEQq8ZyMZeIZzIAR2I5iGE=|)) tom mother)) (not-before "1997-01-01_09:00:00") (not-after "1998-01-01_09:00:00") (tag (spend (account "12345678") (* numeric range "1" "1000"))))sexpp-0.8.7/samples/baseline/sexp-sample-b000066400000000000000000000011031444627452400205220ustar00rootroot00000000000000{KDExOmNlcnRpZmljYXRlKDY6aXNzdWVyKDQ6bmFtZSgxMDpwdWJsaWMta2V5MTI6cnNhLXdpdGgtbWQ1KDE6ZTE1OjRRqvxN8IfX+KySEFV4UikoMTpuNDQ6d738/4ghP9rFZ0gAIYZ5q9y6iskDJwASi5rEQpEQq8ZyMZeIZzIAR2I5iGEpKTEzOmFpZC1jb21taXR0ZWUpKSg3OnN1YmplY3QoMzpyZWYoMTA6cHVibGljLWtleTEyOnJzYS13aXRoLW1kNSgxOmUxNTo0Uar8TfCH1/iskhBVeFIpKDE6bjQ0One9/P+IIT/axWdIACGGeavcuorJAycAEouaxEKREKvGcjGXiGcyAEdiOYhhKSkzOnRvbTY6bW90aGVyKSkoMTA6bm90LWJlZm9yZTE5OjE5OTctMDEtMDFfMDk6MDA6MDApKDk6bm90LWFmdGVyMTk6MTk5OC0wMS0wMV8wOTowMDowMCkoMzp0YWcoNTpzcGVuZCg3OmFjY291bnQ4OjEyMzQ1Njc4KSgxOio3Om51bWVyaWM1OnJhbmdlMToxNDoxMDAwKSkpKQ==} sexpp-0.8.7/samples/baseline/sexp-sample-c000066400000000000000000000006561444627452400205370ustar00rootroot00000000000000(11:certificate(6:issuer(4:name(10:public-key12:rsa-with-md5(1:e15:4QMUxR)(1:n44:w!?gH!yܺ'Br1g2Gb9a))13:aid-committee))(7:subject(3:ref(10:public-key12:rsa-with-md5(1:e15:4QMUxR)(1:n44:w!?gH!yܺ'Br1g2Gb9a))3:tom6:mother))(10:not-before19:1997-01-01_09:00:00)(9:not-after19:1998-01-01_09:00:00)(3:tag(5:spend(7:account8:12345678)(1:*7:numeric5:range1:14:1000))))sexpp-0.8.7/samples/compat/000077500000000000000000000000001444627452400156305ustar00rootroot00000000000000sexpp-0.8.7/samples/compat/g10/000077500000000000000000000000001444627452400162175ustar00rootroot00000000000000sexpp-0.8.7/samples/compat/g10/canonical.key000066400000000000000000000013061444627452400206600ustar00rootroot00000000000000(21:protected-private-key(3:rsa(1:n129:Z~(լ)I[2+TN*D)smPrx0`K9+dDpۈ< E8t4gT(FusLc&r */ false, /* 0x3f ? */ false, /* 0x40 @ */ false, /* 0x41 A */ true, /* 0x42 B */ true, /* 0x43 C */ true, /* 0x44 D */ true, /* 0x45 E */ true, /* 0x46 F */ true, /* 0x47 G */ true, /* 0x48 H */ true, /* 0x49 I */ true, /* 0x4a J */ true, /* 0x4b K */ true, /* 0x4c L */ true, /* 0x4d M */ true, /* 0x4e N */ true, /* 0x4f O */ true, /* 0x50 P */ true, /* 0x51 Q */ true, /* 0x52 R */ true, /* 0x53 S */ true, /* 0x54 T */ true, /* 0x55 U */ true, /* 0x56 V */ true, /* 0x57 W */ true, /* 0x58 X */ true, /* 0x59 Y */ true, /* 0x5a Z */ true, /* 0x5b [ */ false, /* 0x5c \ */ false, /* 0x5d ] */ false, /* 0x5e ^ */ false, /* 0x5f _ */ false, /* 0x60 ` */ false, /* 0x61 a */ true, /* 0x62 b */ true, /* 0x63 c */ true, /* 0x64 d */ true, /* 0x65 e */ true, /* 0x66 f */ true, /* 0x67 g */ true, /* 0x68 h */ true, /* 0x69 i */ true, /* 0x6a j */ true, /* 0x6b k */ true, /* 0x6c l */ true, /* 0x6d m */ true, /* 0x6e n */ true, /* 0x6f o */ true, /* 0x70 p */ true, /* 0x71 q */ true, /* 0x72 r */ true, /* 0x73 s */ true, /* 0x74 t */ true, /* 0x75 u */ true, /* 0x76 v */ true, /* 0x77 w */ true, /* 0x78 x */ true, /* 0x79 y */ true, /* 0x7a z */ true, /* 0x7b { */ false, /* 0x7c | */ false, /* 0x7d } */ false, /* 0x7e ~ */ false, /* 0x7f */ false, /* 0x80 */ false, /* 0x81 */ false, /* 0x82 */ false, /* 0x83 */ false, /* 0x84 */ false, /* 0x85 */ false, /* 0x86 */ false, /* 0x87 */ false, /* 0x88 */ false, /* 0x89 */ false, /* 0x8a */ false, /* 0x8b */ false, /* 0x8c */ false, /* 0x8d */ false, /* 0x8e */ false, /* 0x8f */ false, /* 0x90 */ false, /* 0x91 */ false, /* 0x92 */ false, /* 0x93 */ false, /* 0x94 */ false, /* 0x95 */ false, /* 0x96 */ false, /* 0x97 */ false, /* 0x98 */ false, /* 0x99 */ false, /* 0x9a */ false, /* 0x9b */ false, /* 0x9c */ false, /* 0x9d */ false, /* 0x9e */ false, /* 0x9f */ false, /* 0xa0 */ false, /* 0xa1 */ false, /* 0xa2 */ false, /* 0xa3 */ false, /* 0xa4 */ false, /* 0xa5 */ false, /* 0xa6 */ false, /* 0xa7 */ false, /* 0xa8 */ false, /* 0xa9 */ false, /* 0xaa */ false, /* 0xab */ false, /* 0xac */ false, /* 0xad */ false, /* 0xae */ false, /* 0xaf */ false, /* 0xb0 */ false, /* 0xb1 */ false, /* 0xb2 */ false, /* 0xb3 */ false, /* 0xb4 */ false, /* 0xb5 */ false, /* 0xb6 */ false, /* 0xb7 */ false, /* 0xb8 */ false, /* 0xb9 */ false, /* 0xba */ false, /* 0xbb */ false, /* 0xbc */ false, /* 0xbd */ false, /* 0xbe */ false, /* 0xbf */ false, /* 0xc0 */ false, /* 0xc1 */ false, /* 0xc2 */ false, /* 0xc3 */ false, /* 0xc4 */ false, /* 0xc5 */ false, /* 0xc6 */ false, /* 0xc7 */ false, /* 0xc8 */ false, /* 0xc9 */ false, /* 0xca */ false, /* 0xcb */ false, /* 0xcc */ false, /* 0xcd */ false, /* 0xce */ false, /* 0xcf */ false, /* 0xd0 */ false, /* 0xd1 */ false, /* 0xd2 */ false, /* 0xd3 */ false, /* 0xd4 */ false, /* 0xd5 */ false, /* 0xd6 */ false, /* 0xd7 */ false, /* 0xd8 */ false, /* 0xd9 */ false, /* 0xda */ false, /* 0xdb */ false, /* 0xdc */ false, /* 0xdd */ false, /* 0xde */ false, /* 0xdf */ false, /* 0xe0 */ false, /* 0xe1 */ false, /* 0xe2 */ false, /* 0xe3 */ false, /* 0xe4 */ false, /* 0xe5 */ false, /* 0xe6 */ false, /* 0xe7 */ false, /* 0xe8 */ false, /* 0xe9 */ false, /* 0xea */ false, /* 0xeb */ false, /* 0xec */ false, /* 0xed */ false, /* 0xee */ false, /* 0xef */ false, /* 0xf0 */ false, /* 0xf1 */ false, /* 0xf2 */ false, /* 0xf3 */ false, /* 0xf4 */ false, /* 0xf5 */ false, /* 0xf6 */ false, /* 0xf7 */ false, /* 0xf8 */ false, /* 0xf9 */ false, /* 0xfa */ false, /* 0xfb */ false, /* 0xfc */ false, /* 0xfd */ false, /* 0xfe */ false}; /* * ext_key_input_stream_t::skip_line */ int ext_key_input_stream_t::skip_line(void) { int c; do { c = input_file->get(); } while (!is_newline_char(c) && c != EOF); return c; } /* * ext_key_input_stream_t::read_char */ int ext_key_input_stream_t::read_char(void) { int lookahead_1 = input_file->get(); count++; if (is_scanning_value && is_newline_char(lookahead_1)) { while (true) { int lookahead_2 = input_file->peek(); if (lookahead_1 == '\r' && lookahead_2 == '\n') { lookahead_1 = input_file->get(); count++; lookahead_2 = input_file->peek(); } if (lookahead_2 == ' ') { input_file->get(); count++; lookahead_2 = input_file->peek(); if (lookahead_2 == '#') { lookahead_1 = skip_line(); continue; } if (is_newline_char(lookahead_2)) { lookahead_1 = lookahead_2; continue; } lookahead_1 = input_file->get(); count++; } return lookahead_1; } } return lookahead_1; } /* * ext_key_input_stream_t::scan_name * A name must start with a letter and end with a colon. Valid characters are all ASCII * letters, numbers and the hyphen. Comparison of names is done case insensitively. Names may * be used several times to represent an array of values. Note that the name “Key” is special * in that it is madandory must occur only once. */ std::string ext_key_input_stream_t::scan_name(int c) { std::string name; if (!is_alpha(c)) { ext_key_error(sexp_exception_t::error, isprint(next_char) ? "unexpected character '%c' (0x%x) found starting a name field" : "unexpected character '0x%x' found starting a name field", c, c, count); } else { name += (char) c; c = read_char(); while (c != ':') { if (c == EOF) { ext_key_error(sexp_exception_t::error, "unexpected end of file", 0, 0, count); } if (is_newline_char(c)) { ext_key_error(sexp_exception_t::error, "unexpected end of line", 0, 0, count); } if (!is_namechar(c)) { ext_key_error(sexp_exception_t::error, isprint(next_char) ? "unexpected character '%c' (0x%x) found in a name field" : "unexpected character '0x%x' found in a name field", c, c, count); } name += (int) c; c = read_char(); } } return name; } /* * ext_key_input_stream_t::scan_value * Values are UTF-8 encoded strings. Values can be wrapped at any point, and continued in * the next line indicated by leading whitespace. A continuation line with one leading space * does not introduce a blank so that the lines can be effectively concatenated. A blank * line as part of a continuation line encodes a newline. */ std::string ext_key_input_stream_t::scan_value(void) { std::string value; int c; do { c = read_char(); } while (is_white_space(c)); while (c != EOF && !is_newline_char(c)) { value += c; c = read_char(); } return value; } /* * ext_key_input_stream_t::scan * GnuPG 2.3+ uses a new format to store private keys that is both more flexible and easier to * read and edit by human beings. The new format stores name, value-pairs using the common mail * and http header convention. */ void ext_key_input_stream_t::scan(extended_private_key_t &res) { set_byte_size(8); int c = read_char(); if (c == '(') { set_next_char(c); res.key.parse(this); has_key = true; } else { while (c != EOF) { // Comparison of names is done case insensitively std::string name = scan_name(c); // The name “Key” is special in that it is mandatory and must occur only once. // The associated value holds the actual S-expression with the cryptographic key. // The S-expression is formatted using the ‘Advanced Format’ // (GCRYSEXP_FMT_ADVANCED) that avoids non-printable characters so that the file // can be easily inspected and edited. is_scanning_value = true; if (extended_private_key_t::iequals(name, "key")) { if (has_key) { ext_key_error(sexp_exception_t::error, "'key' field must occur only once", 0, 0, count); } do { c = read_char(); } while (is_white_space(c)); set_next_char(c); res.key.parse(this); has_key = true; } else { std::string value = scan_value(); res.fields.insert(std::pair{name, value}); } c = read_char(); is_scanning_value = false; } } if (!has_key) { ext_key_error(sexp_exception_t::error, "missing mandatory 'key' field", 0, 0, count); } } /* * extended_private_key_t::parse */ void extended_private_key_t::parse(ext_key_input_stream_t &is) { is.scan(*this); } } // namespace ext_key_formatsexpp-0.8.7/src/sexp-char-defs.cpp000066400000000000000000000513571444627452400170200ustar00rootroot00000000000000/** * * Copyright 2021-2023 Ribose Inc. (https://www.ribose.com) * * Permission is hereby granted, free of charge, to any person obtaining a copy of * this software and associated documentation files (the "Software"), to deal in * the Software without restriction, including without limitation the rights to * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of * the Software, and to permit persons to whom the Software is furnished to do so, * subject to the following conditions: * * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * * Original copyright * * SEXP implementation code sexp-input.c * Ron Rivest * 7/21/1997 */ #include "sexpp/sexp.h" namespace sexp { /**************************************/ /* CHARACTER ROUTINES AND DEFINITIONS */ /**************************************/ std::locale sexp_char_defs_t::c_locale{"C"}; const unsigned char sexp_char_defs_t::values[256][3] = {/* values of c as { dec. hex, base64 } digit */ {/* 0x00 */ 0x00, 0x00, 0x00}, {/* 0x01 */ 0x00, 0x00, 0x00}, {/* 0x02 */ 0x00, 0x00, 0x00}, {/* 0x03 */ 0x00, 0x00, 0x00}, {/* 0x04 */ 0x00, 0x00, 0x00}, {/* 0x05 */ 0x00, 0x00, 0x00}, {/* 0x06 */ 0x00, 0x00, 0x00}, {/* 0x07 */ 0x00, 0x00, 0x00}, {/* 0x08 */ 0x00, 0x00, 0x00}, {/* 0x09 */ 0x00, 0x00, 0x00}, {/* 0x0a */ 0x00, 0x00, 0x00}, {/* 0x0b */ 0x00, 0x00, 0x00}, {/* 0x0c */ 0x00, 0x00, 0x00}, {/* 0x0d */ 0x00, 0x00, 0x00}, {/* 0x0e */ 0x00, 0x00, 0x00}, {/* 0x0f */ 0x00, 0x00, 0x00}, {/* 0x10 */ 0x00, 0x00, 0x00}, {/* 0x11 */ 0x00, 0x00, 0x00}, {/* 0x12 */ 0x00, 0x00, 0x00}, {/* 0x13 */ 0x00, 0x00, 0x00}, {/* 0x14 */ 0x00, 0x00, 0x00}, {/* 0x15 */ 0x00, 0x00, 0x00}, {/* 0x16 */ 0x00, 0x00, 0x00}, {/* 0x17 */ 0x00, 0x00, 0x00}, {/* 0x18 */ 0x00, 0x00, 0x00}, {/* 0x19 */ 0x00, 0x00, 0x00}, {/* 0x1a */ 0x00, 0x00, 0x00}, {/* 0x1b */ 0x00, 0x00, 0x00}, {/* 0x1c */ 0x00, 0x00, 0x00}, {/* 0x1d */ 0x00, 0x00, 0x00}, {/* 0x1e */ 0x00, 0x00, 0x00}, {/* 0x1f */ 0x00, 0x00, 0x00}, {/* 0x20 */ 0x00, 0x00, 0x00}, {/* 0x21 ! */ 0x00, 0x00, 0x00}, {/* 0x22 " */ 0x00, 0x00, 0x00}, {/* 0x23 # */ 0x00, 0x00, 0x00}, {/* 0x24 $ */ 0x00, 0x00, 0x00}, {/* 0x25 % */ 0x00, 0x00, 0x00}, {/* 0x26 & */ 0x00, 0x00, 0x00}, {/* 0x27 ' */ 0x00, 0x00, 0x00}, {/* 0x28 ( */ 0x00, 0x00, 0x00}, {/* 0x29 ) */ 0x00, 0x00, 0x00}, {/* 0x2a * */ 0x00, 0x00, 0x00}, {/* 0x2b + */ 0x00, 0x00, 0x3e}, {/* 0x2c , */ 0x00, 0x00, 0x00}, {/* 0x2d - */ 0x00, 0x00, 0x00}, {/* 0x2e . */ 0x00, 0x00, 0x00}, {/* 0x2f / */ 0x00, 0x00, 0x3f}, {/* 0x30 0 */ 0x00, 0x00, 0x34}, {/* 0x31 1 */ 0x01, 0x01, 0x35}, {/* 0x32 2 */ 0x02, 0x02, 0x36}, {/* 0x33 3 */ 0x03, 0x03, 0x37}, {/* 0x34 4 */ 0x04, 0x04, 0x38}, {/* 0x35 5 */ 0x05, 0x05, 0x39}, {/* 0x36 6 */ 0x06, 0x06, 0x3a}, {/* 0x37 7 */ 0x07, 0x07, 0x3b}, {/* 0x38 8 */ 0x08, 0x08, 0x3c}, {/* 0x39 9 */ 0x09, 0x09, 0x3d}, {/* 0x3a : */ 0x00, 0x00, 0x00}, {/* 0x3b ; */ 0x00, 0x00, 0x00}, {/* 0x3c < */ 0x00, 0x00, 0x00}, {/* 0x3d = */ 0x00, 0x00, 0x00}, {/* 0x3e > */ 0x00, 0x00, 0x00}, {/* 0x3f ? */ 0x00, 0x00, 0x00}, {/* 0x40 @ */ 0x00, 0x00, 0x00}, {/* 0x41 A */ 0x00, 0x0a, 0x00}, {/* 0x42 B */ 0x00, 0x0b, 0x01}, {/* 0x43 C */ 0x00, 0x0c, 0x02}, {/* 0x44 D */ 0x00, 0x0d, 0x03}, {/* 0x45 E */ 0x00, 0x0e, 0x04}, {/* 0x46 F */ 0x00, 0x0f, 0x05}, {/* 0x47 G */ 0x00, 0x00, 0x06}, {/* 0x48 H */ 0x00, 0x00, 0x07}, {/* 0x49 I */ 0x00, 0x00, 0x08}, {/* 0x4a J */ 0x00, 0x00, 0x09}, {/* 0x4b K */ 0x00, 0x00, 0x0a}, {/* 0x4c L */ 0x00, 0x00, 0x0b}, {/* 0x4d M */ 0x00, 0x00, 0x0c}, {/* 0x4e N */ 0x00, 0x00, 0x0d}, {/* 0x4f O */ 0x00, 0x00, 0x0e}, {/* 0x50 P */ 0x00, 0x00, 0x0f}, {/* 0x51 Q */ 0x00, 0x00, 0x10}, {/* 0x52 R */ 0x00, 0x00, 0x11}, {/* 0x53 S */ 0x00, 0x00, 0x12}, {/* 0x54 T */ 0x00, 0x00, 0x13}, {/* 0x55 U */ 0x00, 0x00, 0x14}, {/* 0x56 V */ 0x00, 0x00, 0x15}, {/* 0x57 W */ 0x00, 0x00, 0x16}, {/* 0x58 X */ 0x00, 0x00, 0x17}, {/* 0x59 Y */ 0x00, 0x00, 0x18}, {/* 0x5a Z */ 0x00, 0x00, 0x19}, {/* 0x5b [ */ 0x00, 0x00, 0x00}, {/* 0x5c \ */ 0x00, 0x00, 0x00}, {/* 0x5d ] */ 0x00, 0x00, 0x00}, {/* 0x5e ^ */ 0x00, 0x00, 0x00}, {/* 0x5f _ */ 0x00, 0x00, 0x00}, {/* 0x60 ` */ 0x00, 0x00, 0x00}, {/* 0x61 a */ 0x00, 0x0a, 0x1a}, {/* 0x62 b */ 0x00, 0x0b, 0x1b}, {/* 0x63 c */ 0x00, 0x0c, 0x1c}, {/* 0x64 d */ 0x00, 0x0d, 0x1d}, {/* 0x65 e */ 0x00, 0x0e, 0x1e}, {/* 0x66 f */ 0x00, 0x0f, 0x1f}, {/* 0x67 g */ 0x00, 0x00, 0x20}, {/* 0x68 h */ 0x00, 0x00, 0x21}, {/* 0x69 i */ 0x00, 0x00, 0x22}, {/* 0x6a j */ 0x00, 0x00, 0x23}, {/* 0x6b k */ 0x00, 0x00, 0x24}, {/* 0x6c l */ 0x00, 0x00, 0x25}, {/* 0x6d m */ 0x00, 0x00, 0x26}, {/* 0x6e n */ 0x00, 0x00, 0x27}, {/* 0x6f o */ 0x00, 0x00, 0x28}, {/* 0x70 p */ 0x00, 0x00, 0x29}, {/* 0x71 q */ 0x00, 0x00, 0x2a}, {/* 0x72 r */ 0x00, 0x00, 0x2b}, {/* 0x73 s */ 0x00, 0x00, 0x2c}, {/* 0x74 t */ 0x00, 0x00, 0x2d}, {/* 0x75 u */ 0x00, 0x00, 0x2e}, {/* 0x76 v */ 0x00, 0x00, 0x2f}, {/* 0x77 w */ 0x00, 0x00, 0x30}, {/* 0x78 x */ 0x00, 0x00, 0x31}, {/* 0x79 y */ 0x00, 0x00, 0x32}, {/* 0x7a z */ 0x00, 0x00, 0x33}, {/* 0x7b { */ 0x00, 0x00, 0x00}, {/* 0x7c | */ 0x00, 0x00, 0x00}, {/* 0x7d } */ 0x00, 0x00, 0x00}, {/* 0x7e ~ */ 0x00, 0x00, 0x00}, {/* 0x7f */ 0x00, 0x00, 0x00}, {/* 0x80 */ 0x00, 0x00, 0x00}, {/* 0x81 */ 0x00, 0x00, 0x00}, {/* 0x82 */ 0x00, 0x00, 0x00}, {/* 0x83 */ 0x00, 0x00, 0x00}, {/* 0x84 */ 0x00, 0x00, 0x00}, {/* 0x85 */ 0x00, 0x00, 0x00}, {/* 0x86 */ 0x00, 0x00, 0x00}, {/* 0x87 */ 0x00, 0x00, 0x00}, {/* 0x88 */ 0x00, 0x00, 0x00}, {/* 0x89 */ 0x00, 0x00, 0x00}, {/* 0x8a */ 0x00, 0x00, 0x00}, {/* 0x8b */ 0x00, 0x00, 0x00}, {/* 0x8c */ 0x00, 0x00, 0x00}, {/* 0x8d */ 0x00, 0x00, 0x00}, {/* 0x8e */ 0x00, 0x00, 0x00}, {/* 0x8f */ 0x00, 0x00, 0x00}, {/* 0x90 */ 0x00, 0x00, 0x00}, {/* 0x91 */ 0x00, 0x00, 0x00}, {/* 0x92 */ 0x00, 0x00, 0x00}, {/* 0x93 */ 0x00, 0x00, 0x00}, {/* 0x94 */ 0x00, 0x00, 0x00}, {/* 0x95 */ 0x00, 0x00, 0x00}, {/* 0x96 */ 0x00, 0x00, 0x00}, {/* 0x97 */ 0x00, 0x00, 0x00}, {/* 0x98 */ 0x00, 0x00, 0x00}, {/* 0x99 */ 0x00, 0x00, 0x00}, {/* 0x9a */ 0x00, 0x00, 0x00}, {/* 0x9b */ 0x00, 0x00, 0x00}, {/* 0x9c */ 0x00, 0x00, 0x00}, {/* 0x9d */ 0x00, 0x00, 0x00}, {/* 0x9e */ 0x00, 0x00, 0x00}, {/* 0x9f */ 0x00, 0x00, 0x00}, {/* 0xa0 */ 0x00, 0x00, 0x00}, {/* 0xa1 */ 0x00, 0x00, 0x00}, {/* 0xa2 */ 0x00, 0x00, 0x00}, {/* 0xa3 */ 0x00, 0x00, 0x00}, {/* 0xa4 */ 0x00, 0x00, 0x00}, {/* 0xa5 */ 0x00, 0x00, 0x00}, {/* 0xa6 */ 0x00, 0x00, 0x00}, {/* 0xa7 */ 0x00, 0x00, 0x00}, {/* 0xa8 */ 0x00, 0x00, 0x00}, {/* 0xa9 */ 0x00, 0x00, 0x00}, {/* 0xaa */ 0x00, 0x00, 0x00}, {/* 0xab */ 0x00, 0x00, 0x00}, {/* 0xac */ 0x00, 0x00, 0x00}, {/* 0xad */ 0x00, 0x00, 0x00}, {/* 0xae */ 0x00, 0x00, 0x00}, {/* 0xaf */ 0x00, 0x00, 0x00}, {/* 0xb0 */ 0x00, 0x00, 0x00}, {/* 0xb1 */ 0x00, 0x00, 0x00}, {/* 0xb2 */ 0x00, 0x00, 0x00}, {/* 0xb3 */ 0x00, 0x00, 0x00}, {/* 0xb4 */ 0x00, 0x00, 0x00}, {/* 0xb5 */ 0x00, 0x00, 0x00}, {/* 0xb6 */ 0x00, 0x00, 0x00}, {/* 0xb7 */ 0x00, 0x00, 0x00}, {/* 0xb8 */ 0x00, 0x00, 0x00}, {/* 0xb9 */ 0x00, 0x00, 0x00}, {/* 0xba */ 0x00, 0x00, 0x00}, {/* 0xbb */ 0x00, 0x00, 0x00}, {/* 0xbc */ 0x00, 0x00, 0x00}, {/* 0xbd */ 0x00, 0x00, 0x00}, {/* 0xbe */ 0x00, 0x00, 0x00}, {/* 0xbf */ 0x00, 0x00, 0x00}, {/* 0xc0 */ 0x00, 0x00, 0x00}, {/* 0xc1 */ 0x00, 0x00, 0x00}, {/* 0xc2 */ 0x00, 0x00, 0x00}, {/* 0xc3 */ 0x00, 0x00, 0x00}, {/* 0xc4 */ 0x00, 0x00, 0x00}, {/* 0xc5 */ 0x00, 0x00, 0x00}, {/* 0xc6 */ 0x00, 0x00, 0x00}, {/* 0xc7 */ 0x00, 0x00, 0x00}, {/* 0xc8 */ 0x00, 0x00, 0x00}, {/* 0xc9 */ 0x00, 0x00, 0x00}, {/* 0xca */ 0x00, 0x00, 0x00}, {/* 0xcb */ 0x00, 0x00, 0x00}, {/* 0xcc */ 0x00, 0x00, 0x00}, {/* 0xcd */ 0x00, 0x00, 0x00}, {/* 0xce */ 0x00, 0x00, 0x00}, {/* 0xcf */ 0x00, 0x00, 0x00}, {/* 0xd0 */ 0x00, 0x00, 0x00}, {/* 0xd1 */ 0x00, 0x00, 0x00}, {/* 0xd2 */ 0x00, 0x00, 0x00}, {/* 0xd3 */ 0x00, 0x00, 0x00}, {/* 0xd4 */ 0x00, 0x00, 0x00}, {/* 0xd5 */ 0x00, 0x00, 0x00}, {/* 0xd6 */ 0x00, 0x00, 0x00}, {/* 0xd7 */ 0x00, 0x00, 0x00}, {/* 0xd8 */ 0x00, 0x00, 0x00}, {/* 0xd9 */ 0x00, 0x00, 0x00}, {/* 0xda */ 0x00, 0x00, 0x00}, {/* 0xdb */ 0x00, 0x00, 0x00}, {/* 0xdc */ 0x00, 0x00, 0x00}, {/* 0xdd */ 0x00, 0x00, 0x00}, {/* 0xde */ 0x00, 0x00, 0x00}, {/* 0xdf */ 0x00, 0x00, 0x00}, {/* 0xe0 */ 0x00, 0x00, 0x00}, {/* 0xe1 */ 0x00, 0x00, 0x00}, {/* 0xe2 */ 0x00, 0x00, 0x00}, {/* 0xe3 */ 0x00, 0x00, 0x00}, {/* 0xe4 */ 0x00, 0x00, 0x00}, {/* 0xe5 */ 0x00, 0x00, 0x00}, {/* 0xe6 */ 0x00, 0x00, 0x00}, {/* 0xe7 */ 0x00, 0x00, 0x00}, {/* 0xe8 */ 0x00, 0x00, 0x00}, {/* 0xe9 */ 0x00, 0x00, 0x00}, {/* 0xea */ 0x00, 0x00, 0x00}, {/* 0xeb */ 0x00, 0x00, 0x00}, {/* 0xec */ 0x00, 0x00, 0x00}, {/* 0xed */ 0x00, 0x00, 0x00}, {/* 0xee */ 0x00, 0x00, 0x00}, {/* 0xef */ 0x00, 0x00, 0x00}, {/* 0xf0 */ 0x00, 0x00, 0x00}, {/* 0xf1 */ 0x00, 0x00, 0x00}, {/* 0xf2 */ 0x00, 0x00, 0x00}, {/* 0xf3 */ 0x00, 0x00, 0x00}, {/* 0xf4 */ 0x00, 0x00, 0x00}, {/* 0xf5 */ 0x00, 0x00, 0x00}, {/* 0xf6 */ 0x00, 0x00, 0x00}, {/* 0xf7 */ 0x00, 0x00, 0x00}, {/* 0xf8 */ 0x00, 0x00, 0x00}, {/* 0xf9 */ 0x00, 0x00, 0x00}, {/* 0xfa */ 0x00, 0x00, 0x00}, {/* 0xfb */ 0x00, 0x00, 0x00}, {/* 0xfc */ 0x00, 0x00, 0x00}, {/* 0xfd */ 0x00, 0x00, 0x00}, {/* 0xfe */ 0x00, 0x00, 0x00}, {/* 0xff */ 0x00, 0x00, 0x00}}; const bool sexp_char_defs_t::base64digit[256] = {/* c is base64 digit */ /* 0x00 */ false, /* 0x01 */ false, /* 0x02 */ false, /* 0x03 */ false, /* 0x04 */ false, /* 0x05 */ false, /* 0x06 */ false, /* 0x07 */ false, /* 0x08 */ false, /* 0x09 */ false, /* 0x0a */ false, /* 0x0b */ false, /* 0x0c */ false, /* 0x0d */ false, /* 0x0e */ false, /* 0x0f */ false, /* 0x10 */ false, /* 0x11 */ false, /* 0x12 */ false, /* 0x13 */ false, /* 0x14 */ false, /* 0x15 */ false, /* 0x16 */ false, /* 0x17 */ false, /* 0x18 */ false, /* 0x19 */ false, /* 0x1a */ false, /* 0x1b */ false, /* 0x1c */ false, /* 0x1d */ false, /* 0x1e */ false, /* 0x1f */ false, /* 0x20 */ false, /* 0x21 ! */ false, /* 0x22 " */ false, /* 0x23 # */ false, /* 0x24 $ */ false, /* 0x25 % */ false, /* 0x26 & */ false, /* 0x27 ' */ false, /* 0x28 ( */ false, /* 0x29 ) */ false, /* 0x2a * */ false, /* 0x2b + */ true, /* 0x2c , */ false, /* 0x2d - */ false, /* 0x2e . */ false, /* 0x2f / */ true, /* 0x30 0 */ true, /* 0x31 1 */ true, /* 0x32 2 */ true, /* 0x33 3 */ true, /* 0x34 4 */ true, /* 0x35 5 */ true, /* 0x36 6 */ true, /* 0x37 7 */ true, /* 0x38 8 */ true, /* 0x39 9 */ true, /* 0x3a : */ false, /* 0x3b ; */ false, /* 0x3c < */ false, /* 0x3d = */ false, /* 0x3e > */ false, /* 0x3f ? */ false, /* 0x40 @ */ false, /* 0x41 A */ true, /* 0x42 B */ true, /* 0x43 C */ true, /* 0x44 D */ true, /* 0x45 E */ true, /* 0x46 F */ true, /* 0x47 G */ true, /* 0x48 H */ true, /* 0x49 I */ true, /* 0x4a J */ true, /* 0x4b K */ true, /* 0x4c L */ true, /* 0x4d M */ true, /* 0x4e N */ true, /* 0x4f O */ true, /* 0x50 P */ true, /* 0x51 Q */ true, /* 0x52 R */ true, /* 0x53 S */ true, /* 0x54 T */ true, /* 0x55 U */ true, /* 0x56 V */ true, /* 0x57 W */ true, /* 0x58 X */ true, /* 0x59 Y */ true, /* 0x5a Z */ true, /* 0x5b [ */ false, /* 0x5c \ */ false, /* 0x5d ] */ false, /* 0x5e ^ */ false, /* 0x5f _ */ false, /* 0x60 ` */ false, /* 0x61 a */ true, /* 0x62 b */ true, /* 0x63 c */ true, /* 0x64 d */ true, /* 0x65 e */ true, /* 0x66 f */ true, /* 0x67 g */ true, /* 0x68 h */ true, /* 0x69 i */ true, /* 0x6a j */ true, /* 0x6b k */ true, /* 0x6c l */ true, /* 0x6d m */ true, /* 0x6e n */ true, /* 0x6f o */ true, /* 0x70 p */ true, /* 0x71 q */ true, /* 0x72 r */ true, /* 0x73 s */ true, /* 0x74 t */ true, /* 0x75 u */ true, /* 0x76 v */ true, /* 0x77 w */ true, /* 0x78 x */ true, /* 0x79 y */ true, /* 0x7a z */ true, /* 0x7b { */ false, /* 0x7c | */ false, /* 0x7d } */ false, /* 0x7e ~ */ false, /* 0x7f */ false, /* 0x80 */ false, /* 0x81 */ false, /* 0x82 */ false, /* 0x83 */ false, /* 0x84 */ false, /* 0x85 */ false, /* 0x86 */ false, /* 0x87 */ false, /* 0x88 */ false, /* 0x89 */ false, /* 0x8a */ false, /* 0x8b */ false, /* 0x8c */ false, /* 0x8d */ false, /* 0x8e */ false, /* 0x8f */ false, /* 0x90 */ false, /* 0x91 */ false, /* 0x92 */ false, /* 0x93 */ false, /* 0x94 */ false, /* 0x95 */ false, /* 0x96 */ false, /* 0x97 */ false, /* 0x98 */ false, /* 0x99 */ false, /* 0x9a */ false, /* 0x9b */ false, /* 0x9c */ false, /* 0x9d */ false, /* 0x9e */ false, /* 0x9f */ false, /* 0xa0 */ false, /* 0xa1 */ false, /* 0xa2 */ false, /* 0xa3 */ false, /* 0xa4 */ false, /* 0xa5 */ false, /* 0xa6 */ false, /* 0xa7 */ false, /* 0xa8 */ false, /* 0xa9 */ false, /* 0xaa */ false, /* 0xab */ false, /* 0xac */ false, /* 0xad */ false, /* 0xae */ false, /* 0xaf */ false, /* 0xb0 */ false, /* 0xb1 */ false, /* 0xb2 */ false, /* 0xb3 */ false, /* 0xb4 */ false, /* 0xb5 */ false, /* 0xb6 */ false, /* 0xb7 */ false, /* 0xb8 */ false, /* 0xb9 */ false, /* 0xba */ false, /* 0xbb */ false, /* 0xbc */ false, /* 0xbd */ false, /* 0xbe */ false, /* 0xbf */ false, /* 0xc0 */ false, /* 0xc1 */ false, /* 0xc2 */ false, /* 0xc3 */ false, /* 0xc4 */ false, /* 0xc5 */ false, /* 0xc6 */ false, /* 0xc7 */ false, /* 0xc8 */ false, /* 0xc9 */ false, /* 0xca */ false, /* 0xcb */ false, /* 0xcc */ false, /* 0xcd */ false, /* 0xce */ false, /* 0xcf */ false, /* 0xd0 */ false, /* 0xd1 */ false, /* 0xd2 */ false, /* 0xd3 */ false, /* 0xd4 */ false, /* 0xd5 */ false, /* 0xd6 */ false, /* 0xd7 */ false, /* 0xd8 */ false, /* 0xd9 */ false, /* 0xda */ false, /* 0xdb */ false, /* 0xdc */ false, /* 0xdd */ false, /* 0xde */ false, /* 0xdf */ false, /* 0xe0 */ false, /* 0xe1 */ false, /* 0xe2 */ false, /* 0xe3 */ false, /* 0xe4 */ false, /* 0xe5 */ false, /* 0xe6 */ false, /* 0xe7 */ false, /* 0xe8 */ false, /* 0xe9 */ false, /* 0xea */ false, /* 0xeb */ false, /* 0xec */ false, /* 0xed */ false, /* 0xee */ false, /* 0xef */ false, /* 0xf0 */ false, /* 0xf1 */ false, /* 0xf2 */ false, /* 0xf3 */ false, /* 0xf4 */ false, /* 0xf5 */ false, /* 0xf6 */ false, /* 0xf7 */ false, /* 0xf8 */ false, /* 0xf9 */ false, /* 0xfa */ false, /* 0xfb */ false, /* 0xfc */ false, /* 0xfd */ false, /* 0xfe */ false}; const bool sexp_char_defs_t::tokenchar[256] = {/* c can be in a token */ /* 0x00 */ false, /* 0x01 */ false, /* 0x02 */ false, /* 0x03 */ false, /* 0x04 */ false, /* 0x05 */ false, /* 0x06 */ false, /* 0x07 */ false, /* 0x08 */ false, /* 0x09 */ false, /* 0x0a */ false, /* 0x0b */ false, /* 0x0c */ false, /* 0x0d */ false, /* 0x0e */ false, /* 0x0f */ false, /* 0x10 */ false, /* 0x11 */ false, /* 0x12 */ false, /* 0x13 */ false, /* 0x14 */ false, /* 0x15 */ false, /* 0x16 */ false, /* 0x17 */ false, /* 0x18 */ false, /* 0x19 */ false, /* 0x1a */ false, /* 0x1b */ false, /* 0x1c */ false, /* 0x1d */ false, /* 0x1e */ false, /* 0x1f */ false, /* 0x20 */ false, /* 0x21 ! */ false, /* 0x22 " */ false, /* 0x23 # */ false, /* 0x24 $ */ false, /* 0x25 % */ false, /* 0x26 & */ false, /* 0x27 ' */ false, /* 0x28 ( */ false, /* 0x29 ) */ false, /* 0x2a * */ true, /* 0x2b + */ true, /* 0x2c , */ false, /* 0x2d - */ true, /* 0x2e . */ true, /* 0x2f / */ true, /* 0x30 0 */ true, /* 0x31 1 */ true, /* 0x32 2 */ true, /* 0x33 3 */ true, /* 0x34 4 */ true, /* 0x35 5 */ true, /* 0x36 6 */ true, /* 0x37 7 */ true, /* 0x38 8 */ true, /* 0x39 9 */ true, /* 0x3a : */ true, /* 0x3b ; */ false, /* 0x3c < */ false, /* 0x3d = */ true, /* 0x3e > */ false, /* 0x3f ? */ false, /* 0x40 @ */ false, /* 0x41 A */ true, /* 0x42 B */ true, /* 0x43 C */ true, /* 0x44 D */ true, /* 0x45 E */ true, /* 0x46 F */ true, /* 0x47 G */ true, /* 0x48 H */ true, /* 0x49 I */ true, /* 0x4a J */ true, /* 0x4b K */ true, /* 0x4c L */ true, /* 0x4d M */ true, /* 0x4e N */ true, /* 0x4f O */ true, /* 0x50 P */ true, /* 0x51 Q */ true, /* 0x52 R */ true, /* 0x53 S */ true, /* 0x54 T */ true, /* 0x55 U */ true, /* 0x56 V */ true, /* 0x57 W */ true, /* 0x58 X */ true, /* 0x59 Y */ true, /* 0x5a Z */ true, /* 0x5b [ */ false, /* 0x5c \ */ false, /* 0x5d ] */ false, /* 0x5e ^ */ false, /* 0x5f _ */ true, /* 0x60 ` */ false, /* 0x61 a */ true, /* 0x62 b */ true, /* 0x63 c */ true, /* 0x64 d */ true, /* 0x65 e */ true, /* 0x66 f */ true, /* 0x67 g */ true, /* 0x68 h */ true, /* 0x69 i */ true, /* 0x6a j */ true, /* 0x6b k */ true, /* 0x6c l */ true, /* 0x6d m */ true, /* 0x6e n */ true, /* 0x6f o */ true, /* 0x70 p */ true, /* 0x71 q */ true, /* 0x72 r */ true, /* 0x73 s */ true, /* 0x74 t */ true, /* 0x75 u */ true, /* 0x76 v */ true, /* 0x77 w */ true, /* 0x78 x */ true, /* 0x79 y */ true, /* 0x7a z */ true, /* 0x7b { */ false, /* 0x7c | */ false, /* 0x7d } */ false, /* 0x7e ~ */ false, /* 0x7f */ false, /* 0x80 */ false, /* 0x81 */ false, /* 0x82 */ false, /* 0x83 */ false, /* 0x84 */ false, /* 0x85 */ false, /* 0x86 */ false, /* 0x87 */ false, /* 0x88 */ false, /* 0x89 */ false, /* 0x8a */ false, /* 0x8b */ false, /* 0x8c */ false, /* 0x8d */ false, /* 0x8e */ false, /* 0x8f */ false, /* 0x90 */ false, /* 0x91 */ false, /* 0x92 */ false, /* 0x93 */ false, /* 0x94 */ false, /* 0x95 */ false, /* 0x96 */ false, /* 0x97 */ false, /* 0x98 */ false, /* 0x99 */ false, /* 0x9a */ false, /* 0x9b */ false, /* 0x9c */ false, /* 0x9d */ false, /* 0x9e */ false, /* 0x9f */ false, /* 0xa0 */ false, /* 0xa1 */ false, /* 0xa2 */ false, /* 0xa3 */ false, /* 0xa4 */ false, /* 0xa5 */ false, /* 0xa6 */ false, /* 0xa7 */ false, /* 0xa8 */ false, /* 0xa9 */ false, /* 0xaa */ false, /* 0xab */ false, /* 0xac */ false, /* 0xad */ false, /* 0xae */ false, /* 0xaf */ false, /* 0xb0 */ false, /* 0xb1 */ false, /* 0xb2 */ false, /* 0xb3 */ false, /* 0xb4 */ false, /* 0xb5 */ false, /* 0xb6 */ false, /* 0xb7 */ false, /* 0xb8 */ false, /* 0xb9 */ false, /* 0xba */ false, /* 0xbb */ false, /* 0xbc */ false, /* 0xbd */ false, /* 0xbe */ false, /* 0xbf */ false, /* 0xc0 */ false, /* 0xc1 */ false, /* 0xc2 */ false, /* 0xc3 */ false, /* 0xc4 */ false, /* 0xc5 */ false, /* 0xc6 */ false, /* 0xc7 */ false, /* 0xc8 */ false, /* 0xc9 */ false, /* 0xca */ false, /* 0xcb */ false, /* 0xcc */ false, /* 0xcd */ false, /* 0xce */ false, /* 0xcf */ false, /* 0xd0 */ false, /* 0xd1 */ false, /* 0xd2 */ false, /* 0xd3 */ false, /* 0xd4 */ false, /* 0xd5 */ false, /* 0xd6 */ false, /* 0xd7 */ false, /* 0xd8 */ false, /* 0xd9 */ false, /* 0xda */ false, /* 0xdb */ false, /* 0xdc */ false, /* 0xdd */ false, /* 0xde */ false, /* 0xdf */ false, /* 0xe0 */ false, /* 0xe1 */ false, /* 0xe2 */ false, /* 0xe3 */ false, /* 0xe4 */ false, /* 0xe5 */ false, /* 0xe6 */ false, /* 0xe7 */ false, /* 0xe8 */ false, /* 0xe9 */ false, /* 0xea */ false, /* 0xeb */ false, /* 0xec */ false, /* 0xed */ false, /* 0xee */ false, /* 0xef */ false, /* 0xf0 */ false, /* 0xf1 */ false, /* 0xf2 */ false, /* 0xf3 */ false, /* 0xf4 */ false, /* 0xf5 */ false, /* 0xf6 */ false, /* 0xf7 */ false, /* 0xf8 */ false, /* 0xf9 */ false, /* 0xfa */ false, /* 0xfb */ false, /* 0xfc */ false, /* 0xfd */ false, /* 0xfe */ false}; } // namespace sexp sexpp-0.8.7/src/sexp-depth-manager.cpp000066400000000000000000000032721444627452400176710ustar00rootroot00000000000000/** * * Copyright 2023 Ribose Inc. * * Permission is hereby granted, free of charge, to any person obtaining a copy of * this software and associated documentation files (the "Software"), to deal in * the Software without restriction, including without limitation the rights to * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of * the Software, and to permit persons to whom the Software is furnished to do so, * subject to the following conditions: * * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * **/ #include "sexpp/sexp.h" namespace sexp { sexp_depth_manager::sexp_depth_manager(size_t m_depth) { reset_depth(m_depth); } void sexp_depth_manager::reset_depth(size_t m_depth) { depth = 0; max_depth = m_depth; } void sexp_depth_manager::increase_depth(int count) { if (max_depth != 0 && ++depth > max_depth) sexp_error(sexp_exception_t::error, "Maximum allowed SEXP list depth (%u) is exceeded", max_depth, 0, count); } void sexp_depth_manager::decrease_depth(void) { depth--; } } // namespace sexp sexpp-0.8.7/src/sexp-error.cpp000066400000000000000000000044751444627452400163140ustar00rootroot00000000000000/** * * Copyright 2021-2023 Ribose Inc. (https://www.ribose.com) * * Permission is hereby granted, free of charge, to any person obtaining a copy of * this software and associated documentation files (the "Software"), to deal in * the Software without restriction, including without limitation the rights to * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of * the Software, and to permit persons to whom the Software is furnished to do so, * subject to the following conditions: * * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * */ #include "sexpp/sexp-error.h" namespace sexp { sexp_exception_t::severity sexp_exception_t::verbosity = sexp_exception_t::error; bool sexp_exception_t::interactive = false; std::string sexp_exception_t::format(std::string prf, std::string message, severity level, int position) { std::string r = prf + (level == error ? " ERROR: " : " WARNING: ") + message; if (position >= 0) r += " at position " + std::to_string(position); return r; }; void sexp_error( sexp_exception_t::severity level, const char *msg, size_t c1, size_t c2, int pos) { char tmp[256]; sexp_exception_t::severity l = (sexp_exception_t::severity) level; snprintf(tmp, sizeof(tmp) / sizeof(tmp[0]), msg, c1, c2); if (sexp_exception_t::shall_throw(l)) throw sexp_exception_t(tmp, l, pos); if (sexp_exception_t::is_interactive()) { std::cout.flush() << std::endl << "*** " << sexp_exception_t::format("SEXP", tmp, l, pos) << " ***" << std::endl; } } } // namespace sexpsexpp-0.8.7/src/sexp-input.cpp000066400000000000000000000377351444627452400163270ustar00rootroot00000000000000/** * * Copyright 2021-2023 Ribose Inc. (https://www.ribose.com) * * Permission is hereby granted, free of charge, to any person obtaining a copy of * this software and associated documentation files (the "Software"), to deal in * the Software without restriction, including without limitation the rights to * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of * the Software, and to permit persons to whom the Software is furnished to do so, * subject to the following conditions: * * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * * Original copyright * * SEXP implementation code sexp-input.c * Ron Rivest * 7/21/1997 */ #include "sexpp/sexp.h" namespace sexp { /* * sexp_input_stream_t::sexp_input_stream_t * Creates and initializes new sexp_input_stream_t object. */ sexp_input_stream_t::sexp_input_stream_t(std::istream *i, size_t m_depth) { set_input(i, m_depth); } /* * sexp_input_stream_t::set_input(std::istream *i, size_t m_depth) */ sexp_input_stream_t *sexp_input_stream_t::set_input(std::istream *i, size_t m_depth) { input_file = i; byte_size = 8; next_char = ' '; bits = 0; n_bits = 0; count = -1; reset_depth(m_depth); return this; } /* * sexp_input_stream_t::set_byte_size(newByteSize) */ sexp_input_stream_t *sexp_input_stream_t::set_byte_size(uint32_t newByteSize) { byte_size = newByteSize; n_bits = 0; bits = 0; return this; } int sexp_input_stream_t::read_char(void) { count++; return input_file->get(); } /* * sexp_input_stream_t::get_char() * This is one possible character input routine for an input stream. * (This version uses the standard input stream.) * get_char places next 8-bit character into is->next_char. * It also updates the count of number of 8-bit characters read. * The value EOF is obtained when no more input is available. * This code handles 4-bit/6-bit/8-bit channels. */ sexp_input_stream_t *sexp_input_stream_t::get_char(void) { int c; if (next_char == EOF) { byte_size = 8; return this; } while (true) { c = next_char = read_char(); if (c == EOF) return this; if ((byte_size == 6 && (c == '|' || c == '}')) || (byte_size == 4 && (c == '#'))) { // end of region reached; return terminating character, after checking for // unused bits if (n_bits > 0 && (((1 << n_bits) - 1) & bits) != 0) { sexp_error(sexp_exception_t::warning, "%d-bit region ended with %d unused bits left-over", byte_size, n_bits, count); } return set_byte_size(8); } else if (byte_size != 8 && is_white_space(c)) ; /* ignore white space in hex and base64 regions */ else if (byte_size == 6 && c == '=') ; /* ignore equals signs in base64 regions */ else if (byte_size == 8) { return this; } else if (byte_size < 8) { bits = bits << byte_size; n_bits += byte_size; if (byte_size == 6 && is_base64_digit(c)) bits = bits | base64value(c); else if (byte_size == 4 && is_hex_digit(c)) bits = bits | hexvalue(c); else { sexp_error(sexp_exception_t::error, "character '%c' found in %u-bit coding region", next_char, byte_size, count); } if (n_bits >= 8) { next_char = (bits >> (n_bits - 8)) & 0xFF; n_bits -= 8; return this; } } } } /* * sexp_input_stream_t::skip_white_space * Skip over any white space on the given sexp_input_stream_t. */ sexp_input_stream_t *sexp_input_stream_t::skip_white_space(void) { while (is_white_space(next_char)) get_char(); return this; } /* * sexp_input_stream_t::skip_char(c) * Skip the following input character on input stream is, if it is * equal to the character c. If it is not equal, then an error occurs. */ sexp_input_stream_t *sexp_input_stream_t::skip_char(int c) { if (next_char != c) sexp_error(sexp_exception_t::error, "character '%c' found where '%c' was expected", next_char, c, count); return get_char(); } /* * sexp_input_stream_t::scan_token(ss) * scan one or more characters into simple string ss as a token. */ void sexp_input_stream_t::scan_token(sexp_simple_string_t &ss) { skip_white_space(); while (is_token_char(next_char)) { ss.append(next_char); get_char(); } } /* * sexp_input_stream_t::scan_to_eof(void) * scan one or more characters (until EOF reached) * return an object that is just that string */ std::shared_ptr sexp_input_stream_t::scan_to_eof(void) { sexp_simple_string_t ss; skip_white_space(); while (next_char != EOF) { ss.append(next_char); get_char(); } auto s = std::make_shared(); s->set_string(ss); return s; } /* * scan_decimal_string(is) * returns long integer that is value of decimal number */ uint32_t sexp_input_stream_t::scan_decimal_string(void) { uint32_t value = 0; uint32_t i = 0; while (is_dec_digit(next_char)) { value = value * 10 + decvalue(next_char); get_char(); if (i++ > 8) sexp_error(sexp_exception_t::error, "Decimal number is too long", 0, 0, count); } return value; } /* * sexp_input_stream_t::scan_verbatim_string(is,ss,length) * Reads verbatim string of given length into simple string ss. */ void sexp_input_stream_t::scan_verbatim_string(sexp_simple_string_t &ss, uint32_t length) { skip_white_space()->skip_char(':'); // Some length is specified always, this is ensured by the caller's logic assert(length != std::numeric_limits::max()); for (uint32_t i = 0; i < length; i++) { ss.append(next_char); get_char(); } } /* * sexp_input_stream_t::scan_quoted_string(ss,length) * Reads quoted string of given length into simple string ss. * Handles ordinary C escapes. * If of indefinite length, length is std::numeric_limits::max(). */ void sexp_input_stream_t::scan_quoted_string(sexp_simple_string_t &ss, uint32_t length) { skip_char('"'); while (ss.length() <= length) { if (next_char == '\"') { if (length == std::numeric_limits::max() || (ss.length() == length)) { skip_char('\"'); return; } else sexp_error(sexp_exception_t::error, "Declared length was %d, but quoted string ended too early", (int) length, 0, count); } else if (next_char == '\\') /* handle escape sequence */ { get_char(); switch (next_char) { case 'b': ss.append('\b'); break; case 't': ss.append('\t'); break; case 'v': ss.append('\v'); break; case 'n': ss.append('\n'); break; case 'f': ss.append('\f'); break; case 'r': ss.append('\r'); break; case '\"': ss.append('\"'); break; case '\'': ss.append('\''); break; case '\\': ss.append('\\'); break; case 'x': /* hexadecimal number */ { int j, val; val = 0; get_char(); for (j = 0; j < 2; j++) { if (is_hex_digit(next_char)) { val = ((val << 4) | hexvalue(next_char)); if (j < 1) { get_char(); } } else sexp_error(sexp_exception_t::error, "Hex character \x5cx%x... too short", val, 0, count); } ss.append(val); } break; case '\n': /* ignore backslash line feed */ get_char(); /* also ignore following carriage-return if present */ if (next_char != '\r') continue; break; case '\r': /* ignore backslash carriage-return */ get_char(); /* also ignore following linefeed if present */ if (next_char != '\n') continue; break; case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': { /* octal number */ int j, val; val = 0; for (j = 0; j < 3; j++) { if (next_char >= '0' && next_char <= '7') { val = ((val << 3) | (next_char - '0')); if (j < 2) get_char(); } else sexp_error(sexp_exception_t::error, "Octal character \\%o... too short", val, 0, count); } if (val > 255) sexp_error(sexp_exception_t::error, "Octal character \\%o... too big", val, 0, count); ss.append(val); } break; default: sexp_error(sexp_exception_t::error, "Unknown escape sequence \\%c", next_char, 0, count); } } /* end of handling escape sequence */ else if (next_char == EOF) { sexp_error(sexp_exception_t::error, "unexpected end of file", 0, 0, count); } else { ss.append(next_char); } get_char(); } /* end of main while loop */ } /* * scan_hexadecimal_string(ss,length) * Reads hexadecimal string into simple string ss. * String is of given length result, or length = std::numeric_limits::max() * if indefinite length. */ void sexp_input_stream_t::scan_hexadecimal_string(sexp_simple_string_t &ss, uint32_t length) { set_byte_size(4)->skip_char('#'); while (next_char != EOF && (next_char != '#' || get_byte_size() == 4)) { ss.append(next_char); get_char(); } skip_char('#'); if (ss.length() != length && length != std::numeric_limits::max()) sexp_error(sexp_exception_t::warning, "Hex string has length %d different than declared length %d", ss.length(), length, count); } /* * sexp_input_stream_t::scan_base64_string(ss,length) * Reads base64 string into simple string ss. * String is of given length result, or length = std::numeric_limits::max() * if indefinite length. */ void sexp_input_stream_t::scan_base64_string(sexp_simple_string_t &ss, uint32_t length) { set_byte_size(6)->skip_char('|'); while (next_char != EOF && (next_char != '|' || get_byte_size() == 6)) { ss.append(next_char); get_char(); } skip_char('|'); if (ss.length() != length && length != std::numeric_limits::max()) sexp_error(sexp_exception_t::warning, "Base64 string has length %d different than declared length %d", ss.length(), length, count); } /* * sexp_input_stream_t::scan_simple_string(void) * Reads and returns a simple string from the input stream. * Determines type of simple string from the initial character, and * dispatches to appropriate routine based on that. */ sexp_simple_string_t sexp_input_stream_t::scan_simple_string(void) { int length; sexp_simple_string_t ss; skip_white_space(); /* Note that it is important in the following code to test for token-ness * before checking the other cases, so that a token may begin with ":", * which would otherwise be treated as a verbatim string missing a length. */ if (is_token_char(next_char) && !is_dec_digit(next_char)) { scan_token(ss); } else { length = is_dec_digit(next_char) ? scan_decimal_string() : std::numeric_limits::max(); switch (next_char) { case '\"': scan_quoted_string(ss, length); break; case '#': scan_hexadecimal_string(ss, length); break; case '|': scan_base64_string(ss, length); break; case ':': // ':' is 'tokenchar', so some length shall be defined scan_verbatim_string(ss, length); break; default: { const char *const msg = (next_char == EOF) ? "unexpected end of file" : isprint(next_char) ? "illegal character '%c' (0x%x)" : "illegal character 0x%x"; sexp_error(sexp_exception_t::error, msg, next_char, next_char, count); } } } if (ss.length() == 0) sexp_error(sexp_exception_t::warning, "Simple string has zero length", 0, 0, count); return ss; } /* * sexp_input_stream_t::scan_string(void) * Reads and returns a string [presentationhint]string from input stream. */ std::shared_ptr sexp_input_stream_t::scan_string(void) { auto s = std::make_shared(); ; s->parse(this); return s; } /* * sexp_input_stream_t::scan_list(void) * Read and return a sexp_list_t from the input stream. */ std::shared_ptr sexp_input_stream_t::scan_list(void) { auto list = std::make_shared(); list->parse(this); return list; } /* * sexp_input_stream_t::scan_object(void) * Reads and returns a sexp_object_t from the given input stream. */ std::shared_ptr sexp_input_stream_t::scan_object(void) { std::shared_ptr object; skip_white_space(); if (next_char == '{' && byte_size != 6) { set_byte_size(6)->skip_char('{'); object = scan_object(); skip_char('}'); } else { if (next_char == '(') object = scan_list(); else object = scan_string(); } return object; } /* * sexp_input_stream_t::open_list(void) */ sexp_input_stream_t *sexp_input_stream_t::open_list(void) { skip_char('('); // gcc 4.8.5 generates wrong code in case of chaining like // skip_char('(')->increase_depth(count) increase_depth(count); return this; } /* * sexp_input_stream_t::close_list(void) */ sexp_input_stream_t *sexp_input_stream_t::close_list(void) { skip_char(')'); decrease_depth(); return this; } } // namespace sexp sexpp-0.8.7/src/sexp-main.cpp000066400000000000000000000216731444627452400161060ustar00rootroot00000000000000/** * * Copyright 2021-2023 Ribose Inc. (https://www.ribose.com) * * Permission is hereby granted, free of charge, to any person obtaining a copy of * this software and associated documentation files (the "Software"), to deal in * the Software without restriction, including without limitation the rights to * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of * the Software, and to permit persons to whom the Software is furnished to do so, * subject to the following conditions: * * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * * Original copyright * * SEXP implementation code sexp-main.c * Ron Rivest * 6/29/1997 **/ #include #include "sexpp/sexp.h" using namespace sexp; const char *help = "The program 'sexp' reads, parses, and prints out S-expressions.\n" " INPUT:\n" " Input is normally taken from stdin, but this can be changed:\n" " -i filename -- takes input from file instead.\n" " -p -- prompts user for console input\n" " Input is normally parsed, but this can be changed:\n" " -s -- treat input up to EOF as a single string\n" " CONTROL LOOP:\n" " The main routine typically reads one S-expression, prints it out " "again, \n" " and stops. This may be modified:\n" " -x -- execute main loop repeatedly until EOF\n" " OUTPUT:\n" " Output is normally written to stdout, but this can be changed:\n" " -o filename -- write output to file instead\n" " The output format is normally canonical, but this can be changed:\n" " -a -- write output in advanced transport format\n" " -b -- write output in base-64 output format\n" " -c -- write output in canonical format\n" " -l -- suppress linefeeds after output\n" " More than one output format can be requested at once.\n" " There is normally a line-width of 75 on output, but:\n" " -w width -- changes line width to specified width.\n" " (0 implies no line-width constraint)\n" " Running without switches implies: -p -a -b -c -x\n" " Typical usage: cat certificate-file | sexp -a -x \n"; /*************************************************************************/ /* main(argc,argv) */ int main(int argc, char **argv) { char *c; bool swa = true, swb = true, swc = true, swp = true, sws = false, swx = true, swl = false; int i; int ret = -1; sexp_exception_t::set_interactive(true); std::ifstream * ifs = nullptr; sexp_input_stream_t * is = nullptr; std::ofstream * ofs = nullptr; sexp_output_stream_t *os = nullptr; std::string ofname; std::string ifname; try { std::shared_ptr object; is = new sexp_input_stream_t(&std::cin); os = new sexp_output_stream_t(&std::cout); if (argc > 1) swa = swb = swc = swp = sws = swx = swl = false; for (i = 1; i < argc; i++) { c = argv[i]; if (*c != '-') throw sexp_exception_t( std::string("Unrecognized switch ") + c, sexp_exception_t::error, EOF); c++; if (*c == 'a') swa = true; /* advanced output */ else if (*c == 'b') swb = true; /* base-64 output */ else if (*c == 'c') swc = true; /* canonical output */ else if (*c == 'h') { /* help */ std::cout << help; exit(0); } else if (*c == 'i') { /* input file */ if (i + 1 < argc) i++; ifs = new std::ifstream(argv[i], std::ifstream::binary); if (ifs->fail()) sexp_error(sexp_exception_t::error, "Can't open input file.", 0, 0, EOF); is->set_input(ifs); ifname = argv[i]; } else if (*c == 'l') swl = true; /* suppress linefeeds after output */ else if (*c == 'o') { /* output file */ if (i + 1 < argc) i++; ofs = new std::ofstream(argv[i], std::ifstream::binary); if (ofs->fail()) sexp_error(sexp_exception_t::error, "Can't open output file.", 0, 0, EOF); os->set_output(ofs); ofname = argv[i]; } else if (*c == 'p') swp = true; /* prompt for input */ else if (*c == 's') sws = true; /* treat input as one big string */ else if (*c == 'w') { /* set output width */ if (i + 1 < argc) i++; os->set_max_column(atoi(argv[i])); } else if (*c == 'x') swx = true; /* execute repeatedly */ else throw sexp_exception_t( std::string("Unrecognized switch ") + argv[i], sexp_exception_t::error, EOF); } if (swa == false && swb == false && swc == false) swc = true; /* must have some output format! */ /* main loop */ if (swp == 0) is->get_char(); else is->set_next_char(-2); /* this is not EOF */ while (is->get_next_char() != EOF) { if (swp) { if (ifname.empty()) std::cout << "Input:"; else std::cout << "Reading input from " << ifname; std::cout << std::endl; std::cout.flush(); } is->set_byte_size(8); if (is->get_next_char() == -2) is->get_char(); is->skip_white_space(); if (is->get_next_char() == EOF) break; object = sws ? is->scan_to_eof() : is->scan_object(); if (swp) std::cout << std::endl; if (swc) { if (swp) { if (ofname.empty()) std::cout << "Canonical output:" << std::endl; else std::cout << "Writing canonical output to '" << ofname << "'"; } object->print_canonical(os); if (!swl) { std::cout << std::endl; } } if (swb) { if (swp) { if (ofname.empty()) std::cout << "Base64 (of canonical) output:" << std::endl; else std::cout << "Writing base64 (of canonical) output to '" << ofname << "'"; } os->set_output(ofs ? ofs : &std::cout)->print_base64(object); if (!swl) { std::cout << std::endl; std::cout.flush(); } } if (swa) { if (swp) { if (ofname.empty()) std::cout << "Advanced transport output:" << std::endl; else std::cout << "Writing advanced transport output to '" << ofname << "'"; } os->set_output(ofs ? ofs : &std::cout)->print_advanced(object); if (!swl) { std::cout << std::endl; std::cout.flush(); } } if (!swx) break; if (!swp) is->skip_white_space(); else if (!swl) { std::cout << std::endl; std::cout.flush(); } } ret = 0; } catch (sexp_exception_t &e) { std::cout << e.what() << std::endl; } catch (...) { std::cout << "UNEXPECTED ERROR" << std::endl; } if (is) delete is; if (ifs) delete ifs; if (os) delete os; if (ofs) delete ofs; return ret; }sexpp-0.8.7/src/sexp-object.cpp000066400000000000000000000133041444627452400164200ustar00rootroot00000000000000/** * * Copyright 2021-2023 Ribose Inc. (https://www.ribose.com) * * Permission is hereby granted, free of charge, to any person obtaining a copy of * this software and associated documentation files (the "Software"), to deal in * the Software without restriction, including without limitation the rights to * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of * the Software, and to permit persons to whom the Software is furnished to do so, * subject to the following conditions: * * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * * Original copyright * * SEXP implementation code sexp-output.c * Ron Rivest * 5/5/1997 */ #include "sexpp/sexp.h" namespace sexp { /* * sexp_string_t::parse(sis) * Parses the strin from input stream */ void sexp_string_t::parse(sexp_input_stream_t *sis) { if (sis->get_next_char() == '[') { /* scan presentation hint */ sis->skip_char('['); set_presentation_hint(sis->scan_simple_string()); sis->skip_white_space()->skip_char(']')->skip_white_space(); } set_string(sis->scan_simple_string()); } /* * sexp_string_t::print_canonical(os) * Prints out sexp string onto output stream os */ sexp_output_stream_t *sexp_string_t::print_canonical(sexp_output_stream_t *os) const { if (with_presentation_hint) { os->var_put_char('['); presentation_hint.print_canonical_verbatim(os); os->var_put_char(']'); } data_string.print_canonical_verbatim(os); return os; } /* * sexp_string_t::print_advanced(os) * Prints out sexp string onto output stream os */ sexp_output_stream_t *sexp_string_t::print_advanced(sexp_output_stream_t *os) const { sexp_object_t::print_advanced(os); if (with_presentation_hint) { os->put_char('['); presentation_hint.print_advanced(os); os->put_char(']'); } data_string.print_advanced(os); return os; } /* * sexp_string_t::advanced_length(os) * Returns length of printed image of string */ size_t sexp_string_t::advanced_length(sexp_output_stream_t *os) const { size_t len = 0; if (with_presentation_hint) len += 2 + presentation_hint.advanced_length(os); len += data_string.advanced_length(os); return len; } /* * sexp_list_t::parse(sis) * Parses the list from input stream */ void sexp_list_t::parse(sexp_input_stream_t *sis) { sis->open_list()->skip_white_space(); if (sis->get_next_char() == ')') { ; } else { push_back(sis->scan_object()); } while (true) { sis->skip_white_space(); if (sis->get_next_char() == ')') { /* we just grabbed last element of list */ sis->close_list(); return; } else { push_back(sis->scan_object()); } } } /* * sexp_list_t::print_canonical(os) * Prints out the list "list" onto output stream os */ sexp_output_stream_t *sexp_list_t::print_canonical(sexp_output_stream_t *os) const { os->var_open_list(); std::for_each(begin(), end(), [os](const std::shared_ptr &obj) { obj->print_canonical(os); }); os->var_close_list(); return os; } /* * sexp_list_t::print_advanced(os) * Prints out the list onto output stream os. * Uses print-length to determine length of the image. If it all fits * on the current line, then it is printed that way. Otherwise, it is * written out in "vertical" mode, with items of the list starting in * the same column on successive lines. */ sexp_output_stream_t *sexp_list_t::print_advanced(sexp_output_stream_t *os) const { sexp_object_t::print_advanced(os); int vertical = false; int firstelement = true; os->open_list()->inc_indent(); vertical = (advanced_length(os) > os->get_max_column() - os->get_column()); std::for_each(begin(), end(), [&](const std::shared_ptr &obj) { if (!firstelement) { if (vertical) os->new_line(sexp_output_stream_t::advanced); else os->put_char(' '); } obj->print_advanced(os); firstelement = false; }); if (os->get_max_column() > 0 && os->get_column() > os->get_max_column() - 2) os->new_line(sexp_output_stream_t::advanced); return os->dec_indent()->put_char(')'); } /* * sexp_list_t::advanced_length(os) * Returns length of printed image of list given as iterator */ size_t sexp_list_t::advanced_length(sexp_output_stream_t *os) const { size_t len = 1; /* for left paren */ std::for_each(begin(), end(), [&](const std::shared_ptr &obj) { len += obj->advanced_length(os); }); return (len + 1); /* for final paren */ } /* * sexp_object_t::print_advanced(os) * Prints out object on output stream os */ sexp_output_stream_t *sexp_object_t::print_advanced(sexp_output_stream_t *os) const { if (os->get_max_column() > 0 && os->get_column() > os->get_max_column() - 4) os->new_line(sexp_output_stream_t::advanced); return os; } } // namespace sexpsexpp-0.8.7/src/sexp-output.cpp000066400000000000000000000137431444627452400165210ustar00rootroot00000000000000/** * * Copyright 2021-2023 Ribose Inc. (https://www.ribose.com) * * Permission is hereby granted, free of charge, to any person obtaining a copy of * this software and associated documentation files (the "Software"), to deal in * the Software without restriction, including without limitation the rights to * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of * the Software, and to permit persons to whom the Software is furnished to do so, * subject to the following conditions: * * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * * Original copyright * * SEXP implementation code sexp-output.c * Ron Rivest * 5/5/1997 */ #include "sexpp/sexp.h" namespace sexp { static const char *hexDigits = "0123456789ABCDEF"; static const char *base64Digits = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; /* * sexp_output_stream_t::sexp_output_stream_t * Creates and initializes new sexp_output_stream_t object. */ sexp_output_stream_t::sexp_output_stream_t(std::ostream *o, size_t m_depth) { set_output(o, m_depth); } /* * sexp_output_stream_t::set_output * Re-initializes new sexp_output_stream_t object. */ sexp_output_stream_t *sexp_output_stream_t::set_output(std::ostream *o, size_t m_depth) { output_file = o; byte_size = 8; bits = 0; n_bits = 0; mode = canonical; column = 0; max_column = default_line_length; indent = 0; base64_count = 0; reset_depth(m_depth); return this; } /* * sexp_output_stream_t::put_char(c) * Puts the character c out on the output stream os. * Keeps track of the "column" the next output char will go to. */ sexp_output_stream_t *sexp_output_stream_t::put_char(int c) { output_file->put(c); column++; return this; } /* * sexp_output_stream_t::var_put_char(c) * put_char with variable sized output bytes considered. * int c; -- this is always an eight-bit byte being output */ sexp_output_stream_t *sexp_output_stream_t::var_put_char(int c) { c &= 0xFF; bits = (bits << 8) | c; n_bits += 8; while (n_bits >= byte_size) { if ((byte_size == 6 || byte_size == 4 || c == '}' || c == '{' || c == '#' || c == '|') && max_column > 0 && column >= max_column) new_line(mode); if (byte_size == 4) put_char(hexDigits[(bits >> (n_bits - 4)) & 0x0F]); else if (byte_size == 6) put_char(base64Digits[(bits >> (n_bits - 6)) & 0x3F]); else if (byte_size == 8) put_char(bits & 0xFF); n_bits -= byte_size; base64_count++; } return this; } /* * sexp_output_stream_t::change_output_byte_size(newByteSize,newMode) * Change os->byte_size to newByteSize * record mode in output stream for automatic line breaks */ sexp_output_stream_t *sexp_output_stream_t::change_output_byte_size(int newByteSize, sexp_print_mode newMode) { if (newByteSize != 4 && newByteSize != 6 && newByteSize != 8) sexp_error(sexp_exception_t::error, "Illegal output base %d", newByteSize, 0, EOF); if (newByteSize != 8 && byte_size != 8) sexp_error(sexp_exception_t::error, "Illegal change of output byte size from %d to %d", byte_size, newByteSize, EOF); byte_size = newByteSize; n_bits = 0; bits = 0; base64_count = 0; mode = newMode; return this; } /* * sexp_output_stream_t::flush() * flush out any remaining bits */ sexp_output_stream_t *sexp_output_stream_t::flush(void) { if (n_bits > 0) { assert(byte_size == 6); put_char(base64Digits[(bits << (6 - n_bits)) & 0x3F]); n_bits = 0; base64_count++; } if (byte_size == 6) { /* and add switch here */ while ((base64_count & 3) != 0) { if (max_column > 0 && column >= max_column) new_line(mode); put_char('='); base64_count++; } } return this; } /* * sexp_output_stream_t::new_line(mode) * Outputs a newline symbol to the output stream os. * For advanced mode, also outputs indentation as one blank per * indentation level (but never indents more than half of max_column). * Resets column for next output character. */ sexp_output_stream_t *sexp_output_stream_t::new_line(sexp_print_mode mode) { if (mode == advanced || mode == base64) { put_char('\n'); column = 0; } if (mode == advanced) { for (uint32_t i = 0; i < indent && (4 * i) < max_column; i++) put_char(' '); } return this; } /* * sexp_output_stream_t::print_decimal(n) * print out n in decimal to output stream os */ sexp_output_stream_t *sexp_output_stream_t::print_decimal(uint64_t n) { char buffer[20]; // 64*ln(2)/ln(10) // since itoa is not a part of any standard snprintf(buffer, sizeof(buffer) / sizeof(buffer[0]), "%" PRIu64, n); for (uint32_t i = 0; buffer[i] != 0; i++) var_put_char(buffer[i]); return this; } /* * base64 MODE * Same as canonical, except all characters get put out as base 64 ones */ sexp_output_stream_t *sexp_output_stream_t::print_base64( const std::shared_ptr &object) { change_output_byte_size(8, base64)->var_put_char('{')->change_output_byte_size(6, base64); print_canonical(object); return flush()->change_output_byte_size(8, base64)->var_put_char('}'); } } // namespace sexp sexpp-0.8.7/src/sexp-simple-string.cpp000066400000000000000000000147361444627452400177610ustar00rootroot00000000000000/** * * Copyright 2021-2023 Ribose Inc. (https://www.ribose.com) * * Permission is hereby granted, free of charge, to any person obtaining a copy of * this software and associated documentation files (the "Software"), to deal in * the Software without restriction, including without limitation the rights to * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of * the Software, and to permit persons to whom the Software is furnished to do so, * subject to the following conditions: * * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * * Original copyright * * SEXP implementation code sexp-output.c * Ron Rivest * 5/5/1997 */ #include "sexpp/sexp.h" namespace sexp { /* * sexp_simple_string_t::print_canonical_verbatim(os) * Print out simple string on output stream os as verbatim string. */ sexp_output_stream_t *sexp_simple_string_t::print_canonical_verbatim( sexp_output_stream_t *os) const { const octet_t *c = c_str(); /* print out len: */ os->print_decimal(length())->var_put_char(':'); /* print characters in fragment */ for (uint32_t i = 0; i < length(); i++) os->var_put_char((int) *c++); return os; } /* * sexp_simple_string_t::advanced_length(os) * Returns length of printed image of s */ size_t sexp_simple_string_t::advanced_length(sexp_output_stream_t *os) const { if (can_print_as_token(os)) return advanced_length_token(); else if (can_print_as_quoted_string()) return advanced_length_quoted(); else if (length() <= 4 && os->get_byte_size() == 8) return advanced_length_hexadecimal(); else if (os->get_byte_size() == 8) return advanced_length_base64(); else return 0; /* an error condition */ } /* * sexp_simple_string_t::print_token(os) * Prints out simple string ss as a token (assumes that this is OK). * May run over max-column, but there is no fragmentation allowed... */ sexp_output_stream_t *sexp_simple_string_t::print_token(sexp_output_stream_t *os) const { const octet_t *c = c_str(); if (os->get_max_column() > 0 && os->get_column() > (os->get_max_column() - length())) os->new_line(sexp_output_stream_t::advanced); for (uint32_t i = 0; i < length(); i++) os->put_char((int) (*c++)); return os; } /* * sexp_simple_string_t::print_base64(os) * Prints out simple string ss as a base64 value. */ sexp_output_stream_t *sexp_simple_string_t::print_base64(sexp_output_stream_t *os) const { const octet_t *c = c_str(); os->var_put_char('|')->change_output_byte_size(6, sexp_output_stream_t::advanced); for (uint32_t i = 0; i < length(); i++) os->var_put_char((int) (*c++)); return os->flush() ->change_output_byte_size(8, sexp_output_stream_t::advanced) ->var_put_char('|'); } /* * sexp_simple_string_t::print_hexadecimal(os) * Prints out simple string as a hexadecimal value. */ sexp_output_stream_t *sexp_simple_string_t::print_hexadecimal(sexp_output_stream_t *os) const { const octet_t *c = c_str(); os->put_char('#')->change_output_byte_size(4, sexp_output_stream_t::advanced); for (uint32_t i = 0; i < length(); i++) os->var_put_char((int) (*c++)); return os->flush() ->change_output_byte_size(8, sexp_output_stream_t::advanced) ->put_char('#'); } /* * sexp_simple_string_t::print_quoted(os) * Prints out simple string ss as a quoted string * This code assumes that all characters are tokenchars and blanks, * so no escape sequences need to be generated. * May run over max-column, but there is no fragmentation allowed... */ sexp_output_stream_t *sexp_simple_string_t::print_quoted(sexp_output_stream_t *os) const { const octet_t *c = c_str(); os->put_char('\"'); for (uint32_t i = 0; i < length(); i++) { if (os->get_max_column() > 0 && os->get_column() >= os->get_max_column() - 2) { os->put_char('\\')->put_char('\n'); os->reset_column(); } os->put_char(*c++); } return os->put_char('\"'); } /* * sexp_simple_string_t::print_advanced(os) * Prints out simple string onto output stream ss */ sexp_output_stream_t *sexp_simple_string_t::print_advanced(sexp_output_stream_t *os) const { if (can_print_as_token(os)) print_token(os); else if (can_print_as_quoted_string()) print_quoted(os); else if (length() <= 4 && os->get_byte_size() == 8) print_hexadecimal(os); else if (os->get_byte_size() == 8) print_base64(os); else sexp_error(sexp_exception_t::error, "Can't print in advanced mode with restricted output character set", 0, 0, EOF); return os; } /* * sexp_simple_string_t::can_print_as_quoted_string(void) * Returns true if simple string can be printed as a quoted string. * Must have only tokenchars and blanks. */ bool sexp_simple_string_t::can_print_as_quoted_string(void) const { const octet_t *c = c_str(); for (uint32_t i = 0; i < length(); i++, c++) { if (!is_token_char((int) (*c)) && *c != ' ') return false; } return true; } /* * sexp_simple_string_t::can_print_as_token(os) * Returns true if simple string can be printed as a token. * Doesn't begin with a digit, and all characters are tokenchars. */ bool sexp_simple_string_t::can_print_as_token(const sexp_output_stream_t *os) const { const octet_t *c = c_str(); if (length() <= 0) return false; if (is_dec_digit((int) *c)) return false; if (os->get_max_column() > 0 && os->get_column() + length() >= os->get_max_column()) return false; for (uint32_t i = 0; i < length(); i++) { if (!is_token_char((int) (*c++))) return false; } return true; } } // namespace sexp sexpp-0.8.7/tests/000077500000000000000000000000001444627452400140435ustar00rootroot00000000000000sexpp-0.8.7/tests/include/000077500000000000000000000000001444627452400154665ustar00rootroot00000000000000sexpp-0.8.7/tests/include/sexp-tests.h000066400000000000000000000032601444627452400177570ustar00rootroot00000000000000/** * * Copyright 2021-2023 Ribose Inc. (https://www.ribose.com) * * Permission is hereby granted, free of charge, to any person obtaining a copy of * this software and associated documentation files (the "Software"), to deal in * the Software without restriction, including without limitation the rights to * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of * the Software, and to permit persons to whom the Software is furnished to do so, * subject to the following conditions: * * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * */ #pragma once #include #include #include #include #include #include "sexpp/sexp.h" #include "sexp-samples-folder.h" bool compare_binary_files(const std::string &filename1, const std::string &filename2); bool compare_text_files(const std::string &filename1, const std::string &filename2); bool compare_binary_files(const std::string &filename1, std::istream &file2); bool compare_text_files(const std::string &filename1, std::istream &file2); std::istream &safe_get_line(std::istream &is, std::string &t); sexpp-0.8.7/tests/scripts/000077500000000000000000000000001444627452400155325ustar00rootroot00000000000000sexpp-0.8.7/tests/scripts/tests.sh000077500000000000000000000136531444627452400172430ustar00rootroot00000000000000#! /bin/bash # # Copyright 2021-2023 Ribose Inc. (https://www.ribose.com) # # Permission is hereby granted, free of charge, to any person obtaining a copy of # this software and associated documentation files (the "Software"), to deal in # the Software without restriction, including without limitation the rights to # use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of # the Software, and to permit persons to whom the Software is furnished to do so, # subject to the following conditions: # # The above copyright notice and this permission notice shall be included in all # copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS # FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR # COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER # IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN # CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. # # More safety, by turning some bugs into errors. # Without `errexit` you don’t need ! and can replace # PIPESTATUS with a simple $? set -o errexit -o pipefail -o noclobber -o nounset assert_installed() { assertTrue "$1 was not installed" "[ -f $1 ]" } assert_installed_var() { assertTrue "{$1,$2}/$3 was not installed" "[ -f $1/$3 ] || [ -f $2/$3 ]" } assert_installed_var2() { assertTrue "$1/{$2,$3} was not installed" "[ -f $1/$2 ] || [ -f $1/$3 ]" } # ...................................................................... # Check that sexp is installed as expected test_install_script() { echo "==> Install script test" if [[ "${SHARED_LIB:-}" == "on" ]]; then version=$(cat "$DIR_ROOT"/version.txt) version_major="${version:0:1}" case "$OSTYPE" in darwin*) assert_installed "$DIR_INS_B/sexpp" assert_installed "$DIR_INS_L/libsexpp.dylib" assert_installed "$DIR_INS_L/libsexpp.$version_major.dylib" assert_installed "$DIR_INS_L/libsexpp.$version.dylib" ;; windows ) assert_installed "$DIR_INS_B/sexpp.exe" assert_installed "$DIR_INS_B/sexpp.dll" assert_installed "$DIR_INS_L/sexpp.lib" ;; msys) assert_installed "$DIR_INS_B/sexpp.exe" assert_installed "$DIR_INS_B/libsexpp.dll" assert_installed "$DIR_INS_L/libsexpp.dll.a" ;; *) assert_installed "$DIR_INS_B/sexpp" assert_installed_var "$DIR_INS_L" "$DIR_INS_L64" "libsexpp.so" assert_installed_var "$DIR_INS_L" "$DIR_INS_L64" "libsexpp.so.$version_major" assert_installed_var "$DIR_INS_L" "$DIR_INS_L64" "libsexpp.so.$version" ;; esac else case "$OSTYPE" in windows) assert_installed "$DIR_INS_B/sexpp.exe" assert_installed "$DIR_INS_L/sexpp.lib" ;; msys) assert_installed "$DIR_INS_B/sexpp.exe" assert_installed "$DIR_INS_L/libsexpp.a" ;; *) assert_installed "$DIR_INS_B/sexpp" assert_installed_var "$DIR_INS_L" "$DIR_INS_L64" "libsexpp.a" ;; esac fi assert_installed_var "$DIR_INS_P" "$DIR_INS_P64" "sexpp.pc" assert_installed_var2 "$DIR_INS_M/man1" "sexpp.1" "sexpp.1.gz" assert_installed "$DIR_INS_I/sexp.h" assert_installed "$DIR_INS_I/sexp-error.h" } # ...................................................................... # Check sexp client application # THese are the examples from README.adoc test_sexp_cli() { echo "==> SEXP client application test" # On Windows there will be CRLF vs LS mismatch # We would rather skip these tests if [[ "$OSTYPE" == "windows" || "$OSTYPE" == "msys" ]]; then startSkipping fi app="$DIR_INS_B/sexpp" # shellcheck disable=SC2251 ! IFS= read -r -d '' expected << EOM Input: Writing base64 (of canonical) output to certificate.dat EOM export LD_LIBRARY_PATH="$DIR_INS_L":"$DIR_INS_L64" rm -f input1.dat echo "(aa bb (cc dd))" > input1.dat output=$("$app" -o certificate.dat -p -b < input1.dat) # $expected possibly includes extra EOL at the end -- it depends on OS assertContains "$expected" "$output" output=$(cat certificate.dat) assertEquals "{KDI6YWEyOmJiKDI6Y2MyOmRkKSk=}" "$output" output=$("$app" -i certificate.dat -x) assertEquals "(2:aa2:bb(2:cc2:dd))" "$output" # shellcheck disable=SC2251 ! IFS= read -r -d '' expected << EOM Reading input from certificate.dat Canonical output: (2:aa2:bb(2:cc2:dd)) Base64 (of canonical) output: {KDI6YWEyOmJiKDI6Y2MyOmRkKSk=} Advanced transport output: (aa bb (cc dd)) EOM output=$("$app" -i certificate.dat -a -b -c -p -w 0) assertContains "$expected" "$output" # shellcheck disable=SC2251 ! IFS= read -r -d '' expected << EOM Input: Canonical output: (3:abc3:def(3:ghi3:jkl)) Base64 (of canonical) output: {KDM6YWJjMzpkZWYoMzpnaGkzOmprbCkp} Advanced transport output: (abc def (ghi jkl)) Input: EOM rm -f input2.dat echo "(abc def (ghi jkl))" > input2.dat output=$("$app" < input2.dat) assertContains "$expected" "$output" if [[ "$OSTYPE" == "windows" || "$OSTYPE" == "msys" ]]; then endSkipping fi } # ...................................................................... # main DIR00=$( dirname "$0" ) DIR0=$( cd "$DIR00" && pwd ) DIR1="${DIR_ROOT:=$DIR0/../..}" DIR_ROOT=$( cd "$DIR1" && pwd ) if [[ -z "${DIR_INSTALL:-}" ]]; then DIR_INSTALL="$DIR_ROOT/install" fi DIR_INS_B="$DIR_INSTALL/bin" DIR_INS_L="$DIR_INSTALL/lib" DIR_INS_L64="$DIR_INSTALL/lib64" DIR_INS_M="$DIR_INSTALL/share/man" DIR_INS_P="$DIR_INS_L/pkgconfig" DIR_INS_P64="$DIR_INS_L64/pkgconfig" DIR_INS_I="$DIR_INSTALL/include/sexpp" DIR_TESTS=$( cd "$DIR0/.." && pwd) echo "Running sexp additional tests" # shellcheck source=/dev/null . "$DIR_TESTS"/shunit2/shunit2 sexpp-0.8.7/tests/src/000077500000000000000000000000001444627452400146325ustar00rootroot00000000000000sexpp-0.8.7/tests/src/baseline-tests.cpp000066400000000000000000000102171444627452400202610ustar00rootroot00000000000000/** * * Copyright 2021-2023 Ribose Inc. (https://www.ribose.com) * * Permission is hereby granted, free of charge, to any person obtaining a copy of * this software and associated documentation files (the "Software"), to deal in * the Software without restriction, including without limitation the rights to * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of * the Software, and to permit persons to whom the Software is furnished to do so, * subject to the following conditions: * * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * */ #include "sexp-tests.h" using namespace sexp; using ::testing::UnitTest; namespace { class BaselineTests : public testing::Test { protected: static const uint32_t base_sample_advanced = 0; static const uint32_t base_sample_base64 = 1; static const uint32_t base_sample_canonical = 2; static const uint32_t n_base_samples = base_sample_canonical + 1; static std::string base_samples[n_base_samples]; BaselineTests() { base_samples[base_sample_advanced] = sexp_samples_folder + "/baseline/sexp-sample-a"; base_samples[base_sample_base64] = sexp_samples_folder + "/baseline/sexp-sample-b"; base_samples[base_sample_canonical] = sexp_samples_folder + "/baseline/sexp-sample-c"; }; }; const uint32_t BaselineTests::n_base_samples; const uint32_t BaselineTests::base_sample_advanced; const uint32_t BaselineTests::base_sample_base64; const uint32_t BaselineTests::base_sample_canonical; std::string BaselineTests::base_samples[n_base_samples]; TEST_F(BaselineTests, Scan2Canonical) { for (uint32_t i = 0; i < n_base_samples; i++) { std::ifstream ifs(base_samples[i], std::ifstream::binary); bool r = ifs.fail(); EXPECT_FALSE(r); if (!ifs.fail()) { sexp_input_stream_t is(&ifs); const auto obj = is.set_byte_size(8)->get_char()->scan_object(); std::ostringstream oss(std::ios_base::binary); sexp_output_stream_t os(&oss); os.print_canonical(obj); std::istringstream iss(oss.str(), std::ios_base::binary); EXPECT_TRUE(compare_binary_files(base_samples[base_sample_canonical], iss)); } } } TEST_F(BaselineTests, Scan2Base64) { for (uint32_t i = 0; i < n_base_samples; i++) { std::ifstream ifs(base_samples[i], std::ifstream::binary); EXPECT_FALSE(ifs.fail()); if (!ifs.fail()) { sexp_input_stream_t is(&ifs); const auto obj = is.set_byte_size(8)->get_char()->scan_object(); std::ostringstream oss(std::ios_base::binary); sexp_output_stream_t os(&oss); os.set_max_column(0)->print_base64(obj); oss << std::endl; std::istringstream iss(oss.str(), std::ios_base::binary); EXPECT_TRUE(compare_text_files(base_samples[base_sample_base64], iss)); } } } TEST_F(BaselineTests, Scan2Advanced) { for (uint32_t i = 0; i < n_base_samples; i++) { std::ifstream ifs(base_samples[i], std::ifstream::binary); EXPECT_FALSE(ifs.fail()); if (!ifs.fail()) { sexp_input_stream_t is(&ifs); const auto obj = is.set_byte_size(8)->get_char()->scan_object(); std::ostringstream oss(std::ios_base::binary); sexp_output_stream_t os(&oss); os.print_advanced(obj); std::istringstream iss(oss.str(), std::ios_base::binary); EXPECT_TRUE(compare_text_files(base_samples[base_sample_advanced], iss)); } } } } // namespace sexpp-0.8.7/tests/src/compare-files.cpp000066400000000000000000000077411444627452400200750ustar00rootroot00000000000000/** * * Copyright 2021-2023 Ribose Inc. (https://www.ribose.com) * * Permission is hereby granted, free of charge, to any person obtaining a copy of * this software and associated documentation files (the "Software"), to deal in * the Software without restriction, including without limitation the rights to * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of * the Software, and to permit persons to whom the Software is furnished to do so, * subject to the following conditions: * * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * */ #include #include #include "sexp-tests.h" bool compare_binary_files(const std::string &filename1, const std::string &filename2) { bool res = false; std::ifstream file1(filename1, std::ifstream::ate | std::ifstream::binary); std::ifstream file2(filename2, std::ifstream::ate | std::ifstream::binary); if (file1.tellg() == file2.tellg()) { // otherwise different file size file1.seekg(0); file2.seekg(0); std::istreambuf_iterator begin1(file1); std::istreambuf_iterator begin2(file2); res = std::equal(begin1, std::istreambuf_iterator(), begin2); } return res; } bool compare_binary_files(const std::string &filename1, std::istream &file2) { std::ifstream file1(filename1, std::ifstream::binary); std::istreambuf_iterator begin1(file1); std::istreambuf_iterator begin2(file2); return std::equal(begin1, std::istreambuf_iterator(), begin2); } std::istream &safe_get_line(std::istream &is, std::string &t) { t.clear(); // The characters in the stream are read one-by-one using a std::streambuf. // That is faster than reading them one-by-one using the std::istream. // Code that uses streambuf this way must be guarded by a sentry object. // The sentry object performs various tasks, // such as thread synchronization and updating the stream state. std::istream::sentry se(is, true); std::streambuf * sb = is.rdbuf(); for (;;) { int c = sb->sbumpc(); switch (c) { case '\n': return is; case '\r': if (sb->sgetc() == '\n') sb->sbumpc(); return is; case std::streambuf::traits_type::eof(): // Also handle the case when the last line has no line ending if (t.empty()) is.setstate(std::ios::eofbit); return is; default: t += (char) c; } } } bool compare_text_files(const std::string &filename1, const std::string &filename2) { bool res = true; std::ifstream file1(filename1, std::ifstream::binary); std::ifstream file2(filename2, std::ifstream::binary); std::string s1, s2; while (res) { if (file1.eof() && file2.eof()) break; safe_get_line(file1, s1); safe_get_line(file2, s2); if (s1 != s2) res = false; } return res; } bool compare_text_files(const std::string &filename1, std::istream &file2) { bool res = true; std::ifstream file1(filename1, std::ifstream::binary); std::string s1, s2; file2.seekg(0); while (res) { if (file1.eof() && file2.eof()) break; safe_get_line(file1, s1); safe_get_line(file2, s2); if (s1 != s2) res = false; } return res; } sexpp-0.8.7/tests/src/exception-tests.cpp000066400000000000000000000271711444627452400205040ustar00rootroot00000000000000/** * * Copyright 2021-2023 Ribose Inc. (https://www.ribose.com) * * Permission is hereby granted, free of charge, to any person obtaining a copy of * this software and associated documentation files (the "Software"), to deal in * the Software without restriction, including without limitation the rights to * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of * the Software, and to permit persons to whom the Software is furnished to do so, * subject to the following conditions: * * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * */ #include "sexp-tests.h" using namespace sexp; namespace { class ExceptionTests : public testing::Test { protected: static void do_scan_with_exception(const char *str_in, const char *msg) { try { std::istringstream iss(str_in); sexp_input_stream_t is(&iss); is.set_byte_size(8)->get_char()->scan_object(); FAIL() << "sexp::sexp_exception_t expected but has not been thrown"; } catch (sexp::sexp_exception_t &e) { EXPECT_STREQ(e.what(), msg); } } }; TEST_F(ExceptionTests, UnexpectedEof) { do_scan_with_exception("(4:This2:is1:a4:test", "SEXP ERROR: unexpected end of file at position 20"); } TEST_F(ExceptionTests, UnexpectedCharacter4bit) { do_scan_with_exception( "(4:This2:is1:a4:test #)", "SEXP ERROR: character ')' found in 4-bit coding region at position 22"); } TEST_F(ExceptionTests, IllegalCharacter) { do_scan_with_exception("(This is a test ?)", "SEXP ERROR: illegal character '?' (0x3f) at position 16"); } TEST_F(ExceptionTests, UnexpectedEofAfterQoute) { do_scan_with_exception("(\")\n", "SEXP ERROR: unexpected end of file at position 4"); } TEST_F(ExceptionTests, IllegalCharacterBase64) { do_scan_with_exception("(Test {KDQ6VGhpczI6aXMxOmE0OnRlc3Qq})", "SEXP ERROR: illegal character '}' (0x7d) at position 35"); } TEST_F(ExceptionTests, InvalidHex) { do_scan_with_exception("(\"\\x1U\")", "SEXP ERROR: Hex character \\x1... too short at position 5"); } TEST_F(ExceptionTests, InvalidOctal) { do_scan_with_exception("(\"\\12U\")", "SEXP ERROR: Octal character \\12... too short at position 5"); } TEST_F(ExceptionTests, TooBigOctal) { do_scan_with_exception("(\"\\666U\")", "SEXP ERROR: Octal character \\666... too big at position 5"); } TEST_F(ExceptionTests, InvalidEscape) { do_scan_with_exception("(\"\\?\")", "SEXP ERROR: Unknown escape sequence \\? at position 3"); } TEST_F(ExceptionTests, StringTooShortQuoted) { do_scan_with_exception( "(4\"ABC\")", "SEXP ERROR: Declared length was 4, but quoted string ended too early at position 6"); } TEST_F(ExceptionTests, StringTooShortBase64) { sexp::sexp_exception_t::set_verbosity(sexp::sexp_exception_t::warning); do_scan_with_exception("(8|NDpBQkNE|)", "SEXP WARNING: Base64 string has length 6 different than declared " "length 8 at position 12"); sexp::sexp_exception_t::set_verbosity(sexp::sexp_exception_t::error); } TEST_F(ExceptionTests, StringTooShortHex) { sexp::sexp_exception_t::set_verbosity(sexp::sexp_exception_t::warning); do_scan_with_exception( "(8#AAABFCAD#)", "SEXP WARNING: Hex string has length 4 different than declared length 8 at position 12"); sexp::sexp_exception_t::set_verbosity(sexp::sexp_exception_t::error); } TEST_F(ExceptionTests, StringBadLength) { do_scan_with_exception("(1A:AAABFCAD)", "SEXP ERROR: illegal character 'A' (0x41) at position 2"); } TEST_F(ExceptionTests, DecimalTooLong) { do_scan_with_exception("(1234567890:AAABFCAD)", "SEXP ERROR: Decimal number is too long at position 11"); } TEST_F(ExceptionTests, Base64CurlyBracket) { // "ey..." in base64 encoding translates to "{..." do_scan_with_exception("({ey})", "SEXP ERROR: illegal character '{' (0x7b) at position 3"); } TEST_F(ExceptionTests, UnusedBits) { sexp::sexp_exception_t::set_verbosity(sexp::sexp_exception_t::warning); do_scan_with_exception( "(Test |AABBCCDD11|)", "SEXP WARNING: 6-bit region ended with 4 unused bits left-over at position 17"); sexp::sexp_exception_t::set_verbosity(sexp::sexp_exception_t::error); } TEST_F(ExceptionTests, NotAListWhenExpected) { try { std::istringstream iss( "|d738/4ghP9rFZ0gAIYZ5q9y6iskDJwASi5rEQpEQq8ZyMZeIZzIAR2I5iGE=|"); sexp_input_stream_t is(&iss); sexp_list_t a_list; a_list.parse(is.set_byte_size(8)->get_char()); FAIL() << "sexp::sexp_exception_t expected but has not been thrown"; } catch (sexp::sexp_exception_t &e) { EXPECT_STREQ(e.what(), "SEXP ERROR: character '|' found where '(' was expected at position 0"); } } TEST_F(ExceptionTests, InvalidByteSizeAndMode) { try { std::istringstream iss("(3:a\011c)"); sexp_input_stream_t is(&iss); std::shared_ptr obj = is.set_byte_size(8)->get_char()->scan_object(); std::ostringstream oss(std::ios_base::binary); sexp_output_stream_t os(&oss); os.change_output_byte_size(4, sexp_output_stream_t::advanced)->print_advanced(obj); FAIL() << "sexp::sexp_exception_t expected but has not been thrown"; } catch (sexp::sexp_exception_t &e) { EXPECT_STREQ( e.what(), "SEXP ERROR: Can't print in advanced mode with restricted output character set"); } } TEST_F(ExceptionTests, SexpWarning) { testing::internal::CaptureStdout(); sexp::sexp_exception_t::set_interactive(true); sexp_error(sexp_exception_t::warning, "Test warning", 0, 0, 200); std::string output = testing::internal::GetCapturedStdout(); EXPECT_EQ(output, "\n*** SEXP WARNING: Test warning at position 200 ***\n"); sexp::sexp_exception_t::set_interactive(false); } static void do_parse_list_from_string(const char *str) { std::istringstream iss(str); sexp_input_stream_t is(&iss); sexp_list_t lst; lst.parse(is.set_byte_size(8)->get_char()); } static void do_parse_list_from_string_with_limit(const char *str, size_t m_depth) { std::istringstream iss(str); sexp_input_stream_t is(&iss, m_depth); sexp_list_t lst; lst.parse(is.set_byte_size(8)->get_char()); } TEST_F(ExceptionTests, MaxDepthParse) { const char *depth_1 = "(sexp_list_1)"; const char *depth_4 = "(sexp_list_1 (sexp_list_2 (sexp_list_3 (sexp_list_4))))"; const char *depth_4e = "(sexp_list_1 (sexp_list_2 (sexp_list_3 ())))"; const char *depth_5 = "(sexp_list_1 (sexp_list_2 (sexp_list_3 (sexp_list_4 (sexp_list_5)))))"; const char *depth_5e = "(sexp_list_1 (sexp_list_2 (sexp_list_3 (sexp_list_4 ()))))"; do_parse_list_from_string(depth_1); do_parse_list_from_string(depth_4); do_parse_list_from_string(depth_4e); do_parse_list_from_string(depth_5); do_parse_list_from_string(depth_5e); do_parse_list_from_string_with_limit(depth_1, 4); do_parse_list_from_string_with_limit(depth_4, 4); do_parse_list_from_string_with_limit(depth_4e, 4); try { do_parse_list_from_string_with_limit(depth_5, 4); FAIL() << "sexp::sexp_exception_t expected but has not been thrown"; } catch (sexp::sexp_exception_t &e) { EXPECT_STREQ( e.what(), "SEXP ERROR: Maximum allowed SEXP list depth (4) is exceeded at position 53"); } try { do_parse_list_from_string_with_limit(depth_5e, 4); FAIL() << "sexp::sexp_exception_t expected but has not been thrown"; } catch (sexp::sexp_exception_t &e) { EXPECT_STREQ( e.what(), "SEXP ERROR: Maximum allowed SEXP list depth (4) is exceeded at position 53"); } } static void do_print_list_from_string(const char *str, bool advanced, size_t m_depth = 0) { std::istringstream iss(str); sexp_input_stream_t is(&iss); sexp_list_t lst; lst.parse(is.set_byte_size(8)->get_char()); std::ostringstream oss(str); sexp_output_stream_t os(&oss, m_depth); if (advanced) lst.print_advanced(&os); else lst.print_canonical(&os); } TEST_F(ExceptionTests, MaxDepthPrintAdvanced) { const char *depth_1 = "(sexp_list_1)"; const char *depth_4 = "(sexp_list_1 (sexp_list_2 (sexp_list_3 (sexp_list_4))))"; const char *depth_4e = "(sexp_list_1 (sexp_list_2 (sexp_list_3 ())))"; const char *depth_5 = "(sexp_list_1 (sexp_list_2 (sexp_list_3 (sexp_list_4 (sexp_list_5)))))"; const char *depth_5e = "(sexp_list_1 (sexp_list_2 (sexp_list_3 (sexp_list_4 ()))))"; do_print_list_from_string(depth_1, true); do_print_list_from_string(depth_4, true); do_print_list_from_string(depth_4e, true); do_print_list_from_string(depth_5, true); do_print_list_from_string(depth_5e, true); do_print_list_from_string(depth_1, true, 4); do_print_list_from_string(depth_4, true, 4); do_print_list_from_string(depth_4e, true, 4); try { do_print_list_from_string(depth_5, true, 4); FAIL() << "sexp::sexp_exception_t expected but has not been thrown"; } catch (sexp::sexp_exception_t &e) { EXPECT_STREQ(e.what(), "SEXP ERROR: Maximum allowed SEXP list depth (4) is exceeded"); } try { do_print_list_from_string(depth_5e, true, 4); FAIL() << "sexp::sexp_exception_t expected but has not been thrown"; } catch (sexp::sexp_exception_t &e) { EXPECT_STREQ(e.what(), "SEXP ERROR: Maximum allowed SEXP list depth (4) is exceeded"); } } TEST_F(ExceptionTests, MaxDepthPrintCanonical) { const char *depth_1 = "(sexp_list_1)"; const char *depth_4 = "(sexp_list_1 (sexp_list_2 (sexp_list_3 (sexp_list_4))))"; const char *depth_4e = "(sexp_list_1 (sexp_list_2 (sexp_list_3 ())))"; const char *depth_5 = "(sexp_list_1 (sexp_list_2 (sexp_list_3 (sexp_list_4 (sexp_list_5)))))"; const char *depth_5e = "(sexp_list_1 (sexp_list_2 (sexp_list_3 (sexp_list_4 ()))))"; do_print_list_from_string(depth_1, false); do_print_list_from_string(depth_4, false); do_print_list_from_string(depth_4e, false); do_print_list_from_string(depth_5, false); do_print_list_from_string(depth_5e, false); do_print_list_from_string(depth_1, false, 4); do_print_list_from_string(depth_4, false, 4); do_print_list_from_string(depth_4e, false, 4); try { do_print_list_from_string(depth_5, false, 4); FAIL() << "sexp::sexp_exception_t expected but has not been thrown"; } catch (sexp::sexp_exception_t &e) { EXPECT_STREQ(e.what(), "SEXP ERROR: Maximum allowed SEXP list depth (4) is exceeded"); } try { do_print_list_from_string(depth_5e, false, 4); FAIL() << "sexp::sexp_exception_t expected but has not been thrown"; } catch (sexp::sexp_exception_t &e) { EXPECT_STREQ(e.what(), "SEXP ERROR: Maximum allowed SEXP list depth (4) is exceeded"); } } } // namespace sexpp-0.8.7/tests/src/g10-compat-tests.cpp000066400000000000000000000035261444627452400203540ustar00rootroot00000000000000/** * * Copyright 2021-2023 Ribose Inc. (https://www.ribose.com) * * Permission is hereby granted, free of charge, to any person obtaining a copy of * this software and associated documentation files (the "Software"), to deal in * the Software without restriction, including without limitation the rights to * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of * the Software, and to permit persons to whom the Software is furnished to do so, * subject to the following conditions: * * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * */ #include "sexp-tests.h" using namespace sexp; namespace { class G10CompatTests : public testing::Test { }; TEST_F(G10CompatTests, Canonical) { std::string keyfile(sexp_samples_folder + "/compat/g10/canonical.key"); std::ifstream ifs(keyfile, std::ifstream::binary); EXPECT_FALSE(ifs.fail()); if (!ifs.fail()) { sexp_input_stream_t is(&ifs); const auto obj = is.set_byte_size(8)->get_char()->scan_object(); std::ostringstream oss(std::ios_base::binary); sexp_output_stream_t os(&oss); os.print_canonical(obj); std::istringstream iss(oss.str(), std::ios_base::binary); EXPECT_TRUE(compare_binary_files(keyfile, iss)); } } } // namespace sexpp-0.8.7/tests/src/g23-compat-tests.cpp000066400000000000000000000110251444627452400203510ustar00rootroot00000000000000/** * * Copyright 2021-2023 Ribose Inc. (https://www.ribose.com) * * Permission is hereby granted, free of charge, to any person obtaining a copy of * this software and associated documentation files (the "Software"), to deal in * the Software without restriction, including without limitation the rights to * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of * the Software, and to permit persons to whom the Software is furnished to do so, * subject to the following conditions: * * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * */ #include "sexp-tests.h" #include "sexpp/ext-key-format.h" using namespace sexp; using namespace ext_key_format; using ::testing::UnitTest; namespace { class G23CompatTests : public testing::Test { protected: static void scan_and_check_correct(const char *fn) { std::ifstream ifs(sexp_samples_folder + "/compat/g23/" + fn, std::ifstream::binary); bool r = ifs.fail(); EXPECT_FALSE(r); if (!ifs.fail()) { ext_key_input_stream_t is(&ifs); extended_private_key_t extended_key; is.scan(extended_key); EXPECT_EQ(extended_key.fields.size(), 2); EXPECT_EQ(extended_key.fields.count("Created"), 1); EXPECT_EQ(extended_key.fields.count("creaTed"), 1); EXPECT_EQ(extended_key.fields.count("something"), 0); auto search = extended_key.fields.find("Created"); if (search != extended_key.fields.end()) { EXPECT_EQ(search->second, "20221130T160847"); } } } }; TEST_F(G23CompatTests, G10Test) { std::ifstream ifs(sexp_samples_folder + "/compat/g10/canonical.key", std::ifstream::binary); bool r = ifs.fail(); EXPECT_FALSE(r); if (!ifs.fail()) { ext_key_input_stream_t is(&ifs); extended_private_key_t extended_key; is.scan(extended_key); EXPECT_EQ(extended_key.fields.size(), 0); } } // Correct extended key format TEST_F(G23CompatTests, G23Correct) { scan_and_check_correct("correct.key"); } // Correct extended key format, no terminating end of line TEST_F(G23CompatTests, G23CorrectNoEol) { scan_and_check_correct("correct_no_eol.key"); } // Correct extended key format, with a comment TEST_F(G23CompatTests, G23CorrectWithComment) { scan_and_check_correct("correct_with_comment.key"); } // Correct extended key format, with an empty line (which is comment a well) TEST_F(G23CompatTests, G23CorrectWithTwoEmptyLines) { scan_and_check_correct("correct_with_two_empty_lines.key"); } // Correct extended key format, with two empty linea TEST_F(G23CompatTests, G23CorrectWithEmptyLine) { scan_and_check_correct("correct_with_empty_line.key"); } // Correct extended key format, witg windows line endings TEST_F(G23CompatTests, G23CorrectWithWindowsEol) { scan_and_check_correct("correct_with_windows_eol.key"); } // Correct extended key format, with a comment at the end of file TEST_F(G23CompatTests, G23CorrectWithCommentAtEof) { scan_and_check_correct("correct_with_comment_at_eof.key"); } // Correct extended key format, with multiple fields of the same name TEST_F(G23CompatTests, G23CorrectWithMultFields) { std::ifstream ifs(sexp_samples_folder + "/compat/g23/correct_mult_fields.key", std::ifstream::binary); bool r = ifs.fail(); EXPECT_FALSE(r); if (!ifs.fail()) { ext_key_input_stream_t is(&ifs); extended_private_key_t extended_key; extended_key.parse(is); EXPECT_EQ(extended_key.fields.size(), 4); EXPECT_EQ(extended_key.fields.count("Created"), 1); EXPECT_EQ(extended_key.fields.count("Description"), 3); EXPECT_EQ(extended_key.fields.count("something"), 0); auto search = extended_key.fields.find("Description"); if (search != extended_key.fields.end()) { EXPECT_EQ(search->second, "RSA/RSA"); } } } } // namespace sexpp-0.8.7/tests/src/g23-exception-tests.cpp000066400000000000000000000075251444627452400210760ustar00rootroot00000000000000/** * * Copyright 2021-2023 Ribose Inc. (https://www.ribose.com) * * Permission is hereby granted, free of charge, to any person obtaining a copy of * this software and associated documentation files (the "Software"), to deal in * the Software without restriction, including without limitation the rights to * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of * the Software, and to permit persons to whom the Software is furnished to do so, * subject to the following conditions: * * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * */ #include "sexp-tests.h" #include "sexpp/ext-key-format.h" using namespace sexp; using namespace ext_key_format; using ::testing::UnitTest; namespace { class G23ExceptionTests : public testing::Test { protected: static void do_scan_ex(const char *fn, const char *msg) { std::ifstream ifs(sexp_samples_folder + "/compat/g23/" + fn, std::ifstream::binary); EXPECT_FALSE(ifs.fail()); if (!ifs.fail()) { try { ext_key_input_stream_t is(&ifs); extended_private_key_t extended_key; is.scan(extended_key); FAIL() << "sexp::sexp_exception_t expected but has not been thrown"; } catch (sexp::sexp_exception_t &e) { EXPECT_STREQ(e.what(), msg); } } } }; // Malformed extended key format, line break inside name TEST_F(G23ExceptionTests, G23MalformedNameBreak) { do_scan_ex("malformed_name_break.key", "EXTENDED KEY FORMAT ERROR: unexpected end of line at position 5"); } // Malformed extended key format, eof break inside name TEST_F(G23ExceptionTests, G23MalformedNameEof) { do_scan_ex("malformed_name_eof.key", "EXTENDED KEY FORMAT ERROR: unexpected end of file at position 2800"); } // Malformed extended key format, invalid character name TEST_F(G23ExceptionTests, G23MalformedInvalidNameChar) { do_scan_ex( "malformed_invalid_name_char.key", "EXTENDED KEY FORMAT ERROR: unexpected character '@' (0x40) found in a name field " "at position 28"); } // Malformed extended key format, invalid character name TEST_F(G23ExceptionTests, G23MalformedInvalidNameFirstChar) { do_scan_ex( "malformed_invalid_name_first_char.key", "EXTENDED KEY FORMAT ERROR: unexpected character '1' (0x31) found starting a name field " "at position 21"); } // Malformed extended key format, no key field TEST_F(G23ExceptionTests, G23MalformedNoKey) { do_scan_ex("malformed_no_key.key", "EXTENDED KEY FORMAT ERROR: missing mandatory 'key' field at position 2819"); } // Malformed extended key format, two key fields TEST_F(G23ExceptionTests, G23MalformedTwoKeys) { do_scan_ex("malformed_two_keys.key", "EXTENDED KEY FORMAT ERROR: 'key' field must occur only once at position 2822"); } TEST_F(G23ExceptionTests, G23Warning) { testing::internal::CaptureStdout(); sexp::sexp_exception_t::set_interactive(true); ext_key_error(sexp_exception_t::warning, "Test warning", 0, 0, 200); std::string output = testing::internal::GetCapturedStdout(); EXPECT_EQ(output, "\n*** EXTENDED KEY FORMAT WARNING: Test warning at position 200 ***\n"); sexp::sexp_exception_t::set_interactive(false); } } // namespace sexpp-0.8.7/tests/src/primitives-tests.cpp000066400000000000000000000320511444627452400206720ustar00rootroot00000000000000/** * * Copyright 2021-2023 Ribose Inc. (https://www.ribose.com) * * Permission is hereby granted, free of charge, to any person obtaining a copy of * this software and associated documentation files (the "Software"), to deal in * the Software without restriction, including without limitation the rights to * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of * the Software, and to permit persons to whom the Software is furnished to do so, * subject to the following conditions: * * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. * */ #include "sexp-tests.h" using namespace sexp; namespace { class PrimitivesTests : public testing::Test { protected: static void do_test_advanced(const char *str_in, const char *str_out = nullptr) { std::istringstream iss(str_in); sexp_input_stream_t is(&iss); const auto obj = is.set_byte_size(8)->get_char()->scan_object(); std::ostringstream oss(std::ios_base::binary); sexp_output_stream_t os(&oss); os.print_advanced(obj); const char *sample = str_out == nullptr ? str_in : str_out; EXPECT_EQ(oss.str(), sample); } static void do_test_canonical(const char *str_in, const char *str_out = nullptr) { std::istringstream iss(str_in); sexp_input_stream_t is(&iss); const auto obj = is.set_byte_size(8)->get_char()->scan_object(); std::ostringstream oss(std::ios_base::binary); sexp_output_stream_t os(&oss); os.print_canonical(obj); const char *sample = str_out == nullptr ? str_in : str_out; EXPECT_EQ(oss.str(), sample); } }; TEST_F(PrimitivesTests, EmptyList) { do_test_canonical("( )", "()"); do_test_advanced("( )", "()"); } TEST_F(PrimitivesTests, EmptyString) { sexp::sexp_exception_t::set_verbosity(sexp::sexp_exception_t::error); do_test_canonical("(\"\")", "(0:)"); do_test_advanced("(\"\")", "(\"\")"); } TEST_F(PrimitivesTests, String) { sexp::sexp_exception_t::set_verbosity(sexp::sexp_exception_t::error); do_test_canonical("(ab)", "(2:ab)"); do_test_advanced("(ab)", "(ab)"); } TEST_F(PrimitivesTests, QuotedStringWithOctal) { sexp::sexp_exception_t::set_verbosity(sexp::sexp_exception_t::error); do_test_canonical("\"ab\\015\"", "3:ab\r"); do_test_advanced("\"ab\\015\"", "#61620D#"); } TEST_F(PrimitivesTests, QuotedStringWithEscape) { sexp::sexp_exception_t::set_verbosity(sexp::sexp_exception_t::error); do_test_canonical("\"ab\\tc\"", "4:ab\tc"); do_test_advanced("4:ab\tc", "#61620963#"); } TEST_F(PrimitivesTests, HexString) { sexp::sexp_exception_t::set_verbosity(sexp::sexp_exception_t::error); do_test_canonical("#616263#", "3:abc"); do_test_advanced("#616263#", "abc"); } TEST_F(PrimitivesTests, ListList) { do_test_canonical("(string-level-1 (string-level-2) )", "(14:string-level-1(14:string-level-2))"); do_test_advanced("(string-level-1 (string-level-2) )", "(string-level-1 (string-level-2))"); } TEST_F(PrimitivesTests, Base64Ofoctet_t) { do_test_canonical("|YWJj|", "3:abc"); do_test_advanced("|YWJj|", "abc"); } TEST_F(PrimitivesTests, Base64OfVerbatium) { do_test_canonical("{MzphYmM=}", "3:abc"); do_test_advanced("{MzphYmM=}", "abc"); } TEST_F(PrimitivesTests, MultilineLinux) { do_test_canonical("\"abcd\\\nef\"", "6:abcdef"); do_test_advanced("\"abcd\\\nef\"", "abcdef"); } TEST_F(PrimitivesTests, MultilineMac) { do_test_canonical("\"abcd\\\ref\"", "6:abcdef"); do_test_advanced("\"abcd\\\ref\"", "abcdef"); } TEST_F(PrimitivesTests, MultilineWin) { do_test_canonical("\"abcd\\\r\nef\"", "6:abcdef"); do_test_advanced("\"abcd\\\r\nef\"", "abcdef"); } TEST_F(PrimitivesTests, MultilineBsd) { do_test_canonical("\"abcd\\\n\ref\"", "6:abcdef"); do_test_advanced("\"abcd\\\n\ref\"", "abcdef"); } TEST_F(PrimitivesTests, Wrap) { const char *reallyLong = "(a (b (c ddddddddddddddd" "ddddddddddddddddddddddddddddddddddddddddddddddddd" "ddddddddddddddddddddddddddddddddddddddddddddddddd" "ddddddddddddddddddddddddddddddddddddddddddddddddd" "ddddddd)))"; const char *stillLong = "(1:a(1:b(1:c169:ddddddddd" "ddddddddddddddddddddddddddddddddddddddddddddddddd" "ddddddddddddddddddddddddddddddddddddddddddddddddd" "ddddddddddddddddddddddddddddddddddddddddddddddddd" "ddddddddddddd)))"; const char *broken = "(a\n" " (b\n" " (c\n" " " "\"ddddddddddddddddddddddddddddddddddddddddddddddddddddd" "dddddddddddddddd\\\n" "ddddddddddddddddddddddddddddddddddddddddddddddddddddddd" "dddddddddddddddddd\\\n" "ddddddddddddddddddddddddddd\")))"; do_test_canonical(reallyLong, stillLong); do_test_advanced(reallyLong, broken); } TEST_F(PrimitivesTests, Escapes) { do_test_canonical("(\"\\b\\t\\v\\n\\f\\r\\\"\\'\\\\\")", "(9:\b\t\v\n\f\r\"'\\)"); do_test_advanced("(\"\\b\\t\\v\\n\\f\\r\\\"\\'\\\\\")", "(|CAkLCgwNIidc|)"); do_test_canonical("(\"\\040\\041\\042\\043\\044\")", "(5: !\"#$)"); do_test_advanced("(\"\\065\\061\\062\\063\\064\")", "(\"51234\")"); do_test_canonical("(\"\\x40\\x41\\x42\\x43\\x44\")", "(5:@ABCD)"); do_test_advanced("(\"\\x65\\x61\\x62\\x63\\x64\")", "(eabcd)"); } TEST_F(PrimitivesTests, at4rnp) { const char *str_in = "(rnp_block (rnp_list1 rnp_list2))"; std::istringstream iss(str_in); sexp_input_stream_t is(&iss); sexp_list_t lst; lst.parse(is.set_byte_size(8)->get_char()); EXPECT_EQ(lst.sexp_list_at(0), nullptr); EXPECT_NE(lst.sexp_list_at(1), nullptr); EXPECT_NE(lst.sexp_string_at(0), nullptr); EXPECT_EQ(lst.sexp_string_at(1), nullptr); const sexp_object_t *obj = lst.sexp_list_at(1); if (obj != nullptr) { EXPECT_EQ(obj->sexp_list_at(0), nullptr); EXPECT_EQ(obj->sexp_list_at(1), nullptr); } const sexp_string_t *sstr = lst.sexp_string_at(0); EXPECT_STREQ(reinterpret_cast(sstr->get_string().c_str()), "rnp_block"); } TEST_F(PrimitivesTests, eq4rnp) { const char *str_in = "(rnp_block (rnp_list1 rnp_list2))"; std::istringstream iss(str_in); sexp_input_stream_t is(&iss); sexp_list_t lst; lst.parse(is.set_byte_size(8)->get_char()); EXPECT_TRUE(*lst.at(0) == "rnp_block"); EXPECT_FALSE(*lst.at(0) == "not_rnp_block"); EXPECT_FALSE(*lst.at(1) == "rnp_block"); EXPECT_FALSE(*lst.at(1) == "not_rnp_block"); EXPECT_TRUE(*lst.sexp_string_at(0) == "rnp_block"); EXPECT_FALSE(*lst.sexp_string_at(0) == "not_rnp_block"); EXPECT_TRUE(*lst.sexp_simple_string_at(0) == "rnp_block"); EXPECT_FALSE(*lst.sexp_simple_string_at(0) == "not_rnp_block"); EXPECT_TRUE(*lst.sexp_list_at(1)->at(0) == "rnp_list1"); EXPECT_TRUE(*lst.sexp_list_at(1)->sexp_string_at(1) == "rnp_list2"); EXPECT_TRUE(lst.sexp_string_at(0) == std::string("rnp_block")); EXPECT_FALSE(lst.sexp_string_at(0) == std::string("not_rnp_block")); EXPECT_TRUE(lst.sexp_simple_string_at(0) == std::string("rnp_block")); EXPECT_FALSE(lst.sexp_simple_string_at(0) == std::string("not_rnp_block")); } TEST_F(PrimitivesTests, ne4rnp) { const char *str_in = "(rnp_block (rnp_list1 rnp_list2))"; std::istringstream iss(str_in); sexp_input_stream_t is(&iss); sexp_list_t lst; lst.parse(is.set_byte_size(8)->get_char()); EXPECT_FALSE(*lst.at(0) != "rnp_block"); EXPECT_TRUE(*lst.at(0) != "not_rnp_block"); EXPECT_TRUE(*lst.at(1) != "rnp_block"); EXPECT_TRUE(*lst.at(1) != "not_rnp_block"); EXPECT_FALSE(*lst.sexp_string_at(0) != "rnp_block"); EXPECT_TRUE(*lst.sexp_string_at(0) != "not_rnp_block"); EXPECT_FALSE(*lst.sexp_simple_string_at(0) != "rnp_block"); EXPECT_TRUE(*lst.sexp_simple_string_at(0) != "not_rnp_block"); EXPECT_FALSE(*lst.sexp_list_at(1)->at(0) != "rnp_list1"); EXPECT_FALSE(*lst.sexp_list_at(1)->sexp_string_at(1) != "rnp_list2"); EXPECT_FALSE(lst.sexp_string_at(0) != std::string("rnp_block")); EXPECT_TRUE(lst.sexp_string_at(0) != std::string("not_rnp_block")); EXPECT_FALSE(lst.sexp_simple_string_at(0) != std::string("rnp_block")); EXPECT_TRUE(lst.sexp_simple_string_at(0) != std::string("not_rnp_block")); } TEST_F(PrimitivesTests, u4rnp) { const char *str_in1 = "(unsigned_value \"12345\")"; const char *str_in2 = "(14:unsigned_value5:54321)"; std::istringstream iss1(str_in1); std::istringstream iss2(str_in2); sexp_input_stream_t is(&iss1); sexp_list_t lst; lst.parse(is.set_byte_size(8)->get_char()); EXPECT_EQ(lst.sexp_string_at(1)->as_unsigned(), 12345); lst.clear(); lst.parse(is.set_input(&iss2)->set_byte_size(8)->get_char()); EXPECT_EQ(lst.sexp_string_at(1)->as_unsigned(), 54321); } TEST_F(PrimitivesTests, proInheritance) { sexp_list_t lst; EXPECT_FALSE(lst.is_sexp_string()); EXPECT_TRUE(lst.is_sexp_list()); EXPECT_EQ(lst.sexp_string_view(), nullptr); EXPECT_EQ(lst.sexp_list_view(), &lst); EXPECT_EQ(lst.as_unsigned(), std::numeric_limits::max()); EXPECT_EQ(lst.sexp_list_at(0), nullptr); EXPECT_EQ(lst.sexp_string_at(0), nullptr); EXPECT_EQ(lst.sexp_simple_string_at(0), nullptr); sexp_string_t str; EXPECT_FALSE(str.is_sexp_list()); EXPECT_TRUE(str.is_sexp_string()); EXPECT_EQ(str.sexp_string_view(), &str); EXPECT_EQ(str.sexp_list_view(), nullptr); EXPECT_EQ(str.sexp_list_at(0), nullptr); EXPECT_EQ(str.sexp_string_at(0), nullptr); EXPECT_EQ(str.sexp_simple_string_at(0), nullptr); } TEST_F(PrimitivesTests, DisplayHint) { do_test_canonical("(URL [URI]www.ribose.com)", "(3:URL[3:URI]14:www.ribose.com)"); do_test_advanced("(3:URL[3:URI]14:www.ribose.com)", "(URL [URI]www.ribose.com)"); } TEST_F(PrimitivesTests, scanToEof) { const char *str_in = "ABCD"; std::istringstream iss(str_in); sexp_input_stream_t is(&iss); auto object = is.scan_to_eof(); EXPECT_TRUE(object->is_sexp_string()); is.set_byte_size(4); EXPECT_EQ(is.get_byte_size(), 4); EXPECT_EQ(is.get_char(), &is); EXPECT_EQ(is.get_byte_size(), 8); } TEST_F(PrimitivesTests, ChangeOutputByteSizeTest) { std::ostringstream oss(std::ios_base::binary); sexp_output_stream_t os(&oss); EXPECT_EQ(os.change_output_byte_size(8, sexp_output_stream_t::advanced), &os); try { os.change_output_byte_size(7, sexp_output_stream_t::advanced); FAIL() << "sexp::sexp_exception_t expected but has not been thrown"; } catch (sexp::sexp_exception_t &e) { EXPECT_STREQ(e.what(), "SEXP ERROR: Illegal output base 7"); } EXPECT_EQ(os.change_output_byte_size(4, sexp_output_stream_t::advanced), &os); try { os.change_output_byte_size(6, sexp_output_stream_t::advanced); FAIL() << "sexp::sexp_exception_t expected but has not been thrown"; } catch (sexp::sexp_exception_t &e) { EXPECT_STREQ(e.what(), "SEXP ERROR: Illegal change of output byte size from 4 to 6"); } } TEST_F(PrimitivesTests, FlushTest) { std::ostringstream oss1(std::ios_base::binary); std::ostringstream oss2(std::ios_base::binary); sexp_output_stream_t os(&oss1); EXPECT_EQ( os.change_output_byte_size(6, sexp_output_stream_t::advanced)->print_decimal(1)->flush(), &os); EXPECT_EQ(oss1.str(), "MQ=="); os.set_output(&oss2) ->change_output_byte_size(6, sexp_output_stream_t::advanced) ->set_max_column(2) ->print_decimal(2) ->flush(); EXPECT_EQ(oss2.str(), "Mg\n=="); } TEST_F(PrimitivesTests, ListWrapTest) { std::istringstream iss("(abc)"); sexp_input_stream_t is(&iss); const auto obj = is.set_byte_size(8)->get_char()->scan_object(); std::ostringstream oss(std::ios_base::binary); sexp_output_stream_t os(&oss); os.set_max_column(5)->print_advanced(obj); EXPECT_EQ(oss.str(), "(abc\n )"); } TEST_F(PrimitivesTests, EnsureHexTest) { std::istringstream iss("(3:a\011c)"); sexp_input_stream_t is(&iss); const auto obj = is.set_byte_size(8)->get_char()->scan_object(); std::ostringstream oss(std::ios_base::binary); sexp_output_stream_t os(&oss); os.print_advanced(obj); EXPECT_EQ(oss.str(), "(#610963#)"); } } // namespace sexpp-0.8.7/version.txt000066400000000000000000000000061444627452400151230ustar00rootroot000000000000000.8.7