diff --git a/.clang-format b/.clang-format index 2d2cfa7f2c..d2a2a088d6 100644 --- a/.clang-format +++ b/.clang-format @@ -306,22 +306,22 @@ IncludeCategories: - Regex: '^"pyhelpers/' Priority: 49800 - - Regex: '^"app/organicmaps/util/' + - Regex: '^"com/mapswithme/util/' Priority: 49840 - - Regex: '^"app/organicmaps/maps/' + - Regex: '^"com/mapswithme/maps/' Priority: 49850 - - Regex: '^"app/organicmaps/platform/' + - Regex: '^"com/mapswithme/platform/' Priority: 49860 - - Regex: '^"app/organicmaps/opengl/' + - Regex: '^"com/mapswithme/opengl/' Priority: 49870 - - Regex: '^"app/organicmaps/vulkan/' + - Regex: '^"com/mapswithme/vulkan/' Priority: 49880 - - Regex: '^"app/organicmaps/core/' + - Regex: '^"com/mapswithme/core/' Priority: 49890 - Regex: '^"private\.h"$' diff --git a/.git-blame-ignore-revs b/.git-blame-ignore-revs deleted file mode 100644 index 9f1d3bd76b..0000000000 --- a/.git-blame-ignore-revs +++ /dev/null @@ -1 +0,0 @@ -6aa73face8b5eb8e026cfafa40d1983d4a0502c0 diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md deleted file mode 100644 index 6f132ccea1..0000000000 --- a/.github/ISSUE_TEMPLATE/bug_report.md +++ /dev/null @@ -1,31 +0,0 @@ ---- -name: Bug Report -about: Describe your issue in details to help us improve Organic Maps -title: '' -labels: '' -assignees: '' - ---- - -**Describe the issue** -Please write here a clear and concise description of what the bug/issue is about. - -**Steps to reproduce** -1. Go to '...' -2. Click on '....' -3. Scroll down to '....' -4. See error - -**Expected behavior** -A clear and concise description of what you expected to happen. - -**Screenshots** -If applicable, add screenshots or screen recordings to help explain your problem. - -**System information:** - - Operating system and its version: [iOS 12, Android 10, Ubuntu 22, MacOS Big Sur, etc.] - - Organic Maps version: [you can find it by clicking the "?" button] - - Device Model: [e.g. iPhone6, Samsung S22] - -**Additional context** -Please add any other context and important details/notes/comments about the problem here. diff --git a/.github/ISSUE_TEMPLATE/config.yml b/.github/ISSUE_TEMPLATE/config.yml deleted file mode 100644 index ad4b943f95..0000000000 --- a/.github/ISSUE_TEMPLATE/config.yml +++ /dev/null @@ -1,11 +0,0 @@ -blank_issues_enabled: true -contact_links: - - name: Discussions - url: https://github.com/organicmaps/organicmaps/discussions - about: Discuss the usage of OrganicMaps, ask questions, or talk about ideas that are not yet actionable. - - name: Translations - url: https://github.com/organicmaps/organicmaps/blob/master/docs/TRANSLATIONS.md - about: Translate Organic Maps into your language - - name: News - url: https://organicmaps.app/news/ - about: Check the latest project news \ No newline at end of file diff --git a/.github/ISSUE_TEMPLATE/feature_request.md b/.github/ISSUE_TEMPLATE/feature_request.md deleted file mode 100644 index 72f3f207bc..0000000000 --- a/.github/ISSUE_TEMPLATE/feature_request.md +++ /dev/null @@ -1,22 +0,0 @@ ---- -name: Feature request -about: Suggest an idea for OrganicMaps -title: '' -labels: [Enhancement] -assignees: '' - ---- - -**Is your feature request related to a problem? Please describe.** -A clear and concise description of what the problem is. For example: -I'm always frustrated when [...] - -**Describe the solution you would like** -A clear and concise description of what you want to see in Organic Maps. - -**Describe alternatives you have considered** -- How do you solve this issue now with Organic Maps or other apps? -- Attach any examples, screenshots, or screen recordings from other apps that help us to better understand the idea. - -**Additional context** -Add any other context or screenshots about the feature request here. diff --git a/.github/workflows/android-beta.yaml b/.github/workflows/android-beta.yaml index 2f70d6437c..7826151107 100644 --- a/.github/workflows/android-beta.yaml +++ b/.github/workflows/android-beta.yaml @@ -38,17 +38,22 @@ jobs: sudo apt-get update -y sudo apt-get install -y ninja-build + - name: Set up JDK 11 + uses: actions/setup-java@v1 + with: + java-version: 11 + - name: Checkout sources - uses: actions/checkout@v3 + uses: actions/checkout@v2 with: fetch-depth: 100 # enough to get all commits for the current day - name: Parallel submodules checkout shell: bash - run: git submodule update --depth 1 --init --recursive --jobs=$(($(nproc) * 20)) + run: git submodule update --init --recursive --jobs=$(($(nproc) * 2)) - name: Checkout private keys - uses: actions/checkout@v3 + uses: actions/checkout@v2 with: repository: ${{ secrets.PRIVATE_REPO }} ssh-key: ${{ secrets.PRIVATE_SSH_KEY }} @@ -67,7 +72,7 @@ jobs: run: | cmake --version ninja --version - gradle -x lint -x lintVitalGoogleBeta assembleGoogleBeta uploadCrashlyticsSymbolFileGoogleBeta uploadCrashlyticsMappingFileGoogleBeta + gradle -x lint -x lintVitalGoogleBeta assembleGoogleBeta uploadCrashlyticsMappingFileGoogleRelease - name: Upload beta apk to App Distribution shell: bash diff --git a/.github/workflows/android-check-metadata.yaml b/.github/workflows/android-check-metadata.yaml index 10ae5651b6..bb78212edd 100644 --- a/.github/workflows/android-check-metadata.yaml +++ b/.github/workflows/android-check-metadata.yaml @@ -14,7 +14,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout - uses: actions/checkout@v3 + uses: actions/checkout@v2 - name: Check metadata run: ./tools/python/check_store_metadata.py android diff --git a/.github/workflows/android-check.yaml b/.github/workflows/android-check.yaml index 58ed9200de..b9f5b65691 100644 --- a/.github/workflows/android-check.yaml +++ b/.github/workflows/android-check.yaml @@ -26,28 +26,6 @@ on: - xcode/** jobs: - lint: - name: Android Lint - runs-on: ubuntu-latest - steps: - - name: Checkout sources - uses: actions/checkout@v3 - with: - fetch-depth: 1 - - - name: Parallel submodules checkout - shell: bash - run: git submodule update --depth 1 --init --recursive --jobs=$(($(nproc) * 20)) - - - name: Configure in Open Source mode - shell: bash - run: ./configure.sh - - - name: Lint - shell: bash - working-directory: android - run: gradle lint - android-check: name: Build Android Debug runs-on: ubuntu-latest @@ -64,13 +42,13 @@ jobs: sudo apt-get install -y ninja-build - name: Checkout sources - uses: actions/checkout@v3 + uses: actions/checkout@v2 with: fetch-depth: 200 # enough to get all commits for the current day - name: Parallel submodules checkout shell: bash - run: git submodule update --depth 1 --init --recursive --jobs=$(($(nproc) * 20)) + run: git submodule update --init --recursive --jobs=$(($(nproc) * 2)) - name: Configure in Open Source mode shell: bash diff --git a/.github/workflows/android-monkey.yaml b/.github/workflows/android-monkey.yaml index ef313cfb36..1a36f6ac00 100644 --- a/.github/workflows/android-monkey.yaml +++ b/.github/workflows/android-monkey.yaml @@ -10,7 +10,7 @@ jobs: name: Check preconditions steps: - name: Checkout sources - uses: actions/checkout@v3 + uses: actions/checkout@v2 with: fetch-depth: 1000 # fetch month or so @@ -21,9 +21,9 @@ jobs: DIRS="android base drape drape_frontend editor ge0 map platform routing search shaders storage traffic transit" if [ '${{ github.event_name }}' != 'schedule' ] || [ $(git rev-list --count --since="24 hours" HEAD $DIRS) -gt 0 ]; then - echo "updated=true" >> $GITHUB_OUTPUT + echo "::set-output name=updated::true" else - echo "updated=" >> $GITHUB_OUTPUT + echo "::set-output name=updated::" fi outputs: updated: ${{ steps.check.outputs.updated }} @@ -41,20 +41,25 @@ jobs: sudo apt-get update -y sudo apt-get install -y ninja-build + - name: Set up JDK 11 + uses: actions/setup-java@v1 + with: + java-version: 11 + - name: Install Google SDK uses: google-github-actions/setup-gcloud@v0 - name: Checkout sources - uses: actions/checkout@v3 + uses: actions/checkout@v2 with: fetch-depth: 100 # enough to get all commits for the current day - name: Parallel submodules checkout shell: bash - run: git submodule update --depth 1 --init --recursive --jobs=$(($(nproc) * 20)) + run: git submodule update --init --recursive --jobs=$(($(nproc) * 2)) - name: Checkout private keys - uses: actions/checkout@v3 + uses: actions/checkout@v2 with: repository: ${{ secrets.PRIVATE_REPO }} ssh-key: ${{ secrets.PRIVATE_SSH_KEY }} @@ -73,26 +78,16 @@ jobs: run: | cmake --version ninja --version - gradle -Pfirebase assembleGoogleDebug uploadCrashlyticsSymbolFileGoogleDebug + gradle -Parm64 -Parm32 -Pfirebase assembleGoogleDebug - name: Run monkey run: | gcloud auth activate-service-account --key-file android/firebase-test-lab.json gcloud config set project omapsapp gcloud firebase test android run --app ./android/build/outputs/apk/google/debug/OrganicMaps-*-google-debug.apk \ - --device model=panther,version=33 \ - --device model=bluejay,version=32 \ - --device model=b2q,version=31 \ - --device model=f2q,version=30 \ + --device model=redfin,version=30 \ --device model=a10,version=29 \ - --device model=Pixel2.arm,version=30 \ - --device model=MediumPhone.arm,version=29 \ - --device model=MediumPhone.arm,version=28 \ - --device model=MediumPhone.arm,version=27 \ - --device model=Pixel2.arm,version=26,orientation=landscape \ - --device model=Nexus6,version=25 \ - --device model=NexusLowRes,version=24 \ - --device model=NexusLowRes,version=23,orientation=landscape \ - --device model=Nexus6,version=22 \ - --device model=Nexus7,version=21 \ + --device model=dipper,version=28 \ + --device model=OnePlus3T,version=26 \ + --device model=flo,version=21,orientation=landscape \ --timeout 15m diff --git a/.github/workflows/android-release-metadata.yaml b/.github/workflows/android-release-metadata.yaml index 0505a997ea..f8233cb8b6 100644 --- a/.github/workflows/android-release-metadata.yaml +++ b/.github/workflows/android-release-metadata.yaml @@ -9,22 +9,31 @@ jobs: environment: production steps: - name: Checkout sources - uses: actions/checkout@v3 + uses: actions/checkout@v2 - name: Parallel submodules checkout shell: bash - run: git submodule update --depth 1 --init --recursive --jobs=$(($(nproc) * 20)) + run: git submodule update --init --recursive --jobs=$(($(nproc) * 2)) - name: Checkout screenshots - uses: actions/checkout@v3 + uses: actions/checkout@v2 with: repository: ${{ secrets.SCREENSHOTS_REPO }} ssh-key: ${{ secrets.SCREENSHOTS_SSH_KEY }} ref: master path: screenshots + # This symlink is not stored in the repo because Linter checks fail for the FDroid build. + # Linter complains about an invalid symlink (we don't check out screenshots for FDroid). + - name: Create symlink for GP screenshots + shell: bash + run: | + for locale in en-US tr-TR; do + ln -sf ../../../../../../screenshots/android/${locale}/graphics android/src/google/play/listings/${locale}/graphics + done + - name: Checkout private keys - uses: actions/checkout@v3 + uses: actions/checkout@v2 with: repository: ${{ secrets.PRIVATE_REPO }} ssh-key: ${{ secrets.PRIVATE_SSH_KEY }} @@ -39,6 +48,6 @@ jobs: - name: Upload shell: bash - run: ./gradlew prepareGoogleReleaseListing publishGoogleReleaseListing + run: ./gradlew publishGoogleReleaseListing working-directory: android timeout-minutes: 5 diff --git a/.github/workflows/android-release.yaml b/.github/workflows/android-release.yaml index 821417d962..98b1f9b301 100644 --- a/.github/workflows/android-release.yaml +++ b/.github/workflows/android-release.yaml @@ -13,7 +13,7 @@ jobs: environment: production steps: - name: Checkout sources - uses: actions/checkout@v3 + uses: actions/checkout@v2 with: fetch-depth: 100 # Enough to get all commits for the last day. ssh-key: ${{ secrets.RELEASE_SSH_KEY }} @@ -74,8 +74,13 @@ jobs: sudo apt-get update -y sudo apt-get install -y ninja-build + - name: Set up JDK 11 + uses: actions/setup-java@v1 + with: + java-version: 11 + - name: Checkout sources - uses: actions/checkout@v3 + uses: actions/checkout@v2 with: fetch-depth: 100 # enough to get all commits for the current day ref: 'refs/tags/${{ needs.tag.outputs.tag }}' @@ -89,10 +94,10 @@ jobs: - name: Parallel submodules checkout shell: bash - run: git submodule update --depth 1 --init --recursive --jobs=$(($(nproc) * 20)) + run: git submodule update --init --recursive --jobs=$(($(nproc) * 2)) - name: Checkout screenshots - uses: actions/checkout@v3 + uses: actions/checkout@v2 with: repository: ${{ secrets.SCREENSHOTS_REPO }} ssh-key: ${{ secrets.SCREENSHOTS_SSH_KEY }} @@ -100,7 +105,7 @@ jobs: path: screenshots - name: Checkout private keys - uses: actions/checkout@v3 + uses: actions/checkout@v2 with: repository: ${{ secrets.PRIVATE_REPO }} ssh-key: ${{ secrets.PRIVATE_SSH_KEY }} diff --git a/.github/workflows/appstream-check.yaml b/.github/workflows/appstream-check.yaml deleted file mode 100644 index 8e80ebbbc6..0000000000 --- a/.github/workflows/appstream-check.yaml +++ /dev/null @@ -1,29 +0,0 @@ -name: Validate appstream metadata xml -on: - workflow_dispatch: # Manual trigger - pull_request: - paths: - - packaging/app.organicmaps.desktop.metainfo.xml - - .github/workflows/appstream-check.yaml # Run check on self change - -jobs: - validate-appstream: - name: Validate appstream metadata xml - runs-on: ubuntu-22.04 - steps: - - name: Checkout sources - uses: actions/checkout@v3 - - - name: Install appstream validator - shell: bash - run: | - sudo apt update -y - sudo apt install -y \ - flatpak - sudo flatpak remote-add --if-not-exists flathub https://flathub.org/repo/flathub.flatpakrepo - # We get it from flathub to ensure we have a recent version - sudo flatpak install -y org.freedesktop.appstream-glib - - - name: Validate appstream data - shell: bash - run: flatpak run org.freedesktop.appstream-glib validate --nonet packaging/app.organicmaps.desktop.metainfo.xml diff --git a/.github/workflows/ios-beta.yaml b/.github/workflows/ios-beta.yaml index b4d125376c..60fc1344e1 100644 --- a/.github/workflows/ios-beta.yaml +++ b/.github/workflows/ios-beta.yaml @@ -39,15 +39,15 @@ jobs: shell: bash steps: - name: Checkout sources - uses: actions/checkout@v3 + uses: actions/checkout@v2 with: fetch-depth: 100 # enough to get all commits for the current day - name: Parallel submodules checkout - run: git submodule update --depth 1 --init --recursive --jobs=$(($(sysctl -n hw.logicalcpu) * 20)) + run: git submodule update --init --recursive --jobs=4 - name: Checkout private keys - uses: actions/checkout@v3 + uses: actions/checkout@v2 with: repository: ${{ secrets.PRIVATE_REPO }} ssh-key: ${{ secrets.PRIVATE_SSH_KEY }} diff --git a/.github/workflows/ios-check-metadata.yaml b/.github/workflows/ios-check-metadata.yaml index e5922c070a..81579256ae 100644 --- a/.github/workflows/ios-check-metadata.yaml +++ b/.github/workflows/ios-check-metadata.yaml @@ -1,4 +1,4 @@ -name: iOS Check metadata +name: iOS Check on: workflow_dispatch: # Manual trigger pull_request: @@ -13,7 +13,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout - uses: actions/checkout@v3 + uses: actions/checkout@v2 - name: Check metadata run: ./tools/python/check_store_metadata.py ios diff --git a/.github/workflows/ios-check.yaml b/.github/workflows/ios-check.yaml index d20bc3d58c..98002b6e5a 100644 --- a/.github/workflows/ios-check.yaml +++ b/.github/workflows/ios-check.yaml @@ -38,11 +38,11 @@ jobs: buildType: [Debug, Release] steps: - name: Checkout sources - uses: actions/checkout@v3 + uses: actions/checkout@v2 - name: Parallel submodules checkout shell: bash - run: git submodule update --depth 1 --init --recursive --jobs=$(($(sysctl -n hw.logicalcpu) * 20)) + run: git submodule update --init --recursive --jobs=4 - name: Configure shell: bash diff --git a/.github/workflows/ios-release.yaml b/.github/workflows/ios-release.yaml index 55c8af2e98..7ce1117ed4 100644 --- a/.github/workflows/ios-release.yaml +++ b/.github/workflows/ios-release.yaml @@ -13,10 +13,10 @@ jobs: environment: production steps: - name: Checkout - uses: actions/checkout@v3 + uses: actions/checkout@v2 - name: Checkout private keys - uses: actions/checkout@v3 + uses: actions/checkout@v2 with: repository: ${{ secrets.PRIVATE_REPO }} ssh-key: ${{ secrets.PRIVATE_SSH_KEY }} @@ -31,25 +31,13 @@ jobs: rm -rf ./private.git - name: Checkout screenshots - uses: actions/checkout@v3 + uses: actions/checkout@v2 with: repository: ${{ secrets.SCREENSHOTS_REPO }} ssh-key: ${{ secrets.SCREENSHOTS_SSH_KEY }} ref: master path: screenshots - - name: Checkout keywords - uses: actions/checkout@v3 - with: - repository: ${{ secrets.KEYWORDS_REPO }} - ssh-key: ${{ secrets.KEYWORDS_SSH_KEY }} - ref: master - path: keywords - - - name: Update metadata - shell: bash - run: ./tools/python/check_store_metadata.py ios - # NOTE: a new iOS draft must be created before this step - name: Upload metadata shell: bash diff --git a/.github/workflows/linux-check.yaml b/.github/workflows/linux-check.yaml index e9dea31be2..a32f5e463b 100644 --- a/.github/workflows/linux-check.yaml +++ b/.github/workflows/linux-check.yaml @@ -25,7 +25,7 @@ on: jobs: linux-no-unity: name: Linux no unity build - runs-on: ubuntu-22.04 + runs-on: ubuntu-latest strategy: fail-fast: false steps: @@ -35,13 +35,11 @@ jobs: sudo rm -rf /usr/share/dotnet /usr/local/lib/android /opt/ghc - name: Checkout sources - uses: actions/checkout@v3 - with: - fetch-depth: 100 # enough to get all commits for the current day + uses: actions/checkout@v2 - name: Parallel submodules checkout shell: bash - run: git submodule update --depth 1 --init --recursive --jobs=$(($(nproc) * 20)) + run: git submodule update --init --recursive --jobs=$(($(nproc) * 2)) - name: Install build tools and dependencies shell: bash @@ -50,7 +48,8 @@ jobs: sudo apt install -y \ ninja-build \ qtbase5-dev \ - libqt5svg5-dev + libqt5svg5-dev \ + clang-tools-11 - name: Configure shell: bash @@ -59,8 +58,8 @@ jobs: - name: CMake shell: bash env: - CC: clang-14 - CXX: clang++-14 + CC: clang-12 + CXX: clang++-12 # -g1 should slightly reduce build time. run: | cmake . -B build -G Ninja -DCMAKE_BUILD_TYPE=Debug -DCMAKE_CXX_FLAGS=-g1 -DUNITY_DISABLE=ON @@ -72,11 +71,11 @@ jobs: linux-matrix: name: Linux builds and tests - runs-on: ubuntu-22.04 + runs-on: ubuntu-latest strategy: fail-fast: false matrix: - compiler: [{ CXX: g++-12, CC: gcc-12 }, { CXX: clang++-14, CC: clang-14 }] + compiler: [{ CXX: g++-10, CC: gcc-10 }, { CXX: clang++-12, CC: clang-12 }] CMAKE_BUILD_TYPE: [Debug, RelWithDebInfo] steps: @@ -86,22 +85,21 @@ jobs: sudo rm -rf /usr/share/dotnet /usr/local/lib/android /opt/ghc - name: Checkout sources - uses: actions/checkout@v3 + uses: actions/checkout@v2 - name: Parallel submodules checkout shell: bash - run: git submodule update --depth 1 --init --recursive --jobs=$(($(nproc) * 20)) + run: git submodule update --init --recursive --jobs=$(($(nproc) * 2)) - name: Install build tools and dependencies shell: bash run: | sudo apt update -y sudo apt install -y \ - g++-12 \ - gcc-12 \ ninja-build \ qtbase5-dev \ - libqt5svg5-dev + libqt5svg5-dev \ + clang-tools-11 - name: Configure shell: bash @@ -123,9 +121,9 @@ jobs: run: ninja - name: Checkout world_feed_integration_tests_data - uses: actions/checkout@v3 + uses: actions/checkout@v2 with: - repository: organicmaps/world_feed_integration_tests_data + repository: omapsapp/world_feed_integration_tests_data path: data/world_feed_integration_tests_data - name: Tests @@ -155,3 +153,27 @@ jobs: -e routing_consistency_tests \ -e opening_hours_supported_features_tests \ -e storage_integration_tests \ + -e osm_auth_tests \ # Disable temporarily while OSM dev server is down. + + linux-appstream: + name: Linux validate appstream data + runs-on: ubuntu-latest + strategy: + fail-fast: false + steps: + - name: Checkout sources + uses: actions/checkout@v2 + + - name: Install appstream validator + shell: bash + run: | + sudo apt update -y + sudo apt install -y \ + flatpak + sudo flatpak remote-add --if-not-exists flathub https://flathub.org/repo/flathub.flatpakrepo + # We get it from flathub to ensure we have a recent version + sudo flatpak install -y org.freedesktop.appstream-glib + + - name: Validate appstream data + shell: bash + run: flatpak run org.freedesktop.appstream-glib validate --nonet qt/res/app.organicmaps.desktop.metainfo.xml diff --git a/.github/workflows/macos-check.yaml b/.github/workflows/macos-check.yaml deleted file mode 100644 index 3bd9c93236..0000000000 --- a/.github/workflows/macos-check.yaml +++ /dev/null @@ -1,97 +0,0 @@ -name: macOS Check -on: - workflow_dispatch: # Manual trigger - pull_request: - paths-ignore: - - .gitignore - - .github/** - - '!.github/workflows/macos-check.yaml' # Run check on self change - - CONTRIBUTORS - - LICENSE - - NOTICE - - README.md - - android/** - - iphone/** - - data/strings/** - - docs/** - - packaging/** - - pyhelpers/** - - tools/** - - '!tools/python/run_desktop_tests.py' - - '!tools/python/testserver.py' - - '!tools/python/SiblingKiller.py' - - xcode/** - -jobs: - macos-matrix: - name: macOS builds and tests - runs-on: macos-12 - env: - HOMEBREW_NO_ANALYTICS: 1 - HOMEBREW_NO_INSTALL_CLEANUP: 1 - strategy: - fail-fast: false - matrix: - CMAKE_BUILD_TYPE: [Debug, RelWithDebInfo] - - steps: - - name: Checkout sources - uses: actions/checkout@v3 - - - name: Parallel submodules checkout - shell: bash - run: git submodule update --depth 1 --init --recursive --jobs=$(($(sysctl -n hw.logicalcpu) * 20)) - - - name: Install build tools and dependencies - shell: bash - run: | - brew install ninja qt@5 - - - name: Configure - shell: bash - run: ./configure.sh - - - name: CMake - shell: bash - run: | - echo "Building ${{ matrix.CMAKE_BUILD_TYPE }}" - cmake . -B build -G Ninja -DCMAKE_BUILD_TYPE=${{ matrix.CMAKE_BUILD_TYPE }} -DCMAKE_C_FLAGS=-g1 -DCMAKE_CXX_FLAGS=-g1 - - - name: Compile - shell: bash - working-directory: build - run: ninja - - - name: Checkout world_feed_integration_tests_data - uses: actions/checkout@v3 - with: - repository: organicmaps/world_feed_integration_tests_data - path: data/world_feed_integration_tests_data - - - name: Tests - shell: bash - # generator_integration_tests - https://github.com/organicmaps/organicmaps/issues/225 -# # routing_integration_tests - https://github.com/organicmaps/organicmaps/issues/221 - # routing_quality_tests - https://github.com/organicmaps/organicmaps/issues/215 - # drape_tests - requires X Window - - # Separate run of OH boost-based test - run: | - ./build/opening_hours_tests | - ./tools/python/run_desktop_tests.py \ - -f ./build \ - -u ./data \ - -d ./data \ - -e generator_integration_tests \ - -e routing_integration_tests \ - -e routing_quality_tests \ - -e search_quality_tests \ - -e world_feed_integration_tests \ - -e drape_tests \ - -e shaders_tests \ - \ - -e opening_hours_tests \ - -e opening_hours_integration_tests \ - -e routing_consistency_tests \ - -e opening_hours_supported_features_tests \ - -e storage_integration_tests diff --git a/.github/workflows/strings-check.yaml b/.github/workflows/strings-check.yaml index 3e695c089f..d392aa82ea 100644 --- a/.github/workflows/strings-check.yaml +++ b/.github/workflows/strings-check.yaml @@ -14,7 +14,7 @@ jobs: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v2 - uses: actions/setup-python@v2 with: python-version: '3' diff --git a/.gitignore b/.gitignore index 3ed246c9e0..17f0fd2d32 100644 --- a/.gitignore +++ b/.gitignore @@ -176,8 +176,6 @@ tools/python/routing/etc/*.ini # VS Code .vscode -# AppStore metadata -screenshots/ -android/src/google/play/listings/ -keywords/ -iphone/metadata/**/keywords.txt +# Screenshots +screenshots +android/src/google/play/listings/??-??/graphics diff --git a/.gitmodules b/.gitmodules index 113383eba8..15ee07722b 100644 --- a/.gitmodules +++ b/.gitmodules @@ -46,7 +46,4 @@ url = https://github.com/lemire/fast_double_parser.git [submodule "3party/pugixml/pugixml"] path = 3party/pugixml/pugixml - url = https://github.com/zeux/pugixml.git -[submodule "3party/jansson/jansson"] - path = 3party/jansson/jansson - url = https://github.com/akheron/jansson.git + url = https://github.com/organicmaps/pugixml.git diff --git a/3party/boost b/3party/boost index 5002c2d6a2..ecdd60e74c 160000 --- a/3party/boost +++ b/3party/boost @@ -1 +1 @@ -Subproject commit 5002c2d6a2b5ed56a82128797828de95dab2ddba +Subproject commit ecdd60e74c0d43b9710d05f56967b1a01d7c9518 diff --git a/3party/bsdiff-courgette/bsdiff/bsdiff_tests/bsdiff_search_tests.cpp b/3party/bsdiff-courgette/bsdiff/bsdiff_tests/bsdiff_search_tests.cpp index 45a09290cd..dea1fb6fea 100644 --- a/3party/bsdiff-courgette/bsdiff/bsdiff_tests/bsdiff_search_tests.cpp +++ b/3party/bsdiff-courgette/bsdiff/bsdiff_tests/bsdiff_search_tests.cpp @@ -19,7 +19,7 @@ UNIT_TEST(BSDiffSearchTest_Search) // 012345678901234567890123456789012345678901234 string const str = "the quick brown fox jumps over the lazy dog."; int const size = static_cast(str.size()); - auto buf = reinterpret_cast(str.data()); + auto buf = reinterpret_cast(str.data()); vector suffix_array(size + 1); divsuf::divsufsort_include_empty(buf, suffix_array.data(), size); @@ -63,7 +63,7 @@ UNIT_TEST(BSDiffSearchTest_Search) { auto const & testCase = testCases[idx]; int const querySize = static_cast(testCase.m_query_str.size()); - auto query_buf = reinterpret_cast(testCase.m_query_str.data()); + auto query_buf = reinterpret_cast(testCase.m_query_str.data()); // Perform the search. bsdiff::SearchResult const match = @@ -106,7 +106,7 @@ UNIT_TEST(BSDiffSearchTest_SearchExact) { int const size = static_cast(testCases[idx].size()); unsigned char const * const buf = - reinterpret_cast(testCases[idx].data()); + reinterpret_cast(testCases[idx].data()); vector suffix_array(size + 1); divsuf::divsufsort_include_empty(buf, suffix_array.data(), size); @@ -120,7 +120,7 @@ UNIT_TEST(BSDiffSearchTest_SearchExact) int querySize = static_cast(query.size()); CHECK_EQUAL(querySize, hi - lo, ()); unsigned char const * const query_buf = - reinterpret_cast(query.c_str()); + reinterpret_cast(query.c_str()); bsdiff::SearchResult const match = bsdiff::search(suffix_array, buf, size, query_buf, querySize); diff --git a/3party/expat b/3party/expat index 654d2de0da..1bb22cd03a 160000 --- a/3party/expat +++ b/3party/expat @@ -1 +1 @@ -Subproject commit 654d2de0da85662fcc7644a7acd7c2dd2cfb21f0 +Subproject commit 1bb22cd03ab1ad48efb2bdee08cb805b5b593ea5 diff --git a/3party/fast_double_parser b/3party/fast_double_parser index efec03532e..111ad80417 160000 --- a/3party/fast_double_parser +++ b/3party/fast_double_parser @@ -1 +1 @@ -Subproject commit efec03532ef65984786e5e32dbc81f6e6a55a115 +Subproject commit 111ad8041765d1623195bd6eb8b6bc7d97c44507 diff --git a/3party/googletest b/3party/googletest index 58d77fa807..e2f3978937 160000 --- a/3party/googletest +++ b/3party/googletest @@ -1 +1 @@ -Subproject commit 58d77fa8070e8cec2dc1ed015d66b454c8d78850 +Subproject commit e2f3978937c0244508135f126e2617a7734a68be diff --git a/3party/jansson/.travis.yml b/3party/jansson/.travis.yml new file mode 100644 index 0000000000..5b23c9484c --- /dev/null +++ b/3party/jansson/.travis.yml @@ -0,0 +1,22 @@ +env: + matrix: + - JANSSON_BUILD_METHOD=cmake JANSSON_CMAKE_OPTIONS="-DJANSSON_TEST_WITH_VALGRIND=ON" JANSSON_EXTRA_INSTALL="valgrind" + - JANSSON_BUILD_METHOD=autotools + - JANSSON_BUILD_METHOD=coverage JANSSON_CMAKE_OPTIONS="-DJANSSON_COVERAGE=ON -DJANSSON_COVERALLS=ON -DCMAKE_BUILD_TYPE=Debug" JANSSON_EXTRA_INSTALL="lcov curl" +language: c +compiler: + - gcc + - clang +matrix: + exclude: + - compiler: clang + env: JANSSON_BUILD_METHOD=coverage JANSSON_CMAKE_OPTIONS="-DJANSSON_COVERAGE=ON -DJANSSON_COVERALLS=ON -DCMAKE_BUILD_TYPE=Debug" JANSSON_EXTRA_INSTALL="lcov curl" + allow_failures: + - env: JANSSON_BUILD_METHOD=coverage JANSSON_CMAKE_OPTIONS="-DJANSSON_COVERAGE=ON -DJANSSON_COVERALLS=ON -DCMAKE_BUILD_TYPE=Debug" JANSSON_EXTRA_INSTALL="lcov curl" +install: + - sudo apt-get update -qq + - sudo apt-get install -y -qq cmake $JANSSON_EXTRA_INSTALL +script: + - if [ "$JANSSON_BUILD_METHOD" = "autotools" ]; then autoreconf -f -i && CFLAGS=-Werror ./configure && make check; fi + - if [ "$JANSSON_BUILD_METHOD" = "cmake" ]; then mkdir build && cd build && cmake $JANSSON_CMAKE_OPTIONS .. && cmake --build . && ctest --output-on-failure; fi + - if [ "$JANSSON_BUILD_METHOD" = "coverage" ]; then mkdir build && cd build && cmake $JANSSON_CMAKE_OPTIONS .. && cmake --build . && cmake --build . --target coveralls; fi diff --git a/3party/jansson/Android.mk b/3party/jansson/Android.mk new file mode 100644 index 0000000000..e3b09e72cc --- /dev/null +++ b/3party/jansson/Android.mk @@ -0,0 +1,30 @@ +LOCAL_PATH:= $(call my-dir) +include $(CLEAR_VARS) + +LOCAL_ARM_MODE := arm + +LOCAL_SRC_FILES := \ + src/dump.c \ + src/error.c \ + src/hashtable.c \ + src/hashtable_seed.c \ + src/load.c \ + src/memory.c \ + src/pack_unpack.c \ + src/strbuffer.c \ + src/strconv.c \ + src/utf.c \ + src/value.c + +LOCAL_C_INCLUDES += \ + $(LOCAL_PATH) \ + $(LOCAL_PATH)/android \ + $(LOCAL_PATH)/src + +LOCAL_MODULE_TAGS := optional +LOCAL_SHARED_LIBRARIES := libc +LOCAL_CFLAGS += -O3 -DHAVE_STDINT_H=1 + +LOCAL_MODULE:= libjansson + +include $(BUILD_SHARED_LIBRARY) diff --git a/3party/jansson/CHANGES b/3party/jansson/CHANGES new file mode 100644 index 0000000000..211cb5749a --- /dev/null +++ b/3party/jansson/CHANGES @@ -0,0 +1,903 @@ +Version 2.12 + +Released 2018-11-25 + +* Bug fixes: + + - Fix error message in `json_pack()` for NULL object (#409). + + - Avoid invalid memory read in `json_pack()` (#421). + + - Call va_end after va_copy in `json_vsprintf()` (#427). + + - Improve handling of formats with '?' and '*' in `json_pack()` (#438). + + - Remove inappropriate `jsonp_free()` which caused segmentation fault in + error handling (#444). + +* Build: + + - Add function attributes for GCC and CLANG to provide warnings on improper + use of jansson routines (#404). + + - Many CMake fixes (#408, #412, #415). + + - Enable -Bsymbolic-functions linker flag whenever possible. + + - Resolve various compiler warnings (#423, #430, #435, #436). + + - Fix code coverage ignored paths (#439). + +* Other: + + - Test coverage improvements (#398, #400). + + - Add VS 2017 to appveyor, update Visual Studio documentation (#417). + + - Update copyright for 2018 (#424). + + - Update install instructions in README (#401). + +Version 2.11 +============ + +Released 2018-02-09 + +* New features: + + - Add `json_pack()` format specifiers s*, o* and O* for values that + can be omitted if null (#339). + + - Add `json_error_code()` to retrieve numeric error codes (#365, #380, + #381). + + - Enable thread safety for `json_dump()` on all systems. Enable thread + safe `json_decref()` and `json_incref()` for modern compilers (#389). + + - Add `json_sprintf()` and `json_vsprintf()` (#393). + +* Bug Fixes: + + - Fix incorrect report of success from `json_dump_file()` when an error + is returned by `fclose()` (#359). + + - Make json_equal() const-correct (#344). + + - Fix incomplete stealing of references by `json_pack()` (#374). + +* Build: + + - Work around gcc's -Wimplicit-fallthrough. + + - Fix CMake detection of `sys/types.h` header (#375). + + - Fix `jansson.pc` generated by CMake to be more consistent with the one + generated using GNU Autotools (#368). + +* Other: + + - Miscellaneous documentation fixes (#356, #378, #395). + + - Remove unnecessary reference actions from parsers (#377). + +Version 2.10 +============ + +Released 2017-03-02 + +* New features: + + - Add JSON_EMBED encoding flag allowing arrays and objects to be encoded + into existing streams (#329). + + - Add `json_dumpb()` function for dumping to a pre-allocated buffer (#328). + + - Add `json_dumpfd()` and `json_loadfd()` functions for dumping to streaming + file descriptors (#328). + + - Add support for parsing buffers larger than 2GB (#309). + +* Build: + + - Fix CMake build when LONG_LONG_INT is defined as "" (#321) + +* Other: + + - Internal code cleanup (#311, #314) + +Version 2.9 +=========== + +Released 2016-09-18 + +* New features: + + - Add ``json_auto_t`` to automatically decref a value that goes out + of scope. Available only on GCC and Clang. (#301) + +* Build: + + - Fix CMake build (at least on Linux) by removing conflicting + jansson_config.h from the distribution (#306) + + - Change CMake install target generation to be optional (#305) + +* Documentation: + + - Small documentation fixes. + + +Version 2.8 +=========== + +Released 2016-08-30 + +* New features: + + - Always preserve insertion order of object items. + `json_object_iter()` and friends, `json_object_foreach()` and + `json_dumps()` and friends now always work in the insertion order of + object items (#293). + + - Add `json_object_foreach_safe()` macro that allows + `json_object_del()` calls during iteration (#230). + + - Add `json_get_alloc_funcs()` to allow reading the allocation + functions set by `json_set_alloc_funcs()` (#262, #264). + + - Add `json_pack()` format specifiers s?, o? and O? for values that + can be null (#261, #270). + +* Bug fixes: + + - Fix a crash when parsing inputs consisting of very deeply nested + arrays or objects (#282, #284). + + - Never convert numbers to integers in the parser when + JSON_DECODE_INT_AS_REAL is set. This fixes error messages for + overflowing numbers when JSON_DECODE_INT_AS_REAL is set (#212). + + - Fix a use-after-free in `json_pack()` error handling. + + - Fix subnormal number parsing on mingw32. + + - Handle out-of-memory situations gracefully in the hashtable + implementation (#298). + +* Build: + + - Fix build with CMake on all versions of Visual Studio up to 2015 + (#262, #289). + + - Fix pkgconfig libdir when using CMake (#268). + + - Fix CMake config for static CRT builds on Windows (#206). + + - Fix warnings on LLVM 6.0 targeting iOS arm64 (#208). + + - Add coverlls.io support via Travis for a nice test coverage badge + (#211). + + - Don't expect ``jansson_config.h`` to be in the compiler's include + path (#209). + + - Add a build-time option to set initial hashtable size (#213). + + - Use snprintf and strncpy in place of sprintf and strcpy to silence + linker warnings on OpenBSD (#233). + +* Documentation: + + - Fix various typos in documentation, and a broken link (#258). + + - Add an example program in ``examples/`` (#214, #217). + + - Fix building of documentation man pages (#207). + + - Document the fact that copying objects doesn't preserve the + insertion order of keys (#237). + +* Tests: + + - Don't use the nonstandard __FUNCTION__ macro in tests. + + - Use expr instead of $((...)) in shell scripts for Solaris 10 + compatibility. + + - Disable Visual Studio warning C4756 when triggered deliberately in + tests (#216). + + - Other minor fixes (#221, #248). + +* Other changes: + + - List all unrecognized object keys when strict unpacking fails + (#263). + + - Alter the order of the members of the hashtable_pair struct for + easier debugging. + + - Minor performance improvement to `json_dump()` and friends (#234). + + - Minor style fixes (#255, #257). + + +Version 2.7 +=========== + +Released 2014-10-02 + +* New features: + + - `json_pack()` and friends: Add format specifiers ``s%`` and ``+%`` + for a size_t string length (#141). + + - `json_unpack()` and friends: Add format specifier ``s%`` for + unpacking the string length along with the string itself (#141). + + - Add length-aware string constructors `json_stringn()` and + `json_stringn_nocheck()`, length-aware string mutators + `json_string_setn()` and `json_string_setn_nocheck()`, and a + function for getting string's length `json_string_length()` (#141, + #143). + + - Support ``\u0000`` escapes in the decoder. The support can be + enabled by using the ``JSON_ALLOW_NUL`` decoding flag (#141). + + - Add `json_boolean_value()` as an alias for `json_is_true()` + (#146). + + - Add JSON_REAL_PRECISION encoding flag/macro for controlling real + number precision (#178). + + - Define the maximum indentation as JSON_MAX_INDENT (#191). + +* Bug fixes: + + - Some malformed ``\uNNNN`` escapes could crash the decoder with an + assertion failure. + + - Avoid integer overflows with very long strings in UTF-8 decoder and + hashtable. + + - Check for *NULL* key in `json_object_get()` and + `json_object_del()` (#151). + + - Enhance hashtable seeding on Windows (#162). + + - `json_unpack()`: Allow mixing JSON_STRICT with optional keys + (#162, #163). + + - Fix int/int32 mismatch (#142). + + - Parse subnormal numbers correctly (#202). + +* Build: + + - Remove VS2010 build files. CMake should be used on Windows instead + (#165). + + - Fix CMake build flags for MinGW (#193). + + - Add CMake config files for find_package. Rename config.h to + jansson_private_config.h (#157, #159). + + - Make Valgrind checks work with CMake (#160). + + - Fix feature checks to use correct __ATOMIC flags. + + - Fix CMake checks for uint16_t and uint8_t support (#177). + + - Make Jansson build on SmartOS/Solaris (#171). + + - Work around a GCC bug on Solaris (#175). + + - Fix autoreconf on Debian (#182). + + - Don't use GNU make specific export for global AM_CFLAGS (#203, + #204). + + - Fix building on Android using the supplied Android.mk (#166, + #174). + + - Android.mk: Add -DHAVE_STDINT_H to LOCAL_CFLAGS (#200). + +* Documentation: + + - Document JANSSON_BUILD_SHARED_LIBS CMake option (#187). + +* Tests: + + - Close file handles correctly (#198). + +* Other changes: + + - ``\uNNNN`` escapes are now encoded in upper case for better + readability. + + - Enable usage of AddressSanitizer (#180). + + +Version 2.6 +=========== + +Released 2014-02-11 + +* Security: + + - CVE-2013-6401: The hash function used by the hashtable + implementation has been changed, and is automatically seeded with + random data when the first JSON object is created. This prevents + an attacker from causing large JSON objects with specially crafted + keys perform poorly. + +* New features: + + - `json_object_seed()`: Set the seed value of the hash function. + +* Bug fixes: + + - Include CMake specific files in the release tarball. + +* Documentation: + + - Fix tutorial source to send a User-Agent header, which is now + required by the GitHub API. + + - Set all memory to zero in secure_free() example. + + +Version 2.5 +=========== + +Released 2013-09-19 + +* New features: + + - `json_pack()` and friends: Add format specifiers ``s#``, ``+`` and + ``+#``. + + - Add ``JSON_DECODE_INT_AS_REAL`` decoding flag to treat all numbers + as real in the decoder (#123). + + - Add `json_array_foreach()`, paralleling `json_object_foreach()` + (#118). + +* Bug fixes: + + - `json_dumps()` and friends: Don't crash if json is *NULL* and + ``JSON_ENCODE_ANY`` is set. + + - Fix a theoretical integer overflow in `jsonp_strdup()`. + + - Fix `l_isxdigit()` macro (#97). + + - Fix an off-by-one error in `json_array_remove()`. + +* Build: + + - Support CMake in addition to GNU Autotools (#106, #107, #112, + #115, #120, #127). + + - Support building for Android (#109). + + - Don't use ``-Werror`` by default. + + - Support building and testing with VPATH (#93). + + - Fix compilation when ``NDEBUG`` is defined (#128) + +* Tests: + + - Fix a refleak in ``test/bin/json_process.c``. + +* Documentation: + + - Clarify the return value of `json_load_callback_t`. + + - Document how to circumvent problems with separate heaps on Windows. + + - Fix memory leaks and warnings in ``github_commits.c``. + + - Use `json_decref()` properly in tutorial. + +* Other: + + - Make it possible to forward declare ``struct json_t``. + + +Version 2.4 +=========== + +Released 2012-09-23 + +* New features: + + - Add `json_boolean()` macro that returns the JSON true or false + value based on its argument (#86). + + - Add `json_load_callback()` that calls a callback function + repeatedly to read the JSON input (#57). + + - Add JSON_ESCAPE_SLASH encoding flag to escape all occurences of + ``/`` with ``\/``. + +* Bug fixes: + + - Check for and reject NaN and Inf values for reals. Encoding these + values resulted in invalid JSON. + + - Fix `json_real_set()` to return -1 on error. + +* Build: + + - Jansson now builds on Windows with Visual Studio 2010, and + includes solution and project files in ``win32/vs2010/`` + directory. + + - Fix build warnings (#77, #78). + + - Add ``-no-undefined`` to LDFLAGS (#90). + +* Tests: + + - Fix the symbol exports test on Linux/PPC64 (#88). + +* Documentation: + + - Fix typos (#73, #84). + + +Version 2.3.1 +============= + +Released 2012-04-20 + +* Build issues: + + - Only use ``long long`` if ``strtoll()`` is also available. + +* Documentation: + + - Fix the names of library version constants in documentation. (#52) + + - Change the tutorial to use GitHub API v3. (#65) + +* Tests: + + - Make some tests locale independent. (#51) + + - Distribute the library exports test in the tarball. + + - Make test run on shells that don't support the ``export FOO=bar`` + syntax. + + +Version 2.3 +=========== + +Released 2012-01-27 + +* New features: + + - `json_unpack()` and friends: Add support for optional object keys + with the ``{s?o}`` syntax. + + - Add `json_object_update_existing()` and + `json_object_update_missing()`, for updating only existing keys or + only adding missing keys to an object. (#37) + + - Add `json_object_foreach()` for more convenient iteration over + objects. (#45, #46) + + - When decoding JSON, write the number of bytes that were read from + input to ``error.position`` also on success. This is handy with + ``JSON_DISABLE_EOF_CHECK``. + + - Add support for decoding any JSON value, not just arrays or + objects. The support is enabled with the new ``JSON_DECODE_ANY`` + flag. Patch by Andrea Marchesini. (#4) + +* Bug fixes + + - Avoid problems with object's serial number growing too big. (#40, + #41) + + - Decoding functions now return NULL if the first argument is NULL. + Patch by Andrea Marchesini. + + - Include ``jansson_config.h.win32`` in the distribution tarball. + + - Remove ``+`` and leading zeros from exponents in the encoder. + (#39) + + - Make Jansson build and work on MinGW. (#39, #38) + +* Documentation + + - Note that the same JSON values must not be encoded in parallel by + separate threads. (#42) + + - Document MinGW support. + + +Version 2.2.1 +============= + +Released 2011-10-06 + +* Bug fixes: + + - Fix real number encoding and decoding under non-C locales. (#32) + + - Fix identifier decoding under non-UTF-8 locales. (#35) + + - `json_load_file()`: Open the input file in binary mode for maximum + compatiblity. + +* Documentation: + + - Clarify the lifecycle of the result of the ``s`` fromat of + `json_unpack()`. (#31) + + - Add some portability info. (#36) + + - Little clarifications here and there. + +* Other: + + - Some style fixes, issues detected by static analyzers. + + +Version 2.2 +=========== + +Released 2011-09-03 + +* New features: + + - `json_dump_callback()`: Pass the encoder output to a callback + function in chunks. + +* Bug fixes: + + - `json_string_set()`: Check that target is a string and value is + not NULL. + +* Other: + + - Documentation typo fixes and clarifications. + + +Version 2.1 +=========== + +Released 2011-06-10 + +* New features: + + - `json_loadb()`: Decode a string with a given size, useful if the + string is not null terminated. + + - Add ``JSON_ENCODE_ANY`` encoding flag to allow encoding any JSON + value. By default, only arrays and objects can be encoded. (#19) + + - Add ``JSON_REJECT_DUPLICATES`` decoding flag to issue a decoding + error if any JSON object in the input contins duplicate keys. (#3) + + - Add ``JSON_DISABLE_EOF_CHECK`` decoding flag to stop decoding after a + valid JSON input. This allows other data after the JSON data. + +* Bug fixes: + + - Fix an additional memory leak when memory allocation fails in + `json_object_set()` and friends. + + - Clear errno before calling `strtod()` for better portability. (#27) + +* Building: + + - Avoid set-but-not-used warning/error in a test. (#20) + +* Other: + + - Minor clarifications to documentation. + + +Version 2.0.1 +============= + +Released 2011-03-31 + +* Bug fixes: + + - Replace a few `malloc()` and `free()` calls with their + counterparts that support custom memory management. + + - Fix object key hashing in json_unpack() strict checking mode. + + - Fix the parentheses in ``JANSSON_VERSION_HEX`` macro. + + - Fix `json_object_size()` return value. + + - Fix a few compilation issues. + +* Portability: + + - Enhance portability of `va_copy()`. + + - Test framework portability enhancements. + +* Documentation: + + - Distribute ``doc/upgrading.rst`` with the source tarball. + + - Build documentation in strict mode in ``make distcheck``. + + +Version 2.0 +=========== + +Released 2011-02-28 + +This release is backwards incompatible with the 1.x release series. +See the chapter "Upgrading from older versions" in documentation for +details. + +* Backwards incompatible changes: + + - Unify unsigned integer usage in the API: All occurences of + unsigned int and unsigned long have been replaced with size_t. + + - Change JSON integer's underlying type to the widest signed integer + type available, i.e. long long if it's supported, otherwise long. + Add a typedef json_int_t that defines the type. + + - Change the maximum indentation depth to 31 spaces in encoder. This + frees up bits from the flags parameter of encoding functions + `json_dumpf()`, `json_dumps()` and `json_dump_file()`. + + - For future needs, add a flags parameter to all decoding functions + `json_loadf()`, `json_loads()` and `json_load_file()`. + +* New features + + - `json_pack()`, `json_pack_ex()`, `json_vpack_ex()`: Create JSON + values based on a format string. + + - `json_unpack()`, `json_unpack_ex()`, `json_vunpack_ex()`: Simple + value extraction and validation functionality based on a format + string. + + - Add column, position and source fields to the ``json_error_t`` + struct. + + - Enhance error reporting in the decoder. + + - ``JANSSON_VERSION`` et al.: Preprocessor constants that define the + library version. + + - `json_set_alloc_funcs()`: Set custom memory allocation functions. + +* Fix many portability issues, especially on Windows. + +* Configuration + + - Add file ``jansson_config.h`` that contains site specific + configuration. It's created automatically by the configure script, + or can be created by hand if the configure script cannot be used. + The file ``jansson_config.h.win32`` can be used without + modifications on Windows systems. + + - Add a section to documentation describing how to build Jansson on + Windows. + + - Documentation now requires Sphinx 1.0 or newer. + + +Version 1.3 +=========== + +Released 2010-06-13 + +* New functions: + + - `json_object_iter_set()`, `json_object_iter_set_new()`: Change + object contents while iterating over it. + + - `json_object_iter_at()`: Return an iterator that points to a + specific object item. + +* New encoding flags: + + - ``JSON_PRESERVE_ORDER``: Preserve the insertion order of object + keys. + +* Bug fixes: + + - Fix an error that occured when an array or object was first + encoded as empty, then populated with some data, and then + re-encoded + + - Fix the situation like above, but when the first encoding resulted + in an error + +* Documentation: + + - Clarify the documentation on reference stealing, providing an + example usage pattern + + +Version 1.2.1 +============= + +Released 2010-04-03 + +* Bug fixes: + + - Fix reference counting on ``true``, ``false`` and ``null`` + - Estimate real number underflows in decoder with 0.0 instead of + issuing an error + +* Portability: + + - Make ``int32_t`` available on all systems + - Support compilers that don't have the ``inline`` keyword + - Require Autoconf 2.60 (for ``int32_t``) + +* Tests: + + - Print test names correctly when ``VERBOSE=1`` + - ``test/suites/api``: Fail when a test fails + - Enhance tests for iterators + - Enhance tests for decoding texts that contain null bytes + +* Documentation: + + - Don't remove ``changes.rst`` in ``make clean`` + - Add a chapter on RFC conformance + + +Version 1.2 +=========== + +Released 2010-01-21 + +* New functions: + + - `json_equal()`: Test whether two JSON values are equal + - `json_copy()` and `json_deep_copy()`: Make shallow and deep copies + of JSON values + - Add a version of all functions taking a string argument that + doesn't check for valid UTF-8: `json_string_nocheck()`, + `json_string_set_nocheck()`, `json_object_set_nocheck()`, + `json_object_set_new_nocheck()` + +* New encoding flags: + + - ``JSON_SORT_KEYS``: Sort objects by key + - ``JSON_ENSURE_ASCII``: Escape all non-ASCII Unicode characters + - ``JSON_COMPACT``: Use a compact representation with all unneeded + whitespace stripped + +* Bug fixes: + + - Revise and unify whitespace usage in encoder: Add spaces between + array and object items, never append newline to output. + - Remove const qualifier from the ``json_t`` parameter in + `json_string_set()`, `json_integer_set()` and `json_real_set`. + - Use ``int32_t`` internally for representing Unicode code points + (int is not enough on all platforms) + +* Other changes: + + - Convert ``CHANGES`` (this file) to reStructured text and add it to + HTML documentation + - The test system has been refactored. Python is no longer required + to run the tests. + - Documentation can now be built by invoking ``make html`` + - Support for pkg-config + + +Version 1.1.3 +============= + +Released 2009-12-18 + +* Encode reals correctly, so that first encoding and then decoding a + real always produces the same value +* Don't export private symbols in ``libjansson.so`` + + +Version 1.1.2 +============= + +Released 2009-11-08 + +* Fix a bug where an error message was not produced if the input file + could not be opened in `json_load_file()` +* Fix an assertion failure in decoder caused by a minus sign without a + digit after it +* Remove an unneeded include of ``stdint.h`` in ``jansson.h`` + + +Version 1.1.1 +============= + +Released 2009-10-26 + +* All documentation files were not distributed with v1.1; build + documentation in make distcheck to prevent this in the future +* Fix v1.1 release date in ``CHANGES`` + + +Version 1.1 +=========== + +Released 2009-10-20 + +* API additions and improvements: + + - Extend array and object APIs + - Add functions to modify integer, real and string values + - Improve argument validation + - Use unsigned int instead of ``uint32_t`` for encoding flags + +* Enhance documentation + + - Add getting started guide and tutorial + - Fix some typos + - General clarifications and cleanup + +* Check for integer and real overflows and underflows in decoder +* Make singleton values thread-safe (``true``, ``false`` and ``null``) +* Enhance circular reference handling +* Don't define ``-std=c99`` in ``AM_CFLAGS`` +* Add C++ guards to ``jansson.h`` +* Minor performance and portability improvements +* Expand test coverage + + +Version 1.0.4 +============= + +Released 2009-10-11 + +* Relax Autoconf version requirement to 2.59 +* Make Jansson compile on platforms where plain ``char`` is unsigned +* Fix API tests for object + + +Version 1.0.3 +============= + +Released 2009-09-14 + +* Check for integer and real overflows and underflows in decoder +* Use the Python json module for tests, or simplejson if the json + module is not found +* Distribute changelog (this file) + + +Version 1.0.2 +============= + +Released 2009-09-08 + +* Handle EOF correctly in decoder + + +Version 1.0.1 +============= + +Released 2009-09-04 + +* Fixed broken `json_is_boolean()` + + +Version 1.0 +=========== + +Released 2009-08-25 + +* Initial release diff --git a/3party/jansson/CMakeLists.txt b/3party/jansson/CMakeLists.txt new file mode 100644 index 0000000000..7c0b95a734 --- /dev/null +++ b/3party/jansson/CMakeLists.txt @@ -0,0 +1,32 @@ +project(jansson) + +include_directories(src ../../) + +set( + SRC + jansson_handle.cpp + jansson_handle.hpp + myjansson.cpp + myjansson.hpp + src/dump.c + src/error.c + src/hashtable.c + src/hashtable.h + src/hashtable_seed.c + src/jansson_config.h + src/jansson.h + src/jansson_private_config.h + src/jansson_private.h + src/load.c + src/lookup3.h + src/memory.c + src/pack_unpack.c + src/strbuffer.c + src/strbuffer.h + src/strconv.c + src/utf.c + src/utf.h + src/value.c +) + +add_library(${PROJECT_NAME} ${SRC}) diff --git a/3party/jansson/CleanSpec.mk b/3party/jansson/CleanSpec.mk new file mode 100644 index 0000000000..b84e1b65e7 --- /dev/null +++ b/3party/jansson/CleanSpec.mk @@ -0,0 +1,49 @@ +# Copyright (C) 2007 The Android Open Source Project +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +# If you don't need to do a full clean build but would like to touch +# a file or delete some intermediate files, add a clean step to the end +# of the list. These steps will only be run once, if they haven't been +# run before. +# +# E.g.: +# $(call add-clean-step, touch -c external/sqlite/sqlite3.h) +# $(call add-clean-step, rm -rf $(PRODUCT_OUT)/obj/STATIC_LIBRARIES/libz_intermediates) +# +# Always use "touch -c" and "rm -f" or "rm -rf" to gracefully deal with +# files that are missing or have been moved. +# +# Use $(PRODUCT_OUT) to get to the "out/target/product/blah/" directory. +# Use $(OUT_DIR) to refer to the "out" directory. +# +# If you need to re-do something that's already mentioned, just copy +# the command and add it to the bottom of the list. E.g., if a change +# that you made last week required touching a file and a change you +# made today requires touching the same file, just copy the old +# touch step and add it to the end of the list. +# +# ************************************************ +# NEWER CLEAN STEPS MUST BE AT THE END OF THE LIST +# ************************************************ + +# For example: +#$(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/APPS/AndroidTests_intermediates) +#$(call add-clean-step, rm -rf $(OUT_DIR)/target/common/obj/JAVA_LIBRARIES/core_intermediates) +#$(call add-clean-step, find $(OUT_DIR) -type f -name "IGTalkSession*" -print0 | xargs -0 rm -f) +#$(call add-clean-step, rm -rf $(PRODUCT_OUT)/data/*) + +# ************************************************ +# NEWER CLEAN STEPS MUST BE AT THE END OF THE LIST +# ************************************************ diff --git a/3party/jansson/LICENSE b/3party/jansson/LICENSE new file mode 100644 index 0000000000..ca2218c033 --- /dev/null +++ b/3party/jansson/LICENSE @@ -0,0 +1,19 @@ +Copyright (c) 2009-2018 Petri Lehtinen + +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. diff --git a/3party/jansson/Makefile.am b/3party/jansson/Makefile.am new file mode 100644 index 0000000000..0de2ac16d9 --- /dev/null +++ b/3party/jansson/Makefile.am @@ -0,0 +1,10 @@ +EXTRA_DIST = CHANGES LICENSE README.rst CMakeLists.txt cmake android examples +SUBDIRS = doc src test + +# "make distcheck" builds the dvi target, so use it to check that the +# documentation is built correctly. +dvi: + $(MAKE) SPHINXOPTS_EXTRA=-W html + +pkgconfigdir = $(libdir)/pkgconfig +pkgconfig_DATA = jansson.pc diff --git a/3party/jansson/README.rst b/3party/jansson/README.rst new file mode 100644 index 0000000000..371e913671 --- /dev/null +++ b/3party/jansson/README.rst @@ -0,0 +1,69 @@ +Jansson README +============== + +.. image:: https://travis-ci.org/akheron/jansson.png + :target: https://travis-ci.org/akheron/jansson + +.. image:: https://ci.appveyor.com/api/projects/status/lmhkkc4q8cwc65ko + :target: https://ci.appveyor.com/project/akheron/jansson + +.. image:: https://coveralls.io/repos/akheron/jansson/badge.png?branch=master + :target: https://coveralls.io/r/akheron/jansson?branch=master + +Jansson_ is a C library for encoding, decoding and manipulating JSON +data. Its main features and design principles are: + +- Simple and intuitive API and data model + +- `Comprehensive documentation`_ + +- No dependencies on other libraries + +- Full Unicode support (UTF-8) + +- Extensive test suite + +Jansson is licensed under the `MIT license`_; see LICENSE in the +source distribution for details. + + +Compilation and Installation +---------------------------- + +If you obtained a `source tarball`_ from the "Releases" section of the main +site just use the standard autotools commands:: + + $ ./configure + $ make + $ make install + +To run the test suite, invoke:: + + $ make check + +If the source has been checked out from a Git repository, the +./configure script has to be generated first. The easiest way is to +use autoreconf:: + + $ autoreconf -i + + +Documentation +------------- + +Documentation is available at http://jansson.readthedocs.io/en/latest/. + +The documentation source is in the ``doc/`` subdirectory. To generate +HTML documentation, invoke:: + + $ make html + +Then, point your browser to ``doc/_build/html/index.html``. Sphinx_ +1.0 or newer is required to generate the documentation. + + +.. _Jansson: http://www.digip.org/jansson/ +.. _`Comprehensive documentation`: http://jansson.readthedocs.io/en/latest/ +.. _`MIT license`: http://www.opensource.org/licenses/mit-license.php +.. _`source tarball`: http://www.digip.org/jansson#releases +.. _Sphinx: http://sphinx.pocoo.org/ diff --git a/3party/jansson/android/jansson_config.h b/3party/jansson/android/jansson_config.h new file mode 100644 index 0000000000..618a0da73c --- /dev/null +++ b/3party/jansson/android/jansson_config.h @@ -0,0 +1,43 @@ +/* + * Copyright (c) 2010-2016 Petri Lehtinen + * + * Jansson is free software; you can redistribute it and/or modify + * it under the terms of the MIT license. See LICENSE for details. + * + * + * This file specifies a part of the site-specific configuration for + * Jansson, namely those things that affect the public API in + * jansson.h. + * + * The configure script copies this file to jansson_config.h and + * replaces @var@ substitutions by values that fit your system. If you + * cannot run the configure script, you can do the value substitution + * by hand. + */ + +#ifndef JANSSON_CONFIG_H +#define JANSSON_CONFIG_H + +/* If your compiler supports the inline keyword in C, JSON_INLINE is + defined to `inline', otherwise empty. In C++, the inline is always + supported. */ +#ifdef __cplusplus +#define JSON_INLINE inline +#else +#define JSON_INLINE inline +#endif + +/* If your compiler supports the `long long` type and the strtoll() + library function, JSON_INTEGER_IS_LONG_LONG is defined to 1, + otherwise to 0. */ +#define JSON_INTEGER_IS_LONG_LONG 1 + +/* If locale.h and localeconv() are available, define to 1, + otherwise to 0. */ +#define JSON_HAVE_LOCALECONV 0 + +/* Maximum recursion depth for parsing JSON input. + This limits the depth of e.g. array-within-array constructions. */ +#define JSON_PARSER_MAX_DEPTH 2048 + +#endif diff --git a/3party/jansson/appveyor.yml b/3party/jansson/appveyor.yml new file mode 100644 index 0000000000..796fa0ba55 --- /dev/null +++ b/3party/jansson/appveyor.yml @@ -0,0 +1,16 @@ +environment: + matrix: + - VS: Visual Studio 9 2008 + - VS: Visual Studio 10 2010 + - VS: Visual Studio 11 2012 + - VS: Visual Studio 12 2013 + - VS: Visual Studio 14 2015 + - APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2017 + VS: Visual Studio 15 2017 + +build_script: + - md build + - cd build + - cmake -G "%VS%" .. + - cmake --build . --config Release + - ctest --output-on-failure diff --git a/3party/jansson/cmake/CheckFunctionKeywords.cmake b/3party/jansson/cmake/CheckFunctionKeywords.cmake new file mode 100644 index 0000000000..44601fd4e9 --- /dev/null +++ b/3party/jansson/cmake/CheckFunctionKeywords.cmake @@ -0,0 +1,15 @@ +include(CheckCSourceCompiles) + +macro(check_function_keywords _wordlist) + set(${_result} "") + foreach(flag ${_wordlist}) + string(REGEX REPLACE "[-+/ ()]" "_" flagname "${flag}") + string(TOUPPER "${flagname}" flagname) + set(have_flag "HAVE_${flagname}") + check_c_source_compiles("${flag} void func(); void func() { } int main() { func(); return 0; }" ${have_flag}) + if(${have_flag} AND NOT ${_result}) + set(${_result} "${flag}") +# break() + endif(${have_flag} AND NOT ${_result}) + endforeach(flag) +endmacro(check_function_keywords) diff --git a/3party/jansson/cmake/CodeCoverage.cmake b/3party/jansson/cmake/CodeCoverage.cmake new file mode 100644 index 0000000000..79ec8ac080 --- /dev/null +++ b/3party/jansson/cmake/CodeCoverage.cmake @@ -0,0 +1,163 @@ +# +# Boost Software License - Version 1.0 - August 17th, 2003 +# +# Permission is hereby granted, free of charge, to any person or organization +# obtaining a copy of the software and accompanying documentation covered by +# this license (the "Software") to use, reproduce, display, distribute, +# execute, and transmit the Software, and to prepare derivative works of the +# Software, and to permit third-parties to whom the Software is furnished to +# do so, all subject to the following: +# +# The copyright notices in the Software and this entire statement, including +# the above license grant, this restriction and the following disclaimer, +# must be included in all copies of the Software, in whole or in part, and +# all derivative works of the Software, unless such copies or derivative +# works are solely in the form of machine-executable object code generated by +# a source language processor. +# +# 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, TITLE AND NON-INFRINGEMENT. IN NO EVENT +# SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE +# FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE, +# ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +# DEALINGS IN THE SOFTWARE. +# +# 2012-01-31, Lars Bilke +# - Enable Code Coverage +# +# 2013-09-17, Joakim Söderberg +# - Added support for Clang. +# - Some additional usage instructions. +# +# USAGE: +# 1. Copy this file into your cmake modules path. +# +# 2. Add the following line to your CMakeLists.txt: +# INCLUDE(CodeCoverage) +# +# 3. Set compiler flags to turn off optimization and enable coverage: +# SET(CMAKE_CXX_FLAGS "-g -O0 -fprofile-arcs -ftest-coverage") +# SET(CMAKE_C_FLAGS "-g -O0 -fprofile-arcs -ftest-coverage") +# +# 3. Use the function SETUP_TARGET_FOR_COVERAGE to create a custom make target +# which runs your test executable and produces a lcov code coverage report: +# Example: +# SETUP_TARGET_FOR_COVERAGE( +# my_coverage_target # Name for custom target. +# test_driver # Name of the test driver executable that runs the tests. +# # NOTE! This should always have a ZERO as exit code +# # otherwise the coverage generation will not complete. +# coverage # Name of output directory. +# ) +# +# 4. Build a Debug build: +# cmake -DCMAKE_BUILD_TYPE=Debug .. +# make +# make my_coverage_target +# +# + +# Check prereqs +FIND_PROGRAM( GCOV_PATH gcov ) +FIND_PROGRAM( LCOV_PATH lcov ) +FIND_PROGRAM( GENHTML_PATH genhtml ) +FIND_PROGRAM( GCOVR_PATH gcovr PATHS ${CMAKE_SOURCE_DIR}/tests) + +IF(NOT GCOV_PATH) + MESSAGE(FATAL_ERROR "gcov not found! Aborting...") +ENDIF() # NOT GCOV_PATH + +IF(NOT (CMAKE_COMPILER_IS_GNUCXX OR CMAKE_COMPILER_IS_GNUCC)) + # Clang version 3.0.0 and greater now supports gcov as well. + MESSAGE(WARNING "Compiler is not GNU gcc! Clang Version 3.0.0 and greater supports gcov as well, but older versions don't.") + + IF(NOT ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang" OR "${CMAKE_C_COMPILER_ID}" STREQUAL "Clang")) + MESSAGE(FATAL_ERROR "Compiler is not GNU gcc or Clang! Aborting...") + ENDIF() +ENDIF() # NOT CMAKE_COMPILER_IS_GNUCXX + +IF ( NOT CMAKE_BUILD_TYPE STREQUAL "Debug" ) + MESSAGE( WARNING "Code coverage results with an optimized (non-Debug) build may be misleading" ) +ENDIF() # NOT CMAKE_BUILD_TYPE STREQUAL "Debug" + + +# Param _targetname The name of new the custom make target +# Param _outputname lcov output is generated as _outputname.info +# HTML report is generated in _outputname/index.html +# Param _testrunner The name of the target which runs the tests. +# MUST return ZERO always, even on errors. +# If not, no coverage report will be created! +# Optional fourth parameter is passed as arguments to _testrunner +# Pass them in list form, e.g.: "-j;2" for -j 2 +FUNCTION(SETUP_TARGET_FOR_COVERAGE _targetname _outputname _testrunner) + + IF(NOT LCOV_PATH) + MESSAGE(FATAL_ERROR "lcov not found! Aborting...") + ENDIF() # NOT LCOV_PATH + + IF(NOT GENHTML_PATH) + MESSAGE(FATAL_ERROR "genhtml not found! Aborting...") + ENDIF() # NOT GENHTML_PATH + + # Setup target + ADD_CUSTOM_TARGET(${_targetname} + + # Cleanup lcov + ${LCOV_PATH} --directory . --zerocounters + + # Run tests + COMMAND ${_testrunner} ${ARGV3} + + # Capturing lcov counters and generating report + COMMAND ${LCOV_PATH} --directory . --capture --output-file ${_outputname}.info --rc lcov_branch_coverage=1 + COMMAND ${LCOV_PATH} --remove ${_outputname}.info '*/build/include/*' '*/test/*' '/usr/include/*' --output-file ${_outputname}.info.cleaned --rc lcov_branch_coverage=1 + COMMAND ${GENHTML_PATH} --branch-coverage -o ${_outputname} ${_outputname}.info.cleaned + COMMAND ${CMAKE_COMMAND} -E remove ${_outputname}.info ${_outputname}.info.cleaned + + WORKING_DIRECTORY ${CMAKE_BINARY_DIR} + COMMENT "Resetting code coverage counters to zero.\nProcessing code coverage counters and generating report." + ) + + # Show info where to find the report + ADD_CUSTOM_COMMAND(TARGET ${_targetname} POST_BUILD + COMMAND ; + COMMENT "Open ./${_outputname}/index.html in your browser to view the coverage report." + ) + +ENDFUNCTION() # SETUP_TARGET_FOR_COVERAGE + +# Param _targetname The name of new the custom make target +# Param _testrunner The name of the target which runs the tests +# Param _outputname cobertura output is generated as _outputname.xml +# Optional fourth parameter is passed as arguments to _testrunner +# Pass them in list form, e.g.: "-j;2" for -j 2 +FUNCTION(SETUP_TARGET_FOR_COVERAGE_COBERTURA _targetname _testrunner _outputname) + + IF(NOT PYTHON_EXECUTABLE) + MESSAGE(FATAL_ERROR "Python not found! Aborting...") + ENDIF() # NOT PYTHON_EXECUTABLE + + IF(NOT GCOVR_PATH) + MESSAGE(FATAL_ERROR "gcovr not found! Aborting...") + ENDIF() # NOT GCOVR_PATH + + ADD_CUSTOM_TARGET(${_targetname} + + # Run tests + ${_testrunner} ${ARGV3} + + # Running gcovr + COMMAND ${GCOVR_PATH} -x -r ${CMAKE_SOURCE_DIR} -e '${CMAKE_SOURCE_DIR}/tests/' -o ${_outputname}.xml + WORKING_DIRECTORY ${CMAKE_BINARY_DIR} + COMMENT "Running gcovr to produce Cobertura code coverage report." + ) + + # Show info where to find the report + ADD_CUSTOM_COMMAND(TARGET ${_targetname} POST_BUILD + COMMAND ; + COMMENT "Cobertura code coverage report saved in ${_outputname}.xml." + ) + +ENDFUNCTION() # SETUP_TARGET_FOR_COVERAGE_COBERTURA + diff --git a/3party/jansson/cmake/Coveralls.cmake b/3party/jansson/cmake/Coveralls.cmake new file mode 100644 index 0000000000..29221c9173 --- /dev/null +++ b/3party/jansson/cmake/Coveralls.cmake @@ -0,0 +1,111 @@ +# +# 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. +# +# Copyright (C) 2014 Joakim Söderberg +# + + +# +# Param _COVERAGE_SRCS A list of source files that coverage should be collected for. +# Param _COVERALLS_UPLOAD Upload the result to coveralls? +# +function(coveralls_setup _COVERAGE_SRCS _COVERALLS_UPLOAD) + # When passing a CMake list to an external process, the list + # will be converted from the format "1;2;3" to "1 2 3". + # This means the script we're calling won't see it as a list + # of sources, but rather just one long path. We remedy this + # by replacing ";" with "*" and then reversing that in the script + # that we're calling. + # http://cmake.3232098.n2.nabble.com/Passing-a-CMake-list-quot-as-is-quot-to-a-custom-target-td6505681.html + set(COVERAGE_SRCS_TMP ${_COVERAGE_SRCS}) + set(COVERAGE_SRCS "") + foreach (COVERAGE_SRC ${COVERAGE_SRCS_TMP}) + set(COVERAGE_SRCS "${COVERAGE_SRCS}*${COVERAGE_SRC}") + endforeach() + + #message("Coverage sources: ${COVERAGE_SRCS}") + set(COVERALLS_FILE ${PROJECT_BINARY_DIR}/coveralls.json) + + add_custom_target(coveralls_generate + + # Zero the coverage counters. + COMMAND ${CMAKE_COMMAND} + -P "${PROJECT_SOURCE_DIR}/cmake/CoverallsClear.cmake" + + # Run regress tests. + COMMAND ${CMAKE_CTEST_COMMAND} --output-on-failure + + # Generate Gcov and translate it into coveralls JSON. + # We do this by executing an external CMake script. + # (We don't want this to run at CMake generation time, but after compilation and everything has run). + COMMAND ${CMAKE_COMMAND} + -DCOVERAGE_SRCS="${COVERAGE_SRCS}" # TODO: This is passed like: "a b c", not "a;b;c" + -DCOVERALLS_OUTPUT_FILE="${COVERALLS_FILE}" + -DCOV_PATH="${PROJECT_BINARY_DIR}" + -DPROJECT_ROOT="${PROJECT_SOURCE_DIR}" + -P "${PROJECT_SOURCE_DIR}/cmake/CoverallsGenerateGcov.cmake" + + WORKING_DIRECTORY ${PROJECT_BINARY_DIR} + COMMENT "Generating coveralls output..." + ) + + if (_COVERALLS_UPLOAD) + message("COVERALLS UPLOAD: ON") + + find_program(CURL_EXECUTABLE curl) + + if (NOT CURL_EXECUTABLE) + message(FATAL_ERROR "Coveralls: curl not found! Aborting") + endif() + + add_custom_target(coveralls_upload + # Upload the JSON to coveralls. + COMMAND ${CURL_EXECUTABLE} + -S -F json_file=@${COVERALLS_FILE} + https://coveralls.io/api/v1/jobs + + DEPENDS coveralls_generate + + WORKING_DIRECTORY ${PROJECT_BINARY_DIR} + COMMENT "Uploading coveralls output...") + + add_custom_target(coveralls DEPENDS coveralls_upload) + else() + message("COVERALLS UPLOAD: OFF") + add_custom_target(coveralls DEPENDS coveralls_generate) + endif() + +endfunction() + +macro(coveralls_turn_on_coverage) + if(NOT (CMAKE_COMPILER_IS_GNUCC OR CMAKE_COMPILER_IS_GNUCXX) + AND (NOT "${CMAKE_C_COMPILER_ID}" STREQUAL "Clang")) + message(FATAL_ERROR "Coveralls: Compiler ${CMAKE_C_COMPILER_ID} is not GNU gcc! Aborting... You can set this on the command line using CC=/usr/bin/gcc CXX=/usr/bin/g++ cmake ..") + endif() + + if(NOT CMAKE_BUILD_TYPE STREQUAL "Debug") + message(FATAL_ERROR "Coveralls: Code coverage results with an optimised (non-Debug) build may be misleading! Add -DCMAKE_BUILD_TYPE=Debug") + endif() + + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -g -O0 -fprofile-arcs -ftest-coverage") + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -g -O0 -fprofile-arcs -ftest-coverage") +endmacro() + + + diff --git a/3party/jansson/cmake/CoverallsClear.cmake b/3party/jansson/cmake/CoverallsClear.cmake new file mode 100644 index 0000000000..eb68695a2b --- /dev/null +++ b/3party/jansson/cmake/CoverallsClear.cmake @@ -0,0 +1,24 @@ +# +# 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. +# +# Copyright (C) 2014 Joakim Söderberg +# + +file(REMOVE_RECURSE ${PROJECT_BINARY_DIR}/*.gcda) + diff --git a/3party/jansson/cmake/CoverallsGenerateGcov.cmake b/3party/jansson/cmake/CoverallsGenerateGcov.cmake new file mode 100644 index 0000000000..0c4c2b0c15 --- /dev/null +++ b/3party/jansson/cmake/CoverallsGenerateGcov.cmake @@ -0,0 +1,380 @@ +# +# 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. +# +# Copyright (C) 2014 Joakim Söderberg +# +# This is intended to be run by a custom target in a CMake project like this. +# 0. Compile program with coverage support. +# 1. Clear coverage data. (Recursively delete *.gcda in build dir) +# 2. Run the unit tests. +# 3. Run this script specifying which source files the coverage should be performed on. +# +# This script will then use gcov to generate .gcov files in the directory specified +# via the COV_PATH var. This should probably be the same as your cmake build dir. +# +# It then parses the .gcov files to convert them into the Coveralls JSON format: +# https://coveralls.io/docs/api +# +# Example for running as standalone CMake script from the command line: +# (Note it is important the -P is at the end...) +# $ cmake -DCOV_PATH=$(pwd) +# -DCOVERAGE_SRCS="catcierge_rfid.c;catcierge_timer.c" +# -P ../cmake/CoverallsGcovUpload.cmake +# +CMAKE_MINIMUM_REQUIRED(VERSION 2.8) + + +# +# Make sure we have the needed arguments. +# +if (NOT COVERALLS_OUTPUT_FILE) + message(FATAL_ERROR "Coveralls: No coveralls output file specified. Please set COVERALLS_OUTPUT_FILE") +endif() + +if (NOT COV_PATH) + message(FATAL_ERROR "Coveralls: Missing coverage directory path where gcov files will be generated. Please set COV_PATH") +endif() + +if (NOT COVERAGE_SRCS) + message(FATAL_ERROR "Coveralls: Missing the list of source files that we should get the coverage data for COVERAGE_SRCS") +endif() + +if (NOT PROJECT_ROOT) + message(FATAL_ERROR "Coveralls: Missing PROJECT_ROOT.") +endif() + +# Since it's not possible to pass a CMake list properly in the +# "1;2;3" format to an external process, we have replaced the +# ";" with "*", so reverse that here so we get it back into the +# CMake list format. +string(REGEX REPLACE "\\*" ";" COVERAGE_SRCS ${COVERAGE_SRCS}) + +find_program(GCOV_EXECUTABLE gcov) + +if (NOT GCOV_EXECUTABLE) + message(FATAL_ERROR "gcov not found! Aborting...") +endif() + +find_package(Git) + +# TODO: Add these git things to the coveralls json. +if (GIT_FOUND) + # Branch. + execute_process( + COMMAND ${GIT_EXECUTABLE} rev-parse --abbrev-ref HEAD + WORKING_DIRECTORY ${CMAKE_SOURCE_DIR} + OUTPUT_VARIABLE GIT_BRANCH + OUTPUT_STRIP_TRAILING_WHITESPACE + ) + + macro (git_log_format FORMAT_CHARS VAR_NAME) + execute_process( + COMMAND ${GIT_EXECUTABLE} log -1 --pretty=format:%${FORMAT_CHARS} + WORKING_DIRECTORY ${CMAKE_SOURCE_DIR} + OUTPUT_VARIABLE ${VAR_NAME} + OUTPUT_STRIP_TRAILING_WHITESPACE + ) + endmacro() + + git_log_format(an GIT_AUTHOR_EMAIL) + git_log_format(ae GIT_AUTHOR_EMAIL) + git_log_format(cn GIT_COMMITTER_NAME) + git_log_format(ce GIT_COMMITTER_EMAIL) + git_log_format(B GIT_COMMIT_MESSAGE) + + message("Git exe: ${GIT_EXECUTABLE}") + message("Git branch: ${GIT_BRANCH}") + message("Git author: ${GIT_AUTHOR_NAME}") + message("Git e-mail: ${GIT_AUTHOR_EMAIL}") + message("Git commiter name: ${GIT_COMMITTER_NAME}") + message("Git commiter e-mail: ${GIT_COMMITTER_EMAIL}") + message("Git commit message: ${GIT_COMMIT_MESSAGE}") + +endif() + +############################# Macros ######################################### + +# +# This macro converts from the full path format gcov outputs: +# +# /path/to/project/root/build/#path#to#project#root#subdir#the_file.c.gcov +# +# to the original source file path the .gcov is for: +# +# /path/to/project/root/subdir/the_file.c +# +macro(get_source_path_from_gcov_filename _SRC_FILENAME _GCOV_FILENAME) + + # /path/to/project/root/build/#path#to#project#root#subdir#the_file.c.gcov + # -> + # #path#to#project#root#subdir#the_file.c.gcov + get_filename_component(_GCOV_FILENAME_WEXT ${_GCOV_FILENAME} NAME) + + # #path#to#project#root#subdir#the_file.c.gcov -> /path/to/project/root/subdir/the_file.c + string(REGEX REPLACE "\\.gcov$" "" SRC_FILENAME_TMP ${_GCOV_FILENAME_WEXT}) + string(REGEX REPLACE "\#" "/" SRC_FILENAME_TMP ${SRC_FILENAME_TMP}) + set(${_SRC_FILENAME} "${SRC_FILENAME_TMP}") +endmacro() + +############################################################################## + +# Get the coverage data. +file(GLOB_RECURSE GCDA_FILES "${COV_PATH}/*.gcda") +message("GCDA files:") + +# Get a list of all the object directories needed by gcov +# (The directories the .gcda files and .o files are found in) +# and run gcov on those. +foreach(GCDA ${GCDA_FILES}) + message("Process: ${GCDA}") + message("------------------------------------------------------------------------------") + get_filename_component(GCDA_DIR ${GCDA} PATH) + + # + # The -p below refers to "Preserve path components", + # This means that the generated gcov filename of a source file will + # keep the original files entire filepath, but / is replaced with #. + # Example: + # + # /path/to/project/root/build/CMakeFiles/the_file.dir/subdir/the_file.c.gcda + # ------------------------------------------------------------------------------ + # File '/path/to/project/root/subdir/the_file.c' + # Lines executed:68.34% of 199 + # /path/to/project/root/subdir/the_file.c:creating '#path#to#project#root#subdir#the_file.c.gcov' + # + # If -p is not specified then the file is named only "the_file.c.gcov" + # + execute_process( + COMMAND ${GCOV_EXECUTABLE} -p -o ${GCDA_DIR} ${GCDA} + WORKING_DIRECTORY ${COV_PATH} + ) +endforeach() + +# TODO: Make these be absolute path +file(GLOB ALL_GCOV_FILES ${COV_PATH}/*.gcov) + +# Get only the filenames to use for filtering. +#set(COVERAGE_SRCS_NAMES "") +#foreach (COVSRC ${COVERAGE_SRCS}) +# get_filename_component(COVSRC_NAME ${COVSRC} NAME) +# message("${COVSRC} -> ${COVSRC_NAME}") +# list(APPEND COVERAGE_SRCS_NAMES "${COVSRC_NAME}") +#endforeach() + +# +# Filter out all but the gcov files we want. +# +# We do this by comparing the list of COVERAGE_SRCS filepaths that the +# user wants the coverage data for with the paths of the generated .gcov files, +# so that we only keep the relevant gcov files. +# +# Example: +# COVERAGE_SRCS = +# /path/to/project/root/subdir/the_file.c +# +# ALL_GCOV_FILES = +# /path/to/project/root/build/#path#to#project#root#subdir#the_file.c.gcov +# /path/to/project/root/build/#path#to#project#root#subdir#other_file.c.gcov +# +# Result should be: +# GCOV_FILES = +# /path/to/project/root/build/#path#to#project#root#subdir#the_file.c.gcov +# +set(GCOV_FILES "") +#message("Look in coverage sources: ${COVERAGE_SRCS}") +message("\nFilter out unwanted GCOV files:") +message("===============================") + +set(COVERAGE_SRCS_REMAINING ${COVERAGE_SRCS}) + +foreach (GCOV_FILE ${ALL_GCOV_FILES}) + + # + # /path/to/project/root/build/#path#to#project#root#subdir#the_file.c.gcov + # -> + # /path/to/project/root/subdir/the_file.c + get_source_path_from_gcov_filename(GCOV_SRC_PATH ${GCOV_FILE}) + + # Is this in the list of source files? + # TODO: We want to match against relative path filenames from the source file root... + list(FIND COVERAGE_SRCS ${GCOV_SRC_PATH} WAS_FOUND) + + if (NOT WAS_FOUND EQUAL -1) + message("YES: ${GCOV_FILE}") + list(APPEND GCOV_FILES ${GCOV_FILE}) + + # We remove it from the list, so we don't bother searching for it again. + # Also files left in COVERAGE_SRCS_REMAINING after this loop ends should + # have coverage data generated from them (no lines are covered). + list(REMOVE_ITEM COVERAGE_SRCS_REMAINING ${GCOV_SRC_PATH}) + else() + message("NO: ${GCOV_FILE}") + endif() +endforeach() + +# TODO: Enable setting these +set(JSON_SERVICE_NAME "travis-ci") +set(JSON_SERVICE_JOB_ID $ENV{TRAVIS_JOB_ID}) + +set(JSON_TEMPLATE +"{ + \"service_name\": \"\@JSON_SERVICE_NAME\@\", + \"service_job_id\": \"\@JSON_SERVICE_JOB_ID\@\", + \"source_files\": \@JSON_GCOV_FILES\@ +}" +) + +set(SRC_FILE_TEMPLATE +"{ + \"name\": \"\@GCOV_SRC_REL_PATH\@\", + \"source\": \"\@GCOV_FILE_SOURCE\@\", + \"coverage\": \@GCOV_FILE_COVERAGE\@ +}" +) + +message("\nGenerate JSON for files:") +message("=========================") + +set(JSON_GCOV_FILES "[") + +# Read the GCOV files line by line and get the coverage data. +foreach (GCOV_FILE ${GCOV_FILES}) + + get_source_path_from_gcov_filename(GCOV_SRC_PATH ${GCOV_FILE}) + file(RELATIVE_PATH GCOV_SRC_REL_PATH "${PROJECT_ROOT}" "${GCOV_SRC_PATH}") + + # Loads the gcov file as a list of lines. + file(STRINGS ${GCOV_FILE} GCOV_LINES) + + # Instead of trying to parse the source from the + # gcov file, simply read the file contents from the source file. + # (Parsing it from the gcov is hard because C-code uses ; in many places + # which also happens to be the same as the CMake list delimeter). + file(READ ${GCOV_SRC_PATH} GCOV_FILE_SOURCE) + + string(REPLACE "\\" "\\\\" GCOV_FILE_SOURCE "${GCOV_FILE_SOURCE}") + string(REGEX REPLACE "\"" "\\\\\"" GCOV_FILE_SOURCE "${GCOV_FILE_SOURCE}") + string(REPLACE "\t" "\\\\t" GCOV_FILE_SOURCE "${GCOV_FILE_SOURCE}") + string(REPLACE "\r" "\\\\r" GCOV_FILE_SOURCE "${GCOV_FILE_SOURCE}") + string(REPLACE "\n" "\\\\n" GCOV_FILE_SOURCE "${GCOV_FILE_SOURCE}") + # According to http://json.org/ these should be escaped as well. + # Don't know how to do that in CMake however... + #string(REPLACE "\b" "\\\\b" GCOV_FILE_SOURCE "${GCOV_FILE_SOURCE}") + #string(REPLACE "\f" "\\\\f" GCOV_FILE_SOURCE "${GCOV_FILE_SOURCE}") + #string(REGEX REPLACE "\u([a-fA-F0-9]{4})" "\\\\u\\1" GCOV_FILE_SOURCE "${GCOV_FILE_SOURCE}") + + # We want a json array of coverage data as a single string + # start building them from the contents of the .gcov + set(GCOV_FILE_COVERAGE "[") + + foreach (GCOV_LINE ${GCOV_LINES}) + # Example of what we're parsing: + # Hitcount |Line | Source + # " 8: 26: if (!allowed || (strlen(allowed) == 0))" + string(REGEX REPLACE + "^([^:]*):([^:]*):(.*)$" + "\\1;\\2;\\3" + RES + "${GCOV_LINE}") + + list(LENGTH RES RES_COUNT) + if (RES_COUNT GREATER 2) + list(GET RES 0 HITCOUNT) + list(GET RES 1 LINE) + list(GET RES 2 SOURCE) + + string(STRIP ${HITCOUNT} HITCOUNT) + string(STRIP ${LINE} LINE) + + # Lines with 0 line numbers are metadata and can be ignored. + if (NOT ${LINE} EQUAL 0) + + # Translate the hitcount into valid JSON values. + if (${HITCOUNT} STREQUAL "#####") + set(GCOV_FILE_COVERAGE "${GCOV_FILE_COVERAGE}0, ") + elseif (${HITCOUNT} STREQUAL "-") + set(GCOV_FILE_COVERAGE "${GCOV_FILE_COVERAGE}null, ") + else() + set(GCOV_FILE_COVERAGE "${GCOV_FILE_COVERAGE}${HITCOUNT}, ") + endif() + # TODO: Look for LCOV_EXCL_LINE in SOURCE to get rid of false positives. + endif() + else() + message(WARNING "Failed to properly parse line --> ${GCOV_LINE}") + endif() + endforeach() + + # Advanced way of removing the trailing comma in the JSON array. + # "[1, 2, 3, " -> "[1, 2, 3" + string(REGEX REPLACE ",[ ]*$" "" GCOV_FILE_COVERAGE ${GCOV_FILE_COVERAGE}) + + # Append the trailing ] to complete the JSON array. + set(GCOV_FILE_COVERAGE "${GCOV_FILE_COVERAGE}]") + + # Generate the final JSON for this file. + message("Generate JSON for file: ${GCOV_SRC_REL_PATH}...") + string(CONFIGURE ${SRC_FILE_TEMPLATE} FILE_JSON) + + set(JSON_GCOV_FILES "${JSON_GCOV_FILES}${FILE_JSON}, ") +endforeach() + +# Loop through all files we couldn't find any coverage for +# as well, and generate JSON for those as well with 0% coverage. +foreach(NOT_COVERED_SRC ${COVERAGE_SRCS_REMAINING}) + + # Loads the source file as a list of lines. + file(STRINGS ${NOT_COVERED_SRC} SRC_LINES) + + set(GCOV_FILE_COVERAGE "[") + set(GCOV_FILE_SOURCE "") + + foreach (SOURCE ${SRC_LINES}) + set(GCOV_FILE_COVERAGE "${GCOV_FILE_COVERAGE}0, ") + + string(REPLACE "\\" "\\\\" SOURCE "${SOURCE}") + string(REGEX REPLACE "\"" "\\\\\"" SOURCE "${SOURCE}") + string(REPLACE "\t" "\\\\t" SOURCE "${SOURCE}") + string(REPLACE "\r" "\\\\r" SOURCE "${SOURCE}") + set(GCOV_FILE_SOURCE "${GCOV_FILE_SOURCE}${SOURCE}\\n") + endforeach() + + # Remove trailing comma, and complete JSON array with ] + string(REGEX REPLACE ",[ ]*$" "" GCOV_FILE_COVERAGE ${GCOV_FILE_COVERAGE}) + set(GCOV_FILE_COVERAGE "${GCOV_FILE_COVERAGE}]") + + # Generate the final JSON for this file. + message("Generate JSON for non-gcov file: ${NOT_COVERED_SRC}...") + string(CONFIGURE ${SRC_FILE_TEMPLATE} FILE_JSON) + set(JSON_GCOV_FILES "${JSON_GCOV_FILES}${FILE_JSON}, ") +endforeach() + +# Get rid of trailing comma. +string(REGEX REPLACE ",[ ]*$" "" JSON_GCOV_FILES ${JSON_GCOV_FILES}) +set(JSON_GCOV_FILES "${JSON_GCOV_FILES}]") + +# Generate the final complete JSON! +message("Generate final JSON...") +string(CONFIGURE ${JSON_TEMPLATE} JSON) + +file(WRITE "${COVERALLS_OUTPUT_FILE}" "${JSON}") +message("###########################################################################") +message("Generated coveralls JSON containing coverage data:") +message("${COVERALLS_OUTPUT_FILE}") +message("###########################################################################") + diff --git a/3party/jansson/cmake/FindSphinx.cmake b/3party/jansson/cmake/FindSphinx.cmake new file mode 100644 index 0000000000..55539d42c6 --- /dev/null +++ b/3party/jansson/cmake/FindSphinx.cmake @@ -0,0 +1,301 @@ +# +# PART B. DOWNLOADING AGREEMENT - LICENSE FROM SBIA WITH RIGHT TO SUBLICENSE ("SOFTWARE LICENSE"). +# ------------------------------------------------------------------------------------------------ +# +# 1. As used in this Software License, "you" means the individual downloading and/or +# using, reproducing, modifying, displaying and/or distributing the Software and +# the institution or entity which employs or is otherwise affiliated with such +# individual in connection therewith. The Section of Biomedical Image Analysis, +# Department of Radiology at the Universiy of Pennsylvania ("SBIA") hereby grants +# you, with right to sublicense, with respect to SBIA's rights in the software, +# and data, if any, which is the subject of this Software License (collectively, +# the "Software"), a royalty-free, non-exclusive license to use, reproduce, make +# derivative works of, display and distribute the Software, provided that: +# (a) you accept and adhere to all of the terms and conditions of this Software +# License; (b) in connection with any copy of or sublicense of all or any portion +# of the Software, all of the terms and conditions in this Software License shall +# appear in and shall apply to such copy and such sublicense, including without +# limitation all source and executable forms and on any user documentation, +# prefaced with the following words: "All or portions of this licensed product +# (such portions are the "Software") have been obtained under license from the +# Section of Biomedical Image Analysis, Department of Radiology at the University +# of Pennsylvania and are subject to the following terms and conditions:" +# (c) you preserve and maintain all applicable attributions, copyright notices +# and licenses included in or applicable to the Software; (d) modified versions +# of the Software must be clearly identified and marked as such, and must not +# be misrepresented as being the original Software; and (e) you consider making, +# but are under no obligation to make, the source code of any of your modifications +# to the Software freely available to others on an open source basis. +# +# 2. The license granted in this Software License includes without limitation the +# right to (i) incorporate the Software into proprietary programs (subject to +# any restrictions applicable to such programs), (ii) add your own copyright +# statement to your modifications of the Software, and (iii) provide additional +# or different license terms and conditions in your sublicenses of modifications +# of the Software; provided that in each case your use, reproduction or +# distribution of such modifications otherwise complies with the conditions +# stated in this Software License. +# +# 3. This Software License does not grant any rights with respect to third party +# software, except those rights that SBIA has been authorized by a third +# party to grant to you, and accordingly you are solely responsible for +# (i) obtaining any permissions from third parties that you need to use, +# reproduce, make derivative works of, display and distribute the Software, +# and (ii) informing your sublicensees, including without limitation your +# end-users, of their obligations to secure any such required permissions. +# +# 4. The Software has been designed for research purposes only and has not been +# reviewed or approved by the Food and Drug Administration or by any other +# agency. YOU ACKNOWLEDGE AND AGREE THAT CLINICAL APPLICATIONS ARE NEITHER +# RECOMMENDED NOR ADVISED. Any commercialization of the Software is at the +# sole risk of the party or parties engaged in such commercialization. +# You further agree to use, reproduce, make derivative works of, display +# and distribute the Software in compliance with all applicable governmental +# laws, regulations and orders, including without limitation those relating +# to export and import control. +# +# 5. The Software is provided "AS IS" and neither SBIA nor any contributor to +# the software (each a "Contributor") shall have any obligation to provide +# maintenance, support, updates, enhancements or modifications thereto. +# SBIA AND ALL CONTRIBUTORS SPECIFICALLY DISCLAIM ALL EXPRESS AND IMPLIED +# WARRANTIES OF ANY KIND INCLUDING, BUT NOT LIMITED TO, ANY WARRANTIES OF +# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. +# IN NO EVENT SHALL SBIA OR ANY CONTRIBUTOR BE LIABLE TO ANY PARTY FOR +# DIRECT, INDIRECT, SPECIAL, INCIDENTAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES +# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY ARISING IN ANY WAY RELATED +# TO THE SOFTWARE, EVEN IF SBIA OR ANY CONTRIBUTOR HAS BEEN ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGES. TO THE MAXIMUM EXTENT NOT PROHIBITED BY LAW OR +# REGULATION, YOU FURTHER ASSUME ALL LIABILITY FOR YOUR USE, REPRODUCTION, +# MAKING OF DERIVATIVE WORKS, DISPLAY, LICENSE OR DISTRIBUTION OF THE SOFTWARE +# AND AGREE TO INDEMNIFY AND HOLD HARMLESS SBIA AND ALL CONTRIBUTORS FROM +# AND AGAINST ANY AND ALL CLAIMS, SUITS, ACTIONS, DEMANDS AND JUDGMENTS ARISING +# THEREFROM. +# +# 6. None of the names, logos or trademarks of SBIA or any of SBIA's affiliates +# or any of the Contributors, or any funding agency, may be used to endorse +# or promote products produced in whole or in part by operation of the Software +# or derived from or based on the Software without specific prior written +# permission from the applicable party. +# +# 7. Any use, reproduction or distribution of the Software which is not in accordance +# with this Software License shall automatically revoke all rights granted to you +# under this Software License and render Paragraphs 1 and 2 of this Software +# License null and void. +# +# 8. This Software License does not grant any rights in or to any intellectual +# property owned by SBIA or any Contributor except those rights expressly +# granted hereunder. +# +# +# PART C. MISCELLANEOUS +# --------------------- +# +# This Agreement shall be governed by and construed in accordance with the laws +# of The Commonwealth of Pennsylvania without regard to principles of conflicts +# of law. This Agreement shall supercede and replace any license terms that you +# may have agreed to previously with respect to Software from SBIA. +# +############################################################################## +# @file FindSphinx.cmake +# @brief Find Sphinx documentation build tools. +# +# @par Input variables: +# +# +# @tp @b Sphinx_DIR @endtp +# +# +# +# @tp @b SPHINX_DIR @endtp +# +# +# +# @tp @b Sphinx_FIND_COMPONENTS @endtp +# +# +#
Installation directory of Sphinx tools. Can also be set as environment variable.
Alternative environment variable for @c Sphinx_DIR.
Sphinx build tools to look for, i.e., 'apidoc' and/or 'build'.
+# +# @par Output variables: +# +# +# @tp @b Sphinx_FOUND @endtp +# +# +# +# @tp @b SPHINX_FOUND @endtp +# +# +# @tp @b SPHINX_EXECUTABLE @endtp +# +# +# +# @tp @b Sphinx_PYTHON_EXECUTABLE @endtp +# +# +# +# @tp @b Sphinx_PYTHON_OPTIONS @endtp +# +# +# +# @tp @b Sphinx-build_EXECUTABLE @endtp +# +# +# +# @tp @b Sphinx-apidoc_EXECUTABLE @endtp +# +# +# +# @tp @b Sphinx_VERSION_STRING @endtp +# +# +# +# @tp @b Sphinx_VERSION_MAJOR @endtp +# +# +# +# @tp @b Sphinx_VERSION_MINOR @endtp +# +# +# +# @tp @b Sphinx_VERSION_PATCH @endtp +# +# +#
Whether all or only the requested Sphinx build tools were found.
Alias for @c Sphinx_FOUND. +#
Non-cached alias for @c Sphinx-build_EXECUTABLE.
Python executable used to run sphinx-build. This is either the +# by default found Python interpreter or a specific version as +# specified by the shebang (#!) of the sphinx-build script.
A list of Python options extracted from the shebang (#!) of the +# sphinx-build script. The -E option is added by this module +# if the Python executable is not the system default to avoid +# problems with a differing setting of the @c PYTHONHOME.
Absolute path of the found sphinx-build tool.
Absolute path of the found sphinx-apidoc tool.
Sphinx version found e.g. 1.1.2.
Sphinx major version found e.g. 1.
Sphinx minor version found e.g. 1.
Sphinx patch version found e.g. 2.
+# +# @ingroup CMakeFindModules +############################################################################## + +set (_Sphinx_REQUIRED_VARS) + +# ---------------------------------------------------------------------------- +# initialize search +if (NOT Sphinx_DIR) + if (NOT $ENV{Sphinx_DIR} STREQUAL "") + set (Sphinx_DIR "$ENV{Sphinx_DIR}" CACHE PATH "Installation prefix of Sphinx (docutils)." FORCE) + else () + set (Sphinx_DIR "$ENV{SPHINX_DIR}" CACHE PATH "Installation prefix of Sphinx (docutils)." FORCE) + endif () +endif () + +# ---------------------------------------------------------------------------- +# default components to look for +if (NOT Sphinx_FIND_COMPONENTS) + set (Sphinx_FIND_COMPONENTS "build") +elseif (NOT Sphinx_FIND_COMPONENTS MATCHES "^(build|apidoc)$") + message (FATAL_ERROR "Invalid Sphinx component in: ${Sphinx_FIND_COMPONENTS}") +endif () + +# ---------------------------------------------------------------------------- +# find components, i.e., build tools +foreach (_Sphinx_TOOL IN LISTS Sphinx_FIND_COMPONENTS) + if (Sphinx_DIR) + find_program ( + Sphinx-${_Sphinx_TOOL}_EXECUTABLE + NAMES sphinx-${_Sphinx_TOOL} sphinx-${_Sphinx_TOOL}.py + HINTS "${Sphinx_DIR}" + PATH_SUFFIXES bin + DOC "The sphinx-${_Sphinx_TOOL} Python script." + NO_DEFAULT_PATH + ) + else () + find_program ( + Sphinx-${_Sphinx_TOOL}_EXECUTABLE + NAMES sphinx-${_Sphinx_TOOL} sphinx-${_Sphinx_TOOL}.py + DOC "The sphinx-${_Sphinx_TOOL} Python script." + ) + endif () + mark_as_advanced (Sphinx-${_Sphinx_TOOL}_EXECUTABLE) + list (APPEND _Sphinx_REQUIRED_VARS Sphinx-${_Sphinx_TOOL}_EXECUTABLE) +endforeach () + +# ---------------------------------------------------------------------------- +# determine Python executable used by Sphinx +if (Sphinx-build_EXECUTABLE) + # extract python executable from shebang of sphinx-build + find_package (PythonInterp QUIET) + set (Sphinx_PYTHON_EXECUTABLE "${PYTHON_EXECUTABLE}") + set (Sphinx_PYTHON_OPTIONS) + file (STRINGS "${Sphinx-build_EXECUTABLE}" FIRST_LINE LIMIT_COUNT 1) + if (FIRST_LINE MATCHES "^#!(.*/python.*)") # does not match "#!/usr/bin/env python" ! + string (REGEX REPLACE "^ +| +$" "" Sphinx_PYTHON_EXECUTABLE "${CMAKE_MATCH_1}") + if (Sphinx_PYTHON_EXECUTABLE MATCHES "([^ ]+) (.*)") + set (Sphinx_PYTHON_EXECUTABLE "${CMAKE_MATCH_1}") + string (REGEX REPLACE " +" ";" Sphinx_PYTHON_OPTIONS "${CMAKE_MATCH_2}") + endif () + endif () + # this is done to avoid problems with multiple Python versions being installed + # remember: CMake command if(STR EQUAL STR) is bad and may cause many troubles ! + string (REGEX REPLACE "([.+*?^$])" "\\\\\\1" _Sphinx_PYTHON_EXECUTABLE_RE "${PYTHON_EXECUTABLE}") + list (FIND Sphinx_PYTHON_OPTIONS -E IDX) + if (IDX EQUAL -1 AND NOT Sphinx_PYTHON_EXECUTABLE MATCHES "^${_Sphinx_PYTHON_EXECUTABLE_RE}$") + list (INSERT Sphinx_PYTHON_OPTIONS 0 -E) + endif () + unset (_Sphinx_PYTHON_EXECUTABLE_RE) +endif () + +# ---------------------------------------------------------------------------- +# determine Sphinx version +if (Sphinx-build_EXECUTABLE) + # intentionally use invalid -h option here as the help that is shown then + # will include the Sphinx version information + if (Sphinx_PYTHON_EXECUTABLE) + execute_process ( + COMMAND "${Sphinx_PYTHON_EXECUTABLE}" ${Sphinx_PYTHON_OPTIONS} "${Sphinx-build_EXECUTABLE}" -h + OUTPUT_VARIABLE _Sphinx_VERSION + ERROR_VARIABLE _Sphinx_VERSION + ) + elseif (UNIX) + execute_process ( + COMMAND "${Sphinx-build_EXECUTABLE}" -h + OUTPUT_VARIABLE _Sphinx_VERSION + ERROR_VARIABLE _Sphinx_VERSION + ) + endif () + + # The sphinx version can also contain a "b" instead of the last dot. + # For example "Sphinx v1.2b1" so we cannot just split on "." + if (_Sphinx_VERSION MATCHES "Sphinx v([0-9]+\\.[0-9]+(\\.|b)[0-9]+)") + set (Sphinx_VERSION_STRING "${CMAKE_MATCH_1}") + string(REGEX REPLACE "([0-9]+)\\.[0-9]+(\\.|b)[0-9]+" "\\1" Sphinx_VERSION_MAJOR ${Sphinx_VERSION_STRING}) + string(REGEX REPLACE "[0-9]+\\.([0-9]+)(\\.|b)[0-9]+" "\\1" Sphinx_VERSION_MINOR ${Sphinx_VERSION_STRING}) + string(REGEX REPLACE "[0-9]+\\.[0-9]+(\\.|b)([0-9]+)" "\\1" Sphinx_VERSION_PATCH ${Sphinx_VERSION_STRING}) + + # v1.2.0 -> v1.2 + if (Sphinx_VERSION_PATCH EQUAL 0) + string (REGEX REPLACE "\\.0$" "" Sphinx_VERSION_STRING "${Sphinx_VERSION_STRING}") + endif () + endif() +endif () + +# ---------------------------------------------------------------------------- +# compatibility with FindPythonInterp.cmake and FindPerl.cmake +set (SPHINX_EXECUTABLE "${Sphinx-build_EXECUTABLE}") + +# ---------------------------------------------------------------------------- +# handle the QUIETLY and REQUIRED arguments and set SPHINX_FOUND to TRUE if +# all listed variables are TRUE +include (FindPackageHandleStandardArgs) +FIND_PACKAGE_HANDLE_STANDARD_ARGS ( + Sphinx + REQUIRED_VARS + ${_Sphinx_REQUIRED_VARS} +# VERSION_VAR # This isn't available until CMake 2.8.8 so don't use it. + Sphinx_VERSION_STRING +) + +# ---------------------------------------------------------------------------- +# set Sphinx_DIR +if (NOT Sphinx_DIR AND Sphinx-build_EXECUTABLE) + get_filename_component (Sphinx_DIR "${Sphinx-build_EXECUTABLE}" PATH) + string (REGEX REPLACE "/bin/?" "" Sphinx_DIR "${Sphinx_DIR}") + set (Sphinx_DIR "${Sphinx_DIR}" CACHE PATH "Installation directory of Sphinx tools." FORCE) +endif () + +unset (_Sphinx_VERSION) +unset (_Sphinx_REQUIRED_VARS) \ No newline at end of file diff --git a/3party/jansson/cmake/Vendor.cmake b/3party/jansson/cmake/Vendor.cmake new file mode 100644 index 0000000000..33ebd5205b --- /dev/null +++ b/3party/jansson/cmake/Vendor.cmake @@ -0,0 +1,684 @@ +# Notes: +# +# Author: Paul Harris, June 2012 +# Additions: Joakim Soderberg, Febuary 2013 +# +# Supports: building static/shared, release/debug/etc, can also build html docs +# and some of the tests. +# Note that its designed for out-of-tree builds, so it will not pollute your +# source tree. +# +# TODO 1: Finish implementing tests. api tests are working, but the valgrind +# variants are not flagging problems. +# +# TODO 2: There is a check_exports script that would try and incorporate. +# +# TODO 3: Consolidate version numbers, currently the version number is written +# into: * cmake (here) * autotools (the configure) * source code header files. +# Should not be written directly into header files, autotools/cmake can do +# that job. +# +# Brief intro on how to use cmake: +# > mkdir build (somewhere - we do out-of-tree builds) +# > use cmake, ccmake, or cmake-gui to configure the project. for linux, you +# can only choose one variant: release,debug,etc... and static or shared. +# >> example: +# >> cd build +# >> ccmake -i ../path_to_jansson_dir +# >> inside, configure your options. press C until there are no lines +# with * next to them. +# >> note, I like to configure the 'install' path to ../install, so I get +# self-contained clean installs I can point other projects to. +# >> press G to 'generate' the project files. +# >> make (to build the project) +# >> make install +# >> make test (to run the tests, if you enabled them) +# +# Brief description on how it works: +# There is a small heirachy of CMakeLists.txt files which define how the +# project is built. +# Header file detection etc is done, and the results are written into config.h +# and jansson_config.h, which are generated from the corresponding +# config.h.cmake and jansson_config.h.cmake template files. +# The generated header files end up in the build directory - not in +# the source directory. +# The rest is down to the usual make process. + + + +cmake_minimum_required (VERSION 3.1) +project(jansson C) + +# Options +option(JANSSON_BUILD_DOCS "Build Documentattion" OFF) +option(JANSSON_BUILD_SHARED_LIBS "Build shared libraries." OFF) +option(USE_URANDOM "Use /dev/urandom to seed the hash function." ON) +option(USE_WINDOWS_CRYPTOAPI "Use CryptGenRandom to seed the hash function." ON) + +if (MSVC) + # This option must match the settings used in your program, in particular if you + # are linking statically + option(JANSSON_STATIC_CRT "Link the static CRT libraries" OFF ) +endif () + +option(JANSSON_EXAMPLES "Compile example applications" ON) + +if (UNIX) + option(JANSSON_COVERAGE "(GCC Only! Requires gcov/lcov to be installed). Include target for doing coverage analysis for the test suite. Note that -DCMAKE_BUILD_TYPE=Debug must be set" OFF) + option(JANSSON_COVERALLS "Generate coverage info for Coveralls" OFF) + option(JANSSON_COVERALLS_UPLOAD "Upload coverage info to Coveralls (Only works via Travis)" ON) +endif () + +# Set some nicer output dirs. +set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/bin) +set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/lib) +set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/lib) +set(JANSSON_TEMP_DIR ${CMAKE_CURRENT_BINARY_DIR}/tmp) + +# Give the debug version a different postfix for windows, +# so both the debug and release version can be built in the +# same build-tree on Windows (MSVC). +if (WIN32 AND NOT CMAKE_DEBUG_POSTFIX) + set(CMAKE_DEBUG_POSTFIX "_d") +endif() + +# This is how I thought it should go +# set (JANSSON_VERSION "2.3.1") +# set (JANSSON_SOVERSION 2) + +set(JANSSON_DISPLAY_VERSION "2.12") + +# This is what is required to match the same numbers as automake's +set(JANSSON_VERSION "4.11.1") +set(JANSSON_SOVERSION 4) + +# for CheckFunctionKeywords +set(CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake") + +include (CheckCSourceCompiles) +include (CheckFunctionExists) +include (CheckFunctionKeywords) +include (CheckIncludeFiles) +include (CheckTypeSize) + +if (MSVC) + # Turn off Microsofts "security" warnings. + add_definitions( "/W3 /D_CRT_SECURE_NO_WARNINGS /wd4005 /wd4996 /nologo" ) + + if (JANSSON_STATIC_CRT) + set(CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE} /MT") + set(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} /MTd") + endif() +endif() + +message("C compiler: ${CMAKE_C_COMPILER_ID}") + +# Coverage only works with GCC for a debug build. +if (JANSSON_COVERALLS) + set(JANSSON_COVERAGE ON) +endif() + +if (JANSSON_COVERAGE) + include(CodeCoverage) + include(Coveralls) + + # This adds coverage arguments to gcc/clang. + coveralls_turn_on_coverage() +endif() + +check_include_files (endian.h HAVE_ENDIAN_H) +check_include_files (fcntl.h HAVE_FCNTL_H) +check_include_files (sched.h HAVE_SCHED_H) +check_include_files (unistd.h HAVE_UNISTD_H) +check_include_files (sys/param.h HAVE_SYS_PARAM_H) +check_include_files (sys/stat.h HAVE_SYS_STAT_H) +check_include_files (sys/time.h HAVE_SYS_TIME_H) +check_include_files (sys/types.h HAVE_SYS_TYPES_H) + +check_function_exists (close HAVE_CLOSE) +check_function_exists (getpid HAVE_GETPID) +check_function_exists (gettimeofday HAVE_GETTIMEOFDAY) +check_function_exists (open HAVE_OPEN) +check_function_exists (read HAVE_READ) +check_function_exists (sched_yield HAVE_SCHED_YIELD) + +# Check for the int-type includes +check_include_files (stdint.h HAVE_STDINT_H) + +# Check our 64 bit integer sizes +check_type_size (__int64 __INT64) +check_type_size (int64_t INT64_T) +check_type_size ("long long" LONG_LONG_INT) + +# Check our 32 bit integer sizes +check_type_size (int32_t INT32_T) +check_type_size (__int32 __INT32) +check_type_size ("long" LONG_INT) +check_type_size ("int" INT) +if (HAVE_INT32_T) + set (JSON_INT32 int32_t) +elseif (HAVE___INT32) + set (JSON_INT32 __int32) +elseif (HAVE_LONG_INT AND (LONG_INT EQUAL 4)) + set (JSON_INT32 long) +elseif (HAVE_INT AND (INT EQUAL 4)) + set (JSON_INT32 int) +else () + message (FATAL_ERROR "Could not detect a valid 32-bit integer type") +endif () + +check_type_size ("unsigned long" UNSIGNED_LONG_INT) +check_type_size ("unsigned int" UNSIGNED_INT) +check_type_size ("unsigned short" UNSIGNED_SHORT) + +check_type_size (uint32_t UINT32_T) +check_type_size (__uint32 __UINT32) +if (HAVE_UINT32_T) + set (JSON_UINT32 uint32_t) +elseif (HAVE___UINT32) + set (JSON_UINT32 __uint32) +elseif (HAVE_UNSIGNED_LONG_INT AND (UNSIGNED_LONG_INT EQUAL 4)) + set (JSON_UINT32 "unsigned long") +elseif (HAVE_UNSIGNED_INT AND (UNSIGNED_INT EQUAL 4)) + set (JSON_UINT32 "unsigned int") +else () + message (FATAL_ERROR "Could not detect a valid unsigned 32-bit integer type") +endif () + +check_type_size (uint16_t UINT16_T) +check_type_size (__uint16 __UINT16) +if (HAVE_UINT16_T) + set (JSON_UINT16 uint16_t) +elseif (HAVE___UINT16) + set (JSON_UINT16 __uint16) +elseif (HAVE_UNSIGNED_INT AND (UNSIGNED_INT EQUAL 2)) + set (JSON_UINT16 "unsigned int") +elseif (HAVE_UNSIGNED_SHORT AND (UNSIGNED_SHORT EQUAL 2)) + set (JSON_UINT16 "unsigned short") +else () + message (FATAL_ERROR "Could not detect a valid unsigned 16-bit integer type") +endif () + +check_type_size (uint8_t UINT8_T) +check_type_size (__uint8 __UINT8) +if (HAVE_UINT8_T) + set (JSON_UINT8 uint8_t) +elseif (HAVE___UINT8) + set (JSON_UINT8 __uint8) +else () + set (JSON_UINT8 "unsigned char") +endif () + +# Check for ssize_t and SSIZE_T existance. +check_type_size(ssize_t SSIZE_T) +check_type_size(SSIZE_T UPPERCASE_SSIZE_T) +if(NOT HAVE_SSIZE_T) + if(HAVE_UPPERCASE_SSIZE_T) + set(JSON_SSIZE SSIZE_T) + else() + set(JSON_SSIZE int) + endif() +endif() +set(CMAKE_EXTRA_INCLUDE_FILES "") + +# Check for all the variants of strtoll +check_function_exists (strtoll HAVE_STRTOLL) +check_function_exists (strtoq HAVE_STRTOQ) +check_function_exists (_strtoi64 HAVE__STRTOI64) + +# Figure out what variant we should use +if (HAVE_STRTOLL) + set (JSON_STRTOINT strtoll) +elseif (HAVE_STRTOQ) + set (JSON_STRTOINT strtoq) +elseif (HAVE__STRTOI64) + set (JSON_STRTOINT _strtoi64) +else () + # fallback to strtol (32 bit) + # this will set all the required variables + set (JSON_STRTOINT strtol) + set (JSON_INT_T long) + set (JSON_INTEGER_FORMAT "\"ld\"") +endif () + +# if we haven't defined JSON_INT_T, then we have a 64 bit conversion function. +# detect what to use for the 64 bit type. +# Note: I will prefer long long if I can get it, as that is what the automake system aimed for. +if (NOT DEFINED JSON_INT_T) + if (HAVE_LONG_LONG_INT AND (LONG_LONG_INT EQUAL 8)) + set (JSON_INT_T "long long") + elseif (HAVE_INT64_T) + set (JSON_INT_T int64_t) + elseif (HAVE___INT64) + set (JSON_INT_T __int64) + else () + message (FATAL_ERROR "Could not detect 64 bit type, although I detected the strtoll equivalent") + endif () + + # Apparently, Borland BCC and MSVC wants I64d, + # Borland BCC could also accept LD + # and gcc wants ldd, + # I am not sure what cygwin will want, so I will assume I64d + + if (WIN32) # matches both msvc and cygwin + set (JSON_INTEGER_FORMAT "\"I64d\"") + else () + set (JSON_INTEGER_FORMAT "\"lld\"") + endif () +endif () + + +# If locale.h and localeconv() are available, define to 1, otherwise to 0. +check_include_files (locale.h HAVE_LOCALE_H) +check_function_exists (localeconv HAVE_LOCALECONV) + +if (HAVE_LOCALECONV AND HAVE_LOCALE_H) + set (JSON_HAVE_LOCALECONV 1) +else () + set (JSON_HAVE_LOCALECONV 0) +endif() + +# check if we have setlocale +check_function_exists(setlocale HAVE_SETLOCALE) + +# Check what the inline keyword is. +# Note that the original JSON_INLINE was always set to just 'inline', so this goes further. +check_function_keywords("inline") +check_function_keywords("__inline") +check_function_keywords("__inline__") + +if (HAVE_INLINE) + set(JSON_INLINE inline) +elseif (HAVE___INLINE) + set(JSON_INLINE __inline) +elseif (HAVE___INLINE__) + set(JSON_INLINE __inline__) +else() + # no inline on this platform + set (JSON_INLINE) +endif() + +check_c_source_compiles ("int main() { unsigned long val; __sync_bool_compare_and_swap(&val, 0, 1); __sync_add_and_fetch(&val, 1); __sync_sub_and_fetch(&val, 1); return 0; } " HAVE_SYNC_BUILTINS) +check_c_source_compiles ("int main() { char l; unsigned long v; __atomic_test_and_set(&l, __ATOMIC_RELAXED); __atomic_store_n(&v, 1, __ATOMIC_RELEASE); __atomic_load_n(&v, __ATOMIC_ACQUIRE); __atomic_add_fetch(&v, 1, __ATOMIC_ACQUIRE); __atomic_sub_fetch(&v, 1, __ATOMIC_RELEASE); return 0; }" HAVE_ATOMIC_BUILTINS) + +if (HAVE_SYNC_BUILTINS) + set(JSON_HAVE_SYNC_BUILTINS 1) +else() + set(JSON_HAVE_SYNC_BUILTINS 0) +endif() + +if (HAVE_ATOMIC_BUILTINS) + set(JSON_HAVE_ATOMIC_BUILTINS 1) +else() + set(JSON_HAVE_ATOMIC_BUILTINS 0) +endif() + +set (JANSSON_INITIAL_HASHTABLE_ORDER 3 CACHE STRING "Number of buckets new object hashtables contain is 2 raised to this power. The default is 3, so empty hashtables contain 2^3 = 8 buckets.") + +# configure the public config file +configure_file (${CMAKE_CURRENT_SOURCE_DIR}/cmake/jansson_config.h.cmake + ${CMAKE_CURRENT_BINARY_DIR}/include/jansson_config.h) + +# Copy the jansson.h file to the public include folder +file (COPY ${CMAKE_CURRENT_SOURCE_DIR}/src/jansson.h + DESTINATION ${CMAKE_CURRENT_BINARY_DIR}/include/) + +add_definitions(-DJANSSON_USING_CMAKE) + +# configure the private config file +configure_file (${CMAKE_CURRENT_SOURCE_DIR}/cmake/jansson_private_config.h.cmake + ${CMAKE_CURRENT_BINARY_DIR}/private_include/jansson_private_config.h) + +# and tell the source code to include it +add_definitions(-DHAVE_CONFIG_H) + +include_directories (${CMAKE_CURRENT_BINARY_DIR}/include) +include_directories (${CMAKE_CURRENT_BINARY_DIR}/private_include) + +# Add the lib sources. +file(GLOB JANSSON_SRC src/*.c) + +set(JANSSON_HDR_PRIVATE + ${CMAKE_CURRENT_SOURCE_DIR}/src/hashtable.h + ${CMAKE_CURRENT_SOURCE_DIR}/src/jansson_private.h + ${CMAKE_CURRENT_SOURCE_DIR}/src/strbuffer.h + ${CMAKE_CURRENT_SOURCE_DIR}/src/utf.h + ${CMAKE_CURRENT_BINARY_DIR}/private_include/jansson_private_config.h) + +set(JANSSON_HDR_PUBLIC + ${CMAKE_CURRENT_BINARY_DIR}/include/jansson_config.h + ${CMAKE_CURRENT_SOURCE_DIR}/src/jansson.h) + +source_group("Library Sources" FILES ${JANSSON_SRC}) +source_group("Library Private Headers" FILES ${JANSSON_HDR_PRIVATE}) +source_group("Library Public Headers" FILES ${JANSSON_HDR_PUBLIC}) + +if(JANSSON_BUILD_SHARED_LIBS) + add_library(jansson_vendor SHARED + ${JANSSON_SRC} + ${JANSSON_HDR_PRIVATE} + ${JANSSON_HDR_PUBLIC} + src/jansson.def) + + set_target_properties(jansson_vendor PROPERTIES + VERSION ${JANSSON_VERSION} + SOVERSION ${JANSSON_SOVERSION}) +else() + add_library(jansson_vendor STATIC + ${JANSSON_SRC} + ${JANSSON_HDR_PRIVATE} + ${JANSSON_HDR_PUBLIC}) + set_target_properties(jansson_vendor PROPERTIES + POSITION_INDEPENDENT_CODE true) +endif() + +if (JANSSON_EXAMPLES) + add_executable(simple_parse "${CMAKE_CURRENT_SOURCE_DIR}/examples/simple_parse.c") + target_link_libraries(simple_parse jansson_vendor) +endif() + +# For building Documentation (uses Sphinx) +option(JANSSON_BUILD_DOCS "Build documentation (uses python-sphinx)." ON) +if (JANSSON_BUILD_DOCS) + find_package(Sphinx) + + if (NOT SPHINX_FOUND) + message(WARNING "Sphinx not found. Cannot generate documentation! + Set -DJANSSON_BUILD_DOCS=OFF to get rid of this message.") + else() + if (Sphinx_VERSION_STRING VERSION_LESS 1.0) + message(WARNING "Your Sphinx version is too old! + This project requires Sphinx v1.0 or above to produce + proper documentation (you have v${Sphinx_VERSION_STRING}). + You will get output but it will have errors.") + endif() + + # configured documentation tools and intermediate build results + set(BINARY_BUILD_DIR "${CMAKE_CURRENT_BINARY_DIR}/_build") + + # Sphinx cache with pickled ReST documents + set(SPHINX_CACHE_DIR "${CMAKE_CURRENT_BINARY_DIR}/_doctrees") + + # CMake could be used to build the conf.py file too, + # eg it could automatically write the version of the program or change the theme. + # if(NOT DEFINED SPHINX_THEME) + # set(SPHINX_THEME default) + # endif() + # + # if(NOT DEFINED SPHINX_THEME_DIR) + # set(SPHINX_THEME_DIR) + # endif() + # + # configure_file( + # "${CMAKE_CURRENT_SOURCE_DIR}/conf.py.in" + # "${BINARY_BUILD_DIR}/conf.py" + # @ONLY) + + # TODO: Add support for all sphinx builders: http://sphinx-doc.org/builders.html + + # Add documentation targets. + set(DOC_TARGETS html) + + option(JANSSON_BUILD_MAN "Create a target for building man pages." ON) + + if (JANSSON_BUILD_MAN) + if (Sphinx_VERSION_STRING VERSION_LESS 1.0) + message(WARNING "Sphinx version 1.0 > is required to build man pages. You have v${Sphinx_VERSION_STRING}.") + else() + list(APPEND DOC_TARGETS man) + endif() + endif() + + option(JANSSON_BUILD_LATEX "Create a target for building latex docs (to create PDF)." OFF) + + if (JANSSON_BUILD_LATEX) + find_package(LATEX) + + if (NOT LATEX_COMPILER) + message("Couldn't find Latex, can't build latex docs using Sphinx") + else() + message("Latex found! If you have problems building, see Sphinx documentation for required Latex packages.") + list(APPEND DOC_TARGETS latex) + endif() + endif() + + # The doc target will build all documentation targets. + add_custom_target(doc) + + foreach (DOC_TARGET ${DOC_TARGETS}) + add_custom_target(${DOC_TARGET} + ${SPHINX_EXECUTABLE} + # -q # Enable for quiet mode + -b ${DOC_TARGET} + -d "${SPHINX_CACHE_DIR}" + # -c "${BINARY_BUILD_DIR}" # enable if using cmake-generated conf.py + "${CMAKE_CURRENT_SOURCE_DIR}/doc" + "${CMAKE_CURRENT_BINARY_DIR}/doc/${DOC_TARGET}" + COMMENT "Building ${DOC_TARGET} documentation with Sphinx") + + add_dependencies(doc ${DOC_TARGET}) + endforeach() + + message("Building documentation enabled for: ${DOC_TARGETS}") + endif() +endif () + + +option(JANSSON_WITHOUT_TESTS "Don't build tests ('make test' to execute tests)" OFF) + +if (NOT JANSSON_WITHOUT_TESTS) + option(JANSSON_TEST_WITH_VALGRIND "Enable valgrind tests." OFF) + + ENABLE_TESTING() + + if (JANSSON_TEST_WITH_VALGRIND) + # TODO: Add FindValgrind.cmake instead of having a hardcoded path. + + add_definitions(-DVALGRIND) + + # enable valgrind + set(CMAKE_MEMORYCHECK_COMMAND valgrind) + set(CMAKE_MEMORYCHECK_COMMAND_OPTIONS + "--error-exitcode=1 --leak-check=full --show-reachable=yes --track-origins=yes -q") + + set(MEMCHECK_COMMAND + "${CMAKE_MEMORYCHECK_COMMAND} ${CMAKE_MEMORYCHECK_COMMAND_OPTIONS}") + separate_arguments(MEMCHECK_COMMAND) + endif () + + # + # Test suites. + # + if (CMAKE_COMPILER_IS_GNUCC) + add_definitions(-Wall -Wextra -Wdeclaration-after-statement) + endif () + + set(api_tests + test_array + test_copy + test_chaos + test_dump + test_dump_callback + test_equal + test_load + test_loadb + test_load_callback + test_number + test_object + test_pack + test_simple + test_sprintf + test_unpack) + + # Doing arithmetic on void pointers is not allowed by Microsofts compiler + # such as secure_malloc and secure_free is doing, so exclude it for now. + if (NOT MSVC) + list(APPEND api_tests test_memory_funcs) + endif() + + # Helper macro for building and linking a test program. + macro(build_testprog name dir) + add_executable(${name} ${dir}/${name}.c) + add_dependencies(${name} jansson_vendor) + target_link_libraries(${name} jansson_vendor) + endmacro(build_testprog) + + # Create executables and tests/valgrind tests for API tests. + foreach (test ${api_tests}) + build_testprog(${test} ${CMAKE_CURRENT_SOURCE_DIR}/test/suites/api) + + if (JANSSON_TEST_WITH_VALGRIND) + add_test(memcheck__${test} + ${MEMCHECK_COMMAND} ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/${test} + WORKING_DIRECTORY ${JANSSON_TEMP_DIR}) + else() + add_test(${test} + ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/${test} + WORKING_DIRECTORY ${JANSSON_TEMP_DIR}) + endif () + endforeach () + + # Test harness for the suites tests. + build_testprog(json_process ${CMAKE_CURRENT_SOURCE_DIR}/test/bin) + + set(SUITE_TEST_CMD ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/json_process) + set(SUITES encoding-flags valid invalid invalid-unicode) + foreach (SUITE ${SUITES}) + file(GLOB TESTDIRS test/suites/${SUITE}/*) + + foreach (TESTDIR ${TESTDIRS}) + if (IS_DIRECTORY ${TESTDIR}) + get_filename_component(TNAME ${TESTDIR} NAME) + + if (JANSSON_TEST_WITH_VALGRIND) + add_test(memcheck__${SUITE}__${TNAME} + ${MEMCHECK_COMMAND} ${SUITE_TEST_CMD} ${TESTDIR}) + else() + add_test(${SUITE}__${TNAME} + ${SUITE_TEST_CMD} ${TESTDIR}) + endif() + + if ((${SUITE} STREQUAL "valid" OR ${SUITE} STREQUAL "invalid") AND NOT EXISTS ${TESTDIR}/nostrip) + if (JANSSON_TEST_WITH_VALGRIND) + add_test(memcheck__${SUITE}__${TNAME}__strip + ${MEMCHECK_COMMAND} ${SUITE_TEST_CMD} --strip ${TESTDIR}) + else() + add_test(${SUITE}__${TNAME}__strip + ${SUITE_TEST_CMD} --strip ${TESTDIR}) + endif() + endif () + endif () + endforeach () + endforeach () + + if (JANSSON_COVERAGE) + setup_target_for_coverage( + coverage # Coverage make target "make coverage". + coverage # Name of output directory. + make # Name of test runner executable. + test) # Arguments to the test runner above (make test). + + if (JANSSON_COVERALLS) + set(COVERAGE_SRCS ${JANSSON_SRC}) + coveralls_setup("${COVERAGE_SRCS}" ${JANSSON_COVERALLS_UPLOAD}) + endif () + endif () + + # Enable using "make check" just like the autotools project. + # By default cmake creates a target "make test" + add_custom_target(check COMMAND ${CMAKE_CTEST_COMMAND} + DEPENDS json_process ${api_tests}) +endif () + +# +# Installation preparation. +# + +# Allow the user to override installation directories. +set(JANSSON_INSTALL_LIB_DIR lib CACHE PATH "Installation directory for libraries") +set(JANSSON_INSTALL_BIN_DIR bin CACHE PATH "Installation directory for executables") +set(JANSSON_INSTALL_INCLUDE_DIR include CACHE PATH "Installation directory for header files") + +if(WIN32 AND NOT CYGWIN) + set(DEF_INSTALL_CMAKE_DIR cmake) +else() + set(DEF_INSTALL_CMAKE_DIR lib/cmake/jansson) +endif() + +set(JANSSON_INSTALL_CMAKE_DIR ${DEF_INSTALL_CMAKE_DIR} CACHE PATH "Installation directory for CMake files") + +# Create pkg-conf file. +# (We use the same files as ./configure does, so we +# have to defined the same variables used there). +set(prefix ${CMAKE_INSTALL_PREFIX}) +set(exec_prefix "\${prefix}") +set(libdir "\${exec_prefix}/${JANSSON_INSTALL_LIB_DIR}") +set(includedir "\${prefix}/${JANSSON_INSTALL_INCLUDE_DIR}") +set(VERSION ${JANSSON_DISPLAY_VERSION}) +configure_file(${CMAKE_CURRENT_SOURCE_DIR}/jansson.pc.in + ${CMAKE_CURRENT_BINARY_DIR}/jansson.pc @ONLY) + +# Make sure the paths are relative. +foreach(p LIB BIN INCLUDE CMAKE) + set(var JANSSON_INSTALL_${p}_DIR) +endforeach() + +# Generate the config file for the build-tree. +set(JANSSON__INCLUDE_DIRS + "${CMAKE_CURRENT_SOURCE_DIR}/include" + "${CMAKE_CURRENT_BINARY_DIR}/include") +set(JANSSON_INCLUDE_DIRS ${JANSSON__INCLUDE_DIRS} CACHE PATH "Jansson include directories") +configure_file(${CMAKE_CURRENT_SOURCE_DIR}/cmake/janssonConfig.cmake.in + ${CMAKE_CURRENT_BINARY_DIR}/janssonConfig.cmake + @ONLY) + + +# Generate the config file for the installation tree. +include(CMakePackageConfigHelpers) + +write_basic_package_version_file( + "${CMAKE_CURRENT_BINARY_DIR}/cmake/janssonConfigVersion.cmake" + VERSION ${JANSSON_VERSION} + COMPATIBILITY ExactVersion +) + +configure_package_config_file( + "cmake/janssonConfig.cmake.in" + "${CMAKE_CURRENT_BINARY_DIR}/cmake/janssonConfig.cmake" + INSTALL_DESTINATION "${JANSSON_INSTALL_CMAKE_DIR}" +) + +# +# Install targets. +# +option(JANSSON_INSTALL "Generate installation target" ON) +if (JANSSON_INSTALL) + install(TARGETS jansson_vendor + EXPORT janssonTargets + LIBRARY DESTINATION "lib" + ARCHIVE DESTINATION "lib" + RUNTIME DESTINATION "bin" + INCLUDES DESTINATION "include") + + install(FILES ${JANSSON_HDR_PUBLIC} + DESTINATION "include") + + # Install the pkg-config. + install(FILES + ${CMAKE_CURRENT_BINARY_DIR}/jansson.pc + DESTINATION lib/pkgconfig) + + # Install the configs. + install(FILES + ${CMAKE_CURRENT_BINARY_DIR}/cmake/janssonConfig.cmake + ${CMAKE_CURRENT_BINARY_DIR}/cmake/janssonConfigVersion.cmake + DESTINATION "${JANSSON_INSTALL_CMAKE_DIR}") + + # Install exports for the install-tree. + install(EXPORT janssonTargets + NAMESPACE jansson:: + DESTINATION "${JANSSON_INSTALL_CMAKE_DIR}") +endif() + +# For use when simply using add_library from a parent project to build jansson. +set(JANSSON_LIBRARIES jansson_vendor CACHE STRING "jansson libraries") diff --git a/3party/jansson/cmake/janssonConfig.cmake.in b/3party/jansson/cmake/janssonConfig.cmake.in new file mode 100644 index 0000000000..abd6793c59 --- /dev/null +++ b/3party/jansson/cmake/janssonConfig.cmake.in @@ -0,0 +1,4 @@ +@PACKAGE_INIT@ + +include("${CMAKE_CURRENT_LIST_DIR}/janssonTargets.cmake") +check_required_components("@PROJECT_NAME@") diff --git a/3party/jansson/cmake/jansson_config.h.cmake b/3party/jansson/cmake/jansson_config.h.cmake new file mode 100644 index 0000000000..2f248cbcb9 --- /dev/null +++ b/3party/jansson/cmake/jansson_config.h.cmake @@ -0,0 +1,74 @@ +/* + * Copyright (c) 2010-2016 Petri Lehtinen + * + * Jansson is free software; you can redistribute it and/or modify + * it under the terms of the MIT license. See LICENSE for details. + * + * + * This file specifies a part of the site-specific configuration for + * Jansson, namely those things that affect the public API in + * jansson.h. + * + * The CMake system will generate the jansson_config.h file and + * copy it to the build and install directories. + */ + +#ifndef JANSSON_CONFIG_H +#define JANSSON_CONFIG_H + +/* Define this so that we can disable scattered automake configuration in source files */ +#ifndef JANSSON_USING_CMAKE +#define JANSSON_USING_CMAKE +#endif + +/* Note: when using cmake, JSON_INTEGER_IS_LONG_LONG is not defined nor used, + * as we will also check for __int64 etc types. + * (the definition was used in the automake system) */ + +/* Bring in the cmake-detected defines */ +#cmakedefine HAVE_STDINT_H 1 +#cmakedefine HAVE_INTTYPES_H 1 +#cmakedefine HAVE_SYS_TYPES_H 1 + +/* Include our standard type header for the integer typedef */ + +#if defined(HAVE_STDINT_H) +# include +#elif defined(HAVE_INTTYPES_H) +# include +#elif defined(HAVE_SYS_TYPES_H) +# include +#endif + + +/* If your compiler supports the inline keyword in C, JSON_INLINE is + defined to `inline', otherwise empty. In C++, the inline is always + supported. */ +#ifdef __cplusplus +#define JSON_INLINE inline +#else +#define JSON_INLINE @JSON_INLINE@ +#endif + + +#define json_int_t @JSON_INT_T@ +#define json_strtoint @JSON_STRTOINT@ +#define JSON_INTEGER_FORMAT @JSON_INTEGER_FORMAT@ + + +/* If locale.h and localeconv() are available, define to 1, otherwise to 0. */ +#define JSON_HAVE_LOCALECONV @JSON_HAVE_LOCALECONV@ + +/* If __atomic builtins are available they will be used to manage + reference counts of json_t. */ +#define JSON_HAVE_ATOMIC_BUILTINS @JSON_HAVE_ATOMIC_BUILTINS@ + +/* If __atomic builtins are not available we try using __sync builtins + to manage reference counts of json_t. */ +#define JSON_HAVE_SYNC_BUILTINS @JSON_HAVE_SYNC_BUILTINS@ + +/* Maximum recursion depth for parsing JSON input. + This limits the depth of e.g. array-within-array constructions. */ +#define JSON_PARSER_MAX_DEPTH 2048 + +#endif diff --git a/3party/jansson/cmake/jansson_private_config.h.cmake b/3party/jansson/cmake/jansson_private_config.h.cmake new file mode 100644 index 0000000000..b7c4514974 --- /dev/null +++ b/3party/jansson/cmake/jansson_private_config.h.cmake @@ -0,0 +1,53 @@ +#cmakedefine HAVE_ENDIAN_H 1 +#cmakedefine HAVE_FCNTL_H 1 +#cmakedefine HAVE_SCHED_H 1 +#cmakedefine HAVE_UNISTD_H 1 +#cmakedefine HAVE_SYS_PARAM_H 1 +#cmakedefine HAVE_SYS_STAT_H 1 +#cmakedefine HAVE_SYS_TIME_H 1 +#cmakedefine HAVE_SYS_TYPES_H 1 +#cmakedefine HAVE_STDINT_H 1 + +#cmakedefine HAVE_CLOSE 1 +#cmakedefine HAVE_GETPID 1 +#cmakedefine HAVE_GETTIMEOFDAY 1 +#cmakedefine HAVE_OPEN 1 +#cmakedefine HAVE_READ 1 +#cmakedefine HAVE_SCHED_YIELD 1 + +#cmakedefine HAVE_SYNC_BUILTINS 1 +#cmakedefine HAVE_ATOMIC_BUILTINS 1 + +#cmakedefine HAVE_LOCALE_H 1 +#cmakedefine HAVE_SETLOCALE 1 + +#cmakedefine HAVE_INT32_T 1 +#ifndef HAVE_INT32_T +# define int32_t @JSON_INT32@ +#endif + +#cmakedefine HAVE_UINT32_T 1 +#ifndef HAVE_UINT32_T +# define uint32_t @JSON_UINT32@ +#endif + +#cmakedefine HAVE_UINT16_T 1 +#ifndef HAVE_UINT16_T +# define uint16_t @JSON_UINT16@ +#endif + +#cmakedefine HAVE_UINT8_T 1 +#ifndef HAVE_UINT8_T +# define uint8_t @JSON_UINT8@ +#endif + +#cmakedefine HAVE_SSIZE_T 1 + +#ifndef HAVE_SSIZE_T +# define ssize_t @JSON_SSIZE@ +#endif + +#cmakedefine USE_URANDOM 1 +#cmakedefine USE_WINDOWS_CRYPTOAPI 1 + +#define INITIAL_HASHTABLE_ORDER @JANSSON_INITIAL_HASHTABLE_ORDER@ diff --git a/3party/jansson/configure.ac b/3party/jansson/configure.ac new file mode 100644 index 0000000000..cf9ac33498 --- /dev/null +++ b/3party/jansson/configure.ac @@ -0,0 +1,162 @@ +AC_PREREQ([2.60]) +AC_INIT([jansson], [2.12], [petri@digip.org]) + +AC_CONFIG_AUX_DIR([.]) +AM_INIT_AUTOMAKE([1.10 foreign]) + +AC_CONFIG_SRCDIR([src/value.c]) +AC_CONFIG_HEADERS([jansson_private_config.h]) + +# Checks for programs. +AC_PROG_CC +AC_PROG_LIBTOOL +AM_CONDITIONAL([GCC], [test x$GCC = xyes]) + +# Checks for libraries. + +# Checks for header files. +AC_CHECK_HEADERS([endian.h fcntl.h locale.h sched.h unistd.h sys/param.h sys/stat.h sys/time.h sys/types.h]) + +# Checks for typedefs, structures, and compiler characteristics. +AC_TYPE_INT32_T +AC_TYPE_UINT32_T +AC_TYPE_UINT16_T +AC_TYPE_UINT8_T +AC_TYPE_LONG_LONG_INT + +AC_C_INLINE +case $ac_cv_c_inline in + yes) json_inline=inline;; + no) json_inline=;; + *) json_inline=$ac_cv_c_inline;; +esac +AC_SUBST([json_inline]) + +# Checks for library functions. +AC_CHECK_FUNCS([close getpid gettimeofday localeconv open read sched_yield strtoll]) + +AC_MSG_CHECKING([for gcc __sync builtins]) +have_sync_builtins=no +AC_TRY_LINK( + [], [unsigned long val; __sync_bool_compare_and_swap(&val, 0, 1); __sync_add_and_fetch(&val, 1); __sync_sub_and_fetch(&val, 1);], + [have_sync_builtins=yes], +) +if test "x$have_sync_builtins" = "xyes"; then + AC_DEFINE([HAVE_SYNC_BUILTINS], [1], + [Define to 1 if gcc's __sync builtins are available]) + json_have_sync_builtins=1 +else + json_have_sync_builtins=0 +fi +AC_SUBST([json_have_sync_builtins]) +AC_MSG_RESULT([$have_sync_builtins]) + +AC_MSG_CHECKING([for gcc __atomic builtins]) +have_atomic_builtins=no +AC_TRY_LINK( + [], [char l; unsigned long v; __atomic_test_and_set(&l, __ATOMIC_RELAXED); __atomic_store_n(&v, 1, __ATOMIC_RELEASE); __atomic_load_n(&v, __ATOMIC_ACQUIRE); __atomic_add_fetch(&v, 1, __ATOMIC_ACQUIRE); __atomic_sub_fetch(&v, 1, __ATOMIC_RELEASE);], + [have_atomic_builtins=yes], +) +if test "x$have_atomic_builtins" = "xyes"; then + AC_DEFINE([HAVE_ATOMIC_BUILTINS], [1], + [Define to 1 if gcc's __atomic builtins are available]) + json_have_atomic_builtins=1 +else + json_have_atomic_builtins=0 +fi +AC_SUBST([json_have_atomic_builtins]) +AC_MSG_RESULT([$have_atomic_builtins]) + +case "$ac_cv_type_long_long_int$ac_cv_func_strtoll" in + yesyes) json_have_long_long=1;; + *) json_have_long_long=0;; +esac +AC_SUBST([json_have_long_long]) + +case "$ac_cv_header_locale_h$ac_cv_func_localeconv" in + yesyes) json_have_localeconv=1;; + *) json_have_localeconv=0;; +esac +AC_SUBST([json_have_localeconv]) + +# Features +AC_ARG_ENABLE([urandom], + [AS_HELP_STRING([--disable-urandom], + [Don't use /dev/urandom to seed the hash function])], + [use_urandom=$enableval], [use_urandom=yes]) + +if test "x$use_urandom" = xyes; then +AC_DEFINE([USE_URANDOM], [1], + [Define to 1 if /dev/urandom should be used for seeding the hash function]) +fi + +AC_ARG_ENABLE([windows-cryptoapi], + [AS_HELP_STRING([--disable-windows-cryptoapi], + [Don't use CryptGenRandom to seed the hash function])], + [use_windows_cryptoapi=$enableval], [use_windows_cryptoapi=yes]) + +if test "x$use_windows_cryptoapi" = xyes; then +AC_DEFINE([USE_WINDOWS_CRYPTOAPI], [1], + [Define to 1 if CryptGenRandom should be used for seeding the hash function]) +fi + +AC_ARG_ENABLE([initial-hashtable-order], + [AS_HELP_STRING([--enable-initial-hashtable-order=VAL], + [Number of buckets new object hashtables contain is 2 raised to this power. The default is 3, so empty hashtables contain 2^3 = 8 buckets.])], + [initial_hashtable_order=$enableval], [initial_hashtable_order=3]) +AC_DEFINE_UNQUOTED([INITIAL_HASHTABLE_ORDER], [$initial_hashtable_order], + [Number of buckets new object hashtables contain is 2 raised to this power. E.g. 3 -> 2^3 = 8.]) + +AC_ARG_ENABLE([Bsymbolic], + [AS_HELP_STRING([--disable-Bsymbolic], + [Avoid linking with -Bsymbolic-function])], + [], [with_Bsymbolic=check]) + +if test "x$with_Bsymbolic" != "xno" ; then + AC_MSG_CHECKING([for -Bsymbolic-functions linker flag]) + saved_LDFLAGS="${LDFLAGS}" + LDFLAGS=-Wl,-Bsymbolic-functions + AC_TRY_LINK( + [], [int main (void) { return 0; }], + [AC_MSG_RESULT([yes]) + have_Bsymbolic=yes], + [AC_MSG_RESULT([no]) + have_Bsymbolic=no] + ) + LDFLAGS="${saved_LDFLAGS}" + + if test "x$with_Bsymbolic" = "xcheck" ; then + with_Bsymbolic=$have_Bsymbolic; + fi + if test "x$with_Bsymbolic:x$have_Bsymbolic" = "xyes:xno" ; then + AC_MSG_ERROR([linker support is required for -Bsymbolic]) + fi +fi + +AS_IF([test "x$with_Bsymbolic" = "xyes"], [JSON_BSYMBOLIC_LDFLAGS=-Wl[,]-Bsymbolic-functions]) +AC_SUBST(JSON_BSYMBOLIC_LDFLAGS) + +if test x$GCC = xyes; then + AC_MSG_CHECKING(for -Wno-format-truncation) + wnoformat_truncation="-Wno-format-truncation" + AS_IF([${CC} -Wno-format-truncation -Werror -S -o /dev/null -xc /dev/null > /dev/null 2>&1], + [AC_MSG_RESULT(yes)], + [AC_MSG_RESULT(no) + wnoformat_truncation=""]) + + AM_CFLAGS="-Wall -Wextra -Wdeclaration-after-statement -Wshadow ${wnoformat_truncation}" +fi +AC_SUBST([AM_CFLAGS]) + +AC_CONFIG_FILES([ + jansson.pc + Makefile + doc/Makefile + src/Makefile + src/jansson_config.h + test/Makefile + test/bin/Makefile + test/suites/Makefile + test/suites/api/Makefile +]) +AC_OUTPUT diff --git a/3party/jansson/doc/.gitignore b/3party/jansson/doc/.gitignore new file mode 100644 index 0000000000..69fa449dd9 --- /dev/null +++ b/3party/jansson/doc/.gitignore @@ -0,0 +1 @@ +_build/ diff --git a/3party/jansson/doc/Makefile.am b/3party/jansson/doc/Makefile.am new file mode 100644 index 0000000000..5069623fa3 --- /dev/null +++ b/3party/jansson/doc/Makefile.am @@ -0,0 +1,20 @@ +EXTRA_DIST = conf.py apiref.rst changes.rst conformance.rst \ + gettingstarted.rst github_commits.c index.rst portability.rst \ + tutorial.rst upgrading.rst ext/refcounting.py + +SPHINXBUILD = sphinx-build +SPHINXOPTS = -d _build/doctrees $(SPHINXOPTS_EXTRA) + +html-local: + $(SPHINXBUILD) -b html $(SPHINXOPTS) $(srcdir) _build/html + +install-html-local: html + mkdir -p $(DESTDIR)$(htmldir) + cp -r _build/html $(DESTDIR)$(htmldir) + +uninstall-local: + rm -rf $(DESTDIR)$(htmldir) + +clean-local: + rm -rf _build + rm -f ext/refcounting.pyc diff --git a/3party/jansson/doc/README b/3party/jansson/doc/README new file mode 100644 index 0000000000..930b3bf0c3 --- /dev/null +++ b/3party/jansson/doc/README @@ -0,0 +1,5 @@ +To build the documentation, invoke + + make html + +Then point your browser to _build/html/index.html. diff --git a/3party/jansson/doc/apiref.rst b/3party/jansson/doc/apiref.rst new file mode 100644 index 0000000000..3945c113ed --- /dev/null +++ b/3party/jansson/doc/apiref.rst @@ -0,0 +1,1862 @@ +.. _apiref: + +************* +API Reference +************* + +.. highlight:: c + +Preliminaries +============= + +All declarations are in :file:`jansson.h`, so it's enough to + +:: + + #include + +in each source file. + +All constants are prefixed with ``JSON_`` (except for those describing +the library version, prefixed with ``JANSSON_``). Other identifiers +are prefixed with ``json_``. Type names are suffixed with ``_t`` and +``typedef``\ 'd so that the ``struct`` keyword need not be used. + + +Library Version +=============== + +The Jansson version is of the form *A.B.C*, where *A* is the major +version, *B* is the minor version and *C* is the micro version. If the +micro version is zero, it's omitted from the version string, i.e. the +version string is just *A.B*. + +When a new release only fixes bugs and doesn't add new features or +functionality, the micro version is incremented. When new features are +added in a backwards compatible way, the minor version is incremented +and the micro version is set to zero. When there are backwards +incompatible changes, the major version is incremented and others are +set to zero. + +The following preprocessor constants specify the current version of +the library: + +``JANSSON_MAJOR_VERSION``, ``JANSSON_MINOR_VERSION``, ``JANSSON_MICRO_VERSION`` + Integers specifying the major, minor and micro versions, + respectively. + +``JANSSON_VERSION`` + A string representation of the current version, e.g. ``"1.2.1"`` or + ``"1.3"``. + +``JANSSON_VERSION_HEX`` + A 3-byte hexadecimal representation of the version, e.g. + ``0x010201`` for version 1.2.1 and ``0x010300`` for version 1.3. + This is useful in numeric comparisons, e.g.:: + + #if JANSSON_VERSION_HEX >= 0x010300 + /* Code specific to version 1.3 and above */ + #endif + +``JANSSON_THREAD_SAFE_REFCOUNT`` + If this value is defined all read-only operations and reference counting in + Jansson are thread safe. This value is not defined for versions older than + ``2.11`` or when the compiler does not provide built-in atomic functions. + + +Value Representation +==================== + +The JSON specification (:rfc:`4627`) defines the following data types: +*object*, *array*, *string*, *number*, *boolean*, and *null*. JSON +types are used dynamically; arrays and objects can hold any other data +type, including themselves. For this reason, Jansson's type system is +also dynamic in nature. There's one C type to represent all JSON +values, and this structure knows the type of the JSON value it holds. + +.. type:: json_t + + This data structure is used throughout the library to represent all + JSON values. It always contains the type of the JSON value it holds + and the value's reference count. The rest depends on the type of the + value. + +Objects of :type:`json_t` are always used through a pointer. There +are APIs for querying the type, manipulating the reference count, and +for constructing and manipulating values of different types. + +Unless noted otherwise, all API functions return an error value if an +error occurs. Depending on the function's signature, the error value +is either *NULL* or -1. Invalid arguments or invalid input are +apparent sources for errors. Memory allocation and I/O operations may +also cause errors. + + +Type +---- + +.. type:: enum json_type + + The type of a JSON value. The following members are defined: + + +--------------------+ + | ``JSON_OBJECT`` | + +--------------------+ + | ``JSON_ARRAY`` | + +--------------------+ + | ``JSON_STRING`` | + +--------------------+ + | ``JSON_INTEGER`` | + +--------------------+ + | ``JSON_REAL`` | + +--------------------+ + | ``JSON_TRUE`` | + +--------------------+ + | ``JSON_FALSE`` | + +--------------------+ + | ``JSON_NULL`` | + +--------------------+ + + These correspond to JSON object, array, string, number, boolean and + null. A number is represented by either a value of the type + ``JSON_INTEGER`` or of the type ``JSON_REAL``. A true boolean value + is represented by a value of the type ``JSON_TRUE`` and false by a + value of the type ``JSON_FALSE``. + +.. function:: int json_typeof(const json_t *json) + + Return the type of the JSON value (a :type:`json_type` cast to + :type:`int`). *json* MUST NOT be *NULL*. This function is actually + implemented as a macro for speed. + +.. function:: json_is_object(const json_t *json) + json_is_array(const json_t *json) + json_is_string(const json_t *json) + json_is_integer(const json_t *json) + json_is_real(const json_t *json) + json_is_true(const json_t *json) + json_is_false(const json_t *json) + json_is_null(const json_t *json) + + These functions (actually macros) return true (non-zero) for values + of the given type, and false (zero) for values of other types and + for *NULL*. + +.. function:: json_is_number(const json_t *json) + + Returns true for values of types ``JSON_INTEGER`` and + ``JSON_REAL``, and false for other types and for *NULL*. + +.. function:: json_is_boolean(const json_t *json) + + Returns true for types ``JSON_TRUE`` and ``JSON_FALSE``, and false + for values of other types and for *NULL*. + +.. function:: json_boolean_value(const json_t *json) + + Alias of :func:`json_is_true()`, i.e. returns 1 for ``JSON_TRUE`` + and 0 otherwise. + + .. versionadded:: 2.7 + + +.. _apiref-reference-count: + +Reference Count +--------------- + +The reference count is used to track whether a value is still in use +or not. When a value is created, it's reference count is set to 1. If +a reference to a value is kept (e.g. a value is stored somewhere for +later use), its reference count is incremented, and when the value is +no longer needed, the reference count is decremented. When the +reference count drops to zero, there are no references left, and the +value can be destroyed. + +.. function:: json_t *json_incref(json_t *json) + + Increment the reference count of *json* if it's not *NULL*. + Returns *json*. + +.. function:: void json_decref(json_t *json) + + Decrement the reference count of *json*. As soon as a call to + :func:`json_decref()` drops the reference count to zero, the value + is destroyed and it can no longer be used. + +Functions creating new JSON values set the reference count to 1. These +functions are said to return a **new reference**. Other functions +returning (existing) JSON values do not normally increase the +reference count. These functions are said to return a **borrowed +reference**. So, if the user will hold a reference to a value returned +as a borrowed reference, he must call :func:`json_incref`. As soon as +the value is no longer needed, :func:`json_decref` should be called +to release the reference. + +Normally, all functions accepting a JSON value as an argument will +manage the reference, i.e. increase and decrease the reference count +as needed. However, some functions **steal** the reference, i.e. they +have the same result as if the user called :func:`json_decref()` on +the argument right after calling the function. These functions are +suffixed with ``_new`` or have ``_new_`` somewhere in their name. + +For example, the following code creates a new JSON array and appends +an integer to it:: + + json_t *array, *integer; + + array = json_array(); + integer = json_integer(42); + + json_array_append(array, integer); + json_decref(integer); + +Note how the caller has to release the reference to the integer value +by calling :func:`json_decref()`. By using a reference stealing +function :func:`json_array_append_new()` instead of +:func:`json_array_append()`, the code becomes much simpler:: + + json_t *array = json_array(); + json_array_append_new(array, json_integer(42)); + +In this case, the user doesn't have to explicitly release the +reference to the integer value, as :func:`json_array_append_new()` +steals the reference when appending the value to the array. + +In the following sections it is clearly documented whether a function +will return a new or borrowed reference or steal a reference to its +argument. + + +Circular References +------------------- + +A circular reference is created when an object or an array is, +directly or indirectly, inserted inside itself. The direct case is +simple:: + + json_t *obj = json_object(); + json_object_set(obj, "foo", obj); + +Jansson will refuse to do this, and :func:`json_object_set()` (and +all the other such functions for objects and arrays) will return with +an error status. The indirect case is the dangerous one:: + + json_t *arr1 = json_array(), *arr2 = json_array(); + json_array_append(arr1, arr2); + json_array_append(arr2, arr1); + +In this example, the array ``arr2`` is contained in the array +``arr1``, and vice versa. Jansson cannot check for this kind of +indirect circular references without a performance hit, so it's up to +the user to avoid them. + +If a circular reference is created, the memory consumed by the values +cannot be freed by :func:`json_decref()`. The reference counts never +drops to zero because the values are keeping the references to each +other. Moreover, trying to encode the values with any of the encoding +functions will fail. The encoder detects circular references and +returns an error status. + +Scope Dereferencing +------------------- + +.. versionadded:: 2.9 + +It is possible to use the ``json_auto_t`` type to automatically +dereference a value at the end of a scope. For example:: + + void function(void) { + json_auto_t *value = NULL; + value = json_string("foo"); + /* json_decref(value) is automatically called. */ + } + +This feature is only available on GCC and Clang. So if your project +has a portability requirement for other compilers, you should avoid +this feature. + +Additionally, as always, care should be taken when passing values to +functions that steal references. + +True, False and Null +==================== + +These three values are implemented as singletons, so the returned +pointers won't change between invocations of these functions. + +.. function:: json_t *json_true(void) + + .. refcounting:: new + + Returns the JSON true value. + +.. function:: json_t *json_false(void) + + .. refcounting:: new + + Returns the JSON false value. + +.. function:: json_t *json_boolean(val) + + .. refcounting:: new + + Returns JSON false if ``val`` is zero, and JSON true otherwise. + This is a macro, and equivalent to ``val ? json_true() : + json_false()``. + + .. versionadded:: 2.4 + + +.. function:: json_t *json_null(void) + + .. refcounting:: new + + Returns the JSON null value. + + +String +====== + +Jansson uses UTF-8 as the character encoding. All JSON strings must be +valid UTF-8 (or ASCII, as it's a subset of UTF-8). All Unicode +codepoints U+0000 through U+10FFFF are allowed, but you must use +length-aware functions if you wish to embed null bytes in strings. + +.. function:: json_t *json_string(const char *value) + + .. refcounting:: new + + Returns a new JSON string, or *NULL* on error. *value* must be a + valid null terminated UTF-8 encoded Unicode string. + +.. function:: json_t *json_stringn(const char *value, size_t len) + + .. refcounting:: new + + Like :func:`json_string`, but with explicit length, so *value* may + contain null characters or not be null terminated. + + .. versionadded:: 2.7 + +.. function:: json_t *json_string_nocheck(const char *value) + + .. refcounting:: new + + Like :func:`json_string`, but doesn't check that *value* is valid + UTF-8. Use this function only if you are certain that this really + is the case (e.g. you have already checked it by other means). + +.. function:: json_t *json_stringn_nocheck(const char *value, size_t len) + + .. refcounting:: new + + Like :func:`json_string_nocheck`, but with explicit length, so + *value* may contain null characters or not be null terminated. + + .. versionadded:: 2.7 + +.. function:: const char *json_string_value(const json_t *string) + + Returns the associated value of *string* as a null terminated UTF-8 + encoded string, or *NULL* if *string* is not a JSON string. + + The returned value is read-only and must not be modified or freed by + the user. It is valid as long as *string* exists, i.e. as long as + its reference count has not dropped to zero. + +.. function:: size_t json_string_length(const json_t *string) + + Returns the length of *string* in its UTF-8 presentation, or zero + if *string* is not a JSON string. + + .. versionadded:: 2.7 + +.. function:: int json_string_set(json_t *string, const char *value) + + Sets the associated value of *string* to *value*. *value* must be a + valid UTF-8 encoded Unicode string. Returns 0 on success and -1 on + error. + +.. function:: int json_string_setn(json_t *string, const char *value, size_t len) + + Like :func:`json_string_set`, but with explicit length, so *value* + may contain null characters or not be null terminated. + + .. versionadded:: 2.7 + +.. function:: int json_string_set_nocheck(json_t *string, const char *value) + + Like :func:`json_string_set`, but doesn't check that *value* is + valid UTF-8. Use this function only if you are certain that this + really is the case (e.g. you have already checked it by other + means). + +.. function:: int json_string_setn_nocheck(json_t *string, const char *value, size_t len) + + Like :func:`json_string_set_nocheck`, but with explicit length, + so *value* may contain null characters or not be null terminated. + + .. versionadded:: 2.7 + +.. function:: json_t *json_sprintf(const char *format, ...) + json_t *json_vsprintf(const char *format, va_list ap) + + .. refcounting:: new + + Construct a JSON string from a format string and varargs, just like + :func:`printf()`. + + .. versionadded:: 2.11 + + +Number +====== + +The JSON specification only contains one numeric type, "number". The C +programming language has distinct types for integer and floating-point +numbers, so for practical reasons Jansson also has distinct types for +the two. They are called "integer" and "real", respectively. For more +information, see :ref:`rfc-conformance`. + +.. type:: json_int_t + + This is the C type that is used to store JSON integer values. It + represents the widest integer type available on your system. In + practice it's just a typedef of ``long long`` if your compiler + supports it, otherwise ``long``. + + Usually, you can safely use plain ``int`` in place of + ``json_int_t``, and the implicit C integer conversion handles the + rest. Only when you know that you need the full 64-bit range, you + should use ``json_int_t`` explicitly. + +``JSON_INTEGER_IS_LONG_LONG`` + This is a preprocessor variable that holds the value 1 if + :type:`json_int_t` is ``long long``, and 0 if it's ``long``. It + can be used as follows:: + + #if JSON_INTEGER_IS_LONG_LONG + /* Code specific for long long */ + #else + /* Code specific for long */ + #endif + +``JSON_INTEGER_FORMAT`` + This is a macro that expands to a :func:`printf()` conversion + specifier that corresponds to :type:`json_int_t`, without the + leading ``%`` sign, i.e. either ``"lld"`` or ``"ld"``. This macro + is required because the actual type of :type:`json_int_t` can be + either ``long`` or ``long long``, and :func:`printf()` requires + different length modifiers for the two. + + Example:: + + json_int_t x = 123123123; + printf("x is %" JSON_INTEGER_FORMAT "\n", x); + + +.. function:: json_t *json_integer(json_int_t value) + + .. refcounting:: new + + Returns a new JSON integer, or *NULL* on error. + +.. function:: json_int_t json_integer_value(const json_t *integer) + + Returns the associated value of *integer*, or 0 if *json* is not a + JSON integer. + +.. function:: int json_integer_set(const json_t *integer, json_int_t value) + + Sets the associated value of *integer* to *value*. Returns 0 on + success and -1 if *integer* is not a JSON integer. + +.. function:: json_t *json_real(double value) + + .. refcounting:: new + + Returns a new JSON real, or *NULL* on error. + +.. function:: double json_real_value(const json_t *real) + + Returns the associated value of *real*, or 0.0 if *real* is not a + JSON real. + +.. function:: int json_real_set(const json_t *real, double value) + + Sets the associated value of *real* to *value*. Returns 0 on + success and -1 if *real* is not a JSON real. + +.. function:: double json_number_value(const json_t *json) + + Returns the associated value of the JSON integer or JSON real + *json*, cast to double regardless of the actual type. If *json* is + neither JSON real nor JSON integer, 0.0 is returned. + + +Array +===== + +A JSON array is an ordered collection of other JSON values. + +.. function:: json_t *json_array(void) + + .. refcounting:: new + + Returns a new JSON array, or *NULL* on error. Initially, the array + is empty. + +.. function:: size_t json_array_size(const json_t *array) + + Returns the number of elements in *array*, or 0 if *array* is NULL + or not a JSON array. + +.. function:: json_t *json_array_get(const json_t *array, size_t index) + + .. refcounting:: borrow + + Returns the element in *array* at position *index*. The valid range + for *index* is from 0 to the return value of + :func:`json_array_size()` minus 1. If *array* is not a JSON array, + if *array* is *NULL*, or if *index* is out of range, *NULL* is + returned. + +.. function:: int json_array_set(json_t *array, size_t index, json_t *value) + + Replaces the element in *array* at position *index* with *value*. + The valid range for *index* is from 0 to the return value of + :func:`json_array_size()` minus 1. Returns 0 on success and -1 on + error. + +.. function:: int json_array_set_new(json_t *array, size_t index, json_t *value) + + Like :func:`json_array_set()` but steals the reference to *value*. + This is useful when *value* is newly created and not used after + the call. + +.. function:: int json_array_append(json_t *array, json_t *value) + + Appends *value* to the end of *array*, growing the size of *array* + by 1. Returns 0 on success and -1 on error. + +.. function:: int json_array_append_new(json_t *array, json_t *value) + + Like :func:`json_array_append()` but steals the reference to + *value*. This is useful when *value* is newly created and not used + after the call. + +.. function:: int json_array_insert(json_t *array, size_t index, json_t *value) + + Inserts *value* to *array* at position *index*, shifting the + elements at *index* and after it one position towards the end of + the array. Returns 0 on success and -1 on error. + +.. function:: int json_array_insert_new(json_t *array, size_t index, json_t *value) + + Like :func:`json_array_insert()` but steals the reference to + *value*. This is useful when *value* is newly created and not used + after the call. + +.. function:: int json_array_remove(json_t *array, size_t index) + + Removes the element in *array* at position *index*, shifting the + elements after *index* one position towards the start of the array. + Returns 0 on success and -1 on error. The reference count of the + removed value is decremented. + +.. function:: int json_array_clear(json_t *array) + + Removes all elements from *array*. Returns 0 on success and -1 on + error. The reference count of all removed values are decremented. + +.. function:: int json_array_extend(json_t *array, json_t *other_array) + + Appends all elements in *other_array* to the end of *array*. + Returns 0 on success and -1 on error. + +.. function:: json_array_foreach(array, index, value) + + Iterate over every element of ``array``, running the block + of code that follows each time with the proper values set to + variables ``index`` and ``value``, of types :type:`size_t` and + :type:`json_t *` respectively. Example:: + + /* array is a JSON array */ + size_t index; + json_t *value; + + json_array_foreach(array, index, value) { + /* block of code that uses index and value */ + } + + The items are returned in increasing index order. + + This macro expands to an ordinary ``for`` statement upon + preprocessing, so its performance is equivalent to that of + hand-written code using the array access functions. + The main advantage of this macro is that it abstracts + away the complexity, and makes for more concise and readable code. + + .. versionadded:: 2.5 + + +Object +====== + +A JSON object is a dictionary of key-value pairs, where the key is a +Unicode string and the value is any JSON value. + +Even though null bytes are allowed in string values, they are not +allowed in object keys. + +.. function:: json_t *json_object(void) + + .. refcounting:: new + + Returns a new JSON object, or *NULL* on error. Initially, the + object is empty. + +.. function:: size_t json_object_size(const json_t *object) + + Returns the number of elements in *object*, or 0 if *object* is not + a JSON object. + +.. function:: json_t *json_object_get(const json_t *object, const char *key) + + .. refcounting:: borrow + + Get a value corresponding to *key* from *object*. Returns *NULL* if + *key* is not found and on error. + +.. function:: int json_object_set(json_t *object, const char *key, json_t *value) + + Set the value of *key* to *value* in *object*. *key* must be a + valid null terminated UTF-8 encoded Unicode string. If there + already is a value for *key*, it is replaced by the new value. + Returns 0 on success and -1 on error. + +.. function:: int json_object_set_nocheck(json_t *object, const char *key, json_t *value) + + Like :func:`json_object_set`, but doesn't check that *key* is + valid UTF-8. Use this function only if you are certain that this + really is the case (e.g. you have already checked it by other + means). + +.. function:: int json_object_set_new(json_t *object, const char *key, json_t *value) + + Like :func:`json_object_set()` but steals the reference to + *value*. This is useful when *value* is newly created and not used + after the call. + +.. function:: int json_object_set_new_nocheck(json_t *object, const char *key, json_t *value) + + Like :func:`json_object_set_new`, but doesn't check that *key* is + valid UTF-8. Use this function only if you are certain that this + really is the case (e.g. you have already checked it by other + means). + +.. function:: int json_object_del(json_t *object, const char *key) + + Delete *key* from *object* if it exists. Returns 0 on success, or + -1 if *key* was not found. The reference count of the removed value + is decremented. + +.. function:: int json_object_clear(json_t *object) + + Remove all elements from *object*. Returns 0 on success and -1 if + *object* is not a JSON object. The reference count of all removed + values are decremented. + +.. function:: int json_object_update(json_t *object, json_t *other) + + Update *object* with the key-value pairs from *other*, overwriting + existing keys. Returns 0 on success or -1 on error. + +.. function:: int json_object_update_existing(json_t *object, json_t *other) + + Like :func:`json_object_update()`, but only the values of existing + keys are updated. No new keys are created. Returns 0 on success or + -1 on error. + + .. versionadded:: 2.3 + +.. function:: int json_object_update_missing(json_t *object, json_t *other) + + Like :func:`json_object_update()`, but only new keys are created. + The value of any existing key is not changed. Returns 0 on success + or -1 on error. + + .. versionadded:: 2.3 + +.. function:: json_object_foreach(object, key, value) + + Iterate over every key-value pair of ``object``, running the block + of code that follows each time with the proper values set to + variables ``key`` and ``value``, of types :type:`const char *` and + :type:`json_t *` respectively. Example:: + + /* obj is a JSON object */ + const char *key; + json_t *value; + + json_object_foreach(obj, key, value) { + /* block of code that uses key and value */ + } + + The items are returned in the order they were inserted to the + object. + + **Note:** It's not safe to call ``json_object_del(object, key)`` + during iteration. If you need to, use + :func:`json_object_foreach_safe` instead. + + This macro expands to an ordinary ``for`` statement upon + preprocessing, so its performance is equivalent to that of + hand-written iteration code using the object iteration protocol + (see below). The main advantage of this macro is that it abstracts + away the complexity behind iteration, and makes for more concise and + readable code. + + .. versionadded:: 2.3 + + +.. function:: json_object_foreach_safe(object, tmp, key, value) + + Like :func:`json_object_foreach()`, but it's safe to call + ``json_object_del(object, key)`` during iteration. You need to pass + an extra ``void *`` parameter ``tmp`` that is used for temporary storage. + + .. versionadded:: 2.8 + + +The following functions can be used to iterate through all key-value +pairs in an object. The items are returned in the order they were +inserted to the object. + +.. function:: void *json_object_iter(json_t *object) + + Returns an opaque iterator which can be used to iterate over all + key-value pairs in *object*, or *NULL* if *object* is empty. + +.. function:: void *json_object_iter_at(json_t *object, const char *key) + + Like :func:`json_object_iter()`, but returns an iterator to the + key-value pair in *object* whose key is equal to *key*, or NULL if + *key* is not found in *object*. Iterating forward to the end of + *object* only yields all key-value pairs of the object if *key* + happens to be the first key in the underlying hash table. + +.. function:: void *json_object_iter_next(json_t *object, void *iter) + + Returns an iterator pointing to the next key-value pair in *object* + after *iter*, or *NULL* if the whole object has been iterated + through. + +.. function:: const char *json_object_iter_key(void *iter) + + Extract the associated key from *iter*. + +.. function:: json_t *json_object_iter_value(void *iter) + + .. refcounting:: borrow + + Extract the associated value from *iter*. + +.. function:: int json_object_iter_set(json_t *object, void *iter, json_t *value) + + Set the value of the key-value pair in *object*, that is pointed to + by *iter*, to *value*. + +.. function:: int json_object_iter_set_new(json_t *object, void *iter, json_t *value) + + Like :func:`json_object_iter_set()`, but steals the reference to + *value*. This is useful when *value* is newly created and not used + after the call. + +.. function:: void *json_object_key_to_iter(const char *key) + + Like :func:`json_object_iter_at()`, but much faster. Only works for + values returned by :func:`json_object_iter_key()`. Using other keys + will lead to segfaults. This function is used internally to + implement :func:`json_object_foreach`. Example:: + + /* obj is a JSON object */ + const char *key; + json_t *value; + + void *iter = json_object_iter(obj); + while(iter) + { + key = json_object_iter_key(iter); + value = json_object_iter_value(iter); + /* use key and value ... */ + iter = json_object_iter_next(obj, iter); + } + + .. versionadded:: 2.3 + +.. function:: void json_object_seed(size_t seed) + + Seed the hash function used in Jansson's hashtable implementation. + The seed is used to randomize the hash function so that an + attacker cannot control its output. + + If *seed* is 0, Jansson generates the seed itself by reading + random data from the operating system's entropy sources. If no + entropy sources are available, falls back to using a combination + of the current timestamp (with microsecond precision if possible) + and the process ID. + + If called at all, this function must be called before any calls to + :func:`json_object()`, either explicit or implicit. If this + function is not called by the user, the first call to + :func:`json_object()` (either explicit or implicit) seeds the hash + function. See :ref:`portability-thread-safety` for notes on thread + safety. + + If repeatable results are required, for e.g. unit tests, the hash + function can be "unrandomized" by calling :func:`json_object_seed` + with a constant value on program startup, e.g. + ``json_object_seed(1)``. + + .. versionadded:: 2.6 + + +Error reporting +=============== + +Jansson uses a single struct type to pass error information to the +user. See sections :ref:`apiref-decoding`, :ref:`apiref-pack` and +:ref:`apiref-unpack` for functions that pass error information using +this struct. + +.. type:: json_error_t + + .. member:: char text[] + + The error message (in UTF-8), or an empty string if a message is + not available. + + The last byte of this array contains a numeric error code. Use + :func:`json_error_code()` to extract this code. + + .. member:: char source[] + + Source of the error. This can be (a part of) the file name or a + special identifier in angle brackets (e.g. ````). + + .. member:: int line + + The line number on which the error occurred. + + .. member:: int column + + The column on which the error occurred. Note that this is the + *character column*, not the byte column, i.e. a multibyte UTF-8 + character counts as one column. + + .. member:: int position + + The position in bytes from the start of the input. This is + useful for debugging Unicode encoding problems. + +The normal use of :type:`json_error_t` is to allocate it on the stack, +and pass a pointer to a function. Example:: + + int main() { + json_t *json; + json_error_t error; + + json = json_load_file("/path/to/file.json", 0, &error); + if(!json) { + /* the error variable contains error information */ + } + ... + } + +Also note that if the call succeeded (``json != NULL`` in the above +example), the contents of ``error`` are generally left unspecified. +The decoding functions write to the ``position`` member also on +success. See :ref:`apiref-decoding` for more info. + +All functions also accept *NULL* as the :type:`json_error_t` pointer, +in which case no error information is returned to the caller. + +.. type:: enum json_error_code + + An enumeration containing numeric error codes. The following errors are + currently defined: + + ``json_error_unknown`` + + Unknown error. This should only be returned for non-errorneous + :type:`json_error_t` structures. + + ``json_error_out_of_memory`` + + The library couldn’t allocate any heap memory. + + ``json_error_stack_overflow`` + + Nesting too deep. + + ``json_error_cannot_open_file`` + + Couldn’t open input file. + + ``json_error_invalid_argument`` + + A function argument was invalid. + + ``json_error_invalid_utf8`` + + The input string isn’t valid UTF-8. + + ``json_error_premature_end_of_input`` + + The input ended in the middle of a JSON value. + + ``json_error_end_of_input_expected`` + + There was some text after the end of a JSON value. See the + ``JSON_DISABLE_EOF_CHECK`` flag. + + ``json_error_invalid_syntax`` + + JSON syntax error. + + ``json_error_invalid_format`` + + Invalid format string for packing or unpacking. + + ``json_error_wrong_type`` + + When packing or unpacking, the actual type of a value differed from the + one specified in the format string. + + ``json_error_null_character`` + + A null character was detected in a JSON string. See the + ``JSON_ALLOW_NUL`` flag. + + ``json_error_null_value`` + + When packing or unpacking, some key or value was ``NULL``. + + ``json_error_null_byte_in_key`` + + An object key would contain a null byte. Jansson can’t represent such + keys; see :ref:`rfc-conformance`. + + ``json_error_duplicate_key`` + + Duplicate key in object. See the ``JSON_REJECT_DUPLICATES`` flag. + + ``json_error_numeric_overflow`` + + When converting a JSON number to a C numeric type, a numeric overflow + was detected. + + ``json_error_item_not_found`` + + Key in object not found. + + ``json_error_index_out_of_range`` + + Array index is out of range. + + .. versionadded:: 2.11 + +.. function:: enum json_error_code json_error_code(const json_error_t *error) + + Returns the error code embedded in ``error->text``. + + .. versionadded:: 2.11 + + +Encoding +======== + +This sections describes the functions that can be used to encode +values to JSON. By default, only objects and arrays can be encoded +directly, since they are the only valid *root* values of a JSON text. +To encode any JSON value, use the ``JSON_ENCODE_ANY`` flag (see +below). + +By default, the output has no newlines, and spaces are used between +array and object elements for a readable output. This behavior can be +altered by using the ``JSON_INDENT`` and ``JSON_COMPACT`` flags +described below. A newline is never appended to the end of the encoded +JSON data. + +Each function takes a *flags* parameter that controls some aspects of +how the data is encoded. Its default value is 0. The following macros +can be ORed together to obtain *flags*. + +``JSON_INDENT(n)`` + Pretty-print the result, using newlines between array and object + items, and indenting with *n* spaces. The valid range for *n* is + between 0 and 31 (inclusive), other values result in an undefined + output. If ``JSON_INDENT`` is not used or *n* is 0, no newlines are + inserted between array and object items. + + The ``JSON_MAX_INDENT`` constant defines the maximum indentation + that can be used, and its value is 31. + + .. versionchanged:: 2.7 + Added ``JSON_MAX_INDENT``. + +``JSON_COMPACT`` + This flag enables a compact representation, i.e. sets the separator + between array and object items to ``","`` and between object keys + and values to ``":"``. Without this flag, the corresponding + separators are ``", "`` and ``": "`` for more readable output. + +``JSON_ENSURE_ASCII`` + If this flag is used, the output is guaranteed to consist only of + ASCII characters. This is achieved by escaping all Unicode + characters outside the ASCII range. + +``JSON_SORT_KEYS`` + If this flag is used, all the objects in output are sorted by key. + This is useful e.g. if two JSON texts are diffed or visually + compared. + +``JSON_PRESERVE_ORDER`` + **Deprecated since version 2.8:** Order of object keys + is always preserved. + + Prior to version 2.8: If this flag is used, object keys in the + output are sorted into the same order in which they were first + inserted to the object. For example, decoding a JSON text and then + encoding with this flag preserves the order of object keys. + +``JSON_ENCODE_ANY`` + Specifying this flag makes it possible to encode any JSON value on + its own. Without it, only objects and arrays can be passed as the + *json* value to the encoding functions. + + **Note:** Encoding any value may be useful in some scenarios, but + it's generally discouraged as it violates strict compatibility with + :rfc:`4627`. If you use this flag, don't expect interoperability + with other JSON systems. + + .. versionadded:: 2.1 + +``JSON_ESCAPE_SLASH`` + Escape the ``/`` characters in strings with ``\/``. + + .. versionadded:: 2.4 + +``JSON_REAL_PRECISION(n)`` + Output all real numbers with at most *n* digits of precision. The + valid range for *n* is between 0 and 31 (inclusive), and other + values result in an undefined behavior. + + By default, the precision is 17, to correctly and losslessly encode + all IEEE 754 double precision floating point numbers. + + .. versionadded:: 2.7 + +``JSON_EMBED`` + If this flag is used, the opening and closing characters of the top-level + array ('[', ']') or object ('{', '}') are omitted during encoding. This + flag is useful when concatenating multiple arrays or objects into a stream. + + .. versionadded:: 2.10 + +These functions output UTF-8: + +.. function:: char *json_dumps(const json_t *json, size_t flags) + + Returns the JSON representation of *json* as a string, or *NULL* on + error. *flags* is described above. The return value must be freed + by the caller using :func:`free()`. + +.. function:: size_t json_dumpb(const json_t *json, char *buffer, size_t size, size_t flags) + + Writes the JSON representation of *json* to the *buffer* of + *size* bytes. Returns the number of bytes that would be written + or 0 on error. *flags* is described above. *buffer* is not + null-terminated. + + This function never writes more than *size* bytes. If the return + value is greater than *size*, the contents of the *buffer* are + undefined. This behavior enables you to specify a NULL *buffer* + to determine the length of the encoding. For example:: + + size_t size = json_dumpb(json, NULL, 0, 0); + if (size == 0) + return -1; + + char *buf = alloca(size); + + size = json_dumpb(json, buf, size, 0); + + .. versionadded:: 2.10 + +.. function:: int json_dumpf(const json_t *json, FILE *output, size_t flags) + + Write the JSON representation of *json* to the stream *output*. + *flags* is described above. Returns 0 on success and -1 on error. + If an error occurs, something may have already been written to + *output*. In this case, the output is undefined and most likely not + valid JSON. + +.. function:: int json_dumpfd(const json_t *json, int output, size_t flags) + + Write the JSON representation of *json* to the stream *output*. + *flags* is described above. Returns 0 on success and -1 on error. + If an error occurs, something may have already been written to + *output*. In this case, the output is undefined and most likely not + valid JSON. + + It is important to note that this function can only succeed on stream + file descriptors (such as SOCK_STREAM). Using this function on a + non-stream file descriptor will result in undefined behavior. For + non-stream file descriptors, see instead :func:`json_dumpb()`. + + This function requires POSIX and fails on all non-POSIX systems. + + .. versionadded:: 2.10 + +.. function:: int json_dump_file(const json_t *json, const char *path, size_t flags) + + Write the JSON representation of *json* to the file *path*. If + *path* already exists, it is overwritten. *flags* is described + above. Returns 0 on success and -1 on error. + +.. type:: json_dump_callback_t + + A typedef for a function that's called by + :func:`json_dump_callback()`:: + + typedef int (*json_dump_callback_t)(const char *buffer, size_t size, void *data); + + *buffer* points to a buffer containing a chunk of output, *size* is + the length of the buffer, and *data* is the corresponding + :func:`json_dump_callback()` argument passed through. + + *buffer* is guaranteed to be a valid UTF-8 string (i.e. multi-byte + code unit sequences are preserved). *buffer* never contains + embedded null bytes. + + On error, the function should return -1 to stop the encoding + process. On success, it should return 0. + + .. versionadded:: 2.2 + +.. function:: int json_dump_callback(const json_t *json, json_dump_callback_t callback, void *data, size_t flags) + + Call *callback* repeatedly, passing a chunk of the JSON + representation of *json* each time. *flags* is described above. + Returns 0 on success and -1 on error. + + .. versionadded:: 2.2 + + +.. _apiref-decoding: + +Decoding +======== + +This sections describes the functions that can be used to decode JSON +text to the Jansson representation of JSON data. The JSON +specification requires that a JSON text is either a serialized array +or object, and this requirement is also enforced with the following +functions. In other words, the top level value in the JSON text being +decoded must be either array or object. To decode any JSON value, use +the ``JSON_DECODE_ANY`` flag (see below). + +See :ref:`rfc-conformance` for a discussion on Jansson's conformance +to the JSON specification. It explains many design decisions that +affect especially the behavior of the decoder. + +Each function takes a *flags* parameter that can be used to control +the behavior of the decoder. Its default value is 0. The following +macros can be ORed together to obtain *flags*. + +``JSON_REJECT_DUPLICATES`` + Issue a decoding error if any JSON object in the input text + contains duplicate keys. Without this flag, the value of the last + occurrence of each key ends up in the result. Key equivalence is + checked byte-by-byte, without special Unicode comparison + algorithms. + + .. versionadded:: 2.1 + +``JSON_DECODE_ANY`` + By default, the decoder expects an array or object as the input. + With this flag enabled, the decoder accepts any valid JSON value. + + **Note:** Decoding any value may be useful in some scenarios, but + it's generally discouraged as it violates strict compatibility with + :rfc:`4627`. If you use this flag, don't expect interoperability + with other JSON systems. + + .. versionadded:: 2.3 + +``JSON_DISABLE_EOF_CHECK`` + By default, the decoder expects that its whole input constitutes a + valid JSON text, and issues an error if there's extra data after + the otherwise valid JSON input. With this flag enabled, the decoder + stops after decoding a valid JSON array or object, and thus allows + extra data after the JSON text. + + Normally, reading will stop when the last ``]`` or ``}`` in the + JSON input is encountered. If both ``JSON_DISABLE_EOF_CHECK`` and + ``JSON_DECODE_ANY`` flags are used, the decoder may read one extra + UTF-8 code unit (up to 4 bytes of input). For example, decoding + ``4true`` correctly decodes the integer 4, but also reads the + ``t``. For this reason, if reading multiple consecutive values that + are not arrays or objects, they should be separated by at least one + whitespace character. + + .. versionadded:: 2.1 + +``JSON_DECODE_INT_AS_REAL`` + JSON defines only one number type. Jansson distinguishes between + ints and reals. For more information see :ref:`real-vs-integer`. + With this flag enabled the decoder interprets all numbers as real + values. Integers that do not have an exact double representation + will silently result in a loss of precision. Integers that cause + a double overflow will cause an error. + + .. versionadded:: 2.5 + +``JSON_ALLOW_NUL`` + Allow ``\u0000`` escape inside string values. This is a safety + measure; If you know your input can contain null bytes, use this + flag. If you don't use this flag, you don't have to worry about null + bytes inside strings unless you explicitly create themselves by + using e.g. :func:`json_stringn()` or ``s#`` format specifier for + :func:`json_pack()`. + + Object keys cannot have embedded null bytes even if this flag is + used. + + .. versionadded:: 2.6 + +Each function also takes an optional :type:`json_error_t` parameter +that is filled with error information if decoding fails. It's also +updated on success; the number of bytes of input read is written to +its ``position`` field. This is especially useful when using +``JSON_DISABLE_EOF_CHECK`` to read multiple consecutive JSON texts. + +.. versionadded:: 2.3 + Number of bytes of input read is written to the ``position`` field + of the :type:`json_error_t` structure. + +If no error or position information is needed, you can pass *NULL*. + +.. function:: json_t *json_loads(const char *input, size_t flags, json_error_t *error) + + .. refcounting:: new + + Decodes the JSON string *input* and returns the array or object it + contains, or *NULL* on error, in which case *error* is filled with + information about the error. *flags* is described above. + +.. function:: json_t *json_loadb(const char *buffer, size_t buflen, size_t flags, json_error_t *error) + + .. refcounting:: new + + Decodes the JSON string *buffer*, whose length is *buflen*, and + returns the array or object it contains, or *NULL* on error, in + which case *error* is filled with information about the error. This + is similar to :func:`json_loads()` except that the string doesn't + need to be null-terminated. *flags* is described above. + + .. versionadded:: 2.1 + +.. function:: json_t *json_loadf(FILE *input, size_t flags, json_error_t *error) + + .. refcounting:: new + + Decodes the JSON text in stream *input* and returns the array or + object it contains, or *NULL* on error, in which case *error* is + filled with information about the error. *flags* is described + above. + + This function will start reading the input from whatever position + the input file was in, without attempting to seek first. If an error + occurs, the file position will be left indeterminate. On success, + the file position will be at EOF, unless ``JSON_DISABLE_EOF_CHECK`` + flag was used. In this case, the file position will be at the first + character after the last ``]`` or ``}`` in the JSON input. This + allows calling :func:`json_loadf()` on the same ``FILE`` object + multiple times, if the input consists of consecutive JSON texts, + possibly separated by whitespace. + +.. function:: json_t *json_loadfd(int input, size_t flags, json_error_t *error) + + .. refcounting:: new + + Decodes the JSON text in stream *input* and returns the array or + object it contains, or *NULL* on error, in which case *error* is + filled with information about the error. *flags* is described + above. + + This function will start reading the input from whatever position + the input file descriptor was in, without attempting to seek first. + If an error occurs, the file position will be left indeterminate. + On success, the file position will be at EOF, unless + ``JSON_DISABLE_EOF_CHECK`` flag was used. In this case, the file + descriptor's position will be at the first character after the last + ``]`` or ``}`` in the JSON input. This allows calling + :func:`json_loadfd()` on the same file descriptor multiple times, + if the input consists of consecutive JSON texts, possibly separated + by whitespace. + + It is important to note that this function can only succeed on stream + file descriptors (such as SOCK_STREAM). Using this function on a + non-stream file descriptor will result in undefined behavior. For + non-stream file descriptors, see instead :func:`json_loadb()`. + + This function requires POSIX and fails on all non-POSIX systems. + + .. versionadded:: 2.10 + +.. function:: json_t *json_load_file(const char *path, size_t flags, json_error_t *error) + + .. refcounting:: new + + Decodes the JSON text in file *path* and returns the array or + object it contains, or *NULL* on error, in which case *error* is + filled with information about the error. *flags* is described + above. + +.. type:: json_load_callback_t + + A typedef for a function that's called by + :func:`json_load_callback()` to read a chunk of input data:: + + typedef size_t (*json_load_callback_t)(void *buffer, size_t buflen, void *data); + + *buffer* points to a buffer of *buflen* bytes, and *data* is the + corresponding :func:`json_load_callback()` argument passed through. + + On success, the function should write at most *buflen* bytes to + *buffer*, and return the number of bytes written; a returned value + of 0 indicates that no data was produced and that the end of file + has been reached. On error, the function should return + ``(size_t)-1`` to abort the decoding process. + + In UTF-8, some code points are encoded as multi-byte sequences. The + callback function doesn't need to worry about this, as Jansson + handles it at a higher level. For example, you can safely read a + fixed number of bytes from a network connection without having to + care about code unit sequences broken apart by the chunk + boundaries. + + .. versionadded:: 2.4 + +.. function:: json_t *json_load_callback(json_load_callback_t callback, void *data, size_t flags, json_error_t *error) + + .. refcounting:: new + + Decodes the JSON text produced by repeated calls to *callback*, and + returns the array or object it contains, or *NULL* on error, in + which case *error* is filled with information about the error. + *data* is passed through to *callback* on each call. *flags* is + described above. + + .. versionadded:: 2.4 + + +.. _apiref-pack: + +Building Values +=============== + +This section describes functions that help to create, or *pack*, +complex JSON values, especially nested objects and arrays. Value +building is based on a *format string* that is used to tell the +functions about the expected arguments. + +For example, the format string ``"i"`` specifies a single integer +value, while the format string ``"[ssb]"`` or the equivalent ``"[s, s, +b]"`` specifies an array value with two strings and a boolean as its +items:: + + /* Create the JSON integer 42 */ + json_pack("i", 42); + + /* Create the JSON array ["foo", "bar", true] */ + json_pack("[ssb]", "foo", "bar", 1); + +Here's the full list of format specifiers. The type in parentheses +denotes the resulting JSON type, and the type in brackets (if any) +denotes the C type that is expected as the corresponding argument or +arguments. + +``s`` (string) [const char \*] + Convert a null terminated UTF-8 string to a JSON string. + +``s?`` (string) [const char \*] + Like ``s``, but if the argument is *NULL*, output a JSON null + value. + + .. versionadded:: 2.8 + +``s*`` (string) [const char \*] + Like ``s``, but if the argument is *NULL*, do not output any value. + This format can only be used inside an object or an array. If used + inside an object, the corresponding key is additionally suppressed + when the value is omitted. See below for an example. + + .. versionadded:: 2.11 + +``s#`` (string) [const char \*, int] + Convert a UTF-8 buffer of a given length to a JSON string. + + .. versionadded:: 2.5 + +``s%`` (string) [const char \*, size_t] + Like ``s#`` but the length argument is of type :type:`size_t`. + + .. versionadded:: 2.6 + +``+`` [const char \*] + Like ``s``, but concatenate to the previous string. Only valid + after ``s``, ``s#``, ``+`` or ``+#``. + + .. versionadded:: 2.5 + +``+#`` [const char \*, int] + Like ``s#``, but concatenate to the previous string. Only valid + after ``s``, ``s#``, ``+`` or ``+#``. + + .. versionadded:: 2.5 + +``+%`` (string) [const char \*, size_t] + Like ``+#`` but the length argument is of type :type:`size_t`. + + .. versionadded:: 2.6 + +``n`` (null) + Output a JSON null value. No argument is consumed. + +``b`` (boolean) [int] + Convert a C :type:`int` to JSON boolean value. Zero is converted + to ``false`` and non-zero to ``true``. + +``i`` (integer) [int] + Convert a C :type:`int` to JSON integer. + +``I`` (integer) [json_int_t] + Convert a C :type:`json_int_t` to JSON integer. + +``f`` (real) [double] + Convert a C :type:`double` to JSON real. + +``o`` (any value) [json_t \*] + Output any given JSON value as-is. If the value is added to an + array or object, the reference to the value passed to ``o`` is + stolen by the container. + +``O`` (any value) [json_t \*] + Like ``o``, but the argument's reference count is incremented. + This is useful if you pack into an array or object and want to + keep the reference for the JSON value consumed by ``O`` to + yourself. + +``o?``, ``O?`` (any value) [json_t \*] + Like ``o`` and ``O``, respectively, but if the argument is + *NULL*, output a JSON null value. + + .. versionadded:: 2.8 + +``o*``, ``O*`` (any value) [json_t \*] + Like ``o`` and ``O``, respectively, but if the argument is + *NULL*, do not output any value. This format can only be used + inside an object or an array. If used inside an object, the + corresponding key is additionally suppressed. See below for an + example. + + .. versionadded:: 2.11 + +``[fmt]`` (array) + Build an array with contents from the inner format string. ``fmt`` + may contain objects and arrays, i.e. recursive value building is + supported. + +``{fmt}`` (object) + Build an object with contents from the inner format string + ``fmt``. The first, third, etc. format specifier represent a key, + and must be a string (see ``s``, ``s#``, ``+`` and ``+#`` above), + as object keys are always strings. The second, fourth, etc. format + specifier represent a value. Any value may be an object or array, + i.e. recursive value building is supported. + +Whitespace, ``:`` and ``,`` are ignored. + +.. function:: json_t *json_pack(const char *fmt, ...) + + .. refcounting:: new + + Build a new JSON value according to the format string *fmt*. For + each format specifier (except for ``{}[]n``), one or more arguments + are consumed and used to build the corresponding value. Returns + *NULL* on error. + +.. function:: json_t *json_pack_ex(json_error_t *error, size_t flags, const char *fmt, ...) + json_t *json_vpack_ex(json_error_t *error, size_t flags, const char *fmt, va_list ap) + + .. refcounting:: new + + Like :func:`json_pack()`, but an in the case of an error, an error + message is written to *error*, if it's not *NULL*. The *flags* + parameter is currently unused and should be set to 0. + + As only the errors in format string (and out-of-memory errors) can + be caught by the packer, these two functions are most likely only + useful for debugging format strings. + +More examples:: + + /* Build an empty JSON object */ + json_pack("{}"); + + /* Build the JSON object {"foo": 42, "bar": 7} */ + json_pack("{sisi}", "foo", 42, "bar", 7); + + /* Like above, ':', ',' and whitespace are ignored */ + json_pack("{s:i, s:i}", "foo", 42, "bar", 7); + + /* Build the JSON array [[1, 2], {"cool": true}] */ + json_pack("[[i,i],{s:b}]", 1, 2, "cool", 1); + + /* Build a string from a non-null terminated buffer */ + char buffer[4] = {'t', 'e', 's', 't'}; + json_pack("s#", buffer, 4); + + /* Concatenate strings together to build the JSON string "foobarbaz" */ + json_pack("s++", "foo", "bar", "baz"); + + /* Create an empty object or array when optional members are missing */ + json_pack("{s:s*,s:o*,s:O*}", "foo", NULL, "bar", NULL, "baz", NULL); + json_pack("[s*,o*,O*]", NULL, NULL, NULL); + + +.. _apiref-unpack: + +Parsing and Validating Values +============================= + +This section describes functions that help to validate complex values +and extract, or *unpack*, data from them. Like :ref:`building values +`, this is also based on format strings. + +While a JSON value is unpacked, the type specified in the format +string is checked to match that of the JSON value. This is the +validation part of the process. In addition to this, the unpacking +functions can also check that all items of arrays and objects are +unpacked. This check be enabled with the format specifier ``!`` or by +using the flag ``JSON_STRICT``. See below for details. + +Here's the full list of format specifiers. The type in parentheses +denotes the JSON type, and the type in brackets (if any) denotes the C +type whose address should be passed. + +``s`` (string) [const char \*] + Convert a JSON string to a pointer to a null terminated UTF-8 + string. The resulting string is extracted by using + :func:`json_string_value()` internally, so it exists as long as + there are still references to the corresponding JSON string. + +``s%`` (string) [const char \*, size_t \*] + Convert a JSON string to a pointer to a null terminated UTF-8 + string and its length. + + .. versionadded:: 2.6 + +``n`` (null) + Expect a JSON null value. Nothing is extracted. + +``b`` (boolean) [int] + Convert a JSON boolean value to a C :type:`int`, so that ``true`` + is converted to 1 and ``false`` to 0. + +``i`` (integer) [int] + Convert a JSON integer to C :type:`int`. + +``I`` (integer) [json_int_t] + Convert a JSON integer to C :type:`json_int_t`. + +``f`` (real) [double] + Convert a JSON real to C :type:`double`. + +``F`` (integer or real) [double] + Convert a JSON number (integer or real) to C :type:`double`. + +``o`` (any value) [json_t \*] + Store a JSON value with no conversion to a :type:`json_t` pointer. + +``O`` (any value) [json_t \*] + Like ``o``, but the JSON value's reference count is incremented. + Storage pointers should be initialized NULL before using unpack. + The caller is responsible for releasing all references incremented + by unpack, even when an error occurs. + +``[fmt]`` (array) + Convert each item in the JSON array according to the inner format + string. ``fmt`` may contain objects and arrays, i.e. recursive + value extraction is supported. + +``{fmt}`` (object) + Convert each item in the JSON object according to the inner format + string ``fmt``. The first, third, etc. format specifier represent + a key, and must be ``s``. The corresponding argument to unpack + functions is read as the object key. The second fourth, etc. + format specifier represent a value and is written to the address + given as the corresponding argument. **Note** that every other + argument is read from and every other is written to. + + ``fmt`` may contain objects and arrays as values, i.e. recursive + value extraction is supported. + + .. versionadded:: 2.3 + Any ``s`` representing a key may be suffixed with a ``?`` to + make the key optional. If the key is not found, nothing is + extracted. See below for an example. + +``!`` + This special format specifier is used to enable the check that + all object and array items are accessed, on a per-value basis. It + must appear inside an array or object as the last format specifier + before the closing bracket or brace. To enable the check globally, + use the ``JSON_STRICT`` unpacking flag. + +``*`` + This special format specifier is the opposite of ``!``. If the + ``JSON_STRICT`` flag is used, ``*`` can be used to disable the + strict check on a per-value basis. It must appear inside an array + or object as the last format specifier before the closing bracket + or brace. + +Whitespace, ``:`` and ``,`` are ignored. + +.. function:: int json_unpack(json_t *root, const char *fmt, ...) + + Validate and unpack the JSON value *root* according to the format + string *fmt*. Returns 0 on success and -1 on failure. + +.. function:: int json_unpack_ex(json_t *root, json_error_t *error, size_t flags, const char *fmt, ...) + int json_vunpack_ex(json_t *root, json_error_t *error, size_t flags, const char *fmt, va_list ap) + + Validate and unpack the JSON value *root* according to the format + string *fmt*. If an error occurs and *error* is not *NULL*, write + error information to *error*. *flags* can be used to control the + behaviour of the unpacker, see below for the flags. Returns 0 on + success and -1 on failure. + +.. note:: + + The first argument of all unpack functions is ``json_t *root`` + instead of ``const json_t *root``, because the use of ``O`` format + specifier causes the reference count of ``root``, or some value + reachable from ``root``, to be increased. Furthermore, the ``o`` + format specifier may be used to extract a value as-is, which allows + modifying the structure or contents of a value reachable from + ``root``. + + If the ``O`` and ``o`` format specifiers are not used, it's + perfectly safe to cast a ``const json_t *`` variable to plain + ``json_t *`` when used with these functions. + +The following unpacking flags are available: + +``JSON_STRICT`` + Enable the extra validation step checking that all object and + array items are unpacked. This is equivalent to appending the + format specifier ``!`` to the end of every array and object in the + format string. + +``JSON_VALIDATE_ONLY`` + Don't extract any data, just validate the JSON value against the + given format string. Note that object keys must still be specified + after the format string. + +Examples:: + + /* root is the JSON integer 42 */ + int myint; + json_unpack(root, "i", &myint); + assert(myint == 42); + + /* root is the JSON object {"foo": "bar", "quux": true} */ + const char *str; + int boolean; + json_unpack(root, "{s:s, s:b}", "foo", &str, "quux", &boolean); + assert(strcmp(str, "bar") == 0 && boolean == 1); + + /* root is the JSON array [[1, 2], {"baz": null} */ + json_error_t error; + json_unpack_ex(root, &error, JSON_VALIDATE_ONLY, "[[i,i], {s:n}]", "baz"); + /* returns 0 for validation success, nothing is extracted */ + + /* root is the JSON array [1, 2, 3, 4, 5] */ + int myint1, myint2; + json_unpack(root, "[ii!]", &myint1, &myint2); + /* returns -1 for failed validation */ + + /* root is an empty JSON object */ + int myint = 0, myint2 = 0, myint3 = 0; + json_unpack(root, "{s?i, s?[ii]}", + "foo", &myint1, + "bar", &myint2, &myint3); + /* myint1, myint2 or myint3 is no touched as "foo" and "bar" don't exist */ + + +Equality +======== + +Testing for equality of two JSON values cannot, in general, be +achieved using the ``==`` operator. Equality in the terms of the +``==`` operator states that the two :type:`json_t` pointers point to +exactly the same JSON value. However, two JSON values can be equal not +only if they are exactly the same value, but also if they have equal +"contents": + +* Two integer or real values are equal if their contained numeric + values are equal. An integer value is never equal to a real value, + though. + +* Two strings are equal if their contained UTF-8 strings are equal, + byte by byte. Unicode comparison algorithms are not implemented. + +* Two arrays are equal if they have the same number of elements and + each element in the first array is equal to the corresponding + element in the second array. + +* Two objects are equal if they have exactly the same keys and the + value for each key in the first object is equal to the value of the + corresponding key in the second object. + +* Two true, false or null values have no "contents", so they are equal + if their types are equal. (Because these values are singletons, + their equality can actually be tested with ``==``.) + +.. function:: int json_equal(json_t *value1, json_t *value2) + + Returns 1 if *value1* and *value2* are equal, as defined above. + Returns 0 if they are unequal or one or both of the pointers are + *NULL*. + + +Copying +======= + +Because of reference counting, passing JSON values around doesn't +require copying them. But sometimes a fresh copy of a JSON value is +needed. For example, if you need to modify an array, but still want to +use the original afterwards, you should take a copy of it first. + +Jansson supports two kinds of copying: shallow and deep. There is a +difference between these methods only for arrays and objects. Shallow +copying only copies the first level value (array or object) and uses +the same child values in the copied value. Deep copying makes a fresh +copy of the child values, too. Moreover, all the child values are deep +copied in a recursive fashion. + +Copying objects preserves the insertion order of keys. + +.. function:: json_t *json_copy(json_t *value) + + .. refcounting:: new + + Returns a shallow copy of *value*, or *NULL* on error. + +.. function:: json_t *json_deep_copy(const json_t *value) + + .. refcounting:: new + + Returns a deep copy of *value*, or *NULL* on error. + + +.. _apiref-custom-memory-allocation: + +Custom Memory Allocation +======================== + +By default, Jansson uses :func:`malloc()` and :func:`free()` for +memory allocation. These functions can be overridden if custom +behavior is needed. + +.. type:: json_malloc_t + + A typedef for a function pointer with :func:`malloc()`'s + signature:: + + typedef void *(*json_malloc_t)(size_t); + +.. type:: json_free_t + + A typedef for a function pointer with :func:`free()`'s + signature:: + + typedef void (*json_free_t)(void *); + +.. function:: void json_set_alloc_funcs(json_malloc_t malloc_fn, json_free_t free_fn) + + Use *malloc_fn* instead of :func:`malloc()` and *free_fn* instead + of :func:`free()`. This function has to be called before any other + Jansson's API functions to ensure that all memory operations use + the same functions. + +.. function:: void json_get_alloc_funcs(json_malloc_t *malloc_fn, json_free_t *free_fn) + + Fetch the current malloc_fn and free_fn used. Either parameter + may be NULL. + + .. versionadded:: 2.8 + +**Examples:** + +Circumvent problems with different CRT heaps on Windows by using +application's :func:`malloc()` and :func:`free()`:: + + json_set_alloc_funcs(malloc, free); + +Use the `Boehm's conservative garbage collector`_ for memory +operations:: + + json_set_alloc_funcs(GC_malloc, GC_free); + +.. _Boehm's conservative garbage collector: http://www.hboehm.info/gc/ + +Allow storing sensitive data (e.g. passwords or encryption keys) in +JSON structures by zeroing all memory when freed:: + + static void *secure_malloc(size_t size) + { + /* Store the memory area size in the beginning of the block */ + void *ptr = malloc(size + 8); + *((size_t *)ptr) = size; + return ptr + 8; + } + + static void secure_free(void *ptr) + { + size_t size; + + ptr -= 8; + size = *((size_t *)ptr); + + guaranteed_memset(ptr, 0, size + 8); + free(ptr); + } + + int main() + { + json_set_alloc_funcs(secure_malloc, secure_free); + /* ... */ + } + +For more information about the issues of storing sensitive data in +memory, see +http://www.dwheeler.com/secure-programs/Secure-Programs-HOWTO/protect-secrets.html. +The page also explains the :func:`guaranteed_memset()` function used +in the example and gives a sample implementation for it. diff --git a/3party/jansson/doc/changes.rst b/3party/jansson/doc/changes.rst new file mode 100644 index 0000000000..ea56843774 --- /dev/null +++ b/3party/jansson/doc/changes.rst @@ -0,0 +1,5 @@ +****************** +Changes in Jansson +****************** + +.. include:: ../CHANGES diff --git a/3party/jansson/doc/conf.py b/3party/jansson/doc/conf.py new file mode 100644 index 0000000000..6b7f4c33a7 --- /dev/null +++ b/3party/jansson/doc/conf.py @@ -0,0 +1,217 @@ +# -*- coding: utf-8 -*- +# +# Jansson documentation build configuration file, created by +# sphinx-quickstart on Sun Sep 5 21:47:20 2010. +# +# This file is execfile()d with the current directory set to its containing dir. +# +# Note that not all possible configuration values are present in this +# autogenerated file. +# +# All configuration values have a default; values that are commented out +# serve to show the default. + +import sys, os + +# If extensions (or modules to document with autodoc) are in another directory, +# add these directories to sys.path here. If the directory is relative to the +# documentation root, use os.path.abspath to make it absolute, like shown here. +sys.path.insert(0, os.path.abspath('ext')) + +# -- General configuration ----------------------------------------------------- + +# If your documentation needs a minimal Sphinx version, state it here. +needs_sphinx = '1.0' + +# Add any Sphinx extension module names here, as strings. They can be extensions +# coming with Sphinx (named 'sphinx.ext.*') or your custom ones. +extensions = ['refcounting'] + +# Add any paths that contain templates here, relative to this directory. +templates_path = ['_templates'] + +# The suffix of source filenames. +source_suffix = '.rst' + +# The encoding of source files. +#source_encoding = 'utf-8-sig' + +# The master toctree document. +master_doc = 'index' + +# General information about the project. +project = u'Jansson' +copyright = u'2009-2016, Petri Lehtinen' + +# The version info for the project you're documenting, acts as replacement for +# |version| and |release|, also used in various other places throughout the +# built documents. +# +# The short X.Y version. +version = '2.12' +# The full version, including alpha/beta/rc tags. +release = version + +# The language for content autogenerated by Sphinx. Refer to documentation +# for a list of supported languages. +#language = None + +# There are two options for replacing |today|: either, you set today to some +# non-false value, then it is used: +#today = '' +# Else, today_fmt is used as the format for a strftime call. +#today_fmt = '%B %d, %Y' + +# List of patterns, relative to source directory, that match files and +# directories to ignore when looking for source files. +exclude_patterns = ['_build'] + +# The reST default role (used for this markup: `text`) to use for all documents. +default_role = 'c:func' +primary_domain = 'c' + +# If true, '()' will be appended to :func: etc. cross-reference text. +#add_function_parentheses = True + +# If true, the current module name will be prepended to all description +# unit titles (such as .. function::). +#add_module_names = True + +# If true, sectionauthor and moduleauthor directives will be shown in the +# output. They are ignored by default. +#show_authors = False + +# The name of the Pygments (syntax highlighting) style to use. +pygments_style = 'sphinx' + +# A list of ignored prefixes for module index sorting. +#modindex_common_prefix = [] + + +# -- Options for HTML output --------------------------------------------------- + +# The theme to use for HTML and HTML Help pages. See the documentation for +# a list of builtin themes. +#html_theme = 'default' + +# Theme options are theme-specific and customize the look and feel of a theme +# further. For a list of options available for each theme, see the +# documentation. +#html_theme_options = {} + +# Add any paths that contain custom themes here, relative to this directory. +#html_theme_path = [] + +# The name for this set of Sphinx documents. If None, it defaults to +# " v documentation". +#html_title = None + +# A shorter title for the navigation bar. Default is the same as html_title. +#html_short_title = None + +# The name of an image file (relative to this directory) to place at the top +# of the sidebar. +#html_logo = None + +# The name of an image file (within the static path) to use as favicon of the +# docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32 +# pixels large. +#html_favicon = None + +# Add any paths that contain custom static files (such as style sheets) here, +# relative to this directory. They are copied after the builtin static files, +# so a file named "default.css" will overwrite the builtin "default.css". +#html_static_path = ['_static'] + +# If not '', a 'Last updated on:' timestamp is inserted at every page bottom, +# using the given strftime format. +#html_last_updated_fmt = '%b %d, %Y' + +# If true, SmartyPants will be used to convert quotes and dashes to +# typographically correct entities. +#html_use_smartypants = True + +# Custom sidebar templates, maps document names to template names. +#html_sidebars = {} + +# Additional templates that should be rendered to pages, maps page names to +# template names. +#html_additional_pages = {} + +# If false, no module index is generated. +#html_domain_indices = True + +# If false, no index is generated. +#html_use_index = True + +# If true, the index is split into individual pages for each letter. +#html_split_index = False + +# If true, links to the reST sources are added to the pages. +#html_show_sourcelink = True + +# If true, "Created using Sphinx" is shown in the HTML footer. Default is True. +#html_show_sphinx = True + +# If true, "(C) Copyright ..." is shown in the HTML footer. Default is True. +#html_show_copyright = True + +# If true, an OpenSearch description file will be output, and all pages will +# contain a tag referring to it. The value of this option must be the +# base URL from which the finished HTML is served. +#html_use_opensearch = '' + +# This is the file name suffix for HTML files (e.g. ".xhtml"). +#html_file_suffix = None + +# Output file base name for HTML help builder. +htmlhelp_basename = 'Janssondoc' + + +# -- Options for LaTeX output -------------------------------------------------- + +# The paper size ('letter' or 'a4'). +#latex_paper_size = 'letter' + +# The font size ('10pt', '11pt' or '12pt'). +#latex_font_size = '10pt' + +# Grouping the document tree into LaTeX files. List of tuples +# (source start file, target name, title, author, documentclass [howto/manual]). +latex_documents = [ + ('index', 'Jansson.tex', u'Jansson Documentation', + u'Petri Lehtinen', 'manual'), +] + +# The name of an image file (relative to this directory) to place at the top of +# the title page. +#latex_logo = None + +# For "manual" documents, if this is true, then toplevel headings are parts, +# not chapters. +#latex_use_parts = False + +# If true, show page references after internal links. +#latex_show_pagerefs = False + +# If true, show URL addresses after external links. +#latex_show_urls = False + +# Additional stuff for the LaTeX preamble. +#latex_preamble = '' + +# Documents to append as an appendix to all manuals. +#latex_appendices = [] + +# If false, no module index is generated. +#latex_domain_indices = True + + +# -- Options for manual page output -------------------------------------------- + +# One entry per manual page. List of tuples +# (source start file, name, description, authors, manual section). +man_pages = [ + ('index', 'jansson', u'Jansson Documentation', + [u'Petri Lehtinen'], 1) +] diff --git a/3party/jansson/doc/conformance.rst b/3party/jansson/doc/conformance.rst new file mode 100644 index 0000000000..ea41d5cf8a --- /dev/null +++ b/3party/jansson/doc/conformance.rst @@ -0,0 +1,120 @@ +.. _rfc-conformance: + +*************** +RFC Conformance +*************** + +JSON is specified in :rfc:`4627`, *"The application/json Media Type +for JavaScript Object Notation (JSON)"*. + +Character Encoding +================== + +Jansson only supports UTF-8 encoded JSON texts. It does not support or +auto-detect any of the other encodings mentioned in the RFC, namely +UTF-16LE, UTF-16BE, UTF-32LE or UTF-32BE. Pure ASCII is supported, as +it's a subset of UTF-8. + +Strings +======= + +JSON strings are mapped to C-style null-terminated character arrays, +and UTF-8 encoding is used internally. + +All Unicode codepoints U+0000 through U+10FFFF are allowed in string +values. However, U+0000 is not allowed in object keys because of API +restrictions. + +Unicode normalization or any other transformation is never performed +on any strings (string values or object keys). When checking for +equivalence of strings or object keys, the comparison is performed +byte by byte between the original UTF-8 representations of the +strings. + +Numbers +======= + +.. _real-vs-integer: + +Real vs. Integer +---------------- + +JSON makes no distinction between real and integer numbers; Jansson +does. Real numbers are mapped to the ``double`` type and integers to +the ``json_int_t`` type, which is a typedef of ``long long`` or +``long``, depending on whether ``long long`` is supported by your +compiler or not. + +A JSON number is considered to be a real number if its lexical +representation includes one of ``e``, ``E``, or ``.``; regardless if +its actual numeric value is a true integer (e.g., all of ``1E6``, +``3.0``, ``400E-2``, and ``3.14E3`` are mathematical integers, but +will be treated as real values). With the ``JSON_DECODE_INT_AS_REAL`` +decoder flag set all numbers are interpreted as real. + +All other JSON numbers are considered integers. + +When encoding to JSON, real values are always represented +with a fractional part; e.g., the ``double`` value 3.0 will be +represented in JSON as ``3.0``, not ``3``. + +Overflow, Underflow & Precision +------------------------------- + +Real numbers whose absolute values are too small to be represented in +a C ``double`` will be silently estimated with 0.0. Thus, depending on +platform, JSON numbers very close to zero such as 1E-999 may result in +0.0. + +Real numbers whose absolute values are too large to be represented in +a C ``double`` will result in an overflow error (a JSON decoding +error). Thus, depending on platform, JSON numbers like 1E+999 or +-1E+999 may result in a parsing error. + +Likewise, integer numbers whose absolute values are too large to be +represented in the ``json_int_t`` type (see above) will result in an +overflow error (a JSON decoding error). Thus, depending on platform, +JSON numbers like 1000000000000000 may result in parsing error. + +Parsing JSON real numbers may result in a loss of precision. As long +as overflow does not occur (i.e. a total loss of precision), the +rounded approximate value is silently used. Thus the JSON number +1.000000000000000005 may, depending on platform, result in the +``double`` value 1.0. + +Signed zeros +------------ + +JSON makes no statement about what a number means; however Javascript +(ECMAscript) does state that +0.0 and -0.0 must be treated as being +distinct values, i.e. -0.0 |not-equal| 0.0. Jansson relies on the +underlying floating point library in the C environment in which it is +compiled. Therefore it is platform-dependent whether 0.0 and -0.0 will +be distinct values. Most platforms that use the IEEE 754 +floating-point standard will support signed zeros. + +Note that this only applies to floating-point; neither JSON, C, or +IEEE support the concept of signed integer zeros. + +.. |not-equal| unicode:: U+2260 + +Types +----- + +No support is provided in Jansson for any C numeric types other than +``json_int_t`` and ``double``. This excludes things such as unsigned +types, ``long double``, etc. Obviously, shorter types like ``short``, +``int``, ``long`` (if ``json_int_t`` is ``long long``) and ``float`` +are implicitly handled via the ordinary C type coercion rules (subject +to overflow semantics). Also, no support or hooks are provided for any +supplemental "bignum" type add-on packages. + +Depth of nested values +---------------------- + +To avoid stack exhaustion, Jansson currently limits the nesting depth +for arrays and objects to a certain value (default: 2048), defined as +a macro ``JSON_PARSER_MAX_DEPTH`` within ``jansson_config.h``. + +The limit is allowed to be set by the RFC; there is no recommended value +or required minimum depth to be supported. diff --git a/3party/jansson/doc/ext/refcounting.py b/3party/jansson/doc/ext/refcounting.py new file mode 100644 index 0000000000..bba2684999 --- /dev/null +++ b/3party/jansson/doc/ext/refcounting.py @@ -0,0 +1,60 @@ +""" + refcounting + ~~~~~~~~~~~ + + Reference count annotations for C API functions. Has the same + result as the sphinx.ext.refcounting extension but works for all + functions regardless of the signature, and the reference counting + information is written inline with the documentation instead of a + separate file. + + Adds a new directive "refcounting". The directive has no content + and one required positional parameter:: "new" or "borrow". + + Example: + + .. cfunction:: json_t *json_object(void) + + .. refcounting:: new + + + + :copyright: Copyright (c) 2009-2016 Petri Lehtinen + :license: MIT, see LICENSE for details. +""" + +from docutils import nodes + +class refcounting(nodes.emphasis): pass + +def visit(self, node): + self.visit_emphasis(node) + +def depart(self, node): + self.depart_emphasis(node) + +def html_visit(self, node): + self.body.append(self.starttag(node, 'em', '', CLASS='refcount')) + +def html_depart(self, node): + self.body.append('') + + +def refcounting_directive(name, arguments, options, content, lineno, + content_offset, block_text, state, state_machine): + if arguments[0] == 'borrow': + text = 'Return value: Borrowed reference.' + elif arguments[0] == 'new': + text = 'Return value: New reference.' + else: + raise Error('Valid arguments: new, borrow') + + return [refcounting(text, text)] + +def setup(app): + app.add_node(refcounting, + html=(html_visit, html_depart), + latex=(visit, depart), + text=(visit, depart), + man=(visit, depart)) + app.add_directive('refcounting', refcounting_directive, 0, (1, 0, 0)) diff --git a/3party/jansson/doc/gettingstarted.rst b/3party/jansson/doc/gettingstarted.rst new file mode 100644 index 0000000000..64bec43ef0 --- /dev/null +++ b/3party/jansson/doc/gettingstarted.rst @@ -0,0 +1,243 @@ +*************** +Getting Started +*************** + +.. highlight:: c + +Compiling and Installing Jansson +================================ + +The Jansson source is available at +http://www.digip.org/jansson/releases/. + +Unix-like systems (including MinGW) +----------------------------------- + +Unpack the source tarball and change to the source directory: + +.. parsed-literal:: + + bunzip2 -c jansson-|release|.tar.bz2 | tar xf - + cd jansson-|release| + +The source uses GNU Autotools (autoconf_, automake_, libtool_), so +compiling and installing is extremely simple:: + + ./configure + make + make check + make install + +To change the destination directory (``/usr/local`` by default), use +the ``--prefix=DIR`` argument to ``./configure``. See ``./configure +--help`` for the list of all possible configuration options. + +The command ``make check`` runs the test suite distributed with +Jansson. This step is not strictly necessary, but it may find possible +problems that Jansson has on your platform. If any problems are found, +please report them. + +If you obtained the source from a Git repository (or any other source +control system), there's no ``./configure`` script as it's not kept in +version control. To create the script, the build system needs to be +bootstrapped. There are many ways to do this, but the easiest one is +to use ``autoreconf``:: + + autoreconf -fi + +This command creates the ``./configure`` script, which can then be +used as described above. + +.. _autoconf: http://www.gnu.org/software/autoconf/ +.. _automake: http://www.gnu.org/software/automake/ +.. _libtool: http://www.gnu.org/software/libtool/ + + +.. _build-cmake: + +CMake (various platforms, including Windows) +-------------------------------------------- + +Jansson can be built using CMake_. Create a build directory for an +out-of-tree build, change to that directory, and run ``cmake`` (or ``ccmake``, +``cmake-gui``, or similar) to configure the project. + +See the examples below for more detailed information. + +.. note:: In the below examples ``..`` is used as an argument for ``cmake``. + This is simply the path to the jansson project root directory. + In the example it is assumed you've created a sub-directory ``build`` + and are using that. You could use any path you want. + +.. _build-cmake-unix: + +Unix (Make files) +^^^^^^^^^^^^^^^^^ +Generating make files on unix: + +.. parsed-literal:: + + bunzip2 -c jansson-|release|.tar.bz2 | tar xf - + cd jansson-|release| + + mkdir build + cd build + cmake .. # or ccmake .. for a GUI. + +Then to build:: + + make + make check + make install + +Windows (Visual Studio) +^^^^^^^^^^^^^^^^^^^^^^^ +Creating Visual Studio project files from the command line: + +.. parsed-literal:: + + + cd jansson-|release| + + md build + cd build + cmake -G "Visual Studio 15 2017" .. + +.. note:: + + You should replace the name of the generator (``-G`` flag) matching + the Visual Studio version installed on your system. Currently, the + following versions are supported: + + - ``Visual Studio 9 2008`` + - ``Visual Studio 10 2010`` + - ``Visual Studio 11 2012`` + - ``Visual Studio 12 2013`` + - ``Visual Studio 14 2015`` + - ``Visual Studio 15 2017`` + + Any later version should also work. + +You will now have a *Visual Studio Solution* in your build directory. +To run the unit tests build the ``RUN_TESTS`` project. + +If you prefer a GUI the ``cmake`` line in the above example can +be replaced with:: + + cmake-gui .. + +For command line help (including a list of available generators) +for CMake_ simply run:: + + cmake + +To list available CMake_ settings (and what they are currently set to) +for the project, run:: + + cmake -LH .. + +Mac OSX (Xcode) +^^^^^^^^^^^^^^^ +If you prefer using Xcode instead of make files on OSX, +do the following. (Use the same steps as +for :ref:`Unix `):: + + ... + cmake -G "Xcode" .. + +Additional CMake settings +^^^^^^^^^^^^^^^^^^^^^^^^^ + +Shared library +"""""""""""""" +By default the CMake_ project will generate build files for building the +static library. To build the shared version use:: + + ... + cmake -DJANSSON_BUILD_SHARED_LIBS=1 .. + +Changing install directory (same as autoconf --prefix) +"""""""""""""""""""""""""""""""""""""""""""""""""""""" +Just as with the autoconf_ project you can change the destination directory +for ``make install``. The equivalent for autoconfs ``./configure --prefix`` +in CMake_ is:: + + ... + cmake -DCMAKE_INSTALL_PREFIX:PATH=/some/other/path .. + make install + +.. _CMake: http://www.cmake.org + + +Android +------- + +Jansson can be built for Android platforms. Android.mk is in the +source root directory. The configuration header file is located in the +``android`` directory in the source distribution. + + +Other Systems +------------- + +On non Unix-like systems, you may be unable to run the ``./configure`` +script. In this case, follow these steps. All the files mentioned can +be found in the ``src/`` directory. + +1. Create ``jansson_config.h`` (which has some platform-specific + parameters that are normally filled in by the ``./configure`` + script). Edit ``jansson_config.h.in``, replacing all ``@variable@`` + placeholders, and rename the file to ``jansson_config.h``. + +2. Make ``jansson.h`` and ``jansson_config.h`` available to the + compiler, so that they can be found when compiling programs that + use Jansson. + +3. Compile all the ``.c`` files (in the ``src/`` directory) into a + library file. Make the library available to the compiler, as in + step 2. + + +Building the Documentation +-------------------------- + +(This subsection describes how to build the HTML documentation you are +currently reading, so it can be safely skipped.) + +Documentation is in the ``doc/`` subdirectory. It's written in +reStructuredText_ with Sphinx_ annotations. To generate the HTML +documentation, invoke:: + + make html + +and point your browser to ``doc/_build/html/index.html``. Sphinx_ 1.0 +or newer is required to generate the documentation. + +.. _reStructuredText: http://docutils.sourceforge.net/rst.html +.. _Sphinx: http://sphinx.pocoo.org/ + + +Compiling Programs that Use Jansson +=================================== + +Jansson involves one C header file, :file:`jansson.h`, so it's enough +to put the line + +:: + + #include + +in the beginning of every source file that uses Jansson. + +There's also just one library to link with, ``libjansson``. Compile and +link the program as follows:: + + cc -o prog prog.c -ljansson + +Starting from version 1.2, there's also support for pkg-config_: + +.. code-block:: shell + + cc -o prog prog.c `pkg-config --cflags --libs jansson` + +.. _pkg-config: http://pkg-config.freedesktop.org/ diff --git a/3party/jansson/doc/github_commits.c b/3party/jansson/doc/github_commits.c new file mode 100644 index 0000000000..a9a84d8fea --- /dev/null +++ b/3party/jansson/doc/github_commits.c @@ -0,0 +1,201 @@ +/* + * Copyright (c) 2009-2016 Petri Lehtinen + * + * Jansson is free software; you can redistribute it and/or modify + * it under the terms of the MIT license. See LICENSE for details. + */ + +#include +#include + +#include +#include + +#define BUFFER_SIZE (256 * 1024) /* 256 KB */ + +#define URL_FORMAT "https://api.github.com/repos/%s/%s/commits" +#define URL_SIZE 256 + +/* Return the offset of the first newline in text or the length of + text if there's no newline */ +static int newline_offset(const char *text) +{ + const char *newline = strchr(text, '\n'); + if(!newline) + return strlen(text); + else + return (int)(newline - text); +} + +struct write_result +{ + char *data; + int pos; +}; + +static size_t write_response(void *ptr, size_t size, size_t nmemb, void *stream) +{ + struct write_result *result = (struct write_result *)stream; + + if(result->pos + size * nmemb >= BUFFER_SIZE - 1) + { + fprintf(stderr, "error: too small buffer\n"); + return 0; + } + + memcpy(result->data + result->pos, ptr, size * nmemb); + result->pos += size * nmemb; + + return size * nmemb; +} + +static char *request(const char *url) +{ + CURL *curl = NULL; + CURLcode status; + struct curl_slist *headers = NULL; + char *data = NULL; + long code; + + curl_global_init(CURL_GLOBAL_ALL); + curl = curl_easy_init(); + if(!curl) + goto error; + + data = malloc(BUFFER_SIZE); + if(!data) + goto error; + + struct write_result write_result = { + .data = data, + .pos = 0 + }; + + curl_easy_setopt(curl, CURLOPT_URL, url); + + /* GitHub commits API v3 requires a User-Agent header */ + headers = curl_slist_append(headers, "User-Agent: Jansson-Tutorial"); + curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers); + + curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, write_response); + curl_easy_setopt(curl, CURLOPT_WRITEDATA, &write_result); + + status = curl_easy_perform(curl); + if(status != 0) + { + fprintf(stderr, "error: unable to request data from %s:\n", url); + fprintf(stderr, "%s\n", curl_easy_strerror(status)); + goto error; + } + + curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &code); + if(code != 200) + { + fprintf(stderr, "error: server responded with code %ld\n", code); + goto error; + } + + curl_easy_cleanup(curl); + curl_slist_free_all(headers); + curl_global_cleanup(); + + /* zero-terminate the result */ + data[write_result.pos] = '\0'; + + return data; + +error: + if(data) + free(data); + if(curl) + curl_easy_cleanup(curl); + if(headers) + curl_slist_free_all(headers); + curl_global_cleanup(); + return NULL; +} + +int main(int argc, char *argv[]) +{ + size_t i; + char *text; + char url[URL_SIZE]; + + json_t *root; + json_error_t error; + + if(argc != 3) + { + fprintf(stderr, "usage: %s USER REPOSITORY\n\n", argv[0]); + fprintf(stderr, "List commits at USER's REPOSITORY.\n\n"); + return 2; + } + + snprintf(url, URL_SIZE, URL_FORMAT, argv[1], argv[2]); + + text = request(url); + if(!text) + return 1; + + root = json_loads(text, 0, &error); + free(text); + + if(!root) + { + fprintf(stderr, "error: on line %d: %s\n", error.line, error.text); + return 1; + } + + if(!json_is_array(root)) + { + fprintf(stderr, "error: root is not an array\n"); + json_decref(root); + return 1; + } + + for(i = 0; i < json_array_size(root); i++) + { + json_t *data, *sha, *commit, *message; + const char *message_text; + + data = json_array_get(root, i); + if(!json_is_object(data)) + { + fprintf(stderr, "error: commit data %d is not an object\n", (int)(i + 1)); + json_decref(root); + return 1; + } + + sha = json_object_get(data, "sha"); + if(!json_is_string(sha)) + { + fprintf(stderr, "error: commit %d: sha is not a string\n", (int)(i + 1)); + return 1; + } + + commit = json_object_get(data, "commit"); + if(!json_is_object(commit)) + { + fprintf(stderr, "error: commit %d: commit is not an object\n", (int)(i + 1)); + json_decref(root); + return 1; + } + + message = json_object_get(commit, "message"); + if(!json_is_string(message)) + { + fprintf(stderr, "error: commit %d: message is not a string\n", (int)(i + 1)); + json_decref(root); + return 1; + } + + message_text = json_string_value(message); + printf("%.8s %.*s\n", + json_string_value(sha), + newline_offset(message_text), + message_text); + } + + json_decref(root); + return 0; +} diff --git a/3party/jansson/doc/index.rst b/3party/jansson/doc/index.rst new file mode 100644 index 0000000000..1f3f8ef70a --- /dev/null +++ b/3party/jansson/doc/index.rst @@ -0,0 +1,53 @@ +Jansson Documentation +===================== + +This is the documentation for Jansson_ |release|, last updated |today|. + +Introduction +------------ + +Jansson_ is a C library for encoding, decoding and manipulating JSON +data. Its main features and design principles are: + +- Simple and intuitive API and data model + +- Comprehensive documentation + +- No dependencies on other libraries + +- Full Unicode support (UTF-8) + +- Extensive test suite + +Jansson is licensed under the `MIT license`_; see LICENSE in the +source distribution for details. + +Jansson is used in production and its API is stable. It works on +numerous platforms, including numerous Unix like systems and Windows. +It's suitable for use on any system, including desktop, server, and +small embedded systems. + + +.. _`MIT license`: http://www.opensource.org/licenses/mit-license.php +.. _Jansson: http://www.digip.org/jansson/ + +Contents +-------- + +.. toctree:: + :maxdepth: 2 + + gettingstarted + upgrading + tutorial + conformance + portability + apiref + changes + + +Indices and Tables +================== + +* :ref:`genindex` +* :ref:`search` diff --git a/3party/jansson/doc/portability.rst b/3party/jansson/doc/portability.rst new file mode 100644 index 0000000000..f8d81cde52 --- /dev/null +++ b/3party/jansson/doc/portability.rst @@ -0,0 +1,85 @@ +*********** +Portability +*********** + +.. _portability-thread-safety: + +Thread safety +------------- + +Jansson as a library is thread safe and has no mutable global state. +The only exceptions are the hash function seed and memory allocation +functions, see below. + +There's no locking performed inside Jansson's code. **Read-only** +access to JSON values shared by multiple threads is safe, but +**mutating** a JSON value that's shared by multiple threads is not. A +multithreaded program must perform its own locking if JSON values +shared by multiple threads are mutated. + +However, **reference count manipulation** (:func:`json_incref()`, +:func:`json_decref()`) is usually thread-safe, and can be performed on +JSON values that are shared among threads. The thread-safety of +reference counting can be checked with the +``JANSSON_THREAD_SAFE_REFCOUNT`` preprocessor constant. Thread-safe +reference count manipulation is achieved using compiler built-in +atomic functions, which are available in most modern compilers. + +If compiler support is not available (``JANSSON_THREAD_SAFE_REFCOUNT`` +is not defined), it may be very difficult to ensure thread safety of +reference counting. It's possible to have a reference to a value +that's also stored inside an array or object in another thread. +Modifying the container (adding or removing values) may trigger +concurrent access to such values, as containers manage the reference +count of their contained values. + + +Hash function seed +================== + +To prevent an attacker from intentionally causing large JSON objects +with specially crafted keys to perform very slow, the hash function +used by Jansson is randomized using a seed value. The seed is +automatically generated on the first explicit or implicit call to +:func:`json_object()`, if :func:`json_object_seed()` has not been +called beforehand. + +The seed is generated by using operating system's entropy sources if +they are available (``/dev/urandom``, ``CryptGenRandom()``). The +initialization is done in as thread safe manner as possible, by using +architecture specific lockless operations if provided by the platform +or the compiler. + +If you're using threads, it's recommended to autoseed the hashtable +explicitly before spawning any threads by calling +``json_object_seed(0)`` , especially if you're unsure whether the +initialization is thread safe on your platform. + + +Memory allocation functions +=========================== + +Memory allocation functions should be set at most once, and only on +program startup. See :ref:`apiref-custom-memory-allocation`. + + +Locale +------ + +Jansson works fine under any locale. + +However, if the host program is multithreaded and uses ``setlocale()`` +to switch the locale in one thread while Jansson is currently encoding +or decoding JSON data in another thread, the result may be wrong or +the program may even crash. + +Jansson uses locale specific functions for certain string conversions +in the encoder and decoder, and then converts the locale specific +values to/from the JSON representation. This fails if the locale +changes between the string conversion and the locale-to-JSON +conversion. This can only happen in multithreaded programs that use +``setlocale()``, because ``setlocale()`` switches the locale for all +running threads, not only the thread that calls ``setlocale()``. + +If your program uses ``setlocale()`` as described above, consider +using the thread-safe ``uselocale()`` instead. diff --git a/3party/jansson/doc/tutorial.rst b/3party/jansson/doc/tutorial.rst new file mode 100644 index 0000000000..56861c2de5 --- /dev/null +++ b/3party/jansson/doc/tutorial.rst @@ -0,0 +1,288 @@ +.. _tutorial: + +******** +Tutorial +******** + +.. highlight:: c + +In this tutorial, we create a program that fetches the latest commits +of a repository in GitHub_ over the web. `GitHub API`_ uses JSON, so +the result can be parsed using Jansson. + +To stick to the scope of this tutorial, we will only cover the +parts of the program related to handling JSON data. For the best user +experience, the full source code is available: +:download:`github_commits.c`. To compile it (on Unix-like systems with +gcc), use the following command:: + + gcc -o github_commits github_commits.c -ljansson -lcurl + +libcurl_ is used to communicate over the web, so it is required to +compile the program. + +The command line syntax is:: + + github_commits USER REPOSITORY + +``USER`` is a GitHub user ID and ``REPOSITORY`` is the repository +name. Please note that the GitHub API is rate limited, so if you run +the program too many times within a short period of time, the sever +starts to respond with an error. + +.. _GitHub: https://github.com/ +.. _GitHub API: http://developer.github.com/ +.. _libcurl: http://curl.haxx.se/ + + +.. _tutorial-github-commits-api: + +The GitHub Repo Commits API +=========================== + +The `GitHub Repo Commits API`_ is used by sending HTTP requests to +URLs like ``https://api.github.com/repos/USER/REPOSITORY/commits``, +where ``USER`` and ``REPOSITORY`` are the GitHub user ID and the name +of the repository whose commits are to be listed, respectively. + +GitHub responds with a JSON array of the following form: + +.. code-block:: none + + [ + { + "sha": "", + "commit": { + "message": "", + + }, + + }, + { + "sha": "", + "commit": { + "message": "", + + }, + + }, + + ] + +In our program, the HTTP request is sent using the following +function:: + + static char *request(const char *url); + +It takes the URL as a parameter, preforms a HTTP GET request, and +returns a newly allocated string that contains the response body. If +the request fails, an error message is printed to stderr and the +return value is *NULL*. For full details, refer to :download:`the code +`, as the actual implementation is not important +here. + +.. _GitHub Repo Commits API: http://developer.github.com/v3/repos/commits/ + +.. _tutorial-the-program: + +The Program +=========== + +First the includes:: + + #include + #include + +Like all the programs using Jansson, we need to include +:file:`jansson.h`. + +The following definitions are used to build the GitHub API request +URL:: + + #define URL_FORMAT "https://api.github.com/repos/%s/%s/commits" + #define URL_SIZE 256 + +The following function is used when formatting the result to find the +first newline in the commit message:: + + /* Return the offset of the first newline in text or the length of + text if there's no newline */ + static int newline_offset(const char *text) + { + const char *newline = strchr(text, '\n'); + if(!newline) + return strlen(text); + else + return (int)(newline - text); + } + +The main function follows. In the beginning, we first declare a bunch +of variables and check the command line parameters:: + + int main(int argc, char *argv[]) + { + size_t i; + char *text; + char url[URL_SIZE]; + + json_t *root; + json_error_t error; + + if(argc != 3) + { + fprintf(stderr, "usage: %s USER REPOSITORY\n\n", argv[0]); + fprintf(stderr, "List commits at USER's REPOSITORY.\n\n"); + return 2; + } + +Then we build the request URL using the user and repository names +given as command line parameters:: + + snprintf(url, URL_SIZE, URL_FORMAT, argv[1], argv[2]); + +This uses the ``URL_SIZE`` and ``URL_FORMAT`` constants defined above. +Now we're ready to actually request the JSON data over the web:: + + text = request(url); + if(!text) + return 1; + +If an error occurs, our function ``request`` prints the error and +returns *NULL*, so it's enough to just return 1 from the main +function. + +Next we'll call :func:`json_loads()` to decode the JSON text we got +as a response:: + + root = json_loads(text, 0, &error); + free(text); + + if(!root) + { + fprintf(stderr, "error: on line %d: %s\n", error.line, error.text); + return 1; + } + +We don't need the JSON text anymore, so we can free the ``text`` +variable right after decoding it. If :func:`json_loads()` fails, it +returns *NULL* and sets error information to the :type:`json_error_t` +structure given as the second parameter. In this case, our program +prints the error information out and returns 1 from the main function. + +Now we're ready to extract the data out of the decoded JSON response. +The structure of the response JSON was explained in section +:ref:`tutorial-github-commits-api`. + +We check that the returned value really is an array:: + + if(!json_is_array(root)) + { + fprintf(stderr, "error: root is not an array\n"); + json_decref(root); + return 1; + } + +Then we proceed to loop over all the commits in the array:: + + for(i = 0; i < json_array_size(root); i++) + { + json_t *data, *sha, *commit, *message; + const char *message_text; + + data = json_array_get(root, i); + if(!json_is_object(data)) + { + fprintf(stderr, "error: commit data %d is not an object\n", i + 1); + json_decref(root); + return 1; + } + ... + +The function :func:`json_array_size()` returns the size of a JSON +array. First, we again declare some variables and then extract the +i'th element of the ``root`` array using :func:`json_array_get()`. +We also check that the resulting value is a JSON object. + +Next we'll extract the commit ID (a hexadecimal SHA-1 sum), +intermediate commit info object, and the commit message from that +object. We also do proper type checks:: + + sha = json_object_get(data, "sha"); + if(!json_is_string(sha)) + { + fprintf(stderr, "error: commit %d: sha is not a string\n", i + 1); + json_decref(root); + return 1; + } + + commit = json_object_get(data, "commit"); + if(!json_is_object(commit)) + { + fprintf(stderr, "error: commit %d: commit is not an object\n", i + 1); + json_decref(root); + return 1; + } + + message = json_object_get(commit, "message"); + if(!json_is_string(message)) + { + fprintf(stderr, "error: commit %d: message is not a string\n", i + 1); + json_decref(root); + return 1; + } + ... + +And finally, we'll print the first 8 characters of the commit ID and +the first line of the commit message. A C-style string is extracted +from a JSON string using :func:`json_string_value()`:: + + message_text = json_string_value(message); + printf("%.8s %.*s\n", + json_string_value(sha), + newline_offset(message_text), + message_text); + } + +After sending the HTTP request, we decoded the JSON text using +:func:`json_loads()`, remember? It returns a *new reference* to the +JSON value it decodes. When we're finished with the value, we'll need +to decrease the reference count using :func:`json_decref()`. This way +Jansson can release the resources:: + + json_decref(root); + return 0; + +For a detailed explanation of reference counting in Jansson, see +:ref:`apiref-reference-count` in :ref:`apiref`. + +The program's ready, let's test it and view the latest commits in +Jansson's repository: + +.. code-block:: shell + + $ ./github_commits akheron jansson + 1581f26a Merge branch '2.3' + aabfd493 load: Change buffer_pos to be a size_t + bd72efbd load: Avoid unexpected behaviour in macro expansion + e8fd3e30 Document and tweak json_load_callback() + 873eddaf Merge pull request #60 from rogerz/contrib + bd2c0c73 Ignore the binary test_load_callback + 17a51a4b Merge branch '2.3' + 09c39adc Add json_load_callback to the list of exported symbols + cbb80baf Merge pull request #57 from rogerz/contrib + 040bd7b0 Add json_load_callback() + 2637faa4 Make test stripping locale independent + <...> + + +Conclusion +========== + +In this tutorial, we implemented a program that fetches the latest +commits of a GitHub repository using the GitHub Repo Commits API. +Jansson was used to decode the JSON response and to extract the commit +data. + +This tutorial only covered a small part of Jansson. For example, we +did not create or manipulate JSON values at all. Proceed to +:ref:`apiref` to explore all features of Jansson. diff --git a/3party/jansson/doc/upgrading.rst b/3party/jansson/doc/upgrading.rst new file mode 100644 index 0000000000..9b4904610e --- /dev/null +++ b/3party/jansson/doc/upgrading.rst @@ -0,0 +1,76 @@ +.. highlight:: c + +****************** +Upgrading from 1.x +****************** + +This chapter lists the backwards incompatible changes introduced in +Jansson 2.0, and the steps that are needed for upgrading your code. + +**The incompatibilities are not dramatic.** The biggest change is that +all decoding functions now require and extra parameter. Most programs +can be modified to work with 2.0 by adding a ``0`` as the second +parameter to all calls of :func:`json_loads()`, :func:`json_loadf()` +and :func:`json_load_file()`. + + +Compatibility +============= + +Jansson 2.0 is backwards incompatible with the Jansson 1.x releases. +It is ABI incompatible, i.e. all programs dynamically linking to the +Jansson library need to be recompiled. It's also API incompatible, +i.e. the source code of programs using Jansson 1.x may need +modifications to make them compile against Jansson 2.0. + +All the 2.x releases are guaranteed to be backwards compatible for +both ABI and API, so no recompilation or source changes are needed +when upgrading from 2.x to 2.y. + + +List of Incompatible Changes +============================ + +**Decoding flags** + For future needs, a ``flags`` parameter was added as the second + parameter to all decoding functions, i.e. :func:`json_loads()`, + :func:`json_loadf()` and :func:`json_load_file()`. All calls to + these functions need to be changed by adding a ``0`` as the second + argument. For example:: + + /* old code */ + json_loads(input, &error); + + /* new code */ + json_loads(input, 0, &error); + + +**Underlying type of JSON integers** + The underlying C type of JSON integers has been changed from + :type:`int` to the widest available signed integer type, i.e. + :type:`long long` or :type:`long`, depending on whether + :type:`long long` is supported on your system or not. This makes + the whole 64-bit integer range available on most modern systems. + + ``jansson.h`` has a typedef :type:`json_int_t` to the underlying + integer type. :type:`int` should still be used in most cases when + dealing with smallish JSON integers, as the compiler handles + implicit type coercion. Only when the full 64-bit range is needed, + :type:`json_int_t` should be explicitly used. + + +**Maximum encoder indentation depth** + The maximum argument of the ``JSON_INDENT()`` macro has been + changed from 255 to 31, to free up bits from the ``flags`` + parameter of :func:`json_dumps()`, :func:`json_dumpf()` and + :func:`json_dump_file()`. If your code uses a bigger indentation + than 31, it needs to be changed. + + +**Unsigned integers in API functions** + Version 2.0 unifies unsigned integer usage in the API. All uses of + :type:`unsigned int` and :type:`unsigned long` have been replaced + with :type:`size_t`. This includes flags, container sizes, etc. + This should not require source code changes, as both + :type:`unsigned int` and :type:`unsigned long` are usually + compatible with :type:`size_t`. diff --git a/3party/jansson/examples/README.rst b/3party/jansson/examples/README.rst new file mode 100644 index 0000000000..a7c5274dbc --- /dev/null +++ b/3party/jansson/examples/README.rst @@ -0,0 +1,4 @@ +Jansson examples +================ + +This directory contains simple example programs that use Jansson. diff --git a/3party/jansson/examples/simple_parse.c b/3party/jansson/examples/simple_parse.c new file mode 100644 index 0000000000..044337b856 --- /dev/null +++ b/3party/jansson/examples/simple_parse.c @@ -0,0 +1,203 @@ +/* + * Simple example of parsing and printing JSON using jansson. + * + * SYNOPSIS: + * $ examples/simple_parse + * Type some JSON > [true, false, null, 1, 0.0, -0.0, "", {"name": "barney"}] + * JSON Array of 8 elements: + * JSON True + * JSON False + * JSON Null + * JSON Integer: "1" + * JSON Real: 0.000000 + * JSON Real: -0.000000 + * JSON String: "" + * JSON Object of 1 pair: + * JSON Key: "name" + * JSON String: "barney" + * + * Copyright (c) 2014 Robert Poor + * + * Jansson is free software; you can redistribute it and/or modify + * it under the terms of the MIT license. See LICENSE for details. + */ + +#include +#include +#include + +/* forward refs */ +void print_json(json_t *root); +void print_json_aux(json_t *element, int indent); +void print_json_indent(int indent); +const char *json_plural(int count); +void print_json_object(json_t *element, int indent); +void print_json_array(json_t *element, int indent); +void print_json_string(json_t *element, int indent); +void print_json_integer(json_t *element, int indent); +void print_json_real(json_t *element, int indent); +void print_json_true(json_t *element, int indent); +void print_json_false(json_t *element, int indent); +void print_json_null(json_t *element, int indent); + +void print_json(json_t *root) { + print_json_aux(root, 0); +} + +void print_json_aux(json_t *element, int indent) { + switch (json_typeof(element)) { + case JSON_OBJECT: + print_json_object(element, indent); + break; + case JSON_ARRAY: + print_json_array(element, indent); + break; + case JSON_STRING: + print_json_string(element, indent); + break; + case JSON_INTEGER: + print_json_integer(element, indent); + break; + case JSON_REAL: + print_json_real(element, indent); + break; + case JSON_TRUE: + print_json_true(element, indent); + break; + case JSON_FALSE: + print_json_false(element, indent); + break; + case JSON_NULL: + print_json_null(element, indent); + break; + default: + fprintf(stderr, "unrecognized JSON type %d\n", json_typeof(element)); + } +} + +void print_json_indent(int indent) { + int i; + for (i = 0; i < indent; i++) { putchar(' '); } +} + +const char *json_plural(int count) { + return count == 1 ? "" : "s"; +} + +void print_json_object(json_t *element, int indent) { + size_t size; + const char *key; + json_t *value; + + print_json_indent(indent); + size = json_object_size(element); + + printf("JSON Object of %ld pair%s:\n", size, json_plural(size)); + json_object_foreach(element, key, value) { + print_json_indent(indent + 2); + printf("JSON Key: \"%s\"\n", key); + print_json_aux(value, indent + 2); + } + +} + +void print_json_array(json_t *element, int indent) { + size_t i; + size_t size = json_array_size(element); + print_json_indent(indent); + + printf("JSON Array of %ld element%s:\n", size, json_plural(size)); + for (i = 0; i < size; i++) { + print_json_aux(json_array_get(element, i), indent + 2); + } +} + +void print_json_string(json_t *element, int indent) { + print_json_indent(indent); + printf("JSON String: \"%s\"\n", json_string_value(element)); +} + +void print_json_integer(json_t *element, int indent) { + print_json_indent(indent); + printf("JSON Integer: \"%" JSON_INTEGER_FORMAT "\"\n", json_integer_value(element)); +} + +void print_json_real(json_t *element, int indent) { + print_json_indent(indent); + printf("JSON Real: %f\n", json_real_value(element)); +} + +void print_json_true(json_t *element, int indent) { + (void)element; + print_json_indent(indent); + printf("JSON True\n"); +} + +void print_json_false(json_t *element, int indent) { + (void)element; + print_json_indent(indent); + printf("JSON False\n"); +} + +void print_json_null(json_t *element, int indent) { + (void)element; + print_json_indent(indent); + printf("JSON Null\n"); +} + +/* + * Parse text into a JSON object. If text is valid JSON, returns a + * json_t structure, otherwise prints and error and returns null. + */ +json_t *load_json(const char *text) { + json_t *root; + json_error_t error; + + root = json_loads(text, 0, &error); + + if (root) { + return root; + } else { + fprintf(stderr, "json error on line %d: %s\n", error.line, error.text); + return (json_t *)0; + } +} + +/* + * Print a prompt and return (by reference) a null-terminated line of + * text. Returns NULL on eof or some error. + */ +char *read_line(char *line, int max_chars) { + printf("Type some JSON > "); + fflush(stdout); + return fgets(line, max_chars, stdin); +} + +/* ================================================================ + * main + */ + +#define MAX_CHARS 4096 + +int main(int argc, char *argv[]) { + char line[MAX_CHARS]; + + if (argc != 1) { + fprintf(stderr, "Usage: %s\n", argv[0]); + exit(-1); + } + + while (read_line(line, MAX_CHARS) != (char *)NULL) { + + /* parse text into JSON structure */ + json_t *root = load_json(line); + + if (root) { + /* print and release the JSON structure */ + print_json(root); + json_decref(root); + } + } + + return 0; +} diff --git a/3party/jansson/ios/jansson_config.h b/3party/jansson/ios/jansson_config.h new file mode 100644 index 0000000000..a5502fc0ef --- /dev/null +++ b/3party/jansson/ios/jansson_config.h @@ -0,0 +1,74 @@ +/* + * Copyright (c) 2010-2016 Petri Lehtinen + * + * Jansson is free software; you can redistribute it and/or modify + * it under the terms of the MIT license. See LICENSE for details. + * + * + * This file specifies a part of the site-specific configuration for + * Jansson, namely those things that affect the public API in + * jansson.h. + * + * The CMake system will generate the jansson_config.h file and + * copy it to the build and install directories. + */ + +#ifndef JANSSON_CONFIG_H +#define JANSSON_CONFIG_H + +/* Define this so that we can disable scattered automake configuration in source files */ +#ifndef JANSSON_USING_CMAKE +#define JANSSON_USING_CMAKE +#endif + +/* Note: when using cmake, JSON_INTEGER_IS_LONG_LONG is not defined nor used, + * as we will also check for __int64 etc types. + * (the definition was used in the automake system) */ + +/* Bring in the cmake-detected defines */ +#define HAVE_STDINT_H 1 +/* #undef HAVE_INTTYPES_H */ +#define HAVE_SYS_TYPES_H 1 + +/* Include our standard type header for the integer typedef */ + +#if defined(HAVE_STDINT_H) +# include +#elif defined(HAVE_INTTYPES_H) +# include +#elif defined(HAVE_SYS_TYPES_H) +# include +#endif + + +/* If your compiler supports the inline keyword in C, JSON_INLINE is + defined to `inline', otherwise empty. In C++, the inline is always + supported. */ +#ifdef __cplusplus +#define JSON_INLINE inline +#else +#define JSON_INLINE inline +#endif + + +#define json_int_t long long +#define json_strtoint strtoll +#define JSON_INTEGER_FORMAT "lld" + + +/* If locale.h and localeconv() are available, define to 1, otherwise to 0. */ +#define JSON_HAVE_LOCALECONV 1 + +/* If __atomic builtins are available they will be used to manage + reference counts of json_t. */ +#define JSON_HAVE_ATOMIC_BUILTINS 1 + +/* If __atomic builtins are not available we try using __sync builtins + to manage reference counts of json_t. */ +#define JSON_HAVE_SYNC_BUILTINS 1 + +/* Maximum recursion depth for parsing JSON input. + This limits the depth of e.g. array-within-array constructions. */ +#define JSON_PARSER_MAX_DEPTH 2048 + +#endif diff --git a/3party/jansson/jansson_private_config.h b/3party/jansson/ios/jansson_private_config.h similarity index 100% rename from 3party/jansson/jansson_private_config.h rename to 3party/jansson/ios/jansson_private_config.h diff --git a/3party/jansson/jansson b/3party/jansson/jansson deleted file mode 160000 index e23f558007..0000000000 --- a/3party/jansson/jansson +++ /dev/null @@ -1 +0,0 @@ -Subproject commit e23f5580072cb64ce3ab27de2b5110d7ac252424 diff --git a/3party/jansson/jansson.pc.in b/3party/jansson/jansson.pc.in new file mode 100644 index 0000000000..69c9a43aeb --- /dev/null +++ b/3party/jansson/jansson.pc.in @@ -0,0 +1,10 @@ +prefix=@prefix@ +exec_prefix=@exec_prefix@ +libdir=@libdir@ +includedir=@includedir@ + +Name: Jansson +Description: Library for encoding, decoding and manipulating JSON data +Version: @VERSION@ +Libs: -L${libdir} -ljansson +Cflags: -I${includedir} diff --git a/3party/jansson/jansson_config.h b/3party/jansson/jansson_config.h deleted file mode 100644 index bf3b15b2f4..0000000000 --- a/3party/jansson/jansson_config.h +++ /dev/null @@ -1,74 +0,0 @@ -/* - * Copyright (c) 2010-2016 Petri Lehtinen - * - * Jansson is free software; you can redistribute it and/or modify - * it under the terms of the MIT license. See LICENSE for details. - * - * - * This file specifies a part of the site-specific configuration for - * Jansson, namely those things that affect the public API in - * jansson.h. - * - * The CMake system will generate the jansson_config.h file and - * copy it to the build and install directories. - */ - -#ifndef JANSSON_CONFIG_H -#define JANSSON_CONFIG_H - -/* Define this so that we can disable scattered automake configuration in source files */ -#ifndef JANSSON_USING_CMAKE -#define JANSSON_USING_CMAKE -#endif - -/* Note: when using cmake, JSON_INTEGER_IS_LONG_LONG is not defined nor used, - * as we will also check for __int64 etc types. - * (the definition was used in the automake system) */ - -/* Bring in the cmake-detected defines */ -#define HAVE_STDINT_H 1 -#define HAVE_INTTYPES_H 1 -#define HAVE_SYS_TYPES_H 1 - -/* Include our standard type header for the integer typedef */ - -#if defined(HAVE_STDINT_H) -# include -#elif defined(HAVE_INTTYPES_H) -# include -#elif defined(HAVE_SYS_TYPES_H) -# include -#endif - - -/* If your compiler supports the inline keyword in C, JSON_INLINE is - defined to `inline', otherwise empty. In C++, the inline is always - supported. */ -#ifdef __cplusplus -#define JSON_INLINE inline -#else -#define JSON_INLINE inline -#endif - - -#define json_int_t long long -#define json_strtoint strtoll -#define JSON_INTEGER_FORMAT "lld" - - -/* If locale.h and localeconv() are available, define to 1, otherwise to 0. */ -#define JSON_HAVE_LOCALECONV 1 - -/* If __atomic builtins are available they will be used to manage - reference counts of json_t. */ -#define JSON_HAVE_ATOMIC_BUILTINS 1 - -/* If __atomic builtins are not available we try using __sync builtins - to manage reference counts of json_t. */ -#define JSON_HAVE_SYNC_BUILTINS 1 - -/* Maximum recursion depth for parsing JSON input. - This limits the depth of e.g. array-within-array constructions. */ -#define JSON_PARSER_MAX_DEPTH 2048 - -#endif diff --git a/cppjansson/jansson_handle.cpp b/3party/jansson/jansson_handle.cpp similarity index 81% rename from cppjansson/jansson_handle.cpp rename to 3party/jansson/jansson_handle.cpp index 32112c6105..afe0c6733c 100644 --- a/cppjansson/jansson_handle.cpp +++ b/3party/jansson/jansson_handle.cpp @@ -1,4 +1,4 @@ -#include "jansson_handle.hpp" +#include "3party/jansson/jansson_handle.hpp" #include diff --git a/cppjansson/jansson_handle.hpp b/3party/jansson/jansson_handle.hpp similarity index 77% rename from cppjansson/jansson_handle.hpp rename to 3party/jansson/jansson_handle.hpp index 229a5b2221..b6ba745b10 100644 --- a/cppjansson/jansson_handle.hpp +++ b/3party/jansson/jansson_handle.hpp @@ -2,7 +2,7 @@ #include -struct json_t; +struct json_struct_t; namespace base { @@ -12,7 +12,7 @@ class JsonHandle void DecRef(); public: - JsonHandle(json_t * pJson = 0) : m_pJson(pJson) + JsonHandle(json_struct_t * pJson = 0) : m_pJson(pJson) { IncRef(); } @@ -39,12 +39,12 @@ public: std::swap(m_pJson, json.m_pJson); } - json_t * get() const + json_struct_t * get() const { return m_pJson; } - json_t * operator -> () const + json_struct_t * operator -> () const { return m_pJson; } @@ -55,7 +55,7 @@ public: } /// Attach newly created object without incrementing ref count (it's already == 1). - void AttachNew(json_t * pJson) + void AttachNew(json_struct_t * pJson) { DecRef(); @@ -63,6 +63,6 @@ public: } private: - json_t * m_pJson; + json_struct_t * m_pJson; }; } // namespace base diff --git a/3party/jansson/myjansson.cpp b/3party/jansson/myjansson.cpp new file mode 100644 index 0000000000..0b70b89ce7 --- /dev/null +++ b/3party/jansson/myjansson.cpp @@ -0,0 +1,143 @@ +#include "3party/jansson/myjansson.hpp" + +#include + +using namespace std; + +namespace +{ +template +string FromJSONToString(json_t const * root) +{ + T result; + FromJSON(root, result); + return strings::to_string(result); +} +} // namespace + +namespace base +{ +json_t * GetJSONObligatoryField(json_t * root, std::string const & field) +{ + return GetJSONObligatoryField(root, field.c_str()); +} + +json_t * GetJSONObligatoryField(json_t * root, char const * field) +{ + return const_cast(GetJSONObligatoryField(const_cast(root), field)); +} + +json_t const * GetJSONObligatoryField(json_t const * root, std::string const & field) +{ + return GetJSONObligatoryField(root, field.c_str()); +} + +json_t const * GetJSONObligatoryField(json_t const * root, char const * field) +{ + auto * value = base::GetJSONOptionalField(root, field); + if (!value) + MYTHROW(base::Json::Exception, ("Obligatory field", field, "is absent.")); + return value; +} + +json_t * GetJSONOptionalField(json_t * root, std::string const & field) +{ + return GetJSONOptionalField(root, field.c_str()); +} + +json_t * GetJSONOptionalField(json_t * root, char const * field) +{ + return const_cast(GetJSONOptionalField(const_cast(root), field)); +} + +json_t const * GetJSONOptionalField(json_t const * root, std::string const & field) +{ + return GetJSONOptionalField(root, field.c_str()); +} + +json_t const * GetJSONOptionalField(json_t const * root, char const * field) +{ + if (!json_is_object(root)) + MYTHROW(base::Json::Exception, ("Bad json object while parsing", field)); + return json_object_get(root, field); +} + +bool JSONIsNull(json_t const * root) { return json_is_null(root); } + +std::string DumpToString(JSONPtr const & json, size_t flags) +{ + std::string result; + size_t size = json_dumpb(json.get(), nullptr, 0, flags); + if (size == 0) + MYTHROW(base::Json::Exception, ("Zero size JSON while serializing")); + + result.resize(size); + if (size != json_dumpb(json.get(), &result.front(), size, flags)) + MYTHROW(base::Json::Exception, ("Wrong size JSON written while serializing")); + + return result; +} + +JSONPtr LoadFromString(std::string const & str) +{ + json_error_t jsonError = {}; + json_t * result = json_loads(str.c_str(), 0, &jsonError); + if (!result) + MYTHROW(base::Json::Exception, (jsonError.text)); + return JSONPtr(result); +} + +} // namespace base + +void FromJSON(json_t const * root, double & result) +{ + if (!json_is_number(root)) + MYTHROW(base::Json::Exception, ("Object must contain a json number.")); + result = json_number_value(root); +} + +void FromJSON(json_t const * root, bool & result) +{ + if (!json_is_true(root) && !json_is_false(root)) + MYTHROW(base::Json::Exception, ("Object must contain a boolean value.")); + result = json_is_true(root); +} + +string FromJSONToString(json_t const * root) +{ + if (json_is_string(root)) + return FromJSONToString(root); + + if (json_is_integer(root)) + return FromJSONToString(root); + + if (json_is_real(root)) + return FromJSONToString(root); + + if (json_is_boolean(root)) + return FromJSONToString(root); + + MYTHROW(base::Json::Exception, ("Unexpected json type")); +} + +namespace std +{ +void FromJSON(json_t const * root, string & result) +{ + if (!json_is_string(root)) + MYTHROW(base::Json::Exception, ("The field must contain a json string.")); + result = json_string_value(root); +} +} // namespace std + +namespace strings +{ +void FromJSON(json_t const * root, UniString & result) +{ + string s; + FromJSON(root, s); + result = MakeUniString(s); +} + +base::JSONPtr ToJSON(UniString const & s) { return ToJSON(ToUtf8(s)); } +} // namespace strings diff --git a/3party/jansson/myjansson.hpp b/3party/jansson/myjansson.hpp new file mode 100644 index 0000000000..8703dd5ad1 --- /dev/null +++ b/3party/jansson/myjansson.hpp @@ -0,0 +1,341 @@ +#pragma once + +#include "jansson_handle.hpp" + +#include "base/exception.hpp" +#include "base/string_utils.hpp" + +#include +#include +#include +#include +#include + +#include "3party/jansson/src/jansson.h" + +namespace base +{ +struct JSONDecRef +{ + void operator()(json_t * root) const + { + if (root) + json_decref(root); + } +}; + +using JSONPtr = std::unique_ptr; + +inline JSONPtr NewJSONObject() { return JSONPtr(json_object()); } +inline JSONPtr NewJSONArray() { return JSONPtr(json_array()); } +inline JSONPtr NewJSONString(std::string const & s) { return JSONPtr(json_string(s.c_str())); } +inline JSONPtr NewJSONInt(json_int_t value) { return JSONPtr(json_integer(value)); } +inline JSONPtr NewJSONReal(double value) { return JSONPtr(json_real(value)); } +inline JSONPtr NewJSONBool(bool value) { return JSONPtr(value ? json_true() : json_false()); } +inline JSONPtr NewJSONNull() { return JSONPtr(json_null()); } + +class Json +{ +public: + DECLARE_EXCEPTION(Exception, RootException); + + Json() = default; + explicit Json(std::string const & s) { ParseFrom(s); } + explicit Json(char const * s) { ParseFrom(s); } + explicit Json(JSONPtr && json) { m_handle.AttachNew(json.release()); } + + Json GetDeepCopy() const + { + Json copy; + copy.m_handle.AttachNew(get_deep_copy()); + return copy; + } + void ParseFrom(std::string const & s) { ParseFrom(s.c_str()); } + void ParseFrom(char const * s) + { + json_error_t jsonError; + m_handle.AttachNew(json_loads(s, 0, &jsonError)); + if (!m_handle) + MYTHROW(Exception, (jsonError.line, jsonError.text)); + } + + json_t * get() const { return m_handle.get(); } + json_t * get_deep_copy() const { return json_deep_copy(get()); } + +private: + JsonHandle m_handle; +}; + +JSONPtr LoadFromString(std::string const & str); +std::string DumpToString(JSONPtr const & json, size_t flags = 0); + +json_t * GetJSONObligatoryField(json_t * root, std::string const & field); +json_t const * GetJSONObligatoryField(json_t const * root, std::string const & field); +json_t * GetJSONObligatoryField(json_t * root, char const * field); +json_t const * GetJSONObligatoryField(json_t const * root, char const * field); +json_t * GetJSONOptionalField(json_t * root, std::string const & field); +json_t const * GetJSONOptionalField(json_t const * root, std::string const & field); +json_t * GetJSONOptionalField(json_t * root, char const * field); +json_t const * GetJSONOptionalField(json_t const * root, char const * field); + +template +inline json_t const * GetJSONObligatoryFieldByPath(json_t const * root, First && path) +{ + return GetJSONObligatoryField(root, std::forward(path)); +} + +template +inline json_t const * GetJSONObligatoryFieldByPath(json_t const * root, First && path, + Paths &&... paths) +{ + json_t const * newRoot = GetJSONObligatoryFieldByPath(root, std::forward(path)); + return GetJSONObligatoryFieldByPath(newRoot, std::forward(paths)...); +} + +template +inline json_t * GetJSONObligatoryFieldByPath(json_t * root, First && path) +{ + return GetJSONObligatoryField(root, std::forward(path)); +} + +template +inline json_t * GetJSONObligatoryFieldByPath(json_t * root, First && path, + Paths &&... paths) +{ + json_t * newRoot = GetJSONObligatoryFieldByPath(root, std::forward(path)); + return GetJSONObligatoryFieldByPath(newRoot, std::forward(paths)...); +} + +bool JSONIsNull(json_t const * root); +} // namespace base + +template +T FromJSON(json_t const * root) +{ + T result{}; + FromJSON(root, result); + return result; +} + +inline void FromJSON(json_t * root, json_t *& value) { value = root; } +inline void FromJSON(json_t const * root, json_t const *& value) { value = root; } + +void FromJSON(json_t const * root, double & result); +void FromJSON(json_t const * root, bool & result); + +template ::value, void>::type * = nullptr> +void FromJSON(json_t const * root, T & result) +{ + if (!json_is_number(root)) + MYTHROW(base::Json::Exception, ("Object must contain a json number.")); + result = static_cast(json_integer_value(root)); +} + +std::string FromJSONToString(json_t const * root); + +template +T FromJSONObject(json_t const * root, char const * field) +{ + auto const * json = base::GetJSONObligatoryField(root, field); + try + { + return FromJSON(json); + } + catch (base::Json::Exception const & e) + { + MYTHROW(base::Json::Exception, ("An error occured while parsing field", field, e.Msg())); + } +} + +template +void FromJSONObject(json_t * root, std::string const & field, T & result) +{ + auto * json = base::GetJSONObligatoryField(root, field); + try + { + FromJSON(json, result); + } + catch (base::Json::Exception const & e) + { + MYTHROW(base::Json::Exception, ("An error occured while parsing field", field, e.Msg())); + } +} + +template +std::optional FromJSONObjectOptional(json_t const * root, char const * field) +{ + auto * json = base::GetJSONOptionalField(root, field); + if (!json) + return {}; + + std::optional result{T{}}; + FromJSON(json, *result); + return result; +} + +template +void FromJSONObjectOptionalField(json_t const * root, std::string const & field, T & result) +{ + auto * json = base::GetJSONOptionalField(root, field); + if (!json) + { + result = T{}; + return; + } + FromJSON(json, result); +} + +template ::value, void>::type * = nullptr> +inline base::JSONPtr ToJSON(T value) +{ + return base::NewJSONInt(value); +} +inline base::JSONPtr ToJSON(double value) { return base::NewJSONReal(value); } +inline base::JSONPtr ToJSON(bool value) { return base::NewJSONBool(value); } +inline base::JSONPtr ToJSON(char const * s) { return base::NewJSONString(s); } + +template +void ToJSONArray(json_t & root, T const & value) +{ + json_array_append_new(&root, ToJSON(value).release()); +} + +inline void ToJSONArray(json_t & parent, base::JSONPtr & child) +{ + json_array_append_new(&parent, child.release()); +} + +inline void ToJSONArray(json_t & parent, json_t & child) { json_array_append_new(&parent, &child); } + +template +void ToJSONObject(json_t & root, char const * field, T const & value) +{ + json_object_set_new(&root, field, ToJSON(value).release()); +} + +inline void ToJSONObject(json_t & parent, char const * field, base::JSONPtr && child) +{ + json_object_set_new(&parent, field, child.release()); +} + +inline void ToJSONObject(json_t & parent, char const * field, base::JSONPtr & child) +{ + json_object_set_new(&parent, field, child.release()); +} + +inline void ToJSONObject(json_t & parent, char const * field, json_t & child) +{ + json_object_set_new(&parent, field, &child); +} + +template +void ToJSONObject(json_t & root, std::string const & field, T const & value) +{ + ToJSONObject(root, field.c_str(), value); +} + +inline void ToJSONObject(json_t & parent, std::string const & field, base::JSONPtr && child) +{ + ToJSONObject(parent, field.c_str(), std::move(child)); +} + +inline void ToJSONObject(json_t & parent, std::string const & field, base::JSONPtr & child) +{ + ToJSONObject(parent, field.c_str(), child); +} + +inline void ToJSONObject(json_t & parent, std::string const & field, json_t & child) +{ + ToJSONObject(parent, field.c_str(), child); +} + +template +void FromJSONObject(json_t * root, std::string const & field, std::vector & result) +{ + auto * arr = base::GetJSONObligatoryField(root, field); + if (!json_is_array(arr)) + MYTHROW(base::Json::Exception, ("The field", field, "must contain a json array.")); + size_t sz = json_array_size(arr); + result.resize(sz); + for (size_t i = 0; i < sz; ++i) + FromJSON(json_array_get(arr, i), result[i]); +} + +// The function tries to parse array of values from a value +// corresponding to |field| in a json object corresponding to |root|. +// Returns true when the value is non-null and array is successfully +// parsed. Returns false when there is no such |field| in the |root| +// or the value is null. Also, the method may throw an exception in +// case of json parsing errors. +template +bool FromJSONObjectOptional(json_t * root, std::string const & field, std::vector & result) +{ + auto * arr = base::GetJSONOptionalField(root, field); + if (!arr || base::JSONIsNull(arr)) + { + result.clear(); + return false; + } + if (!json_is_array(arr)) + MYTHROW(base::Json::Exception, ("The field", field, "must contain a json array.")); + size_t const sz = json_array_size(arr); + result.resize(sz); + for (size_t i = 0; i < sz; ++i) + FromJSON(json_array_get(arr, i), result[i]); + return true; +} + +template +void ToJSONObject(json_t & root, char const * field, std::vector const & values) +{ + auto arr = base::NewJSONArray(); + for (auto const & value : values) + json_array_append_new(arr.get(), ToJSON(value).release()); + json_object_set_new(&root, field, arr.release()); +} + +template +void ToJSONObject(json_t & root, std::string const & field, std::vector const & values) +{ + ToJSONObject(root, field.c_str(), values); +} + +template +void FromJSONObjectOptionalField(json_t * root, std::string const & field, std::vector & result) +{ + FromJSONObjectOptionalField(const_cast(root), field, result); +} + +template +void FromJSONObjectOptionalField(json_t const * root, std::string const & field, std::vector & result) +{ + json_t const * arr = base::GetJSONOptionalField(root, field); + if (!arr) + { + result.clear(); + return; + } + if (!json_is_array(arr)) + MYTHROW(base::Json::Exception, ("The field", field, "must contain a json array.")); + size_t sz = json_array_size(arr); + result.resize(sz); + for (size_t i = 0; i < sz; ++i) + FromJSON(json_array_get(arr, i), result[i]); +} + +struct JSONFreeDeleter +{ + void operator()(char * buffer) const { free(buffer); } +}; + +namespace std +{ +void FromJSON(json_t const * root, std::string & result); +inline base::JSONPtr ToJSON(std::string const & s) { return base::NewJSONString(s); } +} // namespace std + +namespace strings +{ +void FromJSON(json_t const * root, UniString & result); +base::JSONPtr ToJSON(UniString const & s); +} // namespace strings diff --git a/3party/jansson/release.sh b/3party/jansson/release.sh new file mode 100755 index 0000000000..c2551f8281 --- /dev/null +++ b/3party/jansson/release.sh @@ -0,0 +1,70 @@ +#!/bin/sh +# +# Use this script to easily make releases of Jansson. It configures +# the source tree, and builds and signs all tarballs. + +die() { + echo $1 >&2 + exit 1 +} + +confirm() { + local answer + read -p "$1 [yN]: " answer + [ "$answer" = "Y" -o "$answer" = "y" ] || exit 0 +} + +set -e +[ -f configure.ac ] || die "Must be run at project root directory" + +# Determine version +v=$(grep AC_INIT configure.ac | sed -r 's/.*, \[(.+?)\],.*/\1/') +[ -n "$v" ] || die "Unable to determine version" +confirm "Version is $v, proceed?" + +# Sanity checks +vi=$(grep version-info src/Makefile.am | sed 's/^[ \t]*//g' | cut -d" " -f2) +confirm "Libtool version-info is $vi, proceed?" + +r=$(grep 'Released ' CHANGES | head -n 1) +confirm "Last CHANGES entry says \"$r\", proceed??" + +dv=$(grep ^version doc/conf.py | sed -r "s/.*'(.*)'.*/\1/") +if [ "$dv" != "$v" ]; then + die "Documentation version ($dv) doesn't match library version" +fi + +[ -f Makefile ] && make distclean || true +rm -f jansson-$v.tar.* +rm -rf jansson-$v-doc +rm -f jansson-$v-doc.tar.* + +autoreconf -fi +./configure + +# Run tests and make gz source tarball +: ${VALGRIND:=1} +export VALGRIND +make distcheck + +# Make bzip2 source tarball +make dist-bzip2 + +# Sign source tarballs +for s in gz bz2; do + gpg --detach-sign --armor jansson-$v.tar.$s +done + +# Build documentation +make html +mv doc/_build/html jansson-$v-doc + +# Make and sign documentation tarballs +for s in gz bz2; do + [ $s = gz ] && compress=gzip + [ $s = bz2 ] && compress=bzip2 + tar cf - jansson-$v-doc | $compress -9 -c > jansson-$v-doc.tar.$s + gpg --detach-sign --armor jansson-$v-doc.tar.$s +done + +echo "All done" diff --git a/3party/jansson/src/Makefile.am b/3party/jansson/src/Makefile.am new file mode 100644 index 0000000000..37cfaac4eb --- /dev/null +++ b/3party/jansson/src/Makefile.am @@ -0,0 +1,28 @@ +EXTRA_DIST = jansson.def + +include_HEADERS = jansson.h +nodist_include_HEADERS = jansson_config.h + +lib_LTLIBRARIES = libjansson.la +libjansson_la_SOURCES = \ + dump.c \ + error.c \ + hashtable.c \ + hashtable.h \ + hashtable_seed.c \ + jansson_private.h \ + load.c \ + lookup3.h \ + memory.c \ + pack_unpack.c \ + strbuffer.c \ + strbuffer.h \ + strconv.c \ + utf.c \ + utf.h \ + value.c +libjansson_la_LDFLAGS = \ + -no-undefined \ + -export-symbols-regex '^json_' \ + -version-info 15:1:11 \ + @JSON_BSYMBOLIC_LDFLAGS@ diff --git a/3party/jansson/src/dump.c b/3party/jansson/src/dump.c new file mode 100644 index 0000000000..89802c65dc --- /dev/null +++ b/3party/jansson/src/dump.c @@ -0,0 +1,504 @@ +/* + * Copyright (c) 2009-2016 Petri Lehtinen + * + * Jansson is free software; you can redistribute it and/or modify + * it under the terms of the MIT license. See LICENSE for details. + */ + +#ifndef _GNU_SOURCE +#define _GNU_SOURCE +#endif + +#include "jansson_private.h" + +#include +#include +#include +#include +#ifdef HAVE_UNISTD_H +#include +#endif + +#include "jansson.h" +#include "strbuffer.h" +#include "utf.h" + +#define MAX_INTEGER_STR_LENGTH 100 +#define MAX_REAL_STR_LENGTH 100 + +#define FLAGS_TO_INDENT(f) ((f) & 0x1F) +#define FLAGS_TO_PRECISION(f) (((f) >> 11) & 0x1F) + +struct buffer { + const size_t size; + size_t used; + char *data; +}; + +static int dump_to_strbuffer(const char *buffer, size_t size, void *data) +{ + return strbuffer_append_bytes((strbuffer_t *)data, buffer, size); +} + +static int dump_to_buffer(const char *buffer, size_t size, void *data) +{ + struct buffer *buf = (struct buffer *)data; + + if(buf->used + size <= buf->size) + memcpy(&buf->data[buf->used], buffer, size); + + buf->used += size; + return 0; +} + +static int dump_to_file(const char *buffer, size_t size, void *data) +{ + FILE *dest = (FILE *)data; + if(fwrite(buffer, size, 1, dest) != 1) + return -1; + return 0; +} + +static int dump_to_fd(const char *buffer, size_t size, void *data) +{ +#ifdef HAVE_UNISTD_H + int *dest = (int *)data; + if(write(*dest, buffer, size) == (ssize_t)size) + return 0; +#endif + return -1; +} + +/* 32 spaces (the maximum indentation size) */ +static const char whitespace[] = " "; + +static int dump_indent(size_t flags, int depth, int space, json_dump_callback_t dump, void *data) +{ + if(FLAGS_TO_INDENT(flags) > 0) + { + unsigned int ws_count = FLAGS_TO_INDENT(flags), n_spaces = depth * ws_count; + + if(dump("\n", 1, data)) + return -1; + + while(n_spaces > 0) + { + int cur_n = n_spaces < sizeof whitespace - 1 ? n_spaces : sizeof whitespace - 1; + + if(dump(whitespace, cur_n, data)) + return -1; + + n_spaces -= cur_n; + } + } + else if(space && !(flags & JSON_COMPACT)) + { + return dump(" ", 1, data); + } + return 0; +} + +static int dump_string(const char *str, size_t len, json_dump_callback_t dump, void *data, size_t flags) +{ + const char *pos, *end, *lim; + int32_t codepoint = 0; + + if(dump("\"", 1, data)) + return -1; + + end = pos = str; + lim = str + len; + while(1) + { + const char *text; + char seq[13]; + int length; + + while(end < lim) + { + end = utf8_iterate(pos, lim - pos, &codepoint); + if(!end) + return -1; + + /* mandatory escape or control char */ + if(codepoint == '\\' || codepoint == '"' || codepoint < 0x20) + break; + + /* slash */ + if((flags & JSON_ESCAPE_SLASH) && codepoint == '/') + break; + + /* non-ASCII */ + if((flags & JSON_ENSURE_ASCII) && codepoint > 0x7F) + break; + + pos = end; + } + + if(pos != str) { + if(dump(str, pos - str, data)) + return -1; + } + + if(end == pos) + break; + + /* handle \, /, ", and control codes */ + length = 2; + switch(codepoint) + { + case '\\': text = "\\\\"; break; + case '\"': text = "\\\""; break; + case '\b': text = "\\b"; break; + case '\f': text = "\\f"; break; + case '\n': text = "\\n"; break; + case '\r': text = "\\r"; break; + case '\t': text = "\\t"; break; + case '/': text = "\\/"; break; + default: + { + /* codepoint is in BMP */ + if(codepoint < 0x10000) + { + snprintf(seq, sizeof(seq), "\\u%04X", (unsigned int)codepoint); + length = 6; + } + + /* not in BMP -> construct a UTF-16 surrogate pair */ + else + { + int32_t first, last; + + codepoint -= 0x10000; + first = 0xD800 | ((codepoint & 0xffc00) >> 10); + last = 0xDC00 | (codepoint & 0x003ff); + + snprintf(seq, sizeof(seq), "\\u%04X\\u%04X", (unsigned int)first, (unsigned int)last); + length = 12; + } + + text = seq; + break; + } + } + + if(dump(text, length, data)) + return -1; + + str = pos = end; + } + + return dump("\"", 1, data); +} + +static int compare_keys(const void *key1, const void *key2) +{ + return strcmp(*(const char **)key1, *(const char **)key2); +} + +static int loop_check(hashtable_t *parents, const json_t *json, char *key, size_t key_size) +{ + snprintf(key, key_size, "%p", json); + if (hashtable_get(parents, key)) + return -1; + + return hashtable_set(parents, key, json_null()); +} + +static int do_dump(const json_t *json, size_t flags, int depth, + hashtable_t *parents, json_dump_callback_t dump, void *data) +{ + int embed = flags & JSON_EMBED; + + flags &= ~JSON_EMBED; + + if(!json) + return -1; + + switch(json_typeof(json)) { + case JSON_NULL: + return dump("null", 4, data); + + case JSON_TRUE: + return dump("true", 4, data); + + case JSON_FALSE: + return dump("false", 5, data); + + case JSON_INTEGER: + { + char buffer[MAX_INTEGER_STR_LENGTH]; + int size; + + size = snprintf(buffer, MAX_INTEGER_STR_LENGTH, + "%" JSON_INTEGER_FORMAT, + json_integer_value(json)); + if(size < 0 || size >= MAX_INTEGER_STR_LENGTH) + return -1; + + return dump(buffer, size, data); + } + + case JSON_REAL: + { + char buffer[MAX_REAL_STR_LENGTH]; + int size; + double value = json_real_value(json); + + size = jsonp_dtostr(buffer, MAX_REAL_STR_LENGTH, value, + FLAGS_TO_PRECISION(flags)); + if(size < 0) + return -1; + + return dump(buffer, size, data); + } + + case JSON_STRING: + return dump_string(json_string_value(json), json_string_length(json), dump, data, flags); + + case JSON_ARRAY: + { + size_t n; + size_t i; + /* Space for "0x", double the sizeof a pointer for the hex and a terminator. */ + char key[2 + (sizeof(json) * 2) + 1]; + + /* detect circular references */ + if (loop_check(parents, json, key, sizeof(key))) + return -1; + + n = json_array_size(json); + + if(!embed && dump("[", 1, data)) + return -1; + if(n == 0) { + hashtable_del(parents, key); + return embed ? 0 : dump("]", 1, data); + } + if(dump_indent(flags, depth + 1, 0, dump, data)) + return -1; + + for(i = 0; i < n; ++i) { + if(do_dump(json_array_get(json, i), flags, depth + 1, + parents, dump, data)) + return -1; + + if(i < n - 1) + { + if(dump(",", 1, data) || + dump_indent(flags, depth + 1, 1, dump, data)) + return -1; + } + else + { + if(dump_indent(flags, depth, 0, dump, data)) + return -1; + } + } + + hashtable_del(parents, key); + return embed ? 0 : dump("]", 1, data); + } + + case JSON_OBJECT: + { + void *iter; + const char *separator; + int separator_length; + /* Space for "0x", double the sizeof a pointer for the hex and a terminator. */ + char loop_key[2 + (sizeof(json) * 2) + 1]; + + if(flags & JSON_COMPACT) { + separator = ":"; + separator_length = 1; + } + else { + separator = ": "; + separator_length = 2; + } + + /* detect circular references */ + if (loop_check(parents, json, loop_key, sizeof(loop_key))) + return -1; + + iter = json_object_iter((json_t *)json); + + if(!embed && dump("{", 1, data)) + return -1; + if(!iter) { + hashtable_del(parents, loop_key); + return embed ? 0 : dump("}", 1, data); + } + if(dump_indent(flags, depth + 1, 0, dump, data)) + return -1; + + if(flags & JSON_SORT_KEYS) + { + const char **keys; + size_t size, i; + + size = json_object_size(json); + keys = jsonp_malloc(size * sizeof(const char *)); + if(!keys) + return -1; + + i = 0; + while(iter) + { + keys[i] = json_object_iter_key(iter); + iter = json_object_iter_next((json_t *)json, iter); + i++; + } + assert(i == size); + + qsort(keys, size, sizeof(const char *), compare_keys); + + for(i = 0; i < size; i++) + { + const char *key; + json_t *value; + + key = keys[i]; + value = json_object_get(json, key); + assert(value); + + dump_string(key, strlen(key), dump, data, flags); + if(dump(separator, separator_length, data) || + do_dump(value, flags, depth + 1, parents, dump, data)) + { + jsonp_free(keys); + return -1; + } + + if(i < size - 1) + { + if(dump(",", 1, data) || + dump_indent(flags, depth + 1, 1, dump, data)) + { + jsonp_free(keys); + return -1; + } + } + else + { + if(dump_indent(flags, depth, 0, dump, data)) + { + jsonp_free(keys); + return -1; + } + } + } + + jsonp_free(keys); + } + else + { + /* Don't sort keys */ + + while(iter) + { + void *next = json_object_iter_next((json_t *)json, iter); + const char *key = json_object_iter_key(iter); + + dump_string(key, strlen(key), dump, data, flags); + if(dump(separator, separator_length, data) || + do_dump(json_object_iter_value(iter), flags, depth + 1, + parents, dump, data)) + return -1; + + if(next) + { + if(dump(",", 1, data) || + dump_indent(flags, depth + 1, 1, dump, data)) + return -1; + } + else + { + if(dump_indent(flags, depth, 0, dump, data)) + return -1; + } + + iter = next; + } + } + + hashtable_del(parents, loop_key); + return embed ? 0 : dump("}", 1, data); + } + + default: + /* not reached */ + return -1; + } +} + +char *json_dumps(const json_t *json, size_t flags) +{ + strbuffer_t strbuff; + char *result; + + if(strbuffer_init(&strbuff)) + return NULL; + + if(json_dump_callback(json, dump_to_strbuffer, (void *)&strbuff, flags)) + result = NULL; + else + result = jsonp_strdup(strbuffer_value(&strbuff)); + + strbuffer_close(&strbuff); + return result; +} + +size_t json_dumpb(const json_t *json, char *buffer, size_t size, size_t flags) +{ + struct buffer buf = { size, 0, buffer }; + + if(json_dump_callback(json, dump_to_buffer, (void *)&buf, flags)) + return 0; + + return buf.used; +} + +int json_dumpf(const json_t *json, FILE *output, size_t flags) +{ + return json_dump_callback(json, dump_to_file, (void *)output, flags); +} + +int json_dumpfd(const json_t *json, int output, size_t flags) +{ + return json_dump_callback(json, dump_to_fd, (void *)&output, flags); +} + +int json_dump_file(const json_t *json, const char *path, size_t flags) +{ + int result; + + FILE *output = fopen(path, "w"); + if(!output) + return -1; + + result = json_dumpf(json, output, flags); + + if(fclose(output) != 0) + return -1; + + return result; +} + +int json_dump_callback(const json_t *json, json_dump_callback_t callback, void *data, size_t flags) +{ + int res; + hashtable_t parents_set; + + if(!(flags & JSON_ENCODE_ANY)) { + if(!json_is_array(json) && !json_is_object(json)) + return -1; + } + + if (hashtable_init(&parents_set)) + return -1; + res = do_dump(json, flags, 0, &parents_set, callback, data); + hashtable_close(&parents_set); + + return res; +} diff --git a/3party/jansson/src/error.c b/3party/jansson/src/error.c new file mode 100644 index 0000000000..f5da6b9b0a --- /dev/null +++ b/3party/jansson/src/error.c @@ -0,0 +1,66 @@ +#include +#include "jansson_private.h" + +void jsonp_error_init(json_error_t *error, const char *source) +{ + if(error) + { + error->text[0] = '\0'; + error->line = -1; + error->column = -1; + error->position = 0; + if(source) + jsonp_error_set_source(error, source); + else + error->source[0] = '\0'; + } +} + +void jsonp_error_set_source(json_error_t *error, const char *source) +{ + size_t length; + + if(!error || !source) + return; + + length = strlen(source); + if(length < JSON_ERROR_SOURCE_LENGTH) + strncpy(error->source, source, length + 1); + else { + size_t extra = length - JSON_ERROR_SOURCE_LENGTH + 4; + memcpy(error->source, "...", 3); + strncpy(error->source + 3, source + extra, length - extra + 1); + } +} + +void jsonp_error_set(json_error_t *error, int line, int column, + size_t position, enum json_error_code code, + const char *msg, ...) +{ + va_list ap; + + va_start(ap, msg); + jsonp_error_vset(error, line, column, position, code, msg, ap); + va_end(ap); +} + +void jsonp_error_vset(json_error_t *error, int line, int column, + size_t position, enum json_error_code code, + const char *msg, va_list ap) +{ + if(!error) + return; + + if(error->text[0] != '\0') { + /* error already set */ + return; + } + + error->line = line; + error->column = column; + error->position = (int)position; + + vsnprintf(error->text, JSON_ERROR_TEXT_LENGTH - 1, msg, ap); + error->text[JSON_ERROR_TEXT_LENGTH - 2] = '\0'; + error->text[JSON_ERROR_TEXT_LENGTH - 1] = code; +} diff --git a/3party/jansson/src/hashtable.c b/3party/jansson/src/hashtable.c new file mode 100644 index 0000000000..c819319a76 --- /dev/null +++ b/3party/jansson/src/hashtable.c @@ -0,0 +1,356 @@ +/* + * Copyright (c) 2009-2016 Petri Lehtinen + * + * This library is free software; you can redistribute it and/or modify + * it under the terms of the MIT license. See LICENSE for details. + */ + +#if HAVE_CONFIG_H +#include +#endif + +#include +#include + +#if HAVE_STDINT_H +#include +#endif + +#include /* for JSON_INLINE */ +#include "jansson_private.h" /* for container_of() */ +#include "hashtable.h" + +#ifndef INITIAL_HASHTABLE_ORDER +#define INITIAL_HASHTABLE_ORDER 3 +#endif + +typedef struct hashtable_list list_t; +typedef struct hashtable_pair pair_t; +typedef struct hashtable_bucket bucket_t; + +extern volatile uint32_t hashtable_seed; + +/* Implementation of the hash function */ +#include "lookup3.h" + +#define list_to_pair(list_) container_of(list_, pair_t, list) +#define ordered_list_to_pair(list_) container_of(list_, pair_t, ordered_list) +#define hash_str(key) ((size_t)hashlittle((key), strlen(key), hashtable_seed)) + +static JSON_INLINE void list_init(list_t *list) +{ + list->next = list; + list->prev = list; +} + +static JSON_INLINE void list_insert(list_t *list, list_t *node) +{ + node->next = list; + node->prev = list->prev; + list->prev->next = node; + list->prev = node; +} + +static JSON_INLINE void list_remove(list_t *list) +{ + list->prev->next = list->next; + list->next->prev = list->prev; +} + +static JSON_INLINE int bucket_is_empty(hashtable_t *hashtable, bucket_t *bucket) +{ + return bucket->first == &hashtable->list && bucket->first == bucket->last; +} + +static void insert_to_bucket(hashtable_t *hashtable, bucket_t *bucket, + list_t *list) +{ + if(bucket_is_empty(hashtable, bucket)) + { + list_insert(&hashtable->list, list); + bucket->first = bucket->last = list; + } + else + { + list_insert(bucket->first, list); + bucket->first = list; + } +} + +static pair_t *hashtable_find_pair(hashtable_t *hashtable, bucket_t *bucket, + const char *key, size_t hash) +{ + list_t *list; + pair_t *pair; + + if(bucket_is_empty(hashtable, bucket)) + return NULL; + + list = bucket->first; + while(1) + { + pair = list_to_pair(list); + if(pair->hash == hash && strcmp(pair->key, key) == 0) + return pair; + + if(list == bucket->last) + break; + + list = list->next; + } + + return NULL; +} + +/* returns 0 on success, -1 if key was not found */ +static int hashtable_do_del(hashtable_t *hashtable, + const char *key, size_t hash) +{ + pair_t *pair; + bucket_t *bucket; + size_t index; + + index = hash & hashmask(hashtable->order); + bucket = &hashtable->buckets[index]; + + pair = hashtable_find_pair(hashtable, bucket, key, hash); + if(!pair) + return -1; + + if(&pair->list == bucket->first && &pair->list == bucket->last) + bucket->first = bucket->last = &hashtable->list; + + else if(&pair->list == bucket->first) + bucket->first = pair->list.next; + + else if(&pair->list == bucket->last) + bucket->last = pair->list.prev; + + list_remove(&pair->list); + list_remove(&pair->ordered_list); + json_decref(pair->value); + + jsonp_free(pair); + hashtable->size--; + + return 0; +} + +static void hashtable_do_clear(hashtable_t *hashtable) +{ + list_t *list, *next; + pair_t *pair; + + for(list = hashtable->list.next; list != &hashtable->list; list = next) + { + next = list->next; + pair = list_to_pair(list); + json_decref(pair->value); + jsonp_free(pair); + } +} + +static int hashtable_do_rehash(hashtable_t *hashtable) +{ + list_t *list, *next; + pair_t *pair; + size_t i, index, new_size, new_order; + struct hashtable_bucket *new_buckets; + + new_order = hashtable->order + 1; + new_size = hashsize(new_order); + + new_buckets = jsonp_malloc(new_size * sizeof(bucket_t)); + if(!new_buckets) + return -1; + + jsonp_free(hashtable->buckets); + hashtable->buckets = new_buckets; + hashtable->order = new_order; + + for(i = 0; i < hashsize(hashtable->order); i++) + { + hashtable->buckets[i].first = hashtable->buckets[i].last = + &hashtable->list; + } + + list = hashtable->list.next; + list_init(&hashtable->list); + + for(; list != &hashtable->list; list = next) { + next = list->next; + pair = list_to_pair(list); + index = pair->hash % new_size; + insert_to_bucket(hashtable, &hashtable->buckets[index], &pair->list); + } + + return 0; +} + + +int hashtable_init(hashtable_t *hashtable) +{ + size_t i; + + hashtable->size = 0; + hashtable->order = INITIAL_HASHTABLE_ORDER; + hashtable->buckets = jsonp_malloc(hashsize(hashtable->order) * sizeof(bucket_t)); + if(!hashtable->buckets) + return -1; + + list_init(&hashtable->list); + list_init(&hashtable->ordered_list); + + for(i = 0; i < hashsize(hashtable->order); i++) + { + hashtable->buckets[i].first = hashtable->buckets[i].last = + &hashtable->list; + } + + return 0; +} + +void hashtable_close(hashtable_t *hashtable) +{ + hashtable_do_clear(hashtable); + jsonp_free(hashtable->buckets); +} + +int hashtable_set(hashtable_t *hashtable, const char *key, json_t *value) +{ + pair_t *pair; + bucket_t *bucket; + size_t hash, index; + + /* rehash if the load ratio exceeds 1 */ + if(hashtable->size >= hashsize(hashtable->order)) + if(hashtable_do_rehash(hashtable)) + return -1; + + hash = hash_str(key); + index = hash & hashmask(hashtable->order); + bucket = &hashtable->buckets[index]; + pair = hashtable_find_pair(hashtable, bucket, key, hash); + + if(pair) + { + json_decref(pair->value); + pair->value = value; + } + else + { + /* offsetof(...) returns the size of pair_t without the last, + flexible member. This way, the correct amount is + allocated. */ + + size_t len = strlen(key); + if(len >= (size_t)-1 - offsetof(pair_t, key)) { + /* Avoid an overflow if the key is very long */ + return -1; + } + + pair = jsonp_malloc(offsetof(pair_t, key) + len + 1); + if(!pair) + return -1; + + pair->hash = hash; + strncpy(pair->key, key, len + 1); + pair->value = value; + list_init(&pair->list); + list_init(&pair->ordered_list); + + insert_to_bucket(hashtable, bucket, &pair->list); + list_insert(&hashtable->ordered_list, &pair->ordered_list); + + hashtable->size++; + } + return 0; +} + +void *hashtable_get(hashtable_t *hashtable, const char *key) +{ + pair_t *pair; + size_t hash; + bucket_t *bucket; + + hash = hash_str(key); + bucket = &hashtable->buckets[hash & hashmask(hashtable->order)]; + + pair = hashtable_find_pair(hashtable, bucket, key, hash); + if(!pair) + return NULL; + + return pair->value; +} + +int hashtable_del(hashtable_t *hashtable, const char *key) +{ + size_t hash = hash_str(key); + return hashtable_do_del(hashtable, key, hash); +} + +void hashtable_clear(hashtable_t *hashtable) +{ + size_t i; + + hashtable_do_clear(hashtable); + + for(i = 0; i < hashsize(hashtable->order); i++) + { + hashtable->buckets[i].first = hashtable->buckets[i].last = + &hashtable->list; + } + + list_init(&hashtable->list); + list_init(&hashtable->ordered_list); + hashtable->size = 0; +} + +void *hashtable_iter(hashtable_t *hashtable) +{ + return hashtable_iter_next(hashtable, &hashtable->ordered_list); +} + +void *hashtable_iter_at(hashtable_t *hashtable, const char *key) +{ + pair_t *pair; + size_t hash; + bucket_t *bucket; + + hash = hash_str(key); + bucket = &hashtable->buckets[hash & hashmask(hashtable->order)]; + + pair = hashtable_find_pair(hashtable, bucket, key, hash); + if(!pair) + return NULL; + + return &pair->ordered_list; +} + +void *hashtable_iter_next(hashtable_t *hashtable, void *iter) +{ + list_t *list = (list_t *)iter; + if(list->next == &hashtable->ordered_list) + return NULL; + return list->next; +} + +void *hashtable_iter_key(void *iter) +{ + pair_t *pair = ordered_list_to_pair((list_t *)iter); + return pair->key; +} + +void *hashtable_iter_value(void *iter) +{ + pair_t *pair = ordered_list_to_pair((list_t *)iter); + return pair->value; +} + +void hashtable_iter_set(void *iter, json_t *value) +{ + pair_t *pair = ordered_list_to_pair((list_t *)iter); + + json_decref(pair->value); + pair->value = value; +} diff --git a/3party/jansson/src/hashtable.h b/3party/jansson/src/hashtable.h new file mode 100644 index 0000000000..c112834085 --- /dev/null +++ b/3party/jansson/src/hashtable.h @@ -0,0 +1,176 @@ +/* + * Copyright (c) 2009-2016 Petri Lehtinen + * + * This library is free software; you can redistribute it and/or modify + * it under the terms of the MIT license. See LICENSE for details. + */ + +#ifndef HASHTABLE_H +#define HASHTABLE_H + +#include +#include "jansson.h" + +struct hashtable_list { + struct hashtable_list *prev; + struct hashtable_list *next; +}; + +/* "pair" may be a bit confusing a name, but think of it as a + key-value pair. In this case, it just encodes some extra data, + too */ +struct hashtable_pair { + struct hashtable_list list; + struct hashtable_list ordered_list; + size_t hash; + json_t *value; + char key[1]; +}; + +struct hashtable_bucket { + struct hashtable_list *first; + struct hashtable_list *last; +}; + +typedef struct hashtable { + size_t size; + struct hashtable_bucket *buckets; + size_t order; /* hashtable has pow(2, order) buckets */ + struct hashtable_list list; + struct hashtable_list ordered_list; +} hashtable_t; + + +#define hashtable_key_to_iter(key_) \ + (&(container_of(key_, struct hashtable_pair, key)->ordered_list)) + + +/** + * hashtable_init - Initialize a hashtable object + * + * @hashtable: The (statically allocated) hashtable object + * + * Initializes a statically allocated hashtable object. The object + * should be cleared with hashtable_close when it's no longer used. + * + * Returns 0 on success, -1 on error (out of memory). + */ +int hashtable_init(hashtable_t *hashtable) JANSSON_ATTRS(warn_unused_result); + +/** + * hashtable_close - Release all resources used by a hashtable object + * + * @hashtable: The hashtable + * + * Destroys a statically allocated hashtable object. + */ +void hashtable_close(hashtable_t *hashtable); + +/** + * hashtable_set - Add/modify value in hashtable + * + * @hashtable: The hashtable object + * @key: The key + * @serial: For addition order of keys + * @value: The value + * + * If a value with the given key already exists, its value is replaced + * with the new value. Value is "stealed" in the sense that hashtable + * doesn't increment its refcount but decreases the refcount when the + * value is no longer needed. + * + * Returns 0 on success, -1 on failure (out of memory). + */ +int hashtable_set(hashtable_t *hashtable, const char *key, json_t *value); + +/** + * hashtable_get - Get a value associated with a key + * + * @hashtable: The hashtable object + * @key: The key + * + * Returns value if it is found, or NULL otherwise. + */ +void *hashtable_get(hashtable_t *hashtable, const char *key); + +/** + * hashtable_del - Remove a value from the hashtable + * + * @hashtable: The hashtable object + * @key: The key + * + * Returns 0 on success, or -1 if the key was not found. + */ +int hashtable_del(hashtable_t *hashtable, const char *key); + +/** + * hashtable_clear - Clear hashtable + * + * @hashtable: The hashtable object + * + * Removes all items from the hashtable. + */ +void hashtable_clear(hashtable_t *hashtable); + +/** + * hashtable_iter - Iterate over hashtable + * + * @hashtable: The hashtable object + * + * Returns an opaque iterator to the first element in the hashtable. + * The iterator should be passed to hashtable_iter_* functions. + * The hashtable items are not iterated over in any particular order. + * + * There's no need to free the iterator in any way. The iterator is + * valid as long as the item that is referenced by the iterator is not + * deleted. Other values may be added or deleted. In particular, + * hashtable_iter_next() may be called on an iterator, and after that + * the key/value pair pointed by the old iterator may be deleted. + */ +void *hashtable_iter(hashtable_t *hashtable); + +/** + * hashtable_iter_at - Return an iterator at a specific key + * + * @hashtable: The hashtable object + * @key: The key that the iterator should point to + * + * Like hashtable_iter() but returns an iterator pointing to a + * specific key. + */ +void *hashtable_iter_at(hashtable_t *hashtable, const char *key); + +/** + * hashtable_iter_next - Advance an iterator + * + * @hashtable: The hashtable object + * @iter: The iterator + * + * Returns a new iterator pointing to the next element in the + * hashtable or NULL if the whole hastable has been iterated over. + */ +void *hashtable_iter_next(hashtable_t *hashtable, void *iter); + +/** + * hashtable_iter_key - Retrieve the key pointed by an iterator + * + * @iter: The iterator + */ +void *hashtable_iter_key(void *iter); + +/** + * hashtable_iter_value - Retrieve the value pointed by an iterator + * + * @iter: The iterator + */ +void *hashtable_iter_value(void *iter); + +/** + * hashtable_iter_set - Set the value pointed by an iterator + * + * @iter: The iterator + * @value: The value to set + */ +void hashtable_iter_set(void *iter, json_t *value); + +#endif diff --git a/3party/jansson/src/hashtable_seed.c b/3party/jansson/src/hashtable_seed.c new file mode 100644 index 0000000000..540358ada7 --- /dev/null +++ b/3party/jansson/src/hashtable_seed.c @@ -0,0 +1,277 @@ +/* Generate sizeof(uint32_t) bytes of as random data as possible to seed + the hash function. +*/ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include + +#ifdef HAVE_STDINT_H +#include +#endif + +#ifdef HAVE_FCNTL_H +#include +#endif + +#ifdef HAVE_SCHED_H +#include +#endif + +#ifdef HAVE_UNISTD_H +#include +#endif + +#ifdef HAVE_SYS_STAT_H +#include +#endif + +#ifdef HAVE_SYS_TIME_H +#include +#endif + +#ifdef HAVE_SYS_TYPES_H +#include +#endif + +#if defined(_WIN32) +/* For GetModuleHandle(), GetProcAddress() and GetCurrentProcessId() */ +#include +#endif + +#include "jansson.h" + + +static uint32_t buf_to_uint32(char *data) { + size_t i; + uint32_t result = 0; + + for (i = 0; i < sizeof(uint32_t); i++) + result = (result << 8) | (unsigned char)data[i]; + + return result; +} + + + +/* /dev/urandom */ +#if !defined(_WIN32) && defined(USE_URANDOM) +static int seed_from_urandom(uint32_t *seed) { + /* Use unbuffered I/O if we have open(), close() and read(). Otherwise + fall back to fopen() */ + + char data[sizeof(uint32_t)]; + int ok; + +#if defined(HAVE_OPEN) && defined(HAVE_CLOSE) && defined(HAVE_READ) + int urandom; + urandom = open("/dev/urandom", O_RDONLY); + if (urandom == -1) + return 1; + + ok = read(urandom, data, sizeof(uint32_t)) == sizeof(uint32_t); + close(urandom); +#else + FILE *urandom; + + urandom = fopen("/dev/urandom", "rb"); + if (!urandom) + return 1; + + ok = fread(data, 1, sizeof(uint32_t), urandom) == sizeof(uint32_t); + fclose(urandom); +#endif + + if (!ok) + return 1; + + *seed = buf_to_uint32(data); + return 0; +} +#endif + +/* Windows Crypto API */ +#if defined(_WIN32) && defined(USE_WINDOWS_CRYPTOAPI) +#include + +typedef BOOL (WINAPI *CRYPTACQUIRECONTEXTA)(HCRYPTPROV *phProv, LPCSTR pszContainer, LPCSTR pszProvider, DWORD dwProvType, DWORD dwFlags); +typedef BOOL (WINAPI *CRYPTGENRANDOM)(HCRYPTPROV hProv, DWORD dwLen, BYTE *pbBuffer); +typedef BOOL (WINAPI *CRYPTRELEASECONTEXT)(HCRYPTPROV hProv, DWORD dwFlags); + +static int seed_from_windows_cryptoapi(uint32_t *seed) +{ + HINSTANCE hAdvAPI32 = NULL; + CRYPTACQUIRECONTEXTA pCryptAcquireContext = NULL; + CRYPTGENRANDOM pCryptGenRandom = NULL; + CRYPTRELEASECONTEXT pCryptReleaseContext = NULL; + HCRYPTPROV hCryptProv = 0; + BYTE data[sizeof(uint32_t)]; + int ok; + + hAdvAPI32 = GetModuleHandle(TEXT("advapi32.dll")); + if(hAdvAPI32 == NULL) + return 1; + + pCryptAcquireContext = (CRYPTACQUIRECONTEXTA)GetProcAddress(hAdvAPI32, "CryptAcquireContextA"); + if (!pCryptAcquireContext) + return 1; + + pCryptGenRandom = (CRYPTGENRANDOM)GetProcAddress(hAdvAPI32, "CryptGenRandom"); + if (!pCryptGenRandom) + return 1; + + pCryptReleaseContext = (CRYPTRELEASECONTEXT)GetProcAddress(hAdvAPI32, "CryptReleaseContext"); + if (!pCryptReleaseContext) + return 1; + + if (!pCryptAcquireContext(&hCryptProv, NULL, NULL, PROV_RSA_FULL, CRYPT_VERIFYCONTEXT)) + return 1; + + ok = pCryptGenRandom(hCryptProv, sizeof(uint32_t), data); + pCryptReleaseContext(hCryptProv, 0); + + if (!ok) + return 1; + + *seed = buf_to_uint32((char *)data); + return 0; +} +#endif + +/* gettimeofday() and getpid() */ +static int seed_from_timestamp_and_pid(uint32_t *seed) { +#ifdef HAVE_GETTIMEOFDAY + /* XOR of seconds and microseconds */ + struct timeval tv; + gettimeofday(&tv, NULL); + *seed = (uint32_t)tv.tv_sec ^ (uint32_t)tv.tv_usec; +#else + /* Seconds only */ + *seed = (uint32_t)time(NULL); +#endif + + /* XOR with PID for more randomness */ +#if defined(_WIN32) + *seed ^= (uint32_t)GetCurrentProcessId(); +#elif defined(HAVE_GETPID) + *seed ^= (uint32_t)getpid(); +#endif + + return 0; +} + +static uint32_t generate_seed() { + uint32_t seed = 0; + int done = 0; + +#if !defined(_WIN32) && defined(USE_URANDOM) + if (seed_from_urandom(&seed) == 0) + done = 1; +#endif + +#if defined(_WIN32) && defined(USE_WINDOWS_CRYPTOAPI) + if (seed_from_windows_cryptoapi(&seed) == 0) + done = 1; +#endif + + if (!done) { + /* Fall back to timestamp and PID if no better randomness is + available */ + seed_from_timestamp_and_pid(&seed); + } + + /* Make sure the seed is never zero */ + if (seed == 0) + seed = 1; + + return seed; +} + + +volatile uint32_t hashtable_seed = 0; + +#if defined(HAVE_ATOMIC_BUILTINS) && (defined(HAVE_SCHED_YIELD) || !defined(_WIN32)) +static volatile char seed_initialized = 0; + +void json_object_seed(size_t seed) { + uint32_t new_seed = (uint32_t)seed; + + if (hashtable_seed == 0) { + if (__atomic_test_and_set(&seed_initialized, __ATOMIC_RELAXED) == 0) { + /* Do the seeding ourselves */ + if (new_seed == 0) + new_seed = generate_seed(); + + __atomic_store_n(&hashtable_seed, new_seed, __ATOMIC_RELEASE); + } else { + /* Wait for another thread to do the seeding */ + do { +#ifdef HAVE_SCHED_YIELD + sched_yield(); +#endif + } while(__atomic_load_n(&hashtable_seed, __ATOMIC_ACQUIRE) == 0); + } + } +} +#elif defined(HAVE_SYNC_BUILTINS) && (defined(HAVE_SCHED_YIELD) || !defined(_WIN32)) +void json_object_seed(size_t seed) { + uint32_t new_seed = (uint32_t)seed; + + if (hashtable_seed == 0) { + if (new_seed == 0) { + /* Explicit synchronization fences are not supported by the + __sync builtins, so every thread getting here has to + generate the seed value. + */ + new_seed = generate_seed(); + } + + do { + if (__sync_bool_compare_and_swap(&hashtable_seed, 0, new_seed)) { + /* We were the first to seed */ + break; + } else { + /* Wait for another thread to do the seeding */ +#ifdef HAVE_SCHED_YIELD + sched_yield(); +#endif + } + } while(hashtable_seed == 0); + } +} +#elif defined(_WIN32) +static long seed_initialized = 0; +void json_object_seed(size_t seed) { + uint32_t new_seed = (uint32_t)seed; + + if (hashtable_seed == 0) { + if (InterlockedIncrement(&seed_initialized) == 1) { + /* Do the seeding ourselves */ + if (new_seed == 0) + new_seed = generate_seed(); + + hashtable_seed = new_seed; + } else { + /* Wait for another thread to do the seeding */ + do { + SwitchToThread(); + } while (hashtable_seed == 0); + } + } +} +#else +/* Fall back to a thread-unsafe version */ +void json_object_seed(size_t seed) { + uint32_t new_seed = (uint32_t)seed; + + if (hashtable_seed == 0) { + if (new_seed == 0) + new_seed = generate_seed(); + + hashtable_seed = new_seed; + } +} +#endif diff --git a/3party/jansson/src/jansson.def b/3party/jansson/src/jansson.def new file mode 100644 index 0000000000..15f35c95e5 --- /dev/null +++ b/3party/jansson/src/jansson.def @@ -0,0 +1,75 @@ +EXPORTS + json_delete + json_true + json_false + json_null + json_sprintf + json_vsprintf + json_string + json_stringn + json_string_nocheck + json_stringn_nocheck + json_string_value + json_string_length + json_string_set + json_string_setn + json_string_set_nocheck + json_string_setn_nocheck + json_integer + json_integer_value + json_integer_set + json_real + json_real_value + json_real_set + json_number_value + json_array + json_array_size + json_array_get + json_array_set_new + json_array_append_new + json_array_insert_new + json_array_remove + json_array_clear + json_array_extend + json_object + json_object_size + json_object_get + json_object_set_new + json_object_set_new_nocheck + json_object_del + json_object_clear + json_object_update + json_object_update_existing + json_object_update_missing + json_object_iter + json_object_iter_at + json_object_iter_next + json_object_iter_key + json_object_iter_value + json_object_iter_set_new + json_object_key_to_iter + json_object_seed + json_dumps + json_dumpb + json_dumpf + json_dumpfd + json_dump_file + json_dump_callback + json_loads + json_loadb + json_loadf + json_loadfd + json_load_file + json_load_callback + json_equal + json_copy + json_deep_copy + json_pack + json_pack_ex + json_vpack_ex + json_unpack + json_unpack_ex + json_vunpack_ex + json_set_alloc_funcs + json_get_alloc_funcs + diff --git a/3party/jansson/src/jansson.h b/3party/jansson/src/jansson.h new file mode 100644 index 0000000000..a7b8a9c584 --- /dev/null +++ b/3party/jansson/src/jansson.h @@ -0,0 +1,367 @@ +/* + * Copyright (c) 2009-2016 Petri Lehtinen + * + * Jansson is free software; you can redistribute it and/or modify + * it under the terms of the MIT license. See LICENSE for details. + */ + +#ifndef JANSSON_H +#define JANSSON_H + +#include +#include /* for size_t */ +#include + +#include "jansson_config.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/* version */ + +#define JANSSON_MAJOR_VERSION 2 +#define JANSSON_MINOR_VERSION 12 +#define JANSSON_MICRO_VERSION 0 + +/* Micro version is omitted if it's 0 */ +#define JANSSON_VERSION "2.12" + +/* Version as a 3-byte hex number, e.g. 0x010201 == 1.2.1. Use this + for numeric comparisons, e.g. #if JANSSON_VERSION_HEX >= ... */ +#define JANSSON_VERSION_HEX ((JANSSON_MAJOR_VERSION << 16) | \ + (JANSSON_MINOR_VERSION << 8) | \ + (JANSSON_MICRO_VERSION << 0)) + +/* If __atomic or __sync builtins are available the library is thread + * safe for all read-only functions plus reference counting. */ +#if JSON_HAVE_ATOMIC_BUILTINS || JSON_HAVE_SYNC_BUILTINS +#define JANSSON_THREAD_SAFE_REFCOUNT 1 +#endif + +#if defined(__GNUC__) || defined(__clang__) +#define JANSSON_ATTRS(...) __attribute__((__VA_ARGS__)) +#else +#define JANSSON_ATTRS(...) +#endif + +/* types */ + +typedef enum { + JSON_OBJECT, + JSON_ARRAY, + JSON_STRING, + JSON_INTEGER, + JSON_REAL, + JSON_TRUE, + JSON_FALSE, + JSON_NULL +} json_type; + +typedef struct json_struct_t { + json_type type; + volatile size_t refcount; +} json_t; + +#ifndef JANSSON_USING_CMAKE /* disabled if using cmake */ +#if JSON_INTEGER_IS_LONG_LONG +#ifdef _WIN32 +#define JSON_INTEGER_FORMAT "I64d" +#else +#define JSON_INTEGER_FORMAT "lld" +#endif +typedef long long json_int_t; +#else +#define JSON_INTEGER_FORMAT "ld" +typedef long json_int_t; +#endif /* JSON_INTEGER_IS_LONG_LONG */ +#endif + +#define json_typeof(json) ((json)->type) +#define json_is_object(json) ((json) && json_typeof(json) == JSON_OBJECT) +#define json_is_array(json) ((json) && json_typeof(json) == JSON_ARRAY) +#define json_is_string(json) ((json) && json_typeof(json) == JSON_STRING) +#define json_is_integer(json) ((json) && json_typeof(json) == JSON_INTEGER) +#define json_is_real(json) ((json) && json_typeof(json) == JSON_REAL) +#define json_is_number(json) (json_is_integer(json) || json_is_real(json)) +#define json_is_true(json) ((json) && json_typeof(json) == JSON_TRUE) +#define json_is_false(json) ((json) && json_typeof(json) == JSON_FALSE) +#define json_boolean_value json_is_true +#define json_is_boolean(json) (json_is_true(json) || json_is_false(json)) +#define json_is_null(json) ((json) && json_typeof(json) == JSON_NULL) + +/* construction, destruction, reference counting */ + +json_t *json_object(void); +json_t *json_array(void); +json_t *json_string(const char *value); +json_t *json_stringn(const char *value, size_t len); +json_t *json_string_nocheck(const char *value); +json_t *json_stringn_nocheck(const char *value, size_t len); +json_t *json_integer(json_int_t value); +json_t *json_real(double value); +json_t *json_true(void); +json_t *json_false(void); +#define json_boolean(val) ((val) ? json_true() : json_false()) +json_t *json_null(void); + +/* do not call JSON_INTERNAL_INCREF or JSON_INTERNAL_DECREF directly */ +#if JSON_HAVE_ATOMIC_BUILTINS +#define JSON_INTERNAL_INCREF(json) __atomic_add_fetch(&json->refcount, 1, __ATOMIC_ACQUIRE) +#define JSON_INTERNAL_DECREF(json) __atomic_sub_fetch(&json->refcount, 1, __ATOMIC_RELEASE) +#elif JSON_HAVE_SYNC_BUILTINS +#define JSON_INTERNAL_INCREF(json) __sync_add_and_fetch(&json->refcount, 1) +#define JSON_INTERNAL_DECREF(json) __sync_sub_and_fetch(&json->refcount, 1) +#else +#define JSON_INTERNAL_INCREF(json) (++json->refcount) +#define JSON_INTERNAL_DECREF(json) (--json->refcount) +#endif + +static JSON_INLINE +json_t *json_incref(json_t *json) +{ + if(json && json->refcount != (size_t)-1) + JSON_INTERNAL_INCREF(json); + return json; +} + +/* do not call json_delete directly */ +void json_delete(json_t *json); + +static JSON_INLINE +void json_decref(json_t *json) +{ + if(json && json->refcount != (size_t)-1 && JSON_INTERNAL_DECREF(json) == 0) + json_delete(json); +} + +#if defined(__GNUC__) || defined(__clang__) +static JSON_INLINE +void json_decrefp(json_t **json) +{ + if(json) { + json_decref(*json); + *json = NULL; + } +} + +#define json_auto_t json_t __attribute__((cleanup(json_decrefp))) +#endif + + +/* error reporting */ + +#define JSON_ERROR_TEXT_LENGTH 160 +#define JSON_ERROR_SOURCE_LENGTH 80 + +typedef struct json_error_t { + int line; + int column; + int position; + char source[JSON_ERROR_SOURCE_LENGTH]; + char text[JSON_ERROR_TEXT_LENGTH]; +} json_error_t; + +enum json_error_code { + json_error_unknown, + json_error_out_of_memory, + json_error_stack_overflow, + json_error_cannot_open_file, + json_error_invalid_argument, + json_error_invalid_utf8, + json_error_premature_end_of_input, + json_error_end_of_input_expected, + json_error_invalid_syntax, + json_error_invalid_format, + json_error_wrong_type, + json_error_null_character, + json_error_null_value, + json_error_null_byte_in_key, + json_error_duplicate_key, + json_error_numeric_overflow, + json_error_item_not_found, + json_error_index_out_of_range +}; + +static JSON_INLINE enum json_error_code json_error_code(const json_error_t *e) { + return (enum json_error_code)e->text[JSON_ERROR_TEXT_LENGTH - 1]; +} + +/* getters, setters, manipulation */ + +void json_object_seed(size_t seed); +size_t json_object_size(const json_t *object); +json_t *json_object_get(const json_t *object, const char *key) JANSSON_ATTRS(warn_unused_result); +int json_object_set_new(json_t *object, const char *key, json_t *value); +int json_object_set_new_nocheck(json_t *object, const char *key, json_t *value); +int json_object_del(json_t *object, const char *key); +int json_object_clear(json_t *object); +int json_object_update(json_t *object, json_t *other); +int json_object_update_existing(json_t *object, json_t *other); +int json_object_update_missing(json_t *object, json_t *other); +void *json_object_iter(json_t *object); +void *json_object_iter_at(json_t *object, const char *key); +void *json_object_key_to_iter(const char *key); +void *json_object_iter_next(json_t *object, void *iter); +const char *json_object_iter_key(void *iter); +json_t *json_object_iter_value(void *iter); +int json_object_iter_set_new(json_t *object, void *iter, json_t *value); + +#define json_object_foreach(object, key, value) \ + for(key = json_object_iter_key(json_object_iter(object)); \ + key && (value = json_object_iter_value(json_object_key_to_iter(key))); \ + key = json_object_iter_key(json_object_iter_next(object, json_object_key_to_iter(key)))) + +#define json_object_foreach_safe(object, n, key, value) \ + for(key = json_object_iter_key(json_object_iter(object)), \ + n = json_object_iter_next(object, json_object_key_to_iter(key)); \ + key && (value = json_object_iter_value(json_object_key_to_iter(key))); \ + key = json_object_iter_key(n), \ + n = json_object_iter_next(object, json_object_key_to_iter(key))) + +#define json_array_foreach(array, index, value) \ + for(index = 0; \ + index < json_array_size(array) && (value = json_array_get(array, index)); \ + index++) + +static JSON_INLINE +int json_object_set(json_t *object, const char *key, json_t *value) +{ + return json_object_set_new(object, key, json_incref(value)); +} + +static JSON_INLINE +int json_object_set_nocheck(json_t *object, const char *key, json_t *value) +{ + return json_object_set_new_nocheck(object, key, json_incref(value)); +} + +static JSON_INLINE +int json_object_iter_set(json_t *object, void *iter, json_t *value) +{ + return json_object_iter_set_new(object, iter, json_incref(value)); +} + +size_t json_array_size(const json_t *array); +json_t *json_array_get(const json_t *array, size_t index) JANSSON_ATTRS(warn_unused_result); +int json_array_set_new(json_t *array, size_t index, json_t *value); +int json_array_append_new(json_t *array, json_t *value); +int json_array_insert_new(json_t *array, size_t index, json_t *value); +int json_array_remove(json_t *array, size_t index); +int json_array_clear(json_t *array); +int json_array_extend(json_t *array, json_t *other); + +static JSON_INLINE +int json_array_set(json_t *array, size_t ind, json_t *value) +{ + return json_array_set_new(array, ind, json_incref(value)); +} + +static JSON_INLINE +int json_array_append(json_t *array, json_t *value) +{ + return json_array_append_new(array, json_incref(value)); +} + +static JSON_INLINE +int json_array_insert(json_t *array, size_t ind, json_t *value) +{ + return json_array_insert_new(array, ind, json_incref(value)); +} + +const char *json_string_value(const json_t *string); +size_t json_string_length(const json_t *string); +json_int_t json_integer_value(const json_t *integer); +double json_real_value(const json_t *real); +double json_number_value(const json_t *json); + +int json_string_set(json_t *string, const char *value); +int json_string_setn(json_t *string, const char *value, size_t len); +int json_string_set_nocheck(json_t *string, const char *value); +int json_string_setn_nocheck(json_t *string, const char *value, size_t len); +int json_integer_set(json_t *integer, json_int_t value); +int json_real_set(json_t *real, double value); + +/* pack, unpack */ + +json_t *json_pack(const char *fmt, ...) JANSSON_ATTRS(warn_unused_result); +json_t *json_pack_ex(json_error_t *error, size_t flags, const char *fmt, ...) JANSSON_ATTRS(warn_unused_result); +json_t *json_vpack_ex(json_error_t *error, size_t flags, const char *fmt, va_list ap) JANSSON_ATTRS(warn_unused_result); + +#define JSON_VALIDATE_ONLY 0x1 +#define JSON_STRICT 0x2 + +int json_unpack(json_t *root, const char *fmt, ...); +int json_unpack_ex(json_t *root, json_error_t *error, size_t flags, const char *fmt, ...); +int json_vunpack_ex(json_t *root, json_error_t *error, size_t flags, const char *fmt, va_list ap); + +/* sprintf */ + +json_t *json_sprintf(const char *fmt, ...) JANSSON_ATTRS(warn_unused_result, format(printf, 1, 2)); +json_t *json_vsprintf(const char *fmt, va_list ap) JANSSON_ATTRS(warn_unused_result, format(printf, 1, 0)); + + +/* equality */ + +int json_equal(const json_t *value1, const json_t *value2); + + +/* copying */ + +json_t *json_copy(json_t *value) JANSSON_ATTRS(warn_unused_result); +json_t *json_deep_copy(const json_t *value) JANSSON_ATTRS(warn_unused_result); + + +/* decoding */ + +#define JSON_REJECT_DUPLICATES 0x1 +#define JSON_DISABLE_EOF_CHECK 0x2 +#define JSON_DECODE_ANY 0x4 +#define JSON_DECODE_INT_AS_REAL 0x8 +#define JSON_ALLOW_NUL 0x10 + +typedef size_t (*json_load_callback_t)(void *buffer, size_t buflen, void *data); + +json_t *json_loads(const char *input, size_t flags, json_error_t *error) JANSSON_ATTRS(warn_unused_result); +json_t *json_loadb(const char *buffer, size_t buflen, size_t flags, json_error_t *error) JANSSON_ATTRS(warn_unused_result); +json_t *json_loadf(FILE *input, size_t flags, json_error_t *error) JANSSON_ATTRS(warn_unused_result); +json_t *json_loadfd(int input, size_t flags, json_error_t *error) JANSSON_ATTRS(warn_unused_result); +json_t *json_load_file(const char *path, size_t flags, json_error_t *error) JANSSON_ATTRS(warn_unused_result); +json_t *json_load_callback(json_load_callback_t callback, void *data, size_t flags, json_error_t *error) JANSSON_ATTRS(warn_unused_result); + + +/* encoding */ + +#define JSON_MAX_INDENT 0x1F +#define JSON_INDENT(n) ((n) & JSON_MAX_INDENT) +#define JSON_COMPACT 0x20 +#define JSON_ENSURE_ASCII 0x40 +#define JSON_SORT_KEYS 0x80 +#define JSON_PRESERVE_ORDER 0x100 +#define JSON_ENCODE_ANY 0x200 +#define JSON_ESCAPE_SLASH 0x400 +#define JSON_REAL_PRECISION(n) (((n) & 0x1F) << 11) +#define JSON_EMBED 0x10000 + +typedef int (*json_dump_callback_t)(const char *buffer, size_t size, void *data); + +char *json_dumps(const json_t *json, size_t flags) JANSSON_ATTRS(warn_unused_result); +size_t json_dumpb(const json_t *json, char *buffer, size_t size, size_t flags); +int json_dumpf(const json_t *json, FILE *output, size_t flags); +int json_dumpfd(const json_t *json, int output, size_t flags); +int json_dump_file(const json_t *json, const char *path, size_t flags); +int json_dump_callback(const json_t *json, json_dump_callback_t callback, void *data, size_t flags); + +/* custom memory allocation */ + +typedef void *(*json_malloc_t)(size_t); +typedef void (*json_free_t)(void *); + +void json_set_alloc_funcs(json_malloc_t malloc_fn, json_free_t free_fn); +void json_get_alloc_funcs(json_malloc_t *malloc_fn, json_free_t *free_fn); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/3party/jansson/src/jansson_config.h b/3party/jansson/src/jansson_config.h new file mode 100644 index 0000000000..a5502fc0ef --- /dev/null +++ b/3party/jansson/src/jansson_config.h @@ -0,0 +1,74 @@ +/* + * Copyright (c) 2010-2016 Petri Lehtinen + * + * Jansson is free software; you can redistribute it and/or modify + * it under the terms of the MIT license. See LICENSE for details. + * + * + * This file specifies a part of the site-specific configuration for + * Jansson, namely those things that affect the public API in + * jansson.h. + * + * The CMake system will generate the jansson_config.h file and + * copy it to the build and install directories. + */ + +#ifndef JANSSON_CONFIG_H +#define JANSSON_CONFIG_H + +/* Define this so that we can disable scattered automake configuration in source files */ +#ifndef JANSSON_USING_CMAKE +#define JANSSON_USING_CMAKE +#endif + +/* Note: when using cmake, JSON_INTEGER_IS_LONG_LONG is not defined nor used, + * as we will also check for __int64 etc types. + * (the definition was used in the automake system) */ + +/* Bring in the cmake-detected defines */ +#define HAVE_STDINT_H 1 +/* #undef HAVE_INTTYPES_H */ +#define HAVE_SYS_TYPES_H 1 + +/* Include our standard type header for the integer typedef */ + +#if defined(HAVE_STDINT_H) +# include +#elif defined(HAVE_INTTYPES_H) +# include +#elif defined(HAVE_SYS_TYPES_H) +# include +#endif + + +/* If your compiler supports the inline keyword in C, JSON_INLINE is + defined to `inline', otherwise empty. In C++, the inline is always + supported. */ +#ifdef __cplusplus +#define JSON_INLINE inline +#else +#define JSON_INLINE inline +#endif + + +#define json_int_t long long +#define json_strtoint strtoll +#define JSON_INTEGER_FORMAT "lld" + + +/* If locale.h and localeconv() are available, define to 1, otherwise to 0. */ +#define JSON_HAVE_LOCALECONV 1 + +/* If __atomic builtins are available they will be used to manage + reference counts of json_t. */ +#define JSON_HAVE_ATOMIC_BUILTINS 1 + +/* If __atomic builtins are not available we try using __sync builtins + to manage reference counts of json_t. */ +#define JSON_HAVE_SYNC_BUILTINS 1 + +/* Maximum recursion depth for parsing JSON input. + This limits the depth of e.g. array-within-array constructions. */ +#define JSON_PARSER_MAX_DEPTH 2048 + +#endif diff --git a/3party/jansson/src/jansson_config.h.in b/3party/jansson/src/jansson_config.h.in new file mode 100644 index 0000000000..fe692ab4fc --- /dev/null +++ b/3party/jansson/src/jansson_config.h.in @@ -0,0 +1,51 @@ +/* + * Copyright (c) 2010-2016 Petri Lehtinen + * + * Jansson is free software; you can redistribute it and/or modify + * it under the terms of the MIT license. See LICENSE for details. + * + * + * This file specifies a part of the site-specific configuration for + * Jansson, namely those things that affect the public API in + * jansson.h. + * + * The configure script copies this file to jansson_config.h and + * replaces @var@ substitutions by values that fit your system. If you + * cannot run the configure script, you can do the value substitution + * by hand. + */ + +#ifndef JANSSON_CONFIG_H +#define JANSSON_CONFIG_H + +/* If your compiler supports the inline keyword in C, JSON_INLINE is + defined to `inline', otherwise empty. In C++, the inline is always + supported. */ +#ifdef __cplusplus +#define JSON_INLINE inline +#else +#define JSON_INLINE @json_inline@ +#endif + +/* If your compiler supports the `long long` type and the strtoll() + library function, JSON_INTEGER_IS_LONG_LONG is defined to 1, + otherwise to 0. */ +#define JSON_INTEGER_IS_LONG_LONG @json_have_long_long@ + +/* If locale.h and localeconv() are available, define to 1, + otherwise to 0. */ +#define JSON_HAVE_LOCALECONV @json_have_localeconv@ + +/* If __atomic builtins are available they will be used to manage + reference counts of json_t. */ +#define JSON_HAVE_ATOMIC_BUILTINS @json_have_atomic_builtins@ + +/* If __atomic builtins are not available we try using __sync builtins + to manage reference counts of json_t. */ +#define JSON_HAVE_SYNC_BUILTINS @json_have_sync_builtins@ + +/* Maximum recursion depth for parsing JSON input. + This limits the depth of e.g. array-within-array constructions. */ +#define JSON_PARSER_MAX_DEPTH 2048 + +#endif diff --git a/3party/jansson/src/jansson_private.h b/3party/jansson/src/jansson_private.h new file mode 100644 index 0000000000..bf86c57468 --- /dev/null +++ b/3party/jansson/src/jansson_private.h @@ -0,0 +1,109 @@ +/* + * Copyright (c) 2009-2016 Petri Lehtinen + * + * Jansson is free software; you can redistribute it and/or modify + * it under the terms of the MIT license. See LICENSE for details. + */ + +#ifndef JANSSON_PRIVATE_H +#define JANSSON_PRIVATE_H + +#include "jansson_private_config.h" +#include +#include "jansson.h" +#include "hashtable.h" +#include "strbuffer.h" + +#define container_of(ptr_, type_, member_) \ + ((type_ *)((char *)ptr_ - offsetof(type_, member_))) + +/* On some platforms, max() may already be defined */ +#ifndef max +#define max(a, b) ((a) > (b) ? (a) : (b)) +#endif + +/* va_copy is a C99 feature. In C89 implementations, it's sometimes + available as __va_copy. If not, memcpy() should do the trick. */ +#ifndef va_copy +#ifdef __va_copy +#define va_copy __va_copy +#else +#define va_copy(a, b) memcpy(&(a), &(b), sizeof(va_list)) +#endif +#endif + +typedef struct { + json_t json; + hashtable_t hashtable; +} json_object_t; + +typedef struct { + json_t json; + size_t size; + size_t entries; + json_t **table; +} json_array_t; + +typedef struct { + json_t json; + char *value; + size_t length; +} json_string_t; + +typedef struct { + json_t json; + double value; +} json_real_t; + +typedef struct { + json_t json; + json_int_t value; +} json_integer_t; + +#define json_to_object(json_) container_of(json_, json_object_t, json) +#define json_to_array(json_) container_of(json_, json_array_t, json) +#define json_to_string(json_) container_of(json_, json_string_t, json) +#define json_to_real(json_) container_of(json_, json_real_t, json) +#define json_to_integer(json_) container_of(json_, json_integer_t, json) + +/* Create a string by taking ownership of an existing buffer */ +json_t *jsonp_stringn_nocheck_own(const char *value, size_t len); + +/* Error message formatting */ +void jsonp_error_init(json_error_t *error, const char *source); +void jsonp_error_set_source(json_error_t *error, const char *source); +void jsonp_error_set(json_error_t *error, int line, int column, + size_t position, enum json_error_code code, + const char *msg, ...); +void jsonp_error_vset(json_error_t *error, int line, int column, + size_t position, enum json_error_code code, + const char *msg, va_list ap); + +/* Locale independent string<->double conversions */ +int jsonp_strtod(strbuffer_t *strbuffer, double *out); +int jsonp_dtostr(char *buffer, size_t size, double value, int prec); + +/* Wrappers for custom memory functions */ +void* jsonp_malloc(size_t size) JANSSON_ATTRS(warn_unused_result); +void jsonp_free(void *ptr); +char *jsonp_strndup(const char *str, size_t length) JANSSON_ATTRS(warn_unused_result); +char *jsonp_strdup(const char *str) JANSSON_ATTRS(warn_unused_result); +char *jsonp_strndup(const char *str, size_t len) JANSSON_ATTRS(warn_unused_result); + + +/* Windows compatibility */ +#if defined(_WIN32) || defined(WIN32) +# if defined(_MSC_VER) /* MS compiller */ +# if (_MSC_VER < 1900) && !defined(snprintf) /* snprintf not defined yet & not introduced */ +# define snprintf _snprintf +# endif +# if (_MSC_VER < 1500) && !defined(vsnprintf) /* vsnprintf not defined yet & not introduced */ +# define vsnprintf(b,c,f,a) _vsnprintf(b,c,f,a) +# endif +# else /* Other Windows compiller, old definition */ +# define snprintf _snprintf +# define vsnprintf _vsnprintf +# endif +#endif + +#endif diff --git a/3party/jansson/src/jansson_private_config.h b/3party/jansson/src/jansson_private_config.h new file mode 100644 index 0000000000..bb0c8cde3c --- /dev/null +++ b/3party/jansson/src/jansson_private_config.h @@ -0,0 +1,53 @@ +/* #undef HAVE_ENDIAN_H */ +#define HAVE_FCNTL_H 1 +#define HAVE_SCHED_H 1 +#define HAVE_UNISTD_H 1 +#define HAVE_SYS_PARAM_H 1 +#define HAVE_SYS_STAT_H 1 +#define HAVE_SYS_TIME_H 1 +#define HAVE_SYS_TYPES_H 1 +#define HAVE_STDINT_H 1 + +#define HAVE_CLOSE 1 +#define HAVE_GETPID 1 +#define HAVE_GETTIMEOFDAY 1 +#define HAVE_OPEN 1 +#define HAVE_READ 1 +#define HAVE_SCHED_YIELD 1 + +#define HAVE_SYNC_BUILTINS 1 +#define HAVE_ATOMIC_BUILTINS 1 + +#define HAVE_LOCALE_H 1 +#define HAVE_SETLOCALE 1 + +#define HAVE_INT32_T 1 +#ifndef HAVE_INT32_T +# define int32_t int32_t +#endif + +#define HAVE_UINT32_T 1 +#ifndef HAVE_UINT32_T +# define uint32_t uint32_t +#endif + +#define HAVE_UINT16_T 1 +#ifndef HAVE_UINT16_T +# define uint16_t uint16_t +#endif + +#define HAVE_UINT8_T 1 +#ifndef HAVE_UINT8_T +# define uint8_t uint8_t +#endif + +#define HAVE_SSIZE_T 1 + +#ifndef HAVE_SSIZE_T +# define ssize_t +#endif + +#define USE_URANDOM 1 +#define USE_WINDOWS_CRYPTOAPI 1 + +#define INITIAL_HASHTABLE_ORDER 3 diff --git a/3party/jansson/src/load.c b/3party/jansson/src/load.c new file mode 100644 index 0000000000..8700919fd7 --- /dev/null +++ b/3party/jansson/src/load.c @@ -0,0 +1,1153 @@ +/* + * Copyright (c) 2009-2016 Petri Lehtinen + * + * Jansson is free software; you can redistribute it and/or modify + * it under the terms of the MIT license. See LICENSE for details. + */ + +#ifndef _GNU_SOURCE +#define _GNU_SOURCE +#endif + +#include "jansson_private.h" + +#include +#include +#include +#include +#include +#include +#ifdef HAVE_UNISTD_H +#include +#endif + +#include "jansson.h" +#include "strbuffer.h" +#include "utf.h" + +#define STREAM_STATE_OK 0 +#define STREAM_STATE_EOF -1 +#define STREAM_STATE_ERROR -2 + +#define TOKEN_INVALID -1 +#define TOKEN_EOF 0 +#define TOKEN_STRING 256 +#define TOKEN_INTEGER 257 +#define TOKEN_REAL 258 +#define TOKEN_TRUE 259 +#define TOKEN_FALSE 260 +#define TOKEN_NULL 261 + +/* Locale independent versions of isxxx() functions */ +#define l_isupper(c) ('A' <= (c) && (c) <= 'Z') +#define l_islower(c) ('a' <= (c) && (c) <= 'z') +#define l_isalpha(c) (l_isupper(c) || l_islower(c)) +#define l_isdigit(c) ('0' <= (c) && (c) <= '9') +#define l_isxdigit(c) \ + (l_isdigit(c) || ('A' <= (c) && (c) <= 'F') || ('a' <= (c) && (c) <= 'f')) + +/* Read one byte from stream, convert to unsigned char, then int, and + return. return EOF on end of file. This corresponds to the + behaviour of fgetc(). */ +typedef int (*get_func)(void *data); + +typedef struct { + get_func get; + void *data; + char buffer[5]; + size_t buffer_pos; + int state; + int line; + int column, last_column; + size_t position; +} stream_t; + +typedef struct { + stream_t stream; + strbuffer_t saved_text; + size_t flags; + size_t depth; + int token; + union { + struct { + char *val; + size_t len; + } string; + json_int_t integer; + double real; + } value; +} lex_t; + +#define stream_to_lex(stream) container_of(stream, lex_t, stream) + + +/*** error reporting ***/ + +static void error_set(json_error_t *error, const lex_t *lex, + enum json_error_code code, + const char *msg, ...) +{ + va_list ap; + char msg_text[JSON_ERROR_TEXT_LENGTH]; + char msg_with_context[JSON_ERROR_TEXT_LENGTH]; + + int line = -1, col = -1; + size_t pos = 0; + const char *result = msg_text; + + if(!error) + return; + + va_start(ap, msg); + vsnprintf(msg_text, JSON_ERROR_TEXT_LENGTH, msg, ap); + msg_text[JSON_ERROR_TEXT_LENGTH - 1] = '\0'; + va_end(ap); + + if(lex) + { + const char *saved_text = strbuffer_value(&lex->saved_text); + + line = lex->stream.line; + col = lex->stream.column; + pos = lex->stream.position; + + if(saved_text && saved_text[0]) + { + if(lex->saved_text.length <= 20) { + snprintf(msg_with_context, JSON_ERROR_TEXT_LENGTH, + "%s near '%s'", msg_text, saved_text); + msg_with_context[JSON_ERROR_TEXT_LENGTH - 1] = '\0'; + result = msg_with_context; + } + } + else + { + if(code == json_error_invalid_syntax) { + /* More specific error code for premature end of file. */ + code = json_error_premature_end_of_input; + } + if(lex->stream.state == STREAM_STATE_ERROR) { + /* No context for UTF-8 decoding errors */ + result = msg_text; + } + else { + snprintf(msg_with_context, JSON_ERROR_TEXT_LENGTH, + "%s near end of file", msg_text); + msg_with_context[JSON_ERROR_TEXT_LENGTH - 1] = '\0'; + result = msg_with_context; + } + } + } + + jsonp_error_set(error, line, col, pos, code, "%s", result); +} + + +/*** lexical analyzer ***/ + +static void +stream_init(stream_t *stream, get_func get, void *data) +{ + stream->get = get; + stream->data = data; + stream->buffer[0] = '\0'; + stream->buffer_pos = 0; + + stream->state = STREAM_STATE_OK; + stream->line = 1; + stream->column = 0; + stream->position = 0; +} + +static int stream_get(stream_t *stream, json_error_t *error) +{ + int c; + + if(stream->state != STREAM_STATE_OK) + return stream->state; + + if(!stream->buffer[stream->buffer_pos]) + { + c = stream->get(stream->data); + if(c == EOF) { + stream->state = STREAM_STATE_EOF; + return STREAM_STATE_EOF; + } + + stream->buffer[0] = c; + stream->buffer_pos = 0; + + if(0x80 <= c && c <= 0xFF) + { + /* multi-byte UTF-8 sequence */ + size_t i, count; + + count = utf8_check_first(c); + if(!count) + goto out; + + assert(count >= 2); + + for(i = 1; i < count; i++) + stream->buffer[i] = stream->get(stream->data); + + if(!utf8_check_full(stream->buffer, count, NULL)) + goto out; + + stream->buffer[count] = '\0'; + } + else + stream->buffer[1] = '\0'; + } + + c = stream->buffer[stream->buffer_pos++]; + + stream->position++; + if(c == '\n') { + stream->line++; + stream->last_column = stream->column; + stream->column = 0; + } + else if(utf8_check_first(c)) { + /* track the Unicode character column, so increment only if + this is the first character of a UTF-8 sequence */ + stream->column++; + } + + return c; + +out: + stream->state = STREAM_STATE_ERROR; + error_set(error, stream_to_lex(stream), json_error_invalid_utf8, "unable to decode byte 0x%x", c); + return STREAM_STATE_ERROR; +} + +static void stream_unget(stream_t *stream, int c) +{ + if(c == STREAM_STATE_EOF || c == STREAM_STATE_ERROR) + return; + + stream->position--; + if(c == '\n') { + stream->line--; + stream->column = stream->last_column; + } + else if(utf8_check_first(c)) + stream->column--; + + assert(stream->buffer_pos > 0); + stream->buffer_pos--; + assert(stream->buffer[stream->buffer_pos] == c); +} + + +static int lex_get(lex_t *lex, json_error_t *error) +{ + return stream_get(&lex->stream, error); +} + +static void lex_save(lex_t *lex, int c) +{ + strbuffer_append_byte(&lex->saved_text, c); +} + +static int lex_get_save(lex_t *lex, json_error_t *error) +{ + int c = stream_get(&lex->stream, error); + if(c != STREAM_STATE_EOF && c != STREAM_STATE_ERROR) + lex_save(lex, c); + return c; +} + +static void lex_unget(lex_t *lex, int c) +{ + stream_unget(&lex->stream, c); +} + +static void lex_unget_unsave(lex_t *lex, int c) +{ + if(c != STREAM_STATE_EOF && c != STREAM_STATE_ERROR) { + /* Since we treat warnings as errors, when assertions are turned + * off the "d" variable would be set but never used. Which is + * treated as an error by GCC. + */ + #ifndef NDEBUG + char d; + #endif + stream_unget(&lex->stream, c); + #ifndef NDEBUG + d = + #endif + strbuffer_pop(&lex->saved_text); + assert(c == d); + } +} + +static void lex_save_cached(lex_t *lex) +{ + while(lex->stream.buffer[lex->stream.buffer_pos] != '\0') + { + lex_save(lex, lex->stream.buffer[lex->stream.buffer_pos]); + lex->stream.buffer_pos++; + lex->stream.position++; + } +} + +static void lex_free_string(lex_t *lex) +{ + jsonp_free(lex->value.string.val); + lex->value.string.val = NULL; + lex->value.string.len = 0; +} + +/* assumes that str points to 'u' plus at least 4 valid hex digits */ +static int32_t decode_unicode_escape(const char *str) +{ + int i; + int32_t value = 0; + + assert(str[0] == 'u'); + + for(i = 1; i <= 4; i++) { + char c = str[i]; + value <<= 4; + if(l_isdigit(c)) + value += c - '0'; + else if(l_islower(c)) + value += c - 'a' + 10; + else if(l_isupper(c)) + value += c - 'A' + 10; + else + return -1; + } + + return value; +} + +static void lex_scan_string(lex_t *lex, json_error_t *error) +{ + int c; + const char *p; + char *t; + int i; + + lex->value.string.val = NULL; + lex->token = TOKEN_INVALID; + + c = lex_get_save(lex, error); + + while(c != '"') { + if(c == STREAM_STATE_ERROR) + goto out; + + else if(c == STREAM_STATE_EOF) { + error_set(error, lex, json_error_premature_end_of_input, "premature end of input"); + goto out; + } + + else if(0 <= c && c <= 0x1F) { + /* control character */ + lex_unget_unsave(lex, c); + if(c == '\n') + error_set(error, lex, json_error_invalid_syntax, "unexpected newline"); + else + error_set(error, lex, json_error_invalid_syntax, "control character 0x%x", c); + goto out; + } + + else if(c == '\\') { + c = lex_get_save(lex, error); + if(c == 'u') { + c = lex_get_save(lex, error); + for(i = 0; i < 4; i++) { + if(!l_isxdigit(c)) { + error_set(error, lex, json_error_invalid_syntax, "invalid escape"); + goto out; + } + c = lex_get_save(lex, error); + } + } + else if(c == '"' || c == '\\' || c == '/' || c == 'b' || + c == 'f' || c == 'n' || c == 'r' || c == 't') + c = lex_get_save(lex, error); + else { + error_set(error, lex, json_error_invalid_syntax, "invalid escape"); + goto out; + } + } + else + c = lex_get_save(lex, error); + } + + /* the actual value is at most of the same length as the source + string, because: + - shortcut escapes (e.g. "\t") (length 2) are converted to 1 byte + - a single \uXXXX escape (length 6) is converted to at most 3 bytes + - two \uXXXX escapes (length 12) forming an UTF-16 surrogate pair + are converted to 4 bytes + */ + t = jsonp_malloc(lex->saved_text.length + 1); + if(!t) { + /* this is not very nice, since TOKEN_INVALID is returned */ + goto out; + } + lex->value.string.val = t; + + /* + 1 to skip the " */ + p = strbuffer_value(&lex->saved_text) + 1; + + while(*p != '"') { + if(*p == '\\') { + p++; + if(*p == 'u') { + size_t length; + int32_t value; + + value = decode_unicode_escape(p); + if(value < 0) { + error_set(error, lex, json_error_invalid_syntax, "invalid Unicode escape '%.6s'", p - 1); + goto out; + } + p += 5; + + if(0xD800 <= value && value <= 0xDBFF) { + /* surrogate pair */ + if(*p == '\\' && *(p + 1) == 'u') { + int32_t value2 = decode_unicode_escape(++p); + if(value2 < 0) { + error_set(error, lex, json_error_invalid_syntax, "invalid Unicode escape '%.6s'", p - 1); + goto out; + } + p += 5; + + if(0xDC00 <= value2 && value2 <= 0xDFFF) { + /* valid second surrogate */ + value = + ((value - 0xD800) << 10) + + (value2 - 0xDC00) + + 0x10000; + } + else { + /* invalid second surrogate */ + error_set(error, lex, + json_error_invalid_syntax, + "invalid Unicode '\\u%04X\\u%04X'", + value, value2); + goto out; + } + } + else { + /* no second surrogate */ + error_set(error, lex, json_error_invalid_syntax, "invalid Unicode '\\u%04X'", + value); + goto out; + } + } + else if(0xDC00 <= value && value <= 0xDFFF) { + error_set(error, lex, json_error_invalid_syntax, "invalid Unicode '\\u%04X'", value); + goto out; + } + + if(utf8_encode(value, t, &length)) + assert(0); + t += length; + } + else { + switch(*p) { + case '"': case '\\': case '/': + *t = *p; break; + case 'b': *t = '\b'; break; + case 'f': *t = '\f'; break; + case 'n': *t = '\n'; break; + case 'r': *t = '\r'; break; + case 't': *t = '\t'; break; + default: assert(0); + } + t++; + p++; + } + } + else + *(t++) = *(p++); + } + *t = '\0'; + lex->value.string.len = t - lex->value.string.val; + lex->token = TOKEN_STRING; + return; + +out: + lex_free_string(lex); +} + +#ifndef JANSSON_USING_CMAKE /* disabled if using cmake */ +#if JSON_INTEGER_IS_LONG_LONG +#ifdef _MSC_VER /* Microsoft Visual Studio */ +#define json_strtoint _strtoi64 +#else +#define json_strtoint strtoll +#endif +#else +#define json_strtoint strtol +#endif +#endif + +static int lex_scan_number(lex_t *lex, int c, json_error_t *error) +{ + const char *saved_text; + char *end; + double doubleval; + + lex->token = TOKEN_INVALID; + + if(c == '-') + c = lex_get_save(lex, error); + + if(c == '0') { + c = lex_get_save(lex, error); + if(l_isdigit(c)) { + lex_unget_unsave(lex, c); + goto out; + } + } + else if(l_isdigit(c)) { + do + c = lex_get_save(lex, error); + while(l_isdigit(c)); + } + else { + lex_unget_unsave(lex, c); + goto out; + } + + if(!(lex->flags & JSON_DECODE_INT_AS_REAL) && + c != '.' && c != 'E' && c != 'e') + { + json_int_t intval; + + lex_unget_unsave(lex, c); + + saved_text = strbuffer_value(&lex->saved_text); + + errno = 0; + intval = json_strtoint(saved_text, &end, 10); + if(errno == ERANGE) { + if(intval < 0) + error_set(error, lex, json_error_numeric_overflow, "too big negative integer"); + else + error_set(error, lex, json_error_numeric_overflow, "too big integer"); + goto out; + } + + assert(end == saved_text + lex->saved_text.length); + + lex->token = TOKEN_INTEGER; + lex->value.integer = intval; + return 0; + } + + if(c == '.') { + c = lex_get(lex, error); + if(!l_isdigit(c)) { + lex_unget(lex, c); + goto out; + } + lex_save(lex, c); + + do + c = lex_get_save(lex, error); + while(l_isdigit(c)); + } + + if(c == 'E' || c == 'e') { + c = lex_get_save(lex, error); + if(c == '+' || c == '-') + c = lex_get_save(lex, error); + + if(!l_isdigit(c)) { + lex_unget_unsave(lex, c); + goto out; + } + + do + c = lex_get_save(lex, error); + while(l_isdigit(c)); + } + + lex_unget_unsave(lex, c); + + if(jsonp_strtod(&lex->saved_text, &doubleval)) { + error_set(error, lex, json_error_numeric_overflow, "real number overflow"); + goto out; + } + + lex->token = TOKEN_REAL; + lex->value.real = doubleval; + return 0; + +out: + return -1; +} + +static int lex_scan(lex_t *lex, json_error_t *error) +{ + int c; + + strbuffer_clear(&lex->saved_text); + + if(lex->token == TOKEN_STRING) + lex_free_string(lex); + + do + c = lex_get(lex, error); + while(c == ' ' || c == '\t' || c == '\n' || c == '\r'); + + if(c == STREAM_STATE_EOF) { + lex->token = TOKEN_EOF; + goto out; + } + + if(c == STREAM_STATE_ERROR) { + lex->token = TOKEN_INVALID; + goto out; + } + + lex_save(lex, c); + + if(c == '{' || c == '}' || c == '[' || c == ']' || c == ':' || c == ',') + lex->token = c; + + else if(c == '"') + lex_scan_string(lex, error); + + else if(l_isdigit(c) || c == '-') { + if(lex_scan_number(lex, c, error)) + goto out; + } + + else if(l_isalpha(c)) { + /* eat up the whole identifier for clearer error messages */ + const char *saved_text; + + do + c = lex_get_save(lex, error); + while(l_isalpha(c)); + lex_unget_unsave(lex, c); + + saved_text = strbuffer_value(&lex->saved_text); + + if(strcmp(saved_text, "true") == 0) + lex->token = TOKEN_TRUE; + else if(strcmp(saved_text, "false") == 0) + lex->token = TOKEN_FALSE; + else if(strcmp(saved_text, "null") == 0) + lex->token = TOKEN_NULL; + else + lex->token = TOKEN_INVALID; + } + + else { + /* save the rest of the input UTF-8 sequence to get an error + message of valid UTF-8 */ + lex_save_cached(lex); + lex->token = TOKEN_INVALID; + } + +out: + return lex->token; +} + +static char *lex_steal_string(lex_t *lex, size_t *out_len) +{ + char *result = NULL; + if(lex->token == TOKEN_STRING) { + result = lex->value.string.val; + *out_len = lex->value.string.len; + lex->value.string.val = NULL; + lex->value.string.len = 0; + } + return result; +} + +static int lex_init(lex_t *lex, get_func get, size_t flags, void *data) +{ + stream_init(&lex->stream, get, data); + if(strbuffer_init(&lex->saved_text)) + return -1; + + lex->flags = flags; + lex->token = TOKEN_INVALID; + return 0; +} + +static void lex_close(lex_t *lex) +{ + if(lex->token == TOKEN_STRING) + lex_free_string(lex); + strbuffer_close(&lex->saved_text); +} + + +/*** parser ***/ + +static json_t *parse_value(lex_t *lex, size_t flags, json_error_t *error); + +static json_t *parse_object(lex_t *lex, size_t flags, json_error_t *error) +{ + json_t *object = json_object(); + if(!object) + return NULL; + + lex_scan(lex, error); + if(lex->token == '}') + return object; + + while(1) { + char *key; + size_t len; + json_t *value; + + if(lex->token != TOKEN_STRING) { + error_set(error, lex, json_error_invalid_syntax, "string or '}' expected"); + goto error; + } + + key = lex_steal_string(lex, &len); + if(!key) + return NULL; + if (memchr(key, '\0', len)) { + jsonp_free(key); + error_set(error, lex, json_error_null_byte_in_key, "NUL byte in object key not supported"); + goto error; + } + + if(flags & JSON_REJECT_DUPLICATES) { + if(json_object_get(object, key)) { + jsonp_free(key); + error_set(error, lex, json_error_duplicate_key, "duplicate object key"); + goto error; + } + } + + lex_scan(lex, error); + if(lex->token != ':') { + jsonp_free(key); + error_set(error, lex, json_error_invalid_syntax, "':' expected"); + goto error; + } + + lex_scan(lex, error); + value = parse_value(lex, flags, error); + if(!value) { + jsonp_free(key); + goto error; + } + + if(json_object_set_new_nocheck(object, key, value)) { + jsonp_free(key); + goto error; + } + + jsonp_free(key); + + lex_scan(lex, error); + if(lex->token != ',') + break; + + lex_scan(lex, error); + } + + if(lex->token != '}') { + error_set(error, lex, json_error_invalid_syntax, "'}' expected"); + goto error; + } + + return object; + +error: + json_decref(object); + return NULL; +} + +static json_t *parse_array(lex_t *lex, size_t flags, json_error_t *error) +{ + json_t *array = json_array(); + if(!array) + return NULL; + + lex_scan(lex, error); + if(lex->token == ']') + return array; + + while(lex->token) { + json_t *elem = parse_value(lex, flags, error); + if(!elem) + goto error; + + if(json_array_append_new(array, elem)) { + goto error; + } + + lex_scan(lex, error); + if(lex->token != ',') + break; + + lex_scan(lex, error); + } + + if(lex->token != ']') { + error_set(error, lex, json_error_invalid_syntax, "']' expected"); + goto error; + } + + return array; + +error: + json_decref(array); + return NULL; +} + +static json_t *parse_value(lex_t *lex, size_t flags, json_error_t *error) +{ + json_t *json; + + lex->depth++; + if(lex->depth > JSON_PARSER_MAX_DEPTH) { + error_set(error, lex, json_error_stack_overflow, "maximum parsing depth reached"); + return NULL; + } + + switch(lex->token) { + case TOKEN_STRING: { + const char *value = lex->value.string.val; + size_t len = lex->value.string.len; + + if(!(flags & JSON_ALLOW_NUL)) { + if(memchr(value, '\0', len)) { + error_set(error, lex, json_error_null_character, "\\u0000 is not allowed without JSON_ALLOW_NUL"); + return NULL; + } + } + + json = jsonp_stringn_nocheck_own(value, len); + lex->value.string.val = NULL; + lex->value.string.len = 0; + break; + } + + case TOKEN_INTEGER: { + json = json_integer(lex->value.integer); + break; + } + + case TOKEN_REAL: { + json = json_real(lex->value.real); + break; + } + + case TOKEN_TRUE: + json = json_true(); + break; + + case TOKEN_FALSE: + json = json_false(); + break; + + case TOKEN_NULL: + json = json_null(); + break; + + case '{': + json = parse_object(lex, flags, error); + break; + + case '[': + json = parse_array(lex, flags, error); + break; + + case TOKEN_INVALID: + error_set(error, lex, json_error_invalid_syntax, "invalid token"); + return NULL; + + default: + error_set(error, lex, json_error_invalid_syntax, "unexpected token"); + return NULL; + } + + if(!json) + return NULL; + + lex->depth--; + return json; +} + +static json_t *parse_json(lex_t *lex, size_t flags, json_error_t *error) +{ + json_t *result; + + lex->depth = 0; + + lex_scan(lex, error); + if(!(flags & JSON_DECODE_ANY)) { + if(lex->token != '[' && lex->token != '{') { + error_set(error, lex, json_error_invalid_syntax, "'[' or '{' expected"); + return NULL; + } + } + + result = parse_value(lex, flags, error); + if(!result) + return NULL; + + if(!(flags & JSON_DISABLE_EOF_CHECK)) { + lex_scan(lex, error); + if(lex->token != TOKEN_EOF) { + error_set(error, lex, json_error_end_of_input_expected, "end of file expected"); + json_decref(result); + return NULL; + } + } + + if(error) { + /* Save the position even though there was no error */ + error->position = (int)lex->stream.position; + } + + return result; +} + +typedef struct +{ + const char *data; + size_t pos; +} string_data_t; + +static int string_get(void *data) +{ + char c; + string_data_t *stream = (string_data_t *)data; + c = stream->data[stream->pos]; + if(c == '\0') + return EOF; + else + { + stream->pos++; + return (unsigned char)c; + } +} + +json_t *json_loads(const char *string, size_t flags, json_error_t *error) +{ + lex_t lex; + json_t *result; + string_data_t stream_data; + + jsonp_error_init(error, ""); + + if (string == NULL) { + error_set(error, NULL, json_error_invalid_argument, "wrong arguments"); + return NULL; + } + + stream_data.data = string; + stream_data.pos = 0; + + if(lex_init(&lex, string_get, flags, (void *)&stream_data)) + return NULL; + + result = parse_json(&lex, flags, error); + + lex_close(&lex); + return result; +} + +typedef struct +{ + const char *data; + size_t len; + size_t pos; +} buffer_data_t; + +static int buffer_get(void *data) +{ + char c; + buffer_data_t *stream = data; + if(stream->pos >= stream->len) + return EOF; + + c = stream->data[stream->pos]; + stream->pos++; + return (unsigned char)c; +} + +json_t *json_loadb(const char *buffer, size_t buflen, size_t flags, json_error_t *error) +{ + lex_t lex; + json_t *result; + buffer_data_t stream_data; + + jsonp_error_init(error, ""); + + if (buffer == NULL) { + error_set(error, NULL, json_error_invalid_argument, "wrong arguments"); + return NULL; + } + + stream_data.data = buffer; + stream_data.pos = 0; + stream_data.len = buflen; + + if(lex_init(&lex, buffer_get, flags, (void *)&stream_data)) + return NULL; + + result = parse_json(&lex, flags, error); + + lex_close(&lex); + return result; +} + +json_t *json_loadf(FILE *input, size_t flags, json_error_t *error) +{ + lex_t lex; + const char *source; + json_t *result; + + if(input == stdin) + source = ""; + else + source = ""; + + jsonp_error_init(error, source); + + if (input == NULL) { + error_set(error, NULL, json_error_invalid_argument, "wrong arguments"); + return NULL; + } + + if(lex_init(&lex, (get_func)fgetc, flags, input)) + return NULL; + + result = parse_json(&lex, flags, error); + + lex_close(&lex); + return result; +} + +static int fd_get_func(int *fd) +{ +#ifdef HAVE_UNISTD_H + uint8_t c; + if (read(*fd, &c, 1) == 1) + return c; +#endif + return EOF; +} + +json_t *json_loadfd(int input, size_t flags, json_error_t *error) +{ + lex_t lex; + const char *source; + json_t *result; + +#ifdef HAVE_UNISTD_H + if(input == STDIN_FILENO) + source = ""; + else +#endif + source = ""; + + jsonp_error_init(error, source); + + if (input < 0) { + error_set(error, NULL, json_error_invalid_argument, "wrong arguments"); + return NULL; + } + + if(lex_init(&lex, (get_func)fd_get_func, flags, &input)) + return NULL; + + result = parse_json(&lex, flags, error); + + lex_close(&lex); + return result; +} + +json_t *json_load_file(const char *path, size_t flags, json_error_t *error) +{ + json_t *result; + FILE *fp; + + jsonp_error_init(error, path); + + if (path == NULL) { + error_set(error, NULL, json_error_invalid_argument, "wrong arguments"); + return NULL; + } + + fp = fopen(path, "rb"); + if(!fp) + { + error_set(error, NULL, json_error_cannot_open_file, "unable to open %s: %s", + path, strerror(errno)); + return NULL; + } + + result = json_loadf(fp, flags, error); + + fclose(fp); + return result; +} + +#define MAX_BUF_LEN 1024 + +typedef struct +{ + char data[MAX_BUF_LEN]; + size_t len; + size_t pos; + json_load_callback_t callback; + void *arg; +} callback_data_t; + +static int callback_get(void *data) +{ + char c; + callback_data_t *stream = data; + + if(stream->pos >= stream->len) { + stream->pos = 0; + stream->len = stream->callback(stream->data, MAX_BUF_LEN, stream->arg); + if(stream->len == 0 || stream->len == (size_t)-1) + return EOF; + } + + c = stream->data[stream->pos]; + stream->pos++; + return (unsigned char)c; +} + +json_t *json_load_callback(json_load_callback_t callback, void *arg, size_t flags, json_error_t *error) +{ + lex_t lex; + json_t *result; + + callback_data_t stream_data; + + memset(&stream_data, 0, sizeof(stream_data)); + stream_data.callback = callback; + stream_data.arg = arg; + + jsonp_error_init(error, ""); + + if (callback == NULL) { + error_set(error, NULL, json_error_invalid_argument, "wrong arguments"); + return NULL; + } + + if(lex_init(&lex, (get_func)callback_get, flags, &stream_data)) + return NULL; + + result = parse_json(&lex, flags, error); + + lex_close(&lex); + return result; +} diff --git a/3party/jansson/src/lookup3.h b/3party/jansson/src/lookup3.h new file mode 100644 index 0000000000..2fe4c258f2 --- /dev/null +++ b/3party/jansson/src/lookup3.h @@ -0,0 +1,381 @@ +/* +------------------------------------------------------------------------------- +lookup3.c, by Bob Jenkins, May 2006, Public Domain. + +These are functions for producing 32-bit hashes for hash table lookup. +hashword(), hashlittle(), hashlittle2(), hashbig(), mix(), and final() +are externally useful functions. Routines to test the hash are included +if SELF_TEST is defined. You can use this free for any purpose. It's in +the public domain. It has no warranty. + +You probably want to use hashlittle(). hashlittle() and hashbig() +hash byte arrays. hashlittle() is is faster than hashbig() on +little-endian machines. Intel and AMD are little-endian machines. +On second thought, you probably want hashlittle2(), which is identical to +hashlittle() except it returns two 32-bit hashes for the price of one. +You could implement hashbig2() if you wanted but I haven't bothered here. + +If you want to find a hash of, say, exactly 7 integers, do + a = i1; b = i2; c = i3; + mix(a,b,c); + a += i4; b += i5; c += i6; + mix(a,b,c); + a += i7; + final(a,b,c); +then use c as the hash value. If you have a variable length array of +4-byte integers to hash, use hashword(). If you have a byte array (like +a character string), use hashlittle(). If you have several byte arrays, or +a mix of things, see the comments above hashlittle(). + +Why is this so big? I read 12 bytes at a time into 3 4-byte integers, +then mix those integers. This is fast (you can do a lot more thorough +mixing with 12*3 instructions on 3 integers than you can with 3 instructions +on 1 byte), but shoehorning those bytes into integers efficiently is messy. +------------------------------------------------------------------------------- +*/ + +#include + +#ifdef HAVE_CONFIG_H +#include +#endif + +#ifdef HAVE_STDINT_H +#include /* defines uint32_t etc */ +#endif + +#ifdef HAVE_SYS_PARAM_H +#include /* attempt to define endianness */ +#endif + +#ifdef HAVE_ENDIAN_H +# include /* attempt to define endianness */ +#endif + +/* + * My best guess at if you are big-endian or little-endian. This may + * need adjustment. + */ +#if (defined(__BYTE_ORDER) && defined(__LITTLE_ENDIAN) && \ + __BYTE_ORDER == __LITTLE_ENDIAN) || \ + (defined(i386) || defined(__i386__) || defined(__i486__) || \ + defined(__i586__) || defined(__i686__) || defined(vax) || defined(MIPSEL)) +# define HASH_LITTLE_ENDIAN 1 +# define HASH_BIG_ENDIAN 0 +#elif (defined(__BYTE_ORDER) && defined(__BIG_ENDIAN) && \ + __BYTE_ORDER == __BIG_ENDIAN) || \ + (defined(sparc) || defined(POWERPC) || defined(mc68000) || defined(sel)) +# define HASH_LITTLE_ENDIAN 0 +# define HASH_BIG_ENDIAN 1 +#else +# define HASH_LITTLE_ENDIAN 0 +# define HASH_BIG_ENDIAN 0 +#endif + +#define hashsize(n) ((uint32_t)1<<(n)) +#define hashmask(n) (hashsize(n)-1) +#define rot(x,k) (((x)<<(k)) | ((x)>>(32-(k)))) + +/* +------------------------------------------------------------------------------- +mix -- mix 3 32-bit values reversibly. + +This is reversible, so any information in (a,b,c) before mix() is +still in (a,b,c) after mix(). + +If four pairs of (a,b,c) inputs are run through mix(), or through +mix() in reverse, there are at least 32 bits of the output that +are sometimes the same for one pair and different for another pair. +This was tested for: +* pairs that differed by one bit, by two bits, in any combination + of top bits of (a,b,c), or in any combination of bottom bits of + (a,b,c). +* "differ" is defined as +, -, ^, or ~^. For + and -, I transformed + the output delta to a Gray code (a^(a>>1)) so a string of 1's (as + is commonly produced by subtraction) look like a single 1-bit + difference. +* the base values were pseudorandom, all zero but one bit set, or + all zero plus a counter that starts at zero. + +Some k values for my "a-=c; a^=rot(c,k); c+=b;" arrangement that +satisfy this are + 4 6 8 16 19 4 + 9 15 3 18 27 15 + 14 9 3 7 17 3 +Well, "9 15 3 18 27 15" didn't quite get 32 bits diffing +for "differ" defined as + with a one-bit base and a two-bit delta. I +used http://burtleburtle.net/bob/hash/avalanche.html to choose +the operations, constants, and arrangements of the variables. + +This does not achieve avalanche. There are input bits of (a,b,c) +that fail to affect some output bits of (a,b,c), especially of a. The +most thoroughly mixed value is c, but it doesn't really even achieve +avalanche in c. + +This allows some parallelism. Read-after-writes are good at doubling +the number of bits affected, so the goal of mixing pulls in the opposite +direction as the goal of parallelism. I did what I could. Rotates +seem to cost as much as shifts on every machine I could lay my hands +on, and rotates are much kinder to the top and bottom bits, so I used +rotates. +------------------------------------------------------------------------------- +*/ +#define mix(a,b,c) \ +{ \ + a -= c; a ^= rot(c, 4); c += b; \ + b -= a; b ^= rot(a, 6); a += c; \ + c -= b; c ^= rot(b, 8); b += a; \ + a -= c; a ^= rot(c,16); c += b; \ + b -= a; b ^= rot(a,19); a += c; \ + c -= b; c ^= rot(b, 4); b += a; \ +} + +/* +------------------------------------------------------------------------------- +final -- final mixing of 3 32-bit values (a,b,c) into c + +Pairs of (a,b,c) values differing in only a few bits will usually +produce values of c that look totally different. This was tested for +* pairs that differed by one bit, by two bits, in any combination + of top bits of (a,b,c), or in any combination of bottom bits of + (a,b,c). +* "differ" is defined as +, -, ^, or ~^. For + and -, I transformed + the output delta to a Gray code (a^(a>>1)) so a string of 1's (as + is commonly produced by subtraction) look like a single 1-bit + difference. +* the base values were pseudorandom, all zero but one bit set, or + all zero plus a counter that starts at zero. + +These constants passed: + 14 11 25 16 4 14 24 + 12 14 25 16 4 14 24 +and these came close: + 4 8 15 26 3 22 24 + 10 8 15 26 3 22 24 + 11 8 15 26 3 22 24 +------------------------------------------------------------------------------- +*/ +#define final(a,b,c) \ +{ \ + c ^= b; c -= rot(b,14); \ + a ^= c; a -= rot(c,11); \ + b ^= a; b -= rot(a,25); \ + c ^= b; c -= rot(b,16); \ + a ^= c; a -= rot(c,4); \ + b ^= a; b -= rot(a,14); \ + c ^= b; c -= rot(b,24); \ +} + +/* +------------------------------------------------------------------------------- +hashlittle() -- hash a variable-length key into a 32-bit value + k : the key (the unaligned variable-length array of bytes) + length : the length of the key, counting by bytes + initval : can be any 4-byte value +Returns a 32-bit value. Every bit of the key affects every bit of +the return value. Two keys differing by one or two bits will have +totally different hash values. + +The best hash table sizes are powers of 2. There is no need to do +mod a prime (mod is sooo slow!). If you need less than 32 bits, +use a bitmask. For example, if you need only 10 bits, do + h = (h & hashmask(10)); +In which case, the hash table should have hashsize(10) elements. + +If you are hashing n strings (uint8_t **)k, do it like this: + for (i=0, h=0; i 12) + { + a += k[0]; + b += k[1]; + c += k[2]; + mix(a,b,c); + length -= 12; + k += 3; + } + + /*----------------------------- handle the last (probably partial) block */ + /* + * "k[2]&0xffffff" actually reads beyond the end of the string, but + * then masks off the part it's not allowed to read. Because the + * string is aligned, the masked-off tail is in the same word as the + * rest of the string. Every machine with memory protection I've seen + * does it on word boundaries, so is OK with this. But VALGRIND will + * still catch it and complain. The masking trick does make the hash + * noticably faster for short strings (like English words). + */ +#ifndef NO_MASKING_TRICK + + switch(length) + { + case 12: c+=k[2]; b+=k[1]; a+=k[0]; break; + case 11: c+=k[2]&0xffffff; b+=k[1]; a+=k[0]; break; + case 10: c+=k[2]&0xffff; b+=k[1]; a+=k[0]; break; + case 9 : c+=k[2]&0xff; b+=k[1]; a+=k[0]; break; + case 8 : b+=k[1]; a+=k[0]; break; + case 7 : b+=k[1]&0xffffff; a+=k[0]; break; + case 6 : b+=k[1]&0xffff; a+=k[0]; break; + case 5 : b+=k[1]&0xff; a+=k[0]; break; + case 4 : a+=k[0]; break; + case 3 : a+=k[0]&0xffffff; break; + case 2 : a+=k[0]&0xffff; break; + case 1 : a+=k[0]&0xff; break; + case 0 : return c; /* zero length strings require no mixing */ + } + +#else /* make valgrind happy */ + + k8 = (const uint8_t *)k; + switch(length) + { + case 12: c+=k[2]; b+=k[1]; a+=k[0]; break; + case 11: c+=((uint32_t)k8[10])<<16; /* fall through */ + case 10: c+=((uint32_t)k8[9])<<8; /* fall through */ + case 9 : c+=k8[8]; /* fall through */ + case 8 : b+=k[1]; a+=k[0]; break; + case 7 : b+=((uint32_t)k8[6])<<16; /* fall through */ + case 6 : b+=((uint32_t)k8[5])<<8; /* fall through */ + case 5 : b+=k8[4]; /* fall through */ + case 4 : a+=k[0]; break; + case 3 : a+=((uint32_t)k8[2])<<16; /* fall through */ + case 2 : a+=((uint32_t)k8[1])<<8; /* fall through */ + case 1 : a+=k8[0]; break; + case 0 : return c; + } + +#endif /* !valgrind */ + + } else if (HASH_LITTLE_ENDIAN && ((u.i & 0x1) == 0)) { + const uint16_t *k = (const uint16_t *)key; /* read 16-bit chunks */ + const uint8_t *k8; + + /*--------------- all but last block: aligned reads and different mixing */ + while (length > 12) + { + a += k[0] + (((uint32_t)k[1])<<16); + b += k[2] + (((uint32_t)k[3])<<16); + c += k[4] + (((uint32_t)k[5])<<16); + mix(a,b,c); + length -= 12; + k += 6; + } + + /*----------------------------- handle the last (probably partial) block */ + k8 = (const uint8_t *)k; + switch(length) + { + case 12: c+=k[4]+(((uint32_t)k[5])<<16); + b+=k[2]+(((uint32_t)k[3])<<16); + a+=k[0]+(((uint32_t)k[1])<<16); + break; + case 11: c+=((uint32_t)k8[10])<<16; /* fall through */ + case 10: c+=k[4]; + b+=k[2]+(((uint32_t)k[3])<<16); + a+=k[0]+(((uint32_t)k[1])<<16); + break; + case 9 : c+=k8[8]; /* fall through */ + case 8 : b+=k[2]+(((uint32_t)k[3])<<16); + a+=k[0]+(((uint32_t)k[1])<<16); + break; + case 7 : b+=((uint32_t)k8[6])<<16; /* fall through */ + case 6 : b+=k[2]; + a+=k[0]+(((uint32_t)k[1])<<16); + break; + case 5 : b+=k8[4]; /* fall through */ + case 4 : a+=k[0]+(((uint32_t)k[1])<<16); + break; + case 3 : a+=((uint32_t)k8[2])<<16; /* fall through */ + case 2 : a+=k[0]; + break; + case 1 : a+=k8[0]; + break; + case 0 : return c; /* zero length requires no mixing */ + } + + } else { /* need to read the key one byte at a time */ + const uint8_t *k = (const uint8_t *)key; + + /*--------------- all but the last block: affect some 32 bits of (a,b,c) */ + while (length > 12) + { + a += k[0]; + a += ((uint32_t)k[1])<<8; + a += ((uint32_t)k[2])<<16; + a += ((uint32_t)k[3])<<24; + b += k[4]; + b += ((uint32_t)k[5])<<8; + b += ((uint32_t)k[6])<<16; + b += ((uint32_t)k[7])<<24; + c += k[8]; + c += ((uint32_t)k[9])<<8; + c += ((uint32_t)k[10])<<16; + c += ((uint32_t)k[11])<<24; + mix(a,b,c); + length -= 12; + k += 12; + } + + /*-------------------------------- last block: affect all 32 bits of (c) */ + switch(length) /* all the case statements fall through */ + { + case 12: c+=((uint32_t)k[11])<<24; /* fall through */ + case 11: c+=((uint32_t)k[10])<<16; /* fall through */ + case 10: c+=((uint32_t)k[9])<<8; /* fall through */ + case 9 : c+=k[8]; /* fall through */ + case 8 : b+=((uint32_t)k[7])<<24; /* fall through */ + case 7 : b+=((uint32_t)k[6])<<16; /* fall through */ + case 6 : b+=((uint32_t)k[5])<<8; /* fall through */ + case 5 : b+=k[4]; /* fall through */ + case 4 : a+=((uint32_t)k[3])<<24; /* fall through */ + case 3 : a+=((uint32_t)k[2])<<16; /* fall through */ + case 2 : a+=((uint32_t)k[1])<<8; /* fall through */ + case 1 : a+=k[0]; + break; + case 0 : return c; + } + } + + final(a,b,c); + return c; +} diff --git a/3party/jansson/src/memory.c b/3party/jansson/src/memory.c new file mode 100644 index 0000000000..a2be5d23d8 --- /dev/null +++ b/3party/jansson/src/memory.c @@ -0,0 +1,69 @@ +/* + * Copyright (c) 2009-2016 Petri Lehtinen + * Copyright (c) 2011-2012 Basile Starynkevitch + * + * Jansson is free software; you can redistribute it and/or modify it + * under the terms of the MIT license. See LICENSE for details. + */ + +#include +#include + +#include "jansson.h" +#include "jansson_private.h" + +/* C89 allows these to be macros */ +#undef malloc +#undef free + +/* memory function pointers */ +static json_malloc_t do_malloc = malloc; +static json_free_t do_free = free; + +void *jsonp_malloc(size_t size) +{ + if(!size) + return NULL; + + return (*do_malloc)(size); +} + +void jsonp_free(void *ptr) +{ + if(!ptr) + return; + + (*do_free)(ptr); +} + +char *jsonp_strdup(const char *str) +{ + return jsonp_strndup(str, strlen(str)); +} + +char *jsonp_strndup(const char *str, size_t len) +{ + char *new_str; + + new_str = jsonp_malloc(len + 1); + if(!new_str) + return NULL; + + memcpy(new_str, str, len); + new_str[len] = '\0'; + return new_str; +} + +void json_set_alloc_funcs(json_malloc_t malloc_fn, json_free_t free_fn) +{ + do_malloc = malloc_fn; + do_free = free_fn; +} + +void json_get_alloc_funcs(json_malloc_t *malloc_fn, json_free_t *free_fn) +{ + if (malloc_fn) + *malloc_fn = do_malloc; + if (free_fn) + *free_fn = do_free; +} diff --git a/3party/jansson/src/pack_unpack.c b/3party/jansson/src/pack_unpack.c new file mode 100644 index 0000000000..3b9977667e --- /dev/null +++ b/3party/jansson/src/pack_unpack.c @@ -0,0 +1,952 @@ +/* + * Copyright (c) 2009-2016 Petri Lehtinen + * Copyright (c) 2011-2012 Graeme Smecher + * + * Jansson is free software; you can redistribute it and/or modify + * it under the terms of the MIT license. See LICENSE for details. + */ + +#include +#include "jansson.h" +#include "jansson_private.h" +#include "utf.h" + +typedef struct { + int line; + int column; + size_t pos; + char token; +} token_t; + +typedef struct { + const char *start; + const char *fmt; + token_t prev_token; + token_t token; + token_t next_token; + json_error_t *error; + size_t flags; + int line; + int column; + size_t pos; + int has_error; +} scanner_t; + +#define token(scanner) ((scanner)->token.token) + +static const char * const type_names[] = { + "object", + "array", + "string", + "integer", + "real", + "true", + "false", + "null" +}; + +#define type_name(x) type_names[json_typeof(x)] + +static const char unpack_value_starters[] = "{[siIbfFOon"; + +static void scanner_init(scanner_t *s, json_error_t *error, + size_t flags, const char *fmt) +{ + s->error = error; + s->flags = flags; + s->fmt = s->start = fmt; + memset(&s->prev_token, 0, sizeof(token_t)); + memset(&s->token, 0, sizeof(token_t)); + memset(&s->next_token, 0, sizeof(token_t)); + s->line = 1; + s->column = 0; + s->pos = 0; + s->has_error = 0; +} + +static void next_token(scanner_t *s) +{ + const char *t; + s->prev_token = s->token; + + if(s->next_token.line) { + s->token = s->next_token; + s->next_token.line = 0; + return; + } + + if (!token(s) && !*s->fmt) + return; + + t = s->fmt; + s->column++; + s->pos++; + + /* skip space and ignored chars */ + while(*t == ' ' || *t == '\t' || *t == '\n' || *t == ',' || *t == ':') { + if(*t == '\n') { + s->line++; + s->column = 1; + } + else + s->column++; + + s->pos++; + t++; + } + + s->token.token = *t; + s->token.line = s->line; + s->token.column = s->column; + s->token.pos = s->pos; + + if (*t) t++; + s->fmt = t; +} + +static void prev_token(scanner_t *s) +{ + s->next_token = s->token; + s->token = s->prev_token; +} + +static void set_error(scanner_t *s, const char *source, enum json_error_code code, + const char *fmt, ...) +{ + va_list ap; + va_start(ap, fmt); + + jsonp_error_vset(s->error, s->token.line, s->token.column, s->token.pos, + code, fmt, ap); + + jsonp_error_set_source(s->error, source); + + va_end(ap); +} + +static json_t *pack(scanner_t *s, va_list *ap); + + +/* ours will be set to 1 if jsonp_free() must be called for the result + afterwards */ +static char *read_string(scanner_t *s, va_list *ap, + const char *purpose, size_t *out_len, int *ours, int optional) +{ + char t; + strbuffer_t strbuff; + const char *str; + size_t length; + + next_token(s); + t = token(s); + prev_token(s); + + *ours = 0; + if(t != '#' && t != '%' && t != '+') { + /* Optimize the simple case */ + str = va_arg(*ap, const char *); + + if(!str) { + if (!optional) { + set_error(s, "", json_error_null_value, "NULL %s", purpose); + s->has_error = 1; + } + return NULL; + } + + length = strlen(str); + + if(!utf8_check_string(str, length)) { + set_error(s, "", json_error_invalid_utf8, "Invalid UTF-8 %s", purpose); + s->has_error = 1; + return NULL; + } + + *out_len = length; + return (char *)str; + } else if (optional) { + set_error(s, "", json_error_invalid_format, "Cannot use '%c' on optional strings", t); + s->has_error = 1; + + return NULL; + } + + if(strbuffer_init(&strbuff)) { + set_error(s, "", json_error_out_of_memory, "Out of memory"); + s->has_error = 1; + } + + while(1) { + str = va_arg(*ap, const char *); + if(!str) { + set_error(s, "", json_error_null_value, "NULL %s", purpose); + s->has_error = 1; + } + + next_token(s); + + if(token(s) == '#') { + length = va_arg(*ap, int); + } + else if(token(s) == '%') { + length = va_arg(*ap, size_t); + } + else { + prev_token(s); + length = s->has_error ? 0 : strlen(str); + } + + if(!s->has_error && strbuffer_append_bytes(&strbuff, str, length) == -1) { + set_error(s, "", json_error_out_of_memory, "Out of memory"); + s->has_error = 1; + } + + next_token(s); + if(token(s) != '+') { + prev_token(s); + break; + } + } + + if(s->has_error) { + strbuffer_close(&strbuff); + return NULL; + } + + if(!utf8_check_string(strbuff.value, strbuff.length)) { + set_error(s, "", json_error_invalid_utf8, "Invalid UTF-8 %s", purpose); + strbuffer_close(&strbuff); + s->has_error = 1; + return NULL; + } + + *out_len = strbuff.length; + *ours = 1; + return strbuffer_steal_value(&strbuff); +} + +static json_t *pack_object(scanner_t *s, va_list *ap) +{ + json_t *object = json_object(); + next_token(s); + + while(token(s) != '}') { + char *key; + size_t len; + int ours; + json_t *value; + char valueOptional; + + if(!token(s)) { + set_error(s, "", json_error_invalid_format, "Unexpected end of format string"); + goto error; + } + + if(token(s) != 's') { + set_error(s, "", json_error_invalid_format, "Expected format 's', got '%c'", token(s)); + goto error; + } + + key = read_string(s, ap, "object key", &len, &ours, 0); + + next_token(s); + + next_token(s); + valueOptional = token(s); + prev_token(s); + + value = pack(s, ap); + if(!value) { + if(ours) + jsonp_free(key); + + if(valueOptional != '*') { + set_error(s, "", json_error_null_value, "NULL object value"); + s->has_error = 1; + } + + next_token(s); + continue; + } + + if(s->has_error) + json_decref(value); + + if(!s->has_error && json_object_set_new_nocheck(object, key, value)) { + set_error(s, "", json_error_out_of_memory, "Unable to add key \"%s\"", key); + s->has_error = 1; + } + + if(ours) + jsonp_free(key); + + next_token(s); + } + + if(!s->has_error) + return object; + +error: + json_decref(object); + return NULL; +} + +static json_t *pack_array(scanner_t *s, va_list *ap) +{ + json_t *array = json_array(); + next_token(s); + + while(token(s) != ']') { + json_t *value; + char valueOptional; + + if(!token(s)) { + set_error(s, "", json_error_invalid_format, "Unexpected end of format string"); + /* Format string errors are unrecoverable. */ + goto error; + } + + next_token(s); + valueOptional = token(s); + prev_token(s); + + value = pack(s, ap); + if(!value) { + if(valueOptional != '*') { + s->has_error = 1; + } + + next_token(s); + continue; + } + + if(s->has_error) + json_decref(value); + + if(!s->has_error && json_array_append_new(array, value)) { + set_error(s, "", json_error_out_of_memory, "Unable to append to array"); + s->has_error = 1; + } + + next_token(s); + } + + if(!s->has_error) + return array; + +error: + json_decref(array); + return NULL; +} + +static json_t *pack_string(scanner_t *s, va_list *ap) +{ + char *str; + char t; + size_t len; + int ours; + int optional; + + next_token(s); + t = token(s); + optional = t == '?' || t == '*'; + if (!optional) + prev_token(s); + + str = read_string(s, ap, "string", &len, &ours, optional); + + if (!str) + return t == '?' && !s->has_error ? json_null() : NULL; + + if (s->has_error) { + /* It's impossible to reach this point if ours != 0, do not free str. */ + return NULL; + } + + if (ours) + return jsonp_stringn_nocheck_own(str, len); + + return json_stringn_nocheck(str, len); +} + +static json_t *pack_object_inter(scanner_t *s, va_list *ap, int need_incref) +{ + json_t *json; + char ntoken; + + next_token(s); + ntoken = token(s); + + if (ntoken != '?' && ntoken != '*') + prev_token(s); + + json = va_arg(*ap, json_t *); + + if (json) + return need_incref ? json_incref(json) : json; + + switch (ntoken) { + case '?': + return json_null(); + case '*': + return NULL; + default: + break; + } + + set_error(s, "", json_error_null_value, "NULL object"); + s->has_error = 1; + return NULL; +} + +static json_t *pack_integer(scanner_t *s, json_int_t value) +{ + json_t *json = json_integer(value); + + if (!json) { + set_error(s, "", json_error_out_of_memory, "Out of memory"); + s->has_error = 1; + } + + return json; +} + +static json_t *pack_real(scanner_t *s, double value) +{ + /* Allocate without setting value so we can identify OOM error. */ + json_t *json = json_real(0.0); + + if (!json) { + set_error(s, "", json_error_out_of_memory, "Out of memory"); + s->has_error = 1; + + return NULL; + } + + if (json_real_set(json, value)) { + json_decref(json); + + set_error(s, "", json_error_numeric_overflow, "Invalid floating point value"); + s->has_error = 1; + + return NULL; + } + + return json; +} + +static json_t *pack(scanner_t *s, va_list *ap) +{ + switch(token(s)) { + case '{': + return pack_object(s, ap); + + case '[': + return pack_array(s, ap); + + case 's': /* string */ + return pack_string(s, ap); + + case 'n': /* null */ + return json_null(); + + case 'b': /* boolean */ + return va_arg(*ap, int) ? json_true() : json_false(); + + case 'i': /* integer from int */ + return pack_integer(s, va_arg(*ap, int)); + + case 'I': /* integer from json_int_t */ + return pack_integer(s, va_arg(*ap, json_int_t)); + + case 'f': /* real */ + return pack_real(s, va_arg(*ap, double)); + + case 'O': /* a json_t object; increments refcount */ + return pack_object_inter(s, ap, 1); + + case 'o': /* a json_t object; doesn't increment refcount */ + return pack_object_inter(s, ap, 0); + + default: + set_error(s, "", json_error_invalid_format, "Unexpected format character '%c'", + token(s)); + s->has_error = 1; + return NULL; + } +} + +static int unpack(scanner_t *s, json_t *root, va_list *ap); + +static int unpack_object(scanner_t *s, json_t *root, va_list *ap) +{ + int ret = -1; + int strict = 0; + int gotopt = 0; + + /* Use a set (emulated by a hashtable) to check that all object + keys are accessed. Checking that the correct number of keys + were accessed is not enough, as the same key can be unpacked + multiple times. + */ + hashtable_t key_set; + + if(hashtable_init(&key_set)) { + set_error(s, "", json_error_out_of_memory, "Out of memory"); + return -1; + } + + if(root && !json_is_object(root)) { + set_error(s, "", json_error_wrong_type, "Expected object, got %s", + type_name(root)); + goto out; + } + next_token(s); + + while(token(s) != '}') { + const char *key; + json_t *value; + int opt = 0; + + if(strict != 0) { + set_error(s, "", json_error_invalid_format, "Expected '}' after '%c', got '%c'", + (strict == 1 ? '!' : '*'), token(s)); + goto out; + } + + if(!token(s)) { + set_error(s, "", json_error_invalid_format, "Unexpected end of format string"); + goto out; + } + + if(token(s) == '!' || token(s) == '*') { + strict = (token(s) == '!' ? 1 : -1); + next_token(s); + continue; + } + + if(token(s) != 's') { + set_error(s, "", json_error_invalid_format, "Expected format 's', got '%c'", token(s)); + goto out; + } + + key = va_arg(*ap, const char *); + if(!key) { + set_error(s, "", json_error_null_value, "NULL object key"); + goto out; + } + + next_token(s); + + if(token(s) == '?') { + opt = gotopt = 1; + next_token(s); + } + + if(!root) { + /* skipping */ + value = NULL; + } + else { + value = json_object_get(root, key); + if(!value && !opt) { + set_error(s, "", json_error_item_not_found, "Object item not found: %s", key); + goto out; + } + } + + if(unpack(s, value, ap)) + goto out; + + hashtable_set(&key_set, key, json_null()); + next_token(s); + } + + if(strict == 0 && (s->flags & JSON_STRICT)) + strict = 1; + + if(root && strict == 1) { + /* We need to check that all non optional items have been parsed */ + const char *key; + /* keys_res is 1 for uninitialized, 0 for success, -1 for error. */ + int keys_res = 1; + strbuffer_t unrecognized_keys; + json_t *value; + long unpacked = 0; + + if (gotopt || json_object_size(root) != key_set.size) { + json_object_foreach(root, key, value) { + if(!hashtable_get(&key_set, key)) { + unpacked++; + + /* Save unrecognized keys for the error message */ + if (keys_res == 1) { + keys_res = strbuffer_init(&unrecognized_keys); + } else if (!keys_res) { + keys_res = strbuffer_append_bytes(&unrecognized_keys, ", ", 2); + } + + if (!keys_res) + keys_res = strbuffer_append_bytes(&unrecognized_keys, key, strlen(key)); + } + } + } + if (unpacked) { + set_error(s, "", json_error_end_of_input_expected, + "%li object item(s) left unpacked: %s", + unpacked, + keys_res ? "" : strbuffer_value(&unrecognized_keys)); + strbuffer_close(&unrecognized_keys); + goto out; + } + } + + ret = 0; + +out: + hashtable_close(&key_set); + return ret; +} + +static int unpack_array(scanner_t *s, json_t *root, va_list *ap) +{ + size_t i = 0; + int strict = 0; + + if(root && !json_is_array(root)) { + set_error(s, "", json_error_wrong_type, "Expected array, got %s", type_name(root)); + return -1; + } + next_token(s); + + while(token(s) != ']') { + json_t *value; + + if(strict != 0) { + set_error(s, "", json_error_invalid_format, "Expected ']' after '%c', got '%c'", + (strict == 1 ? '!' : '*'), + token(s)); + return -1; + } + + if(!token(s)) { + set_error(s, "", json_error_invalid_format, "Unexpected end of format string"); + return -1; + } + + if(token(s) == '!' || token(s) == '*') { + strict = (token(s) == '!' ? 1 : -1); + next_token(s); + continue; + } + + if(!strchr(unpack_value_starters, token(s))) { + set_error(s, "", json_error_invalid_format, "Unexpected format character '%c'", + token(s)); + return -1; + } + + if(!root) { + /* skipping */ + value = NULL; + } + else { + value = json_array_get(root, i); + if(!value) { + set_error(s, "", json_error_index_out_of_range, "Array index %lu out of range", + (unsigned long)i); + return -1; + } + } + + if(unpack(s, value, ap)) + return -1; + + next_token(s); + i++; + } + + if(strict == 0 && (s->flags & JSON_STRICT)) + strict = 1; + + if(root && strict == 1 && i != json_array_size(root)) { + long diff = (long)json_array_size(root) - (long)i; + set_error(s, "", json_error_end_of_input_expected, "%li array item(s) left unpacked", diff); + return -1; + } + + return 0; +} + +static int unpack(scanner_t *s, json_t *root, va_list *ap) +{ + switch(token(s)) + { + case '{': + return unpack_object(s, root, ap); + + case '[': + return unpack_array(s, root, ap); + + case 's': + if(root && !json_is_string(root)) { + set_error(s, "", json_error_wrong_type, "Expected string, got %s", + type_name(root)); + return -1; + } + + if(!(s->flags & JSON_VALIDATE_ONLY)) { + const char **str_target; + size_t *len_target = NULL; + + str_target = va_arg(*ap, const char **); + if(!str_target) { + set_error(s, "", json_error_null_value, "NULL string argument"); + return -1; + } + + next_token(s); + + if(token(s) == '%') { + len_target = va_arg(*ap, size_t *); + if(!len_target) { + set_error(s, "", json_error_null_value, "NULL string length argument"); + return -1; + } + } + else + prev_token(s); + + if(root) { + *str_target = json_string_value(root); + if(len_target) + *len_target = json_string_length(root); + } + } + return 0; + + case 'i': + if(root && !json_is_integer(root)) { + set_error(s, "", json_error_wrong_type, "Expected integer, got %s", + type_name(root)); + return -1; + } + + if(!(s->flags & JSON_VALIDATE_ONLY)) { + int *target = va_arg(*ap, int*); + if(root) + *target = (int)json_integer_value(root); + } + + return 0; + + case 'I': + if(root && !json_is_integer(root)) { + set_error(s, "", json_error_wrong_type, "Expected integer, got %s", + type_name(root)); + return -1; + } + + if(!(s->flags & JSON_VALIDATE_ONLY)) { + json_int_t *target = va_arg(*ap, json_int_t*); + if(root) + *target = json_integer_value(root); + } + + return 0; + + case 'b': + if(root && !json_is_boolean(root)) { + set_error(s, "", json_error_wrong_type, "Expected true or false, got %s", + type_name(root)); + return -1; + } + + if(!(s->flags & JSON_VALIDATE_ONLY)) { + int *target = va_arg(*ap, int*); + if(root) + *target = json_is_true(root); + } + + return 0; + + case 'f': + if(root && !json_is_real(root)) { + set_error(s, "", json_error_wrong_type, "Expected real, got %s", + type_name(root)); + return -1; + } + + if(!(s->flags & JSON_VALIDATE_ONLY)) { + double *target = va_arg(*ap, double*); + if(root) + *target = json_real_value(root); + } + + return 0; + + case 'F': + if(root && !json_is_number(root)) { + set_error(s, "", json_error_wrong_type, "Expected real or integer, got %s", + type_name(root)); + return -1; + } + + if(!(s->flags & JSON_VALIDATE_ONLY)) { + double *target = va_arg(*ap, double*); + if(root) + *target = json_number_value(root); + } + + return 0; + + case 'O': + if(root && !(s->flags & JSON_VALIDATE_ONLY)) + json_incref(root); + /* Fall through */ + + case 'o': + if(!(s->flags & JSON_VALIDATE_ONLY)) { + json_t **target = va_arg(*ap, json_t**); + if(root) + *target = root; + } + + return 0; + + case 'n': + /* Never assign, just validate */ + if(root && !json_is_null(root)) { + set_error(s, "", json_error_wrong_type, "Expected null, got %s", + type_name(root)); + return -1; + } + return 0; + + default: + set_error(s, "", json_error_invalid_format, "Unexpected format character '%c'", + token(s)); + return -1; + } +} + +json_t *json_vpack_ex(json_error_t *error, size_t flags, + const char *fmt, va_list ap) +{ + scanner_t s; + va_list ap_copy; + json_t *value; + + if(!fmt || !*fmt) { + jsonp_error_init(error, ""); + jsonp_error_set(error, -1, -1, 0, json_error_invalid_argument, "NULL or empty format string"); + return NULL; + } + jsonp_error_init(error, NULL); + + scanner_init(&s, error, flags, fmt); + next_token(&s); + + va_copy(ap_copy, ap); + value = pack(&s, &ap_copy); + va_end(ap_copy); + + /* This will cover all situations where s.has_error is true */ + if(!value) + return NULL; + + next_token(&s); + if(token(&s)) { + json_decref(value); + set_error(&s, "", json_error_invalid_format, "Garbage after format string"); + return NULL; + } + + return value; +} + +json_t *json_pack_ex(json_error_t *error, size_t flags, const char *fmt, ...) +{ + json_t *value; + va_list ap; + + va_start(ap, fmt); + value = json_vpack_ex(error, flags, fmt, ap); + va_end(ap); + + return value; +} + +json_t *json_pack(const char *fmt, ...) +{ + json_t *value; + va_list ap; + + va_start(ap, fmt); + value = json_vpack_ex(NULL, 0, fmt, ap); + va_end(ap); + + return value; +} + +int json_vunpack_ex(json_t *root, json_error_t *error, size_t flags, + const char *fmt, va_list ap) +{ + scanner_t s; + va_list ap_copy; + + if(!root) { + jsonp_error_init(error, ""); + jsonp_error_set(error, -1, -1, 0, json_error_null_value, "NULL root value"); + return -1; + } + + if(!fmt || !*fmt) { + jsonp_error_init(error, ""); + jsonp_error_set(error, -1, -1, 0, json_error_invalid_argument, "NULL or empty format string"); + return -1; + } + jsonp_error_init(error, NULL); + + scanner_init(&s, error, flags, fmt); + next_token(&s); + + va_copy(ap_copy, ap); + if(unpack(&s, root, &ap_copy)) { + va_end(ap_copy); + return -1; + } + va_end(ap_copy); + + next_token(&s); + if(token(&s)) { + set_error(&s, "", json_error_invalid_format, "Garbage after format string"); + return -1; + } + + return 0; +} + +int json_unpack_ex(json_t *root, json_error_t *error, size_t flags, const char *fmt, ...) +{ + int ret; + va_list ap; + + va_start(ap, fmt); + ret = json_vunpack_ex(root, error, flags, fmt, ap); + va_end(ap); + + return ret; +} + +int json_unpack(json_t *root, const char *fmt, ...) +{ + int ret; + va_list ap; + + va_start(ap, fmt); + ret = json_vunpack_ex(root, NULL, 0, fmt, ap); + va_end(ap); + + return ret; +} diff --git a/3party/jansson/src/strbuffer.c b/3party/jansson/src/strbuffer.c new file mode 100644 index 0000000000..5e8c003956 --- /dev/null +++ b/3party/jansson/src/strbuffer.c @@ -0,0 +1,111 @@ +/* + * Copyright (c) 2009-2016 Petri Lehtinen + * + * Jansson is free software; you can redistribute it and/or modify + * it under the terms of the MIT license. See LICENSE for details. + */ + +#ifndef _GNU_SOURCE +#define _GNU_SOURCE +#endif + +#include +#include +#include "jansson_private.h" +#include "strbuffer.h" + +#define STRBUFFER_MIN_SIZE 16 +#define STRBUFFER_FACTOR 2 +#define STRBUFFER_SIZE_MAX ((size_t)-1) + +int strbuffer_init(strbuffer_t *strbuff) +{ + strbuff->size = STRBUFFER_MIN_SIZE; + strbuff->length = 0; + + strbuff->value = jsonp_malloc(strbuff->size); + if(!strbuff->value) + return -1; + + /* initialize to empty */ + strbuff->value[0] = '\0'; + return 0; +} + +void strbuffer_close(strbuffer_t *strbuff) +{ + if(strbuff->value) + jsonp_free(strbuff->value); + + strbuff->size = 0; + strbuff->length = 0; + strbuff->value = NULL; +} + +void strbuffer_clear(strbuffer_t *strbuff) +{ + strbuff->length = 0; + strbuff->value[0] = '\0'; +} + +const char *strbuffer_value(const strbuffer_t *strbuff) +{ + return strbuff->value; +} + +char *strbuffer_steal_value(strbuffer_t *strbuff) +{ + char *result = strbuff->value; + strbuff->value = NULL; + return result; +} + +int strbuffer_append_byte(strbuffer_t *strbuff, char byte) +{ + return strbuffer_append_bytes(strbuff, &byte, 1); +} + +int strbuffer_append_bytes(strbuffer_t *strbuff, const char *data, size_t size) +{ + if(size >= strbuff->size - strbuff->length) + { + size_t new_size; + char *new_value; + + /* avoid integer overflow */ + if (strbuff->size > STRBUFFER_SIZE_MAX / STRBUFFER_FACTOR + || size > STRBUFFER_SIZE_MAX - 1 + || strbuff->length > STRBUFFER_SIZE_MAX - 1 - size) + return -1; + + new_size = max(strbuff->size * STRBUFFER_FACTOR, + strbuff->length + size + 1); + + new_value = jsonp_malloc(new_size); + if(!new_value) + return -1; + + memcpy(new_value, strbuff->value, strbuff->length); + + jsonp_free(strbuff->value); + strbuff->value = new_value; + strbuff->size = new_size; + } + + memcpy(strbuff->value + strbuff->length, data, size); + strbuff->length += size; + strbuff->value[strbuff->length] = '\0'; + + return 0; +} + +char strbuffer_pop(strbuffer_t *strbuff) +{ + if(strbuff->length > 0) { + char c = strbuff->value[--strbuff->length]; + strbuff->value[strbuff->length] = '\0'; + return c; + } + else + return '\0'; +} diff --git a/3party/jansson/src/strbuffer.h b/3party/jansson/src/strbuffer.h new file mode 100644 index 0000000000..a0276d4b1c --- /dev/null +++ b/3party/jansson/src/strbuffer.h @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2009-2016 Petri Lehtinen + * + * Jansson is free software; you can redistribute it and/or modify + * it under the terms of the MIT license. See LICENSE for details. + */ + +#ifndef STRBUFFER_H +#define STRBUFFER_H + +#include + +typedef struct { + char *value; + size_t length; /* bytes used */ + size_t size; /* bytes allocated */ +} strbuffer_t; + +int strbuffer_init(strbuffer_t *strbuff) JANSSON_ATTRS(warn_unused_result); +void strbuffer_close(strbuffer_t *strbuff); + +void strbuffer_clear(strbuffer_t *strbuff); + +const char *strbuffer_value(const strbuffer_t *strbuff); + +/* Steal the value and close the strbuffer */ +char *strbuffer_steal_value(strbuffer_t *strbuff); + +int strbuffer_append_byte(strbuffer_t *strbuff, char byte); +int strbuffer_append_bytes(strbuffer_t *strbuff, const char *data, size_t size); + +char strbuffer_pop(strbuffer_t *strbuff); + +#endif diff --git a/3party/jansson/src/strconv.c b/3party/jansson/src/strconv.c new file mode 100644 index 0000000000..8075481e3b --- /dev/null +++ b/3party/jansson/src/strconv.c @@ -0,0 +1,145 @@ +#include +#include +#include +#include +#include +#ifdef __MINGW32__ +#undef __NO_ISOCEXT /* ensure stdlib.h will declare prototypes for mingw own 'strtod' replacement, called '__strtod' */ +#endif +#include "jansson_private.h" +#include "strbuffer.h" + +/* need jansson_private_config.h to get the correct snprintf */ +#ifdef HAVE_CONFIG_H +#include +#endif + +#ifdef __MINGW32__ +#define strtod __strtod +#endif + +#if JSON_HAVE_LOCALECONV +#include + +/* + - This code assumes that the decimal separator is exactly one + character. + + - If setlocale() is called by another thread between the call to + localeconv() and the call to sprintf() or strtod(), the result may + be wrong. setlocale() is not thread-safe and should not be used + this way. Multi-threaded programs should use uselocale() instead. +*/ + +static void to_locale(strbuffer_t *strbuffer) +{ + const char *point; + char *pos; + + point = localeconv()->decimal_point; + if(*point == '.') { + /* No conversion needed */ + return; + } + + pos = strchr(strbuffer->value, '.'); + if(pos) + *pos = *point; +} + +static void from_locale(char *buffer) +{ + const char *point; + char *pos; + + point = localeconv()->decimal_point; + if(*point == '.') { + /* No conversion needed */ + return; + } + + pos = strchr(buffer, *point); + if(pos) + *pos = '.'; +} +#endif + +int jsonp_strtod(strbuffer_t *strbuffer, double *out) +{ + double value; + char *end; + +#if JSON_HAVE_LOCALECONV + to_locale(strbuffer); +#endif + + errno = 0; + value = strtod(strbuffer->value, &end); + assert(end == strbuffer->value + strbuffer->length); + + if((value == HUGE_VAL || value == -HUGE_VAL) && errno == ERANGE) { + /* Overflow */ + return -1; + } + + *out = value; + return 0; +} + +int jsonp_dtostr(char *buffer, size_t size, double value, int precision) +{ + int ret; + char *start, *end; + size_t length; + + if (precision == 0) + precision = 17; + + ret = snprintf(buffer, size, "%.*g", precision, value); + if(ret < 0) + return -1; + + length = (size_t)ret; + if(length >= size) + return -1; + +#if JSON_HAVE_LOCALECONV + from_locale(buffer); +#endif + + /* Make sure there's a dot or 'e' in the output. Otherwise + a real is converted to an integer when decoding */ + if(strchr(buffer, '.') == NULL && + strchr(buffer, 'e') == NULL) + { + if(length + 3 >= size) { + /* No space to append ".0" */ + return -1; + } + buffer[length] = '.'; + buffer[length + 1] = '0'; + buffer[length + 2] = '\0'; + length += 2; + } + + /* Remove leading '+' from positive exponent. Also remove leading + zeros from exponents (added by some printf() implementations) */ + start = strchr(buffer, 'e'); + if(start) { + start++; + end = start + 1; + + if(*start == '-') + start++; + + while(*end == '0') + end++; + + if(end != start) { + memmove(start, end, length - (size_t)(end - buffer)); + length -= (size_t)(end - start); + } + } + + return (int)length; +} diff --git a/3party/jansson/src/utf.c b/3party/jansson/src/utf.c new file mode 100644 index 0000000000..be966cbd80 --- /dev/null +++ b/3party/jansson/src/utf.c @@ -0,0 +1,187 @@ +/* + * Copyright (c) 2009-2016 Petri Lehtinen + * + * Jansson is free software; you can redistribute it and/or modify + * it under the terms of the MIT license. See LICENSE for details. + */ + +#include +#include "utf.h" + +int utf8_encode(int32_t codepoint, char *buffer, size_t *size) +{ + if(codepoint < 0) + return -1; + else if(codepoint < 0x80) + { + buffer[0] = (char)codepoint; + *size = 1; + } + else if(codepoint < 0x800) + { + buffer[0] = 0xC0 + ((codepoint & 0x7C0) >> 6); + buffer[1] = 0x80 + ((codepoint & 0x03F)); + *size = 2; + } + else if(codepoint < 0x10000) + { + buffer[0] = 0xE0 + ((codepoint & 0xF000) >> 12); + buffer[1] = 0x80 + ((codepoint & 0x0FC0) >> 6); + buffer[2] = 0x80 + ((codepoint & 0x003F)); + *size = 3; + } + else if(codepoint <= 0x10FFFF) + { + buffer[0] = 0xF0 + ((codepoint & 0x1C0000) >> 18); + buffer[1] = 0x80 + ((codepoint & 0x03F000) >> 12); + buffer[2] = 0x80 + ((codepoint & 0x000FC0) >> 6); + buffer[3] = 0x80 + ((codepoint & 0x00003F)); + *size = 4; + } + else + return -1; + + return 0; +} + +size_t utf8_check_first(char byte) +{ + unsigned char u = (unsigned char)byte; + + if(u < 0x80) + return 1; + + if(0x80 <= u && u <= 0xBF) { + /* second, third or fourth byte of a multi-byte + sequence, i.e. a "continuation byte" */ + return 0; + } + else if(u == 0xC0 || u == 0xC1) { + /* overlong encoding of an ASCII byte */ + return 0; + } + else if(0xC2 <= u && u <= 0xDF) { + /* 2-byte sequence */ + return 2; + } + + else if(0xE0 <= u && u <= 0xEF) { + /* 3-byte sequence */ + return 3; + } + else if(0xF0 <= u && u <= 0xF4) { + /* 4-byte sequence */ + return 4; + } + else { /* u >= 0xF5 */ + /* Restricted (start of 4-, 5- or 6-byte sequence) or invalid + UTF-8 */ + return 0; + } +} + +size_t utf8_check_full(const char *buffer, size_t size, int32_t *codepoint) +{ + size_t i; + int32_t value = 0; + unsigned char u = (unsigned char)buffer[0]; + + if(size == 2) + { + value = u & 0x1F; + } + else if(size == 3) + { + value = u & 0xF; + } + else if(size == 4) + { + value = u & 0x7; + } + else + return 0; + + for(i = 1; i < size; i++) + { + u = (unsigned char)buffer[i]; + + if(u < 0x80 || u > 0xBF) { + /* not a continuation byte */ + return 0; + } + + value = (value << 6) + (u & 0x3F); + } + + if(value > 0x10FFFF) { + /* not in Unicode range */ + return 0; + } + + else if(0xD800 <= value && value <= 0xDFFF) { + /* invalid code point (UTF-16 surrogate halves) */ + return 0; + } + + else if((size == 2 && value < 0x80) || + (size == 3 && value < 0x800) || + (size == 4 && value < 0x10000)) { + /* overlong encoding */ + return 0; + } + + if(codepoint) + *codepoint = value; + + return 1; +} + +const char *utf8_iterate(const char *buffer, size_t bufsize, int32_t *codepoint) +{ + size_t count; + int32_t value; + + if(!bufsize) + return buffer; + + count = utf8_check_first(buffer[0]); + if(count <= 0) + return NULL; + + if(count == 1) + value = (unsigned char)buffer[0]; + else + { + if(count > bufsize || !utf8_check_full(buffer, count, &value)) + return NULL; + } + + if(codepoint) + *codepoint = value; + + return buffer + count; +} + +int utf8_check_string(const char *string, size_t length) +{ + size_t i; + + for(i = 0; i < length; i++) + { + size_t count = utf8_check_first(string[i]); + if(count == 0) + return 0; + else if(count > 1) + { + if(count > length - i) + return 0; + + if(!utf8_check_full(&string[i], count, NULL)) + return 0; + + i += count - 1; + } + } + + return 1; +} diff --git a/3party/jansson/src/utf.h b/3party/jansson/src/utf.h new file mode 100644 index 0000000000..f4cda08dbc --- /dev/null +++ b/3party/jansson/src/utf.h @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2009-2016 Petri Lehtinen + * + * Jansson is free software; you can redistribute it and/or modify + * it under the terms of the MIT license. See LICENSE for details. + */ + +#ifndef UTF_H +#define UTF_H + +#ifdef HAVE_CONFIG_H +#include +#endif + + +#ifdef _WIN32 +typedef int int32_t; +#else /* !_WIN32 */ +/* Assume a standard environment */ +#include +#endif /* _WIN32 */ + +#ifdef HAVE_STDINT_H +#include +#endif + + +int utf8_encode(int32_t codepoint, char *buffer, size_t *size); + +size_t utf8_check_first(char byte); +size_t utf8_check_full(const char *buffer, size_t size, int32_t *codepoint); +const char *utf8_iterate(const char *buffer, size_t size, int32_t *codepoint); + +int utf8_check_string(const char *string, size_t length); + +#endif diff --git a/3party/jansson/src/value.c b/3party/jansson/src/value.c new file mode 100644 index 0000000000..3f964a041c --- /dev/null +++ b/3party/jansson/src/value.c @@ -0,0 +1,1074 @@ +/* + * Copyright (c) 2009-2016 Petri Lehtinen + * + * Jansson is free software; you can redistribute it and/or modify + * it under the terms of the MIT license. See LICENSE for details. + */ + +#ifndef _GNU_SOURCE +#define _GNU_SOURCE +#endif + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include +#include + +#ifdef HAVE_STDINT_H +#include +#endif + +#include "jansson.h" +#include "hashtable.h" +#include "jansson_private.h" +#include "utf.h" + +/* Work around nonstandard isnan() and isinf() implementations */ +#ifndef isnan +#ifndef __sun +static JSON_INLINE int isnan(double x) { return x != x; } +#endif +#endif +#ifndef isinf +static JSON_INLINE int isinf(double x) { return !isnan(x) && isnan(x - x); } +#endif + +static JSON_INLINE void json_init(json_t *json, json_type type) +{ + json->type = type; + json->refcount = 1; +} + + +/*** object ***/ + +extern volatile uint32_t hashtable_seed; + +json_t *json_object(void) +{ + json_object_t *object = jsonp_malloc(sizeof(json_object_t)); + if(!object) + return NULL; + + if (!hashtable_seed) { + /* Autoseed */ + json_object_seed(0); + } + + json_init(&object->json, JSON_OBJECT); + + if(hashtable_init(&object->hashtable)) + { + jsonp_free(object); + return NULL; + } + + return &object->json; +} + +static void json_delete_object(json_object_t *object) +{ + hashtable_close(&object->hashtable); + jsonp_free(object); +} + +size_t json_object_size(const json_t *json) +{ + json_object_t *object; + + if(!json_is_object(json)) + return 0; + + object = json_to_object(json); + return object->hashtable.size; +} + +json_t *json_object_get(const json_t *json, const char *key) +{ + json_object_t *object; + + if(!key || !json_is_object(json)) + return NULL; + + object = json_to_object(json); + return hashtable_get(&object->hashtable, key); +} + +int json_object_set_new_nocheck(json_t *json, const char *key, json_t *value) +{ + json_object_t *object; + + if(!value) + return -1; + + if(!key || !json_is_object(json) || json == value) + { + json_decref(value); + return -1; + } + object = json_to_object(json); + + if(hashtable_set(&object->hashtable, key, value)) + { + json_decref(value); + return -1; + } + + return 0; +} + +int json_object_set_new(json_t *json, const char *key, json_t *value) +{ + if(!key || !utf8_check_string(key, strlen(key))) + { + json_decref(value); + return -1; + } + + return json_object_set_new_nocheck(json, key, value); +} + +int json_object_del(json_t *json, const char *key) +{ + json_object_t *object; + + if(!key || !json_is_object(json)) + return -1; + + object = json_to_object(json); + return hashtable_del(&object->hashtable, key); +} + +int json_object_clear(json_t *json) +{ + json_object_t *object; + + if(!json_is_object(json)) + return -1; + + object = json_to_object(json); + hashtable_clear(&object->hashtable); + + return 0; +} + +int json_object_update(json_t *object, json_t *other) +{ + const char *key; + json_t *value; + + if(!json_is_object(object) || !json_is_object(other)) + return -1; + + json_object_foreach(other, key, value) { + if(json_object_set_nocheck(object, key, value)) + return -1; + } + + return 0; +} + +int json_object_update_existing(json_t *object, json_t *other) +{ + const char *key; + json_t *value; + + if(!json_is_object(object) || !json_is_object(other)) + return -1; + + json_object_foreach(other, key, value) { + if(json_object_get(object, key)) + json_object_set_nocheck(object, key, value); + } + + return 0; +} + +int json_object_update_missing(json_t *object, json_t *other) +{ + const char *key; + json_t *value; + + if(!json_is_object(object) || !json_is_object(other)) + return -1; + + json_object_foreach(other, key, value) { + if(!json_object_get(object, key)) + json_object_set_nocheck(object, key, value); + } + + return 0; +} + +void *json_object_iter(json_t *json) +{ + json_object_t *object; + + if(!json_is_object(json)) + return NULL; + + object = json_to_object(json); + return hashtable_iter(&object->hashtable); +} + +void *json_object_iter_at(json_t *json, const char *key) +{ + json_object_t *object; + + if(!key || !json_is_object(json)) + return NULL; + + object = json_to_object(json); + return hashtable_iter_at(&object->hashtable, key); +} + +void *json_object_iter_next(json_t *json, void *iter) +{ + json_object_t *object; + + if(!json_is_object(json) || iter == NULL) + return NULL; + + object = json_to_object(json); + return hashtable_iter_next(&object->hashtable, iter); +} + +const char *json_object_iter_key(void *iter) +{ + if(!iter) + return NULL; + + return hashtable_iter_key(iter); +} + +json_t *json_object_iter_value(void *iter) +{ + if(!iter) + return NULL; + + return (json_t *)hashtable_iter_value(iter); +} + +int json_object_iter_set_new(json_t *json, void *iter, json_t *value) +{ + if(!json_is_object(json) || !iter || !value) + { + json_decref(value); + return -1; + } + + hashtable_iter_set(iter, value); + return 0; +} + +void *json_object_key_to_iter(const char *key) +{ + if(!key) + return NULL; + + return hashtable_key_to_iter(key); +} + +static int json_object_equal(const json_t *object1, const json_t *object2) +{ + const char *key; + const json_t *value1, *value2; + + if(json_object_size(object1) != json_object_size(object2)) + return 0; + + json_object_foreach((json_t *)object1, key, value1) { + value2 = json_object_get(object2, key); + + if(!json_equal(value1, value2)) + return 0; + } + + return 1; +} + +static json_t *json_object_copy(json_t *object) +{ + json_t *result; + + const char *key; + json_t *value; + + result = json_object(); + if(!result) + return NULL; + + json_object_foreach(object, key, value) + json_object_set_nocheck(result, key, value); + + return result; +} + +static json_t *json_object_deep_copy(const json_t *object) +{ + json_t *result; + void *iter; + + result = json_object(); + if(!result) + return NULL; + + /* Cannot use json_object_foreach because object has to be cast + non-const */ + iter = json_object_iter((json_t *)object); + while(iter) { + const char *key; + const json_t *value; + key = json_object_iter_key(iter); + value = json_object_iter_value(iter); + + json_object_set_new_nocheck(result, key, json_deep_copy(value)); + iter = json_object_iter_next((json_t *)object, iter); + } + + return result; +} + + +/*** array ***/ + +json_t *json_array(void) +{ + json_array_t *array = jsonp_malloc(sizeof(json_array_t)); + if(!array) + return NULL; + json_init(&array->json, JSON_ARRAY); + + array->entries = 0; + array->size = 8; + + array->table = jsonp_malloc(array->size * sizeof(json_t *)); + if(!array->table) { + jsonp_free(array); + return NULL; + } + + return &array->json; +} + +static void json_delete_array(json_array_t *array) +{ + size_t i; + + for(i = 0; i < array->entries; i++) + json_decref(array->table[i]); + + jsonp_free(array->table); + jsonp_free(array); +} + +size_t json_array_size(const json_t *json) +{ + if(!json_is_array(json)) + return 0; + + return json_to_array(json)->entries; +} + +json_t *json_array_get(const json_t *json, size_t index) +{ + json_array_t *array; + if(!json_is_array(json)) + return NULL; + array = json_to_array(json); + + if(index >= array->entries) + return NULL; + + return array->table[index]; +} + +int json_array_set_new(json_t *json, size_t index, json_t *value) +{ + json_array_t *array; + + if(!value) + return -1; + + if(!json_is_array(json) || json == value) + { + json_decref(value); + return -1; + } + array = json_to_array(json); + + if(index >= array->entries) + { + json_decref(value); + return -1; + } + + json_decref(array->table[index]); + array->table[index] = value; + + return 0; +} + +static void array_move(json_array_t *array, size_t dest, + size_t src, size_t count) +{ + memmove(&array->table[dest], &array->table[src], count * sizeof(json_t *)); +} + +static void array_copy(json_t **dest, size_t dpos, + json_t **src, size_t spos, + size_t count) +{ + memcpy(&dest[dpos], &src[spos], count * sizeof(json_t *)); +} + +static json_t **json_array_grow(json_array_t *array, + size_t amount, + int copy) +{ + size_t new_size; + json_t **old_table, **new_table; + + if(array->entries + amount <= array->size) + return array->table; + + old_table = array->table; + + new_size = max(array->size + amount, array->size * 2); + new_table = jsonp_malloc(new_size * sizeof(json_t *)); + if(!new_table) + return NULL; + + array->size = new_size; + array->table = new_table; + + if(copy) { + array_copy(array->table, 0, old_table, 0, array->entries); + jsonp_free(old_table); + return array->table; + } + + return old_table; +} + +int json_array_append_new(json_t *json, json_t *value) +{ + json_array_t *array; + + if(!value) + return -1; + + if(!json_is_array(json) || json == value) + { + json_decref(value); + return -1; + } + array = json_to_array(json); + + if(!json_array_grow(array, 1, 1)) { + json_decref(value); + return -1; + } + + array->table[array->entries] = value; + array->entries++; + + return 0; +} + +int json_array_insert_new(json_t *json, size_t index, json_t *value) +{ + json_array_t *array; + json_t **old_table; + + if(!value) + return -1; + + if(!json_is_array(json) || json == value) { + json_decref(value); + return -1; + } + array = json_to_array(json); + + if(index > array->entries) { + json_decref(value); + return -1; + } + + old_table = json_array_grow(array, 1, 0); + if(!old_table) { + json_decref(value); + return -1; + } + + if(old_table != array->table) { + array_copy(array->table, 0, old_table, 0, index); + array_copy(array->table, index + 1, old_table, index, + array->entries - index); + jsonp_free(old_table); + } + else + array_move(array, index + 1, index, array->entries - index); + + array->table[index] = value; + array->entries++; + + return 0; +} + +int json_array_remove(json_t *json, size_t index) +{ + json_array_t *array; + + if(!json_is_array(json)) + return -1; + array = json_to_array(json); + + if(index >= array->entries) + return -1; + + json_decref(array->table[index]); + + /* If we're removing the last element, nothing has to be moved */ + if(index < array->entries - 1) + array_move(array, index, index + 1, array->entries - index - 1); + + array->entries--; + + return 0; +} + +int json_array_clear(json_t *json) +{ + json_array_t *array; + size_t i; + + if(!json_is_array(json)) + return -1; + array = json_to_array(json); + + for(i = 0; i < array->entries; i++) + json_decref(array->table[i]); + + array->entries = 0; + return 0; +} + +int json_array_extend(json_t *json, json_t *other_json) +{ + json_array_t *array, *other; + size_t i; + + if(!json_is_array(json) || !json_is_array(other_json)) + return -1; + array = json_to_array(json); + other = json_to_array(other_json); + + if(!json_array_grow(array, other->entries, 1)) + return -1; + + for(i = 0; i < other->entries; i++) + json_incref(other->table[i]); + + array_copy(array->table, array->entries, other->table, 0, other->entries); + + array->entries += other->entries; + return 0; +} + +static int json_array_equal(const json_t *array1, const json_t *array2) +{ + size_t i, size; + + size = json_array_size(array1); + if(size != json_array_size(array2)) + return 0; + + for(i = 0; i < size; i++) + { + json_t *value1, *value2; + + value1 = json_array_get(array1, i); + value2 = json_array_get(array2, i); + + if(!json_equal(value1, value2)) + return 0; + } + + return 1; +} + +static json_t *json_array_copy(json_t *array) +{ + json_t *result; + size_t i; + + result = json_array(); + if(!result) + return NULL; + + for(i = 0; i < json_array_size(array); i++) + json_array_append(result, json_array_get(array, i)); + + return result; +} + +static json_t *json_array_deep_copy(const json_t *array) +{ + json_t *result; + size_t i; + + result = json_array(); + if(!result) + return NULL; + + for(i = 0; i < json_array_size(array); i++) + json_array_append_new(result, json_deep_copy(json_array_get(array, i))); + + return result; +} + +/*** string ***/ + +static json_t *string_create(const char *value, size_t len, int own) +{ + char *v; + json_string_t *string; + + if(!value) + return NULL; + + if(own) + v = (char *)value; + else { + v = jsonp_strndup(value, len); + if(!v) + return NULL; + } + + string = jsonp_malloc(sizeof(json_string_t)); + if(!string) { + jsonp_free(v); + return NULL; + } + json_init(&string->json, JSON_STRING); + string->value = v; + string->length = len; + + return &string->json; +} + +json_t *json_string_nocheck(const char *value) +{ + if(!value) + return NULL; + + return string_create(value, strlen(value), 0); +} + +json_t *json_stringn_nocheck(const char *value, size_t len) +{ + return string_create(value, len, 0); +} + +/* this is private; "steal" is not a public API concept */ +json_t *jsonp_stringn_nocheck_own(const char *value, size_t len) +{ + return string_create(value, len, 1); +} + +json_t *json_string(const char *value) +{ + if(!value) + return NULL; + + return json_stringn(value, strlen(value)); +} + +json_t *json_stringn(const char *value, size_t len) +{ + if(!value || !utf8_check_string(value, len)) + return NULL; + + return json_stringn_nocheck(value, len); +} + +const char *json_string_value(const json_t *json) +{ + if(!json_is_string(json)) + return NULL; + + return json_to_string(json)->value; +} + +size_t json_string_length(const json_t *json) +{ + if(!json_is_string(json)) + return 0; + + return json_to_string(json)->length; +} + +int json_string_set_nocheck(json_t *json, const char *value) +{ + if(!value) + return -1; + + return json_string_setn_nocheck(json, value, strlen(value)); +} + +int json_string_setn_nocheck(json_t *json, const char *value, size_t len) +{ + char *dup; + json_string_t *string; + + if(!json_is_string(json) || !value) + return -1; + + dup = jsonp_strndup(value, len); + if(!dup) + return -1; + + string = json_to_string(json); + jsonp_free(string->value); + string->value = dup; + string->length = len; + + return 0; +} + +int json_string_set(json_t *json, const char *value) +{ + if(!value) + return -1; + + return json_string_setn(json, value, strlen(value)); +} + +int json_string_setn(json_t *json, const char *value, size_t len) +{ + if(!value || !utf8_check_string(value, len)) + return -1; + + return json_string_setn_nocheck(json, value, len); +} + +static void json_delete_string(json_string_t *string) +{ + jsonp_free(string->value); + jsonp_free(string); +} + +static int json_string_equal(const json_t *string1, const json_t *string2) +{ + json_string_t *s1, *s2; + + s1 = json_to_string(string1); + s2 = json_to_string(string2); + return s1->length == s2->length && !memcmp(s1->value, s2->value, s1->length); +} + +static json_t *json_string_copy(const json_t *string) +{ + json_string_t *s; + + s = json_to_string(string); + return json_stringn_nocheck(s->value, s->length); +} + +json_t *json_vsprintf(const char *fmt, va_list ap) { + json_t *json = NULL; + int length; + char *buf; + va_list aq; + va_copy(aq, ap); + + length = vsnprintf(NULL, 0, fmt, ap); + if (length == 0) { + json = json_string(""); + goto out; + } + + buf = jsonp_malloc(length + 1); + if (!buf) + goto out; + + vsnprintf(buf, length + 1, fmt, aq); + if (!utf8_check_string(buf, length)) { + jsonp_free(buf); + goto out; + } + + json = jsonp_stringn_nocheck_own(buf, length); + +out: + va_end(aq); + return json; +} + +json_t *json_sprintf(const char *fmt, ...) { + json_t *result; + va_list ap; + + va_start(ap, fmt); + result = json_vsprintf(fmt, ap); + va_end(ap); + + return result; +} + + +/*** integer ***/ + +json_t *json_integer(json_int_t value) +{ + json_integer_t *integer = jsonp_malloc(sizeof(json_integer_t)); + if(!integer) + return NULL; + json_init(&integer->json, JSON_INTEGER); + + integer->value = value; + return &integer->json; +} + +json_int_t json_integer_value(const json_t *json) +{ + if(!json_is_integer(json)) + return 0; + + return json_to_integer(json)->value; +} + +int json_integer_set(json_t *json, json_int_t value) +{ + if(!json_is_integer(json)) + return -1; + + json_to_integer(json)->value = value; + + return 0; +} + +static void json_delete_integer(json_integer_t *integer) +{ + jsonp_free(integer); +} + +static int json_integer_equal(const json_t *integer1, const json_t *integer2) +{ + return json_integer_value(integer1) == json_integer_value(integer2); +} + +static json_t *json_integer_copy(const json_t *integer) +{ + return json_integer(json_integer_value(integer)); +} + + +/*** real ***/ + +json_t *json_real(double value) +{ + json_real_t *real; + + if(isnan(value) || isinf(value)) + return NULL; + + real = jsonp_malloc(sizeof(json_real_t)); + if(!real) + return NULL; + json_init(&real->json, JSON_REAL); + + real->value = value; + return &real->json; +} + +double json_real_value(const json_t *json) +{ + if(!json_is_real(json)) + return 0; + + return json_to_real(json)->value; +} + +int json_real_set(json_t *json, double value) +{ + if(!json_is_real(json) || isnan(value) || isinf(value)) + return -1; + + json_to_real(json)->value = value; + + return 0; +} + +static void json_delete_real(json_real_t *real) +{ + jsonp_free(real); +} + +static int json_real_equal(const json_t *real1, const json_t *real2) +{ + return json_real_value(real1) == json_real_value(real2); +} + +static json_t *json_real_copy(const json_t *real) +{ + return json_real(json_real_value(real)); +} + + +/*** number ***/ + +double json_number_value(const json_t *json) +{ + if(json_is_integer(json)) + return (double)json_integer_value(json); + else if(json_is_real(json)) + return json_real_value(json); + else + return 0.0; +} + + +/*** simple values ***/ + +json_t *json_true(void) +{ + static json_t the_true = {JSON_TRUE, (size_t)-1}; + return &the_true; +} + + +json_t *json_false(void) +{ + static json_t the_false = {JSON_FALSE, (size_t)-1}; + return &the_false; +} + + +json_t *json_null(void) +{ + static json_t the_null = {JSON_NULL, (size_t)-1}; + return &the_null; +} + + +/*** deletion ***/ + +void json_delete(json_t *json) +{ + if (!json) + return; + + switch(json_typeof(json)) { + case JSON_OBJECT: + json_delete_object(json_to_object(json)); + break; + case JSON_ARRAY: + json_delete_array(json_to_array(json)); + break; + case JSON_STRING: + json_delete_string(json_to_string(json)); + break; + case JSON_INTEGER: + json_delete_integer(json_to_integer(json)); + break; + case JSON_REAL: + json_delete_real(json_to_real(json)); + break; + default: + return; + } + + /* json_delete is not called for true, false or null */ +} + + +/*** equality ***/ + +int json_equal(const json_t *json1, const json_t *json2) +{ + if(!json1 || !json2) + return 0; + + if(json_typeof(json1) != json_typeof(json2)) + return 0; + + /* this covers true, false and null as they are singletons */ + if(json1 == json2) + return 1; + + switch(json_typeof(json1)) { + case JSON_OBJECT: + return json_object_equal(json1, json2); + case JSON_ARRAY: + return json_array_equal(json1, json2); + case JSON_STRING: + return json_string_equal(json1, json2); + case JSON_INTEGER: + return json_integer_equal(json1, json2); + case JSON_REAL: + return json_real_equal(json1, json2); + default: + return 0; + } +} + + +/*** copying ***/ + +json_t *json_copy(json_t *json) +{ + if(!json) + return NULL; + + switch(json_typeof(json)) { + case JSON_OBJECT: + return json_object_copy(json); + case JSON_ARRAY: + return json_array_copy(json); + case JSON_STRING: + return json_string_copy(json); + case JSON_INTEGER: + return json_integer_copy(json); + case JSON_REAL: + return json_real_copy(json); + case JSON_TRUE: + case JSON_FALSE: + case JSON_NULL: + return json; + default: + return NULL; + } +} + +json_t *json_deep_copy(const json_t *json) +{ + if(!json) + return NULL; + + switch(json_typeof(json)) { + case JSON_OBJECT: + return json_object_deep_copy(json); + case JSON_ARRAY: + return json_array_deep_copy(json); + /* for the rest of the types, deep copying doesn't differ from + shallow copying */ + case JSON_STRING: + return json_string_copy(json); + case JSON_INTEGER: + return json_integer_copy(json); + case JSON_REAL: + return json_real_copy(json); + case JSON_TRUE: + case JSON_FALSE: + case JSON_NULL: + return (json_t *)json; + default: + return NULL; + } +} diff --git a/3party/jansson/test/.gitignore b/3party/jansson/test/.gitignore new file mode 100644 index 0000000000..401ca5c19f --- /dev/null +++ b/3party/jansson/test/.gitignore @@ -0,0 +1,23 @@ +logs +bin/json_process +suites/api/test_array +suites/api/test_chaos +suites/api/test_copy +suites/api/test_cpp +suites/api/test_dump +suites/api/test_dump_callback +suites/api/test_equal +suites/api/test_load +suites/api/test_load_callback +suites/api/test_loadb +suites/api/test_memory_funcs +suites/api/test_number +suites/api/test_object +suites/api/test_pack +suites/api/test_simple +suites/api/test_sprintf +suites/api/test_unpack +run-suites.log +run-suites.trs +test-suite.log + diff --git a/3party/jansson/test/Makefile.am b/3party/jansson/test/Makefile.am new file mode 100644 index 0000000000..86d1614e06 --- /dev/null +++ b/3party/jansson/test/Makefile.am @@ -0,0 +1,10 @@ +SUBDIRS = bin suites +EXTRA_DIST = scripts run-suites + +TESTS = run-suites +TESTS_ENVIRONMENT = \ + top_srcdir=$(top_srcdir) \ + top_builddir=$(top_builddir) + +clean-local: + rm -rf logs diff --git a/3party/jansson/test/bin/Makefile.am b/3party/jansson/test/bin/Makefile.am new file mode 100644 index 0000000000..63b6dce7e2 --- /dev/null +++ b/3party/jansson/test/bin/Makefile.am @@ -0,0 +1,5 @@ +check_PROGRAMS = json_process + +AM_CPPFLAGS = -I$(top_builddir)/src -I$(top_srcdir)/src +LDFLAGS = -static # for speed and Valgrind +LDADD = $(top_builddir)/src/libjansson.la diff --git a/3party/jansson/test/bin/json_process.c b/3party/jansson/test/bin/json_process.c new file mode 100644 index 0000000000..0b9ece8a92 --- /dev/null +++ b/3party/jansson/test/bin/json_process.c @@ -0,0 +1,385 @@ +/* + * Copyright (c) 2009-2016 Petri Lehtinen + * + * Jansson is free software; you can redistribute it and/or modify + * it under the terms of the MIT license. See LICENSE for details. + */ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#include +#include +#include + +#ifdef HAVE_LOCALE_H +#include + #endif + +#if _WIN32 +#include /* for _setmode() */ +#include /* for _O_BINARY */ + +static const char dir_sep = '\\'; +#else +static const char dir_sep = '/'; +#endif + + +struct config { + int indent; + int compact; + int preserve_order; + int ensure_ascii; + int sort_keys; + int strip; + int use_env; + int have_hashseed; + int hashseed; + int precision; +} conf; + +#define l_isspace(c) ((c) == ' ' || (c) == '\n' || (c) == '\r' || (c) == '\t') + +/* Return a pointer to the first non-whitespace character of str. + Modifies str so that all trailing whitespace characters are + replaced by '\0'. */ +static const char *strip(char *str) +{ + size_t length; + char *result = str; + while (*result && l_isspace(*result)) + result++; + + length = strlen(result); + if (length == 0) + return result; + + while (l_isspace(result[length - 1])) + result[--length] = '\0'; + + return result; +} + + +static char *loadfile(FILE *file) +{ + long fsize, ret; + char *buf; + + fseek(file, 0, SEEK_END); + fsize = ftell(file); + fseek(file, 0, SEEK_SET); + + buf = malloc(fsize+1); + ret = fread(buf, 1, fsize, file); + if (ret != fsize) + exit(1); + buf[fsize] = '\0'; + + return buf; +} + + +static void read_conf(FILE *conffile) +{ + char *buffer, *line, *val; + + buffer = loadfile(conffile); + for (line = strtok(buffer, "\r\n"); line; line = strtok(NULL, "\r\n")) { + if (!strncmp(line, "export ", 7)) + continue; + val = strchr(line, '='); + if (!val) { + printf("invalid configuration line\n"); + break; + } + *val++ = '\0'; + + if (!strcmp(line, "JSON_INDENT")) + conf.indent = atoi(val); + if (!strcmp(line, "JSON_COMPACT")) + conf.compact = atoi(val); + if (!strcmp(line, "JSON_ENSURE_ASCII")) + conf.ensure_ascii = atoi(val); + if (!strcmp(line, "JSON_PRESERVE_ORDER")) + conf.preserve_order = atoi(val); + if (!strcmp(line, "JSON_SORT_KEYS")) + conf.sort_keys = atoi(val); + if (!strcmp(line, "JSON_REAL_PRECISION")) + conf.precision = atoi(val); + if (!strcmp(line, "STRIP")) + conf.strip = atoi(val); + if (!strcmp(line, "HASHSEED")) { + conf.have_hashseed = 1; + conf.hashseed = atoi(val); + } else { + conf.have_hashseed = 0; + } + } + + free(buffer); +} + + +static int cmpfile(const char *str, const char *path, const char *fname) +{ + char filename[1024], *buffer; + int ret; + FILE *file; + + sprintf(filename, "%s%c%s", path, dir_sep, fname); + file = fopen(filename, "rb"); + if (!file) { + if (conf.strip) + strcat(filename, ".strip"); + else + strcat(filename, ".normal"); + file = fopen(filename, "rb"); + } + if (!file) { + printf("Error: test result file could not be opened.\n"); + exit(1); + } + + buffer = loadfile(file); + if (strcmp(buffer, str) != 0) + ret = 1; + else + ret = 0; + free(buffer); + fclose(file); + + return ret; +} + +int use_conf(char *test_path) +{ + int ret; + size_t flags = 0; + char filename[1024], errstr[1024]; + char *buffer; + FILE *infile, *conffile; + json_t *json; + json_error_t error; + + sprintf(filename, "%s%cinput", test_path, dir_sep); + if (!(infile = fopen(filename, "rb"))) { + fprintf(stderr, "Could not open \"%s\"\n", filename); + return 2; + } + + sprintf(filename, "%s%cenv", test_path, dir_sep); + conffile = fopen(filename, "rb"); + if (conffile) { + read_conf(conffile); + fclose(conffile); + } + + if (conf.indent < 0 || conf.indent > 31) { + fprintf(stderr, "invalid value for JSON_INDENT: %d\n", conf.indent); + fclose(infile); + return 2; + } + if (conf.indent) + flags |= JSON_INDENT(conf.indent); + + if (conf.compact) + flags |= JSON_COMPACT; + + if (conf.ensure_ascii) + flags |= JSON_ENSURE_ASCII; + + if (conf.preserve_order) + flags |= JSON_PRESERVE_ORDER; + + if (conf.sort_keys) + flags |= JSON_SORT_KEYS; + + if (conf.precision < 0 || conf.precision > 31) { + fprintf(stderr, "invalid value for JSON_REAL_PRECISION: %d\n", + conf.precision); + fclose(infile); + return 2; + } + if (conf.precision) + flags |= JSON_REAL_PRECISION(conf.precision); + + if (conf.have_hashseed) + json_object_seed(conf.hashseed); + + if (conf.strip) { + /* Load to memory, strip leading and trailing whitespace */ + buffer = loadfile(infile); + json = json_loads(strip(buffer), 0, &error); + free(buffer); + } + else + json = json_loadf(infile, 0, &error); + + fclose(infile); + + if (!json) { + sprintf(errstr, "%d %d %d\n%s\n", + error.line, error.column, error.position, + error.text); + + ret = cmpfile(errstr, test_path, "error"); + return ret; + } + + buffer = json_dumps(json, flags); + ret = cmpfile(buffer, test_path, "output"); + free(buffer); + json_decref(json); + + return ret; +} + +static int getenv_int(const char *name) +{ + char *value, *end; + long result; + + value = getenv(name); + if(!value) + return 0; + + result = strtol(value, &end, 10); + if(*end != '\0') + return 0; + + return (int)result; +} + +int use_env() +{ + int indent, precision; + size_t flags = 0; + json_t *json; + json_error_t error; + + #ifdef _WIN32 + /* On Windows, set stdout and stderr to binary mode to avoid + outputting DOS line terminators */ + _setmode(_fileno(stdout), _O_BINARY); + _setmode(_fileno(stderr), _O_BINARY); + #endif + + indent = getenv_int("JSON_INDENT"); + if(indent < 0 || indent > 31) { + fprintf(stderr, "invalid value for JSON_INDENT: %d\n", indent); + return 2; + } + if(indent > 0) + flags |= JSON_INDENT(indent); + + if(getenv_int("JSON_COMPACT") > 0) + flags |= JSON_COMPACT; + + if(getenv_int("JSON_ENSURE_ASCII")) + flags |= JSON_ENSURE_ASCII; + + if(getenv_int("JSON_PRESERVE_ORDER")) + flags |= JSON_PRESERVE_ORDER; + + if(getenv_int("JSON_SORT_KEYS")) + flags |= JSON_SORT_KEYS; + + precision = getenv_int("JSON_REAL_PRECISION"); + if(precision < 0 || precision > 31) { + fprintf(stderr, "invalid value for JSON_REAL_PRECISION: %d\n", + precision); + return 2; + } + + if(getenv("HASHSEED")) + json_object_seed(getenv_int("HASHSEED")); + + if(precision > 0) + flags |= JSON_REAL_PRECISION(precision); + + if(getenv_int("STRIP")) { + /* Load to memory, strip leading and trailing whitespace */ + size_t size = 0, used = 0; + char *buffer = NULL, *buf_ck = NULL; + + while(1) { + size_t count; + + size = (size == 0 ? 128 : size * 2); + buf_ck = realloc(buffer, size); + if(!buf_ck) { + fprintf(stderr, "Unable to allocate %d bytes\n", (int)size); + free(buffer); + return 1; + } + buffer = buf_ck; + + count = fread(buffer + used, 1, size - used, stdin); + if(count < size - used) { + buffer[used + count] = '\0'; + break; + } + used += count; + } + + json = json_loads(strip(buffer), 0, &error); + free(buffer); + } + else + json = json_loadf(stdin, 0, &error); + + if(!json) { + fprintf(stderr, "%d %d %d\n%s\n", + error.line, error.column, + error.position, error.text); + return 1; + } + + json_dumpf(json, stdout, flags); + json_decref(json); + + return 0; +} + +int main(int argc, char *argv[]) +{ + int i; + char *test_path = NULL; + + #ifdef HAVE_SETLOCALE + setlocale(LC_ALL, ""); + #endif + + if (argc < 2) { + goto usage; + } + + for (i = 1; i < argc; i++) { + if (!strcmp(argv[i], "--strip")) + conf.strip = 1; + else if (!strcmp(argv[i], "--env")) + conf.use_env = 1; + else + test_path = argv[i]; + } + + if (conf.use_env) + return use_env(); + else + { + if (!test_path) + goto usage; + + return use_conf(test_path); + } + +usage: + fprintf(stderr, "argc =%d\n", argc); + fprintf(stderr, "usage: %s [--strip] [--env] test_dir\n", argv[0]); + return 2; +} diff --git a/3party/jansson/test/run-suites b/3party/jansson/test/run-suites new file mode 100755 index 0000000000..fd1b89b5a7 --- /dev/null +++ b/3party/jansson/test/run-suites @@ -0,0 +1,50 @@ +#!/bin/sh + +while [ -n "$1" ]; do + suite=$1 + if [ -x $top_srcdir/test/suites/$suite/run ]; then + SUITES="$SUITES $suite" + else + echo "No such suite: $suite" + exit 1 + fi + shift +done + +if [ -z "$SUITES" ]; then + suitedirs=$top_srcdir/test/suites/* + for suitedir in $suitedirs; do + if [ -d $suitedir ]; then + SUITES="$SUITES `basename $suitedir`" + fi + done +fi + +[ -z "$STOP" ] && STOP=0 + +suites_srcdir=$top_srcdir/test/suites +suites_builddir=suites +scriptdir=$top_srcdir/test/scripts +logdir=logs +bindir=bin +export suites_srcdir suites_builddir scriptdir logdir bindir + +passed=0 +failed=0 +for suite in $SUITES; do + echo "Suite: $suite" + if $suites_srcdir/$suite/run $suite; then + passed=`expr $passed + 1` + else + failed=`expr $failed + 1` + [ $STOP -eq 1 ] && break + fi +done + +if [ $failed -gt 0 ]; then + echo "$failed of `expr $passed + $failed` test suites failed" + exit 1 +else + echo "$passed test suites passed" + rm -rf $logdir +fi diff --git a/3party/jansson/test/scripts/run-tests.sh b/3party/jansson/test/scripts/run-tests.sh new file mode 100644 index 0000000000..f980a7657a --- /dev/null +++ b/3party/jansson/test/scripts/run-tests.sh @@ -0,0 +1,100 @@ +# Copyright (c) 2009-2016 Petri Lehtinen +# +# Jansson is free software; you can redistribute it and/or modify +# it under the terms of the MIT license. See LICENSE for details. + +die() { + echo "$1" >&2 + exit 1 +} + +[ -n "$1" ] || die "Usage: $0 suite-name" +[ -n "$bindir" ] || die "Set bindir" +[ -n "$logdir" ] || die "Set logdir" +[ -n "$scriptdir" ] || die "Set scriptdir" +[ -n "$suites_srcdir" ] || die "Set suites_srcdir" +[ -n "$suites_builddir" ] || die "Set suites_builddir" + +json_process=$bindir/json_process + +suite_name=$1 +suite_srcdir=$suites_srcdir/$suite_name +suite_builddir=$suites_builddir/$suite_name +suite_log=$logdir/$suite_name + +[ -z "$VERBOSE" ] && VERBOSE=0 +[ -z "$STOP" ] && STOP=0 + +. $scriptdir/valgrind.sh + +rm -rf $suite_log +mkdir -p $suite_log + +for test_path in $suite_srcdir/*; do + test_name=$(basename $test_path) + test_builddir=$suite_builddir/$test_name + test_log=$suite_log/$test_name + + [ "$test_name" = "run" ] && continue + is_test || continue + + rm -rf $test_log + mkdir -p $test_log + if [ $VERBOSE -eq 1 ]; then + printf '%s... ' "$test_name" + fi + + run_test + case $? in + 0) + # Success + if [ $VERBOSE -eq 1 ]; then + printf 'ok\n' + else + printf '.' + fi + rm -rf $test_log + ;; + + 77) + # Skip + if [ $VERBOSE -eq 1 ]; then + printf 'skipped\n' + else + printf 'S' + fi + rm -rf $test_log + ;; + + *) + # Failure + if [ $VERBOSE -eq 1 ]; then + printf 'FAILED\n' + else + printf 'F' + fi + + [ $STOP -eq 1 ] && break + ;; + esac +done + +if [ $VERBOSE -eq 0 ]; then + printf '\n' +fi + +if [ -n "$(ls -A $suite_log)" ]; then + for test_log in $suite_log/*; do + test_name=$(basename $test_log) + test_path=$suite_srcdir/$test_name + echo "=================================================================" + echo "$suite_name/$test_name" + echo "=================================================================" + show_error + echo + done + echo "=================================================================" + exit 1 +else + rm -rf $suite_log +fi diff --git a/3party/jansson/test/scripts/valgrind.sh b/3party/jansson/test/scripts/valgrind.sh new file mode 100644 index 0000000000..afbdcee154 --- /dev/null +++ b/3party/jansson/test/scripts/valgrind.sh @@ -0,0 +1,35 @@ +# Copyright (c) 2009-2016 Petri Lehtinen +# +# Jansson is free software; you can redistribute it and/or modify +# it under the terms of the MIT license. See LICENSE for details. + +[ -z "$VALGRIND" ] && VALGRIND=0 + +VALGRIND_CMDLINE="valgrind --leak-check=full --show-reachable=yes --track-origins=yes -q" + +if [ $VALGRIND -eq 1 ]; then + test_runner="$VALGRIND_CMDLINE" + json_process="$VALGRIND_CMDLINE $json_process" +else + test_runner="" +fi + +valgrind_check() { + if [ $VALGRIND -eq 1 ]; then + # Check for Valgrind error output. The valgrind option + # --error-exitcode is not enough because Valgrind doesn't + # think unfreed allocs are errors. + if grep -E -q '^==[0-9]+== ' $1; then + touch $test_log/valgrind_error + return 1 + fi + fi +} + +valgrind_show_error() { + if [ $VALGRIND -eq 1 -a -f $test_log/valgrind_error ]; then + echo "valgrind detected an error" + return 0 + fi + return 1 +} diff --git a/3party/jansson/test/suites/.gitattributes b/3party/jansson/test/suites/.gitattributes new file mode 100644 index 0000000000..68d88612cd --- /dev/null +++ b/3party/jansson/test/suites/.gitattributes @@ -0,0 +1,2 @@ +api/ text=auto +* text eol=lf \ No newline at end of file diff --git a/3party/jansson/test/suites/Makefile.am b/3party/jansson/test/suites/Makefile.am new file mode 100644 index 0000000000..a53eb07f13 --- /dev/null +++ b/3party/jansson/test/suites/Makefile.am @@ -0,0 +1,2 @@ +SUBDIRS = api +EXTRA_DIST = invalid invalid-unicode valid diff --git a/3party/jansson/test/suites/api/Makefile.am b/3party/jansson/test/suites/api/Makefile.am new file mode 100644 index 0000000000..63548ac9db --- /dev/null +++ b/3party/jansson/test/suites/api/Makefile.am @@ -0,0 +1,38 @@ +EXTRA_DIST = run check-exports + +check_PROGRAMS = \ + test_array \ + test_chaos \ + test_copy \ + test_dump \ + test_dump_callback \ + test_equal \ + test_load \ + test_loadb \ + test_load_callback \ + test_memory_funcs \ + test_number \ + test_object \ + test_pack \ + test_simple \ + test_sprintf \ + test_unpack + +test_array_SOURCES = test_array.c util.h +test_chaos_SOURCES = test_chaos.c util.h +test_copy_SOURCES = test_copy.c util.h +test_dump_SOURCES = test_dump.c util.h +test_dump_callback_SOURCES = test_dump_callback.c util.h +test_load_SOURCES = test_load.c util.h +test_loadb_SOURCES = test_loadb.c util.h +test_memory_funcs_SOURCES = test_memory_funcs.c util.h +test_number_SOURCES = test_number.c util.h +test_object_SOURCES = test_object.c util.h +test_pack_SOURCES = test_pack.c util.h +test_simple_SOURCES = test_simple.c util.h +test_sprintf_SOURCES = test_sprintf.c util.h +test_unpack_SOURCES = test_unpack.c util.h + +AM_CPPFLAGS = -I$(top_builddir)/src -I$(top_srcdir)/src +LDFLAGS = -static # for speed and Valgrind +LDADD = $(top_builddir)/src/libjansson.la diff --git a/3party/jansson/test/suites/api/check-exports b/3party/jansson/test/suites/api/check-exports new file mode 100755 index 0000000000..9adca7d391 --- /dev/null +++ b/3party/jansson/test/suites/api/check-exports @@ -0,0 +1,23 @@ +#!/bin/sh +# +# This test checks that libjansson.so exports the correct symbols. +# + +SOFILE="../src/.libs/libjansson.so" + +# The list of symbols, which the shared object should export, is read +# from the def file, which is used in Windows builds +grep 'json_' $top_srcdir/src/jansson.def \ + | sed -e 's/ //g' \ + | sort \ + >$test_log/exports + +nm -D $SOFILE >/dev/null >$test_log/symbols 2>/dev/null \ + || exit 77 # Skip if "nm -D" doesn't seem to work + +grep ' [DT] ' $test_log/symbols | cut -d' ' -f3 | grep -v '^_' | sort >$test_log/output + +if ! cmp -s $test_log/exports $test_log/output; then + diff -u $test_log/exports $test_log/output >&2 + exit 1 +fi diff --git a/3party/jansson/test/suites/api/run b/3party/jansson/test/suites/api/run new file mode 100755 index 0000000000..0c017bca65 --- /dev/null +++ b/3party/jansson/test/suites/api/run @@ -0,0 +1,36 @@ +#!/bin/sh +# +# Copyright (c) 2009-2016 Petri Lehtinen +# +# Jansson is free software; you can redistribute it and/or modify +# it under the terms of the MIT license. See LICENSE for details. + +is_test() { + case "$test_name" in + *.c|check-exports) + return 0 + ;; + *) + return 1 + ;; + esac +} + +run_test() { + if [ "$test_name" = "check-exports" ]; then + test_log=$test_log $test_path >$test_log/stdout 2>$test_log/stderr + else + $test_runner $suite_builddir/${test_name%.c} \ + >$test_log/stdout \ + 2>$test_log/stderr \ + || return 1 + valgrind_check $test_log/stderr || return 1 + fi +} + +show_error() { + valgrind_show_error && return + cat $test_log/stderr +} + +. $top_srcdir/test/scripts/run-tests.sh diff --git a/3party/jansson/test/suites/api/test_array.c b/3party/jansson/test/suites/api/test_array.c new file mode 100644 index 0000000000..9991fa07e7 --- /dev/null +++ b/3party/jansson/test/suites/api/test_array.c @@ -0,0 +1,505 @@ +/* + * Copyright (c) 2009-2016 Petri Lehtinen + * + * Jansson is free software; you can redistribute it and/or modify + * it under the terms of the MIT license. See LICENSE for details. + */ + +#include +#include "util.h" + +static void test_misc(void) +{ + json_t *array, *five, *seven, *value; + size_t i; + + array = json_array(); + five = json_integer(5); + seven = json_integer(7); + + if(!array) + fail("unable to create array"); + if(!five || !seven) + fail("unable to create integer"); + + if(json_array_size(array) != 0) + fail("empty array has nonzero size"); + + if(!json_array_append(array, NULL)) + fail("able to append NULL"); + + if(json_array_append(array, five)) + fail("unable to append"); + + if(json_array_size(array) != 1) + fail("wrong array size"); + + value = json_array_get(array, 0); + if(!value) + fail("unable to get item"); + if(value != five) + fail("got wrong value"); + + if(json_array_append(array, seven)) + fail("unable to append value"); + + if(json_array_size(array) != 2) + fail("wrong array size"); + + value = json_array_get(array, 1); + if(!value) + fail("unable to get item"); + if(value != seven) + fail("got wrong value"); + + if(json_array_set(array, 0, seven)) + fail("unable to set value"); + + if(!json_array_set(array, 0, NULL)) + fail("able to set NULL"); + + if(json_array_size(array) != 2) + fail("wrong array size"); + + value = json_array_get(array, 0); + if(!value) + fail("unable to get item"); + if(value != seven) + fail("got wrong value"); + + if(json_array_get(array, 2) != NULL) + fail("able to get value out of bounds"); + + if(!json_array_set(array, 2, seven)) + fail("able to set value out of bounds"); + + for(i = 2; i < 30; i++) { + if(json_array_append(array, seven)) + fail("unable to append value"); + + if(json_array_size(array) != i + 1) + fail("wrong array size"); + } + + for(i = 0; i < 30; i++) { + value = json_array_get(array, i); + if(!value) + fail("unable to get item"); + if(value != seven) + fail("got wrong value"); + } + + if(json_array_set_new(array, 15, json_integer(123))) + fail("unable to set new value"); + + value = json_array_get(array, 15); + if(!json_is_integer(value) || json_integer_value(value) != 123) + fail("json_array_set_new works incorrectly"); + + if(!json_array_set_new(array, 15, NULL)) + fail("able to set_new NULL value"); + + if(json_array_append_new(array, json_integer(321))) + fail("unable to append new value"); + + value = json_array_get(array, json_array_size(array) - 1); + if(!json_is_integer(value) || json_integer_value(value) != 321) + fail("json_array_append_new works incorrectly"); + + if(!json_array_append_new(array, NULL)) + fail("able to append_new NULL value"); + + json_decref(five); + json_decref(seven); + json_decref(array); +} + +static void test_insert(void) +{ + json_t *array, *five, *seven, *eleven, *value; + int i; + + array = json_array(); + five = json_integer(5); + seven = json_integer(7); + eleven = json_integer(11); + + if(!array) + fail("unable to create array"); + if(!five || !seven || !eleven) + fail("unable to create integer"); + + + if(!json_array_insert(array, 1, five)) + fail("able to insert value out of bounds"); + + + if(json_array_insert(array, 0, five)) + fail("unable to insert value in an empty array"); + + if(json_array_get(array, 0) != five) + fail("json_array_insert works incorrectly"); + + if(json_array_size(array) != 1) + fail("array size is invalid after insertion"); + + + if(json_array_insert(array, 1, seven)) + fail("unable to insert value at the end of an array"); + + if(json_array_get(array, 0) != five) + fail("json_array_insert works incorrectly"); + + if(json_array_get(array, 1) != seven) + fail("json_array_insert works incorrectly"); + + if(json_array_size(array) != 2) + fail("array size is invalid after insertion"); + + + if(json_array_insert(array, 1, eleven)) + fail("unable to insert value in the middle of an array"); + + if(json_array_get(array, 0) != five) + fail("json_array_insert works incorrectly"); + + if(json_array_get(array, 1) != eleven) + fail("json_array_insert works incorrectly"); + + if(json_array_get(array, 2) != seven) + fail("json_array_insert works incorrectly"); + + if(json_array_size(array) != 3) + fail("array size is invalid after insertion"); + + + if(json_array_insert_new(array, 2, json_integer(123))) + fail("unable to insert value in the middle of an array"); + + value = json_array_get(array, 2); + if(!json_is_integer(value) || json_integer_value(value) != 123) + fail("json_array_insert_new works incorrectly"); + + if(json_array_size(array) != 4) + fail("array size is invalid after insertion"); + + + for(i = 0; i < 20; i++) { + if(json_array_insert(array, 0, seven)) + fail("unable to insert value at the begining of an array"); + } + + for(i = 0; i < 20; i++) { + if(json_array_get(array, i) != seven) + fail("json_aray_insert works incorrectly"); + } + + if(json_array_size(array) != 24) + fail("array size is invalid after loop insertion"); + + json_decref(five); + json_decref(seven); + json_decref(eleven); + json_decref(array); +} + +static void test_remove(void) +{ + json_t *array, *five, *seven; + int i; + + array = json_array(); + five = json_integer(5); + seven = json_integer(7); + + if(!array) + fail("unable to create array"); + if(!five) + fail("unable to create integer"); + if(!seven) + fail("unable to create integer"); + + + if(!json_array_remove(array, 0)) + fail("able to remove an unexisting index"); + + + if(json_array_append(array, five)) + fail("unable to append"); + + if(!json_array_remove(array, 1)) + fail("able to remove an unexisting index"); + + if(json_array_remove(array, 0)) + fail("unable to remove"); + + if(json_array_size(array) != 0) + fail("array size is invalid after removing"); + + + if(json_array_append(array, five) || + json_array_append(array, seven) || + json_array_append(array, five) || + json_array_append(array, seven)) + fail("unable to append"); + + if(json_array_remove(array, 2)) + fail("unable to remove"); + + if(json_array_size(array) != 3) + fail("array size is invalid after removing"); + + if(json_array_get(array, 0) != five || + json_array_get(array, 1) != seven || + json_array_get(array, 2) != seven) + fail("remove works incorrectly"); + + json_decref(array); + + array = json_array(); + for(i = 0; i < 4; i++) { + json_array_append(array, five); + json_array_append(array, seven); + } + if(json_array_size(array) != 8) + fail("unable to append 8 items to array"); + + /* Remove an element from a "full" array. */ + json_array_remove(array, 5); + + json_decref(five); + json_decref(seven); + json_decref(array); +} + +static void test_clear(void) +{ + json_t *array, *five, *seven; + int i; + + array = json_array(); + five = json_integer(5); + seven = json_integer(7); + + if(!array) + fail("unable to create array"); + if(!five || !seven) + fail("unable to create integer"); + + for(i = 0; i < 10; i++) { + if(json_array_append(array, five)) + fail("unable to append"); + } + for(i = 0; i < 10; i++) { + if(json_array_append(array, seven)) + fail("unable to append"); + } + + if(json_array_size(array) != 20) + fail("array size is invalid after appending"); + + if(json_array_clear(array)) + fail("unable to clear"); + + if(json_array_size(array) != 0) + fail("array size is invalid after clearing"); + + json_decref(five); + json_decref(seven); + json_decref(array); +} + +static void test_extend(void) +{ + json_t *array1, *array2, *five, *seven; + int i; + + array1 = json_array(); + array2 = json_array(); + five = json_integer(5); + seven = json_integer(7); + + if(!array1 || !array2) + fail("unable to create array"); + if(!five || !seven) + fail("unable to create integer"); + + for(i = 0; i < 10; i++) { + if(json_array_append(array1, five)) + fail("unable to append"); + } + for(i = 0; i < 10; i++) { + if(json_array_append(array2, seven)) + fail("unable to append"); + } + + if(json_array_size(array1) != 10 || json_array_size(array2) != 10) + fail("array size is invalid after appending"); + + if(json_array_extend(array1, array2)) + fail("unable to extend"); + + for(i = 0; i < 10; i++) { + if(json_array_get(array1, i) != five) + fail("invalid array contents after extending"); + } + for(i = 10; i < 20; i++) { + if(json_array_get(array1, i) != seven) + fail("invalid array contents after extending"); + } + + json_decref(five); + json_decref(seven); + json_decref(array1); + json_decref(array2); +} + +static void test_circular() +{ + json_t *array1, *array2; + + /* the simple cases are checked */ + + array1 = json_array(); + if(!array1) + fail("unable to create array"); + + if(json_array_append(array1, array1) == 0) + fail("able to append self"); + + if(json_array_insert(array1, 0, array1) == 0) + fail("able to insert self"); + + if(json_array_append_new(array1, json_true())) + fail("failed to append true"); + + if(json_array_set(array1, 0, array1) == 0) + fail("able to set self"); + + json_decref(array1); + + + /* create circular references */ + + array1 = json_array(); + array2 = json_array(); + if(!array1 || !array2) + fail("unable to create array"); + + if(json_array_append(array1, array2) || + json_array_append(array2, array1)) + fail("unable to append"); + + /* circularity is detected when dumping */ + if(json_dumps(array1, 0) != NULL) + fail("able to dump circulars"); + + /* decref twice to deal with the circular references */ + json_decref(array1); + json_decref(array2); + json_decref(array1); +} + +static void test_array_foreach() +{ + size_t index; + json_t *array1, *array2, *value; + + array1 = json_pack("[sisisi]", "foo", 1, "bar", 2, "baz", 3); + array2 = json_array(); + + json_array_foreach(array1, index, value) { + json_array_append(array2, value); + } + + if(!json_equal(array1, array2)) + fail("json_array_foreach failed to iterate all elements"); + + json_decref(array1); + json_decref(array2); +} + +static void test_bad_args(void) +{ + json_t *arr = json_array(); + json_t *num = json_integer(1); + + if(!arr || !num) + fail("failed to create required objects"); + + if(json_array_size(NULL) != 0) + fail("NULL array has nonzero size"); + if(json_array_size(num) != 0) + fail("non-array has nonzero array size"); + + if(json_array_get(NULL, 0)) + fail("json_array_get did not return NULL for non-array"); + if(json_array_get(num, 0)) + fail("json_array_get did not return NULL for non-array"); + + if(!json_array_set_new(NULL, 0, json_incref(num))) + fail("json_array_set_new did not return error for non-array"); + if(!json_array_set_new(num, 0, json_incref(num))) + fail("json_array_set_new did not return error for non-array"); + if(!json_array_set_new(arr, 0, NULL)) + fail("json_array_set_new did not return error for NULL value"); + if(!json_array_set_new(arr, 0, json_incref(arr))) + fail("json_array_set_new did not return error for value == array"); + + if(!json_array_remove(NULL, 0)) + fail("json_array_remove did not return error for non-array"); + if(!json_array_remove(num, 0)) + fail("json_array_remove did not return error for non-array"); + + if(!json_array_clear(NULL)) + fail("json_array_clear did not return error for non-array"); + if(!json_array_clear(num)) + fail("json_array_clear did not return error for non-array"); + + if(!json_array_append_new(NULL, json_incref(num))) + fail("json_array_append_new did not return error for non-array"); + if(!json_array_append_new(num, json_incref(num))) + fail("json_array_append_new did not return error for non-array"); + if(!json_array_append_new(arr, NULL)) + fail("json_array_append_new did not return error for NULL value"); + if(!json_array_append_new(arr, json_incref(arr))) + fail("json_array_append_new did not return error for value == array"); + + if(!json_array_insert_new(NULL, 0, json_incref(num))) + fail("json_array_insert_new did not return error for non-array"); + if(!json_array_insert_new(num, 0, json_incref(num))) + fail("json_array_insert_new did not return error for non-array"); + if(!json_array_insert_new(arr, 0, NULL)) + fail("json_array_insert_new did not return error for NULL value"); + if(!json_array_insert_new(arr, 0, json_incref(arr))) + fail("json_array_insert_new did not return error for value == array"); + + if(!json_array_extend(NULL, arr)) + fail("json_array_extend did not return error for first argument non-array"); + if(!json_array_extend(num, arr)) + fail("json_array_extend did not return error for first argument non-array"); + if(!json_array_extend(arr, NULL)) + fail("json_array_extend did not return error for second arguemnt non-array"); + if(!json_array_extend(arr, num)) + fail("json_array_extend did not return error for second arguemnt non-array"); + + if(num->refcount != 1) + fail("unexpected reference count on num"); + if(arr->refcount != 1) + fail("unexpected reference count on arr"); + + json_decref(num); + json_decref(arr); +} + +static void run_tests() +{ + test_misc(); + test_insert(); + test_remove(); + test_clear(); + test_extend(); + test_circular(); + test_array_foreach(); + test_bad_args(); +} diff --git a/3party/jansson/test/suites/api/test_chaos.c b/3party/jansson/test/suites/api/test_chaos.c new file mode 100644 index 0000000000..82776a6f3a --- /dev/null +++ b/3party/jansson/test/suites/api/test_chaos.c @@ -0,0 +1,177 @@ +#ifndef _GNU_SOURCE +#define _GNU_SOURCE +#endif + +#include +#include +#include +#include "util.h" + +static int chaos_pos = 0; +static int chaos_fail = 0; +#define CHAOS_MAX_FAILURE 100 + +void *chaos_malloc(size_t size) +{ + if (chaos_pos == chaos_fail) + return NULL; + + chaos_pos++; + + return malloc(size); +} + +void chaos_free(void *obj) +{ + free(obj); +} + +/* Test all potential allocation failures. */ +#define chaos_loop(condition, code, cleanup) \ + { \ + chaos_pos = chaos_fail = 0; \ + while (condition) { \ + if (chaos_fail > CHAOS_MAX_FAILURE) \ + fail("too many chaos failures"); \ + code \ + chaos_pos = 0; \ + chaos_fail++; \ + } \ + cleanup \ + } + +#define chaos_loop_new_value(json, initcall) \ + chaos_loop(!json, json = initcall;, json_decref(json); json = NULL;) + +int test_unpack() +{ + int ret = -1; + int v1; + int v2; + json_error_t error; + json_t *root = json_pack("{s:i, s:i, s:i, s:i}", "n1", 1, "n2", 2, "n3", 3, "n4", 4); + + if (!root) + return -1; + + if (!json_unpack_ex(root, &error, JSON_STRICT, "{s:i, s:i}", "n1", &v1, "n2", &v2)) + fail("Unexpected success"); + + if (json_error_code(&error) != json_error_end_of_input_expected) { + if (json_error_code(&error) != json_error_out_of_memory) + fail("Unexpected error code"); + + goto out; + } + + if (strcmp(error.text, "2 object item(s) left unpacked: n3, n4")) + goto out; + + ret = 0; + +out: + json_decref(root); + return ret; +} + +int dump_chaos_callback(const char *buffer, size_t size, void *data) +{ + json_t *obj = json_object(); + + (void)buffer; + (void)size; + (void)data; + + if (!obj) + return -1; + + json_decref(obj); + + return 0; +} + +static void test_chaos() +{ + json_malloc_t orig_malloc; + json_free_t orig_free; + json_t *json = NULL; + json_t *obj = json_object(); + json_t *arr1 = json_array(); + json_t *arr2 = json_array(); + json_t *txt = json_string("test"); + json_t *intnum = json_integer(1); + json_t *dblnum = json_real(0.5); + char *dumptxt = NULL; + json_t *dumpobj = json_pack("{s:[iiis], s:s}", + "key1", 1, 2, 3, "txt", + "key2", "v2"); + int keyno; + + if (!obj || !arr1 || !arr2 || !txt || !intnum || !dblnum || !dumpobj) + fail("failed to allocate basic objects"); + + json_get_alloc_funcs(&orig_malloc, &orig_free); + json_set_alloc_funcs(chaos_malloc, chaos_free); + + chaos_loop_new_value(json, json_pack("{s:s}", "key", "value")); + chaos_loop_new_value(json, json_pack("{s:[]}", "key")); + chaos_loop_new_value(json, json_pack("[biIf]", 1, 1, (json_int_t)1, 1.0)); + chaos_loop_new_value(json, json_pack("[s*,s*]", "v1", "v2")); + chaos_loop_new_value(json, json_pack("o", json_incref(txt))); + chaos_loop_new_value(json, json_pack("O", txt)); + chaos_loop_new_value(json, json_pack("s++", "a", + "long string to force realloc", + "another long string to force yet another reallocation of the string because " + "that's what we are testing.")); + + chaos_loop(test_unpack(),,); + + chaos_loop(json_dump_callback(dumpobj, dump_chaos_callback, NULL, JSON_INDENT(1)),,); + chaos_loop(json_dump_callback(dumpobj, dump_chaos_callback, NULL, JSON_INDENT(1) | JSON_SORT_KEYS),,); + chaos_loop(!dumptxt, dumptxt = json_dumps(dumpobj, JSON_COMPACT);, free(dumptxt); dumptxt = NULL;); + + chaos_loop_new_value(json, json_copy(obj)); + chaos_loop_new_value(json, json_deep_copy(obj)); + + chaos_loop_new_value(json, json_copy(arr1)); + chaos_loop_new_value(json, json_deep_copy(arr1)); + + chaos_loop_new_value(json, json_copy(txt)); + chaos_loop_new_value(json, json_copy(intnum)); + chaos_loop_new_value(json, json_copy(dblnum)); + +#define JSON_LOAD_TXT "{\"n\":[1,2,3,4,5,6,7,8,9,10]}" + chaos_loop_new_value(json, json_loads(JSON_LOAD_TXT, 0, NULL)); + chaos_loop_new_value(json, json_loadb(JSON_LOAD_TXT, strlen(JSON_LOAD_TXT), 0, NULL)); + + chaos_loop_new_value(json, json_sprintf("%s", "string")); + + for (keyno = 0; keyno < 100; ++keyno) { +#if !defined(_MSC_VER) || _MSC_VER >= 1900 + /* Skip this test on old Windows compilers. */ + char testkey[10]; + + snprintf(testkey, sizeof(testkey), "test%d", keyno); + chaos_loop(json_object_set_new_nocheck(obj, testkey, json_object()),,); +#endif + chaos_loop(json_array_append_new(arr1, json_null()),,); + chaos_loop(json_array_insert_new(arr2, 0, json_null()),,); + } + + chaos_loop(json_array_extend(arr1, arr2),,); + chaos_loop(json_string_set_nocheck(txt, "test"),,); + + json_set_alloc_funcs(orig_malloc, orig_free); + json_decref(obj); + json_decref(arr1); + json_decref(arr2); + json_decref(txt); + json_decref(intnum); + json_decref(dblnum); + json_decref(dumpobj); +} + +static void run_tests() +{ + test_chaos(); +} diff --git a/3party/jansson/test/suites/api/test_copy.c b/3party/jansson/test/suites/api/test_copy.c new file mode 100644 index 0000000000..41f0c7f648 --- /dev/null +++ b/3party/jansson/test/suites/api/test_copy.c @@ -0,0 +1,334 @@ +/* + * Copyright (c) 2009-2016 Petri Lehtinen + * + * Jansson is free software; you can redistribute it and/or modify + * it under the terms of the MIT license. See LICENSE for details. + */ + +#include +#include +#include "util.h" + +static void test_copy_simple(void) +{ + json_t *value, *copy; + + if(json_copy(NULL)) + fail("copying NULL doesn't return NULL"); + + /* true */ + value = json_true(); + copy = json_copy(value); + if(value != copy) + fail("copying true failed"); + json_decref(value); + json_decref(copy); + + /* false */ + value = json_false(); + copy = json_copy(value); + if(value != copy) + fail("copying false failed"); + json_decref(value); + json_decref(copy); + + /* null */ + value = json_null(); + copy = json_copy(value); + if(value != copy) + fail("copying null failed"); + json_decref(value); + json_decref(copy); + + /* string */ + value = json_string("foo"); + if(!value) + fail("unable to create a string"); + copy = json_copy(value); + if(!copy) + fail("unable to copy a string"); + if(copy == value) + fail("copying a string doesn't copy"); + if(!json_equal(copy, value)) + fail("copying a string produces an inequal copy"); + if(value->refcount != 1 || copy->refcount != 1) + fail("invalid refcounts"); + json_decref(value); + json_decref(copy); + + /* integer */ + value = json_integer(543); + if(!value) + fail("unable to create an integer"); + copy = json_copy(value); + if(!copy) + fail("unable to copy an integer"); + if(copy == value) + fail("copying an integer doesn't copy"); + if(!json_equal(copy, value)) + fail("copying an integer produces an inequal copy"); + if(value->refcount != 1 || copy->refcount != 1) + fail("invalid refcounts"); + json_decref(value); + json_decref(copy); + + /* real */ + value = json_real(123e9); + if(!value) + fail("unable to create a real"); + copy = json_copy(value); + if(!copy) + fail("unable to copy a real"); + if(copy == value) + fail("copying a real doesn't copy"); + if(!json_equal(copy, value)) + fail("copying a real produces an inequal copy"); + if(value->refcount != 1 || copy->refcount != 1) + fail("invalid refcounts"); + json_decref(value); + json_decref(copy); +} + +static void test_deep_copy_simple(void) +{ + json_t *value, *copy; + + if(json_deep_copy(NULL)) + fail("deep copying NULL doesn't return NULL"); + + /* true */ + value = json_true(); + copy = json_deep_copy(value); + if(value != copy) + fail("deep copying true failed"); + json_decref(value); + json_decref(copy); + + /* false */ + value = json_false(); + copy = json_deep_copy(value); + if(value != copy) + fail("deep copying false failed"); + json_decref(value); + json_decref(copy); + + /* null */ + value = json_null(); + copy = json_deep_copy(value); + if(value != copy) + fail("deep copying null failed"); + json_decref(value); + json_decref(copy); + + /* string */ + value = json_string("foo"); + if(!value) + fail("unable to create a string"); + copy = json_deep_copy(value); + if(!copy) + fail("unable to deep copy a string"); + if(copy == value) + fail("deep copying a string doesn't copy"); + if(!json_equal(copy, value)) + fail("deep copying a string produces an inequal copy"); + if(value->refcount != 1 || copy->refcount != 1) + fail("invalid refcounts"); + json_decref(value); + json_decref(copy); + + /* integer */ + value = json_integer(543); + if(!value) + fail("unable to create an integer"); + copy = json_deep_copy(value); + if(!copy) + fail("unable to deep copy an integer"); + if(copy == value) + fail("deep copying an integer doesn't copy"); + if(!json_equal(copy, value)) + fail("deep copying an integer produces an inequal copy"); + if(value->refcount != 1 || copy->refcount != 1) + fail("invalid refcounts"); + json_decref(value); + json_decref(copy); + + /* real */ + value = json_real(123e9); + if(!value) + fail("unable to create a real"); + copy = json_deep_copy(value); + if(!copy) + fail("unable to deep copy a real"); + if(copy == value) + fail("deep copying a real doesn't copy"); + if(!json_equal(copy, value)) + fail("deep copying a real produces an inequal copy"); + if(value->refcount != 1 || copy->refcount != 1) + fail("invalid refcounts"); + json_decref(value); + json_decref(copy); +} + +static void test_copy_array(void) +{ + const char *json_array_text = "[1, \"foo\", 3.141592, {\"foo\": \"bar\"}]"; + + json_t *array, *copy; + size_t i; + + array = json_loads(json_array_text, 0, NULL); + if(!array) + fail("unable to parse an array"); + + copy = json_copy(array); + if(!copy) + fail("unable to copy an array"); + if(copy == array) + fail("copying an array doesn't copy"); + if(!json_equal(copy, array)) + fail("copying an array produces an inequal copy"); + + for(i = 0; i < json_array_size(copy); i++) + { + if(json_array_get(array, i) != json_array_get(copy, i)) + fail("copying an array modifies its elements"); + } + + json_decref(array); + json_decref(copy); +} + +static void test_deep_copy_array(void) +{ + const char *json_array_text = "[1, \"foo\", 3.141592, {\"foo\": \"bar\"}]"; + + json_t *array, *copy; + size_t i; + + array = json_loads(json_array_text, 0, NULL); + if(!array) + fail("unable to parse an array"); + + copy = json_deep_copy(array); + if(!copy) + fail("unable to deep copy an array"); + if(copy == array) + fail("deep copying an array doesn't copy"); + if(!json_equal(copy, array)) + fail("deep copying an array produces an inequal copy"); + + for(i = 0; i < json_array_size(copy); i++) + { + if(json_array_get(array, i) == json_array_get(copy, i)) + fail("deep copying an array doesn't copy its elements"); + } + + json_decref(array); + json_decref(copy); +} + +static void test_copy_object(void) +{ + const char *json_object_text = + "{\"foo\": \"bar\", \"a\": 1, \"b\": 3.141592, \"c\": [1,2,3,4]}"; + + const char *keys[] = {"foo", "a", "b", "c"}; + int i; + + json_t *object, *copy; + void *iter; + + object = json_loads(json_object_text, 0, NULL); + if(!object) + fail("unable to parse an object"); + + copy = json_copy(object); + if(!copy) + fail("unable to copy an object"); + if(copy == object) + fail("copying an object doesn't copy"); + if(!json_equal(copy, object)) + fail("copying an object produces an inequal copy"); + + i = 0; + iter = json_object_iter(object); + while(iter) + { + const char *key; + json_t *value1, *value2; + + key = json_object_iter_key(iter); + value1 = json_object_iter_value(iter); + value2 = json_object_get(copy, key); + + if(value1 != value2) + fail("copying an object modifies its items"); + + if (strcmp(key, keys[i]) != 0) + fail("copying an object doesn't preserve key order"); + + iter = json_object_iter_next(object, iter); + i++; + } + + json_decref(object); + json_decref(copy); +} + +static void test_deep_copy_object(void) +{ + const char *json_object_text = + "{\"foo\": \"bar\", \"a\": 1, \"b\": 3.141592, \"c\": [1,2,3,4]}"; + + const char *keys[] = {"foo", "a", "b", "c"}; + int i; + + json_t *object, *copy; + void *iter; + + object = json_loads(json_object_text, 0, NULL); + if(!object) + fail("unable to parse an object"); + + copy = json_deep_copy(object); + if(!copy) + fail("unable to deep copy an object"); + if(copy == object) + fail("deep copying an object doesn't copy"); + if(!json_equal(copy, object)) + fail("deep copying an object produces an inequal copy"); + + i = 0; + iter = json_object_iter(object); + while(iter) + { + const char *key; + json_t *value1, *value2; + + key = json_object_iter_key(iter); + value1 = json_object_iter_value(iter); + value2 = json_object_get(copy, key); + + if(value1 == value2) + fail("deep copying an object doesn't copy its items"); + + if (strcmp(key, keys[i]) != 0) + fail("deep copying an object doesn't preserve key order"); + + iter = json_object_iter_next(object, iter); + i++; + } + + json_decref(object); + json_decref(copy); +} + +static void run_tests() +{ + test_copy_simple(); + test_deep_copy_simple(); + test_copy_array(); + test_deep_copy_array(); + test_copy_object(); + test_deep_copy_object(); +} diff --git a/3party/jansson/test/suites/api/test_dump.c b/3party/jansson/test/suites/api/test_dump.c new file mode 100644 index 0000000000..17c495a18b --- /dev/null +++ b/3party/jansson/test/suites/api/test_dump.c @@ -0,0 +1,326 @@ +/* + * Copyright (c) 2009-2016 Petri Lehtinen + * + * Jansson is free software; you can redistribute it and/or modify + * it under the terms of the MIT license. See LICENSE for details. + */ + +#include "jansson_private_config.h" + +#include +#include +#ifdef HAVE_UNISTD_H +#include +#endif +#include "util.h" + +static int encode_null_callback(const char *buffer, size_t size, void *data) +{ + (void)buffer; + (void)size; + (void)data; + return 0; +} + +static void encode_null() +{ + if(json_dumps(NULL, JSON_ENCODE_ANY) != NULL) + fail("json_dumps didn't fail for NULL"); + + if(json_dumpb(NULL, NULL, 0, JSON_ENCODE_ANY) != 0) + fail("json_dumps didn't fail for NULL"); + + if(json_dumpf(NULL, stderr, JSON_ENCODE_ANY) != -1) + fail("json_dumpf didn't fail for NULL"); + +#ifdef HAVE_UNISTD_H + if(json_dumpfd(NULL, STDERR_FILENO, JSON_ENCODE_ANY) != -1) + fail("json_dumpfd didn't fail for NULL"); +#endif + + /* Don't test json_dump_file to avoid creating a file */ + + if(json_dump_callback(NULL, encode_null_callback, NULL, JSON_ENCODE_ANY) != -1) + fail("json_dump_callback didn't fail for NULL"); +} + + +static void encode_twice() +{ + /* Encode an empty object/array, add an item, encode again */ + + json_t *json; + char *result; + + json = json_object(); + result = json_dumps(json, 0); + if(!result || strcmp(result, "{}")) + fail("json_dumps failed"); + free(result); + + json_object_set_new(json, "foo", json_integer(5)); + result = json_dumps(json, 0); + if(!result || strcmp(result, "{\"foo\": 5}")) + fail("json_dumps failed"); + free(result); + + json_decref(json); + + json = json_array(); + result = json_dumps(json, 0); + if(!result || strcmp(result, "[]")) + fail("json_dumps failed"); + free(result); + + json_array_append_new(json, json_integer(5)); + result = json_dumps(json, 0); + if(!result || strcmp(result, "[5]")) + fail("json_dumps failed"); + free(result); + + json_decref(json); +} + +static void circular_references() +{ + /* Construct a JSON object/array with a circular reference: + + object: {"a": {"b": {"c": }}} + array: [[[]]] + + Encode it, remove the circular reference and encode again. + */ + + json_t *json; + char *result; + + json = json_object(); + json_object_set_new(json, "a", json_object()); + json_object_set_new(json_object_get(json, "a"), "b", json_object()); + json_object_set(json_object_get(json_object_get(json, "a"), "b"), "c", + json_object_get(json, "a")); + + if(json_dumps(json, 0)) + fail("json_dumps encoded a circular reference!"); + + json_object_del(json_object_get(json_object_get(json, "a"), "b"), "c"); + + result = json_dumps(json, 0); + if(!result || strcmp(result, "{\"a\": {\"b\": {}}}")) + fail("json_dumps failed!"); + free(result); + + json_decref(json); + + json = json_array(); + json_array_append_new(json, json_array()); + json_array_append_new(json_array_get(json, 0), json_array()); + json_array_append(json_array_get(json_array_get(json, 0), 0), + json_array_get(json, 0)); + + if(json_dumps(json, 0)) + fail("json_dumps encoded a circular reference!"); + + json_array_remove(json_array_get(json_array_get(json, 0), 0), 0); + + result = json_dumps(json, 0); + if(!result || strcmp(result, "[[[]]]")) + fail("json_dumps failed!"); + free(result); + + json_decref(json); +} + +static void encode_other_than_array_or_object() +{ + /* Encoding anything other than array or object should only + * succeed if the JSON_ENCODE_ANY flag is used */ + + json_t *json; + char *result; + + json = json_string("foo"); + if(json_dumps(json, 0) != NULL) + fail("json_dumps encoded a string!"); + if(json_dumpf(json, NULL, 0) == 0) + fail("json_dumpf encoded a string!"); + if(json_dumpfd(json, -1, 0) == 0) + fail("json_dumpfd encoded a string!"); + + result = json_dumps(json, JSON_ENCODE_ANY); + if(!result || strcmp(result, "\"foo\"") != 0) + fail("json_dumps failed to encode a string with JSON_ENCODE_ANY"); + + free(result); + json_decref(json); + + json = json_integer(42); + if(json_dumps(json, 0) != NULL) + fail("json_dumps encoded an integer!"); + if(json_dumpf(json, NULL, 0) == 0) + fail("json_dumpf encoded an integer!"); + if(json_dumpfd(json, -1, 0) == 0) + fail("json_dumpfd encoded an integer!"); + + result = json_dumps(json, JSON_ENCODE_ANY); + if(!result || strcmp(result, "42") != 0) + fail("json_dumps failed to encode an integer with JSON_ENCODE_ANY"); + + free(result); + json_decref(json); + + +} + +static void escape_slashes() +{ + /* Test dump escaping slashes */ + + json_t *json; + char *result; + + json = json_object(); + json_object_set_new(json, "url", json_string("https://github.com/akheron/jansson")); + + result = json_dumps(json, 0); + if(!result || strcmp(result, "{\"url\": \"https://github.com/akheron/jansson\"}")) + fail("json_dumps failed to not escape slashes"); + + free(result); + + result = json_dumps(json, JSON_ESCAPE_SLASH); + if(!result || strcmp(result, "{\"url\": \"https:\\/\\/github.com\\/akheron\\/jansson\"}")) + fail("json_dumps failed to escape slashes"); + + free(result); + json_decref(json); +} + +static void encode_nul_byte() +{ + json_t *json; + char *result; + + json = json_stringn("nul byte \0 in string", 20); + result = json_dumps(json, JSON_ENCODE_ANY); + if(!result || memcmp(result, "\"nul byte \\u0000 in string\"", 27)) + fail("json_dumps failed to dump an embedded NUL byte"); + + free(result); + json_decref(json); +} + +static void dump_file() +{ + json_t *json; + int result; + + result = json_dump_file(NULL, "", 0); + if (result != -1) + fail("json_dump_file succeeded with invalid args"); + + json = json_object(); + result = json_dump_file(json, "json_dump_file.json", 0); + if (result != 0) + fail("json_dump_file failed"); + + json_decref(json); + remove("json_dump_file.json"); +} + +static void dumpb() +{ + char buf[2]; + json_t *obj; + size_t size; + + obj = json_object(); + + size = json_dumpb(obj, buf, sizeof(buf), 0); + if(size != 2 || strncmp(buf, "{}", 2)) + fail("json_dumpb failed"); + + json_decref(obj); + obj = json_pack("{s:s}", "foo", "bar"); + + size = json_dumpb(obj, buf, sizeof(buf), JSON_COMPACT); + if(size != 13) + fail("json_dumpb size check failed"); + + json_decref(obj); +} + +static void dumpfd() +{ +#ifdef HAVE_UNISTD_H + int fds[2] = {-1, -1}; + json_t *a, *b; + + if(pipe(fds)) + fail("pipe() failed"); + + a = json_pack("{s:s}", "foo", "bar"); + + if(json_dumpfd(a, fds[1], 0)) + fail("json_dumpfd() failed"); + close(fds[1]); + + b = json_loadfd(fds[0], 0, NULL); + if (!b) + fail("json_loadfd() failed"); + close(fds[0]); + + if (!json_equal(a, b)) + fail("json_equal() failed for fd test"); + + json_decref(a); + json_decref(b); +#endif +} + +static void embed() +{ + static const char *plains[] = { + "{\"bar\":[],\"foo\":{}}", + "[[],{}]", + "{}", + "[]", + NULL + }; + + size_t i; + + for(i = 0; plains[i]; i++) { + const char *plain = plains[i]; + json_t *parse = NULL; + char *embed = NULL; + size_t psize = 0; + size_t esize = 0; + + psize = strlen(plain) - 2; + embed = calloc(1, psize); + parse = json_loads(plain, 0, NULL); + esize = json_dumpb(parse, embed, psize, + JSON_COMPACT | JSON_SORT_KEYS | JSON_EMBED); + json_decref(parse); + if(esize != psize) + fail("json_dumpb(JSON_EMBED) returned an invalid size"); + if(strncmp(plain + 1, embed, esize) != 0) + fail("json_dumps(JSON_EMBED) returned an invalid value"); + free(embed); + } +} + +static void run_tests() +{ + encode_null(); + encode_twice(); + circular_references(); + encode_other_than_array_or_object(); + escape_slashes(); + encode_nul_byte(); + dump_file(); + dumpb(); + dumpfd(); + embed(); +} diff --git a/3party/jansson/test/suites/api/test_dump_callback.c b/3party/jansson/test/suites/api/test_dump_callback.c new file mode 100644 index 0000000000..1ceb968f2e --- /dev/null +++ b/3party/jansson/test/suites/api/test_dump_callback.c @@ -0,0 +1,81 @@ +/* + * Copyright (c) 2009-2016 Petri Lehtinen + * + * Jansson is free software; you can redistribute it and/or modify + * it under the terms of the MIT license. See LICENSE for details. + */ + +#include +#include +#include +#include "util.h" + +struct my_sink { + char *buf; + size_t off; + size_t cap; +}; + +static int my_writer(const char *buffer, size_t len, void *data) { + struct my_sink *s = data; + if (len > s->cap - s->off) { + return -1; + } + memcpy(s->buf + s->off, buffer, len); + s->off += len; + return 0; +} + +static void run_tests() +{ + struct my_sink s; + json_t *json; + const char str[] = "[\"A\", {\"B\": \"C\", \"e\": false}, 1, null, \"foo\"]"; + char *dumped_to_string; + + json = json_loads(str, 0, NULL); + if(!json) { + fail("json_loads failed"); + } + + dumped_to_string = json_dumps(json, 0); + if (!dumped_to_string) { + json_decref(json); + fail("json_dumps failed"); + } + + s.off = 0; + s.cap = strlen(dumped_to_string); + s.buf = malloc(s.cap); + if (!s.buf) { + json_decref(json); + free(dumped_to_string); + fail("malloc failed"); + } + + if (json_dump_callback(json, my_writer, &s, 0) == -1) { + json_decref(json); + free(dumped_to_string); + free(s.buf); + fail("json_dump_callback failed on an exact-length sink buffer"); + } + + if (strncmp(dumped_to_string, s.buf, s.off) != 0) { + json_decref(json); + free(dumped_to_string); + free(s.buf); + fail("json_dump_callback and json_dumps did not produce identical output"); + } + + s.off = 1; + if (json_dump_callback(json, my_writer, &s, 0) != -1) { + json_decref(json); + free(dumped_to_string); + free(s.buf); + fail("json_dump_callback succeeded on a short buffer when it should have failed"); + } + + json_decref(json); + free(dumped_to_string); + free(s.buf); +} diff --git a/3party/jansson/test/suites/api/test_equal.c b/3party/jansson/test/suites/api/test_equal.c new file mode 100644 index 0000000000..339bab62bd --- /dev/null +++ b/3party/jansson/test/suites/api/test_equal.c @@ -0,0 +1,196 @@ +/* + * Copyright (c) 2009-2016 Petri Lehtinen + * + * Jansson is free software; you can redistribute it and/or modify + * it under the terms of the MIT license. See LICENSE for details. + */ + +#include +#include "util.h" + +static void test_equal_simple() +{ + json_t *value1, *value2; + + if(json_equal(NULL, NULL)) + fail("json_equal fails for two NULLs"); + + value1 = json_true(); + if(json_equal(value1, NULL) || json_equal(NULL, value1)) + fail("json_equal fails for NULL"); + + /* this covers true, false and null as they are singletons */ + if(!json_equal(value1, value1)) + fail("identical objects are not equal"); + json_decref(value1); + + /* integer */ + value1 = json_integer(1); + value2 = json_integer(1); + if(!value1 || !value2) + fail("unable to create integers"); + if(!json_equal(value1, value2)) + fail("json_equal fails for two equal integers"); + json_decref(value2); + + value2 = json_integer(2); + if(!value2) + fail("unable to create an integer"); + if(json_equal(value1, value2)) + fail("json_equal fails for two inequal integers"); + + json_decref(value1); + json_decref(value2); + + /* real */ + value1 = json_real(1.2); + value2 = json_real(1.2); + if(!value1 || !value2) + fail("unable to create reals"); + if(!json_equal(value1, value2)) + fail("json_equal fails for two equal reals"); + json_decref(value2); + + value2 = json_real(3.141592); + if(!value2) + fail("unable to create an real"); + if(json_equal(value1, value2)) + fail("json_equal fails for two inequal reals"); + + json_decref(value1); + json_decref(value2); + + /* string */ + value1 = json_string("foo"); + value2 = json_string("foo"); + if(!value1 || !value2) + fail("unable to create strings"); + if(!json_equal(value1, value2)) + fail("json_equal fails for two equal strings"); + json_decref(value2); + + value2 = json_string("bar"); + if(!value2) + fail("unable to create an string"); + if(json_equal(value1, value2)) + fail("json_equal fails for two inequal strings"); + json_decref(value2); + + value2 = json_string("bar2"); + if(!value2) + fail("unable to create an string"); + if(json_equal(value1, value2)) + fail("json_equal fails for two inequal length strings"); + + json_decref(value1); + json_decref(value2); +} + +static void test_equal_array() +{ + json_t *array1, *array2; + + array1 = json_array(); + array2 = json_array(); + if(!array1 || !array2) + fail("unable to create arrays"); + + if(!json_equal(array1, array2)) + fail("json_equal fails for two empty arrays"); + + json_array_append_new(array1, json_integer(1)); + json_array_append_new(array2, json_integer(1)); + json_array_append_new(array1, json_string("foo")); + json_array_append_new(array2, json_string("foo")); + json_array_append_new(array1, json_integer(2)); + json_array_append_new(array2, json_integer(2)); + if(!json_equal(array1, array2)) + fail("json_equal fails for two equal arrays"); + + json_array_remove(array2, 2); + if(json_equal(array1, array2)) + fail("json_equal fails for two inequal arrays"); + + json_array_append_new(array2, json_integer(3)); + if(json_equal(array1, array2)) + fail("json_equal fails for two inequal arrays"); + + json_decref(array1); + json_decref(array2); +} + +static void test_equal_object() +{ + json_t *object1, *object2; + + object1 = json_object(); + object2 = json_object(); + if(!object1 || !object2) + fail("unable to create objects"); + + if(!json_equal(object1, object2)) + fail("json_equal fails for two empty objects"); + + json_object_set_new(object1, "a", json_integer(1)); + json_object_set_new(object2, "a", json_integer(1)); + json_object_set_new(object1, "b", json_string("foo")); + json_object_set_new(object2, "b", json_string("foo")); + json_object_set_new(object1, "c", json_integer(2)); + json_object_set_new(object2, "c", json_integer(2)); + if(!json_equal(object1, object2)) + fail("json_equal fails for two equal objects"); + + json_object_del(object2, "c"); + if(json_equal(object1, object2)) + fail("json_equal fails for two inequal objects"); + + json_object_set_new(object2, "c", json_integer(3)); + if(json_equal(object1, object2)) + fail("json_equal fails for two inequal objects"); + + json_object_del(object2, "c"); + json_object_set_new(object2, "d", json_integer(2)); + if(json_equal(object1, object2)) + fail("json_equal fails for two inequal objects"); + + json_decref(object1); + json_decref(object2); +} + +static void test_equal_complex() +{ + json_t *value1, *value2; + + const char *complex_json = +"{" +" \"integer\": 1, " +" \"real\": 3.141592, " +" \"string\": \"foobar\", " +" \"true\": true, " +" \"object\": {" +" \"array-in-object\": [1,true,\"foo\",{}]," +" \"object-in-object\": {\"foo\": \"bar\"}" +" }," +" \"array\": [\"foo\", false, null, 1.234]" +"}"; + + value1 = json_loads(complex_json, 0, NULL); + value2 = json_loads(complex_json, 0, NULL); + if(!value1 || !value2) + fail("unable to parse JSON"); + if(!json_equal(value1, value2)) + fail("json_equal fails for two inequal strings"); + + json_decref(value1); + json_decref(value2); + + /* TODO: There's no negative test case here */ +} + +static void run_tests() +{ + test_equal_simple(); + test_equal_array(); + test_equal_object(); + test_equal_complex(); +} diff --git a/3party/jansson/test/suites/api/test_load.c b/3party/jansson/test/suites/api/test_load.c new file mode 100644 index 0000000000..a3bdc5785f --- /dev/null +++ b/3party/jansson/test/suites/api/test_load.c @@ -0,0 +1,246 @@ +/* + * Copyright (c) 2009-2016 Petri Lehtinen + * + * Jansson is free software; you can redistribute it and/or modify + * it under the terms of the MIT license. See LICENSE for details. + */ + +#include +#include +#include "util.h" + +static void file_not_found() +{ + json_t *json; + json_error_t error; + char *pos; + + json = json_load_file("/path/to/nonexistent/file.json", 0, &error); + if(json) + fail("json_load_file returned non-NULL for a nonexistent file"); + if(error.line != -1) + fail("json_load_file returned an invalid line number"); + + /* The error message is locale specific, only check the beginning + of the error message. */ + + pos = strchr(error.text, ':'); + if(!pos) + fail("json_load_file returne an invalid error message"); + + *pos = '\0'; + + if(strcmp(error.text, "unable to open /path/to/nonexistent/file.json") != 0) + fail("json_load_file returned an invalid error message"); + if(json_error_code(&error) != json_error_cannot_open_file) + fail("json_load_file returned an invalid error code"); +} + +static void very_long_file_name() { + json_t *json; + json_error_t error; + + json = json_load_file("aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", 0, &error); + if(json) + fail("json_load_file returned non-NULL for a nonexistent file"); + if(error.line != -1) + fail("json_load_file returned an invalid line number"); + + if (strncmp(error.source, "...aaa", 6) != 0) + fail("error source was set incorrectly"); + if(json_error_code(&error) != json_error_cannot_open_file) + fail("error code was set incorrectly"); +} + +static void reject_duplicates() +{ + json_error_t error; + + if(json_loads("{\"foo\": 1, \"foo\": 2}", JSON_REJECT_DUPLICATES, &error)) + fail("json_loads did not detect a duplicate key"); + check_error(json_error_duplicate_key, "duplicate object key near '\"foo\"'", "", 1, 16, 16); +} + +static void disable_eof_check() +{ + json_error_t error; + json_t *json; + + const char *text = "{\"foo\": 1} garbage"; + + if(json_loads(text, 0, &error)) + fail("json_loads did not detect garbage after JSON text"); + check_error(json_error_end_of_input_expected, "end of file expected near 'garbage'", "", 1, 18, 18); + + json = json_loads(text, JSON_DISABLE_EOF_CHECK, &error); + if(!json) + fail("json_loads failed with JSON_DISABLE_EOF_CHECK"); + + json_decref(json); +} + +static void decode_any() +{ + json_t *json; + json_error_t error; + + json = json_loads("\"foo\"", JSON_DECODE_ANY, &error); + if (!json || !json_is_string(json)) + fail("json_load decoded any failed - string"); + json_decref(json); + + json = json_loads("42", JSON_DECODE_ANY, &error); + if (!json || !json_is_integer(json)) + fail("json_load decoded any failed - integer"); + json_decref(json); + + json = json_loads("true", JSON_DECODE_ANY, &error); + if (!json || !json_is_true(json)) + fail("json_load decoded any failed - boolean"); + json_decref(json); + + json = json_loads("null", JSON_DECODE_ANY, &error); + if (!json || !json_is_null(json)) + fail("json_load decoded any failed - null"); + json_decref(json); +} + +static void decode_int_as_real() +{ + json_t *json; + json_error_t error; + +#if JSON_INTEGER_IS_LONG_LONG + const char *imprecise; + json_int_t expected; +#endif + + char big[311]; + + json = json_loads("42", JSON_DECODE_INT_AS_REAL | JSON_DECODE_ANY, &error); + if (!json || !json_is_real(json) || json_real_value(json) != 42.0) + fail("json_load decode int as real failed - int"); + json_decref(json); + +#if JSON_INTEGER_IS_LONG_LONG + /* This number cannot be represented exactly by a double */ + imprecise = "9007199254740993"; + expected = 9007199254740992ll; + + json = json_loads(imprecise, JSON_DECODE_INT_AS_REAL | JSON_DECODE_ANY, + &error); + if (!json || !json_is_real(json) || expected != (json_int_t)json_real_value(json)) + fail("json_load decode int as real failed - expected imprecision"); + json_decref(json); +#endif + + /* 1E309 overflows. Here we create 1E309 as a decimal number, i.e. + 1000...(309 zeroes)...0. */ + big[0] = '1'; + memset(big + 1, '0', 309); + big[310] = '\0'; + + json = json_loads(big, JSON_DECODE_INT_AS_REAL | JSON_DECODE_ANY, &error); + if (json || strcmp(error.text, "real number overflow") != 0 || + json_error_code(&error) != json_error_numeric_overflow) + fail("json_load decode int as real failed - expected overflow"); + json_decref(json); + +} + +static void allow_nul() +{ + const char *text = "\"nul byte \\u0000 in string\""; + const char *expected = "nul byte \0 in string"; + size_t len = 20; + json_t *json; + + json = json_loads(text, JSON_ALLOW_NUL | JSON_DECODE_ANY, NULL); + if(!json || !json_is_string(json)) + fail("unable to decode embedded NUL byte"); + + if(json_string_length(json) != len) + fail("decoder returned wrong string length"); + + if(memcmp(json_string_value(json), expected, len + 1)) + fail("decoder returned wrong string content"); + + json_decref(json); +} + +static void load_wrong_args() +{ + json_t *json; + json_error_t error; + + json = json_loads(NULL, 0, &error); + if (json) + fail("json_loads should return NULL if the first argument is NULL"); + + json = json_loadb(NULL, 0, 0, &error); + if (json) + fail("json_loadb should return NULL if the first argument is NULL"); + + json = json_loadf(NULL, 0, &error); + if (json) + fail("json_loadf should return NULL if the first argument is NULL"); + + json = json_loadfd(-1, 0, &error); + if (json) + fail("json_loadfd should return NULL if the first argument is < 0"); + + json = json_load_file(NULL, 0, &error); + if (json) + fail("json_load_file should return NULL if the first argument is NULL"); +} + +static void position() +{ + json_t *json; + size_t flags = JSON_DISABLE_EOF_CHECK; + json_error_t error; + + json = json_loads("{\"foo\": \"bar\"}", 0, &error); + if(error.position != 14) + fail("json_loads returned a wrong position"); + json_decref(json); + + json = json_loads("{\"foo\": \"bar\"} baz quux", flags, &error); + if(error.position != 14) + fail("json_loads returned a wrong position"); + json_decref(json); +} + +static void error_code() +{ + json_error_t error; + json_t *json = json_loads("[123] garbage", 0, &error); + if(json != NULL) + fail("json_loads returned not NULL"); + if(strlen(error.text) >= JSON_ERROR_TEXT_LENGTH) + fail("error.text longer than expected"); + if(json_error_code(&error) != json_error_end_of_input_expected) + fail("json_loads returned incorrect error code"); + + json = json_loads("{\"foo\": ", 0, &error); + if(json != NULL) + fail("json_loads returned not NULL"); + if(strlen(error.text) >= JSON_ERROR_TEXT_LENGTH) + fail("error.text longer than expected"); + if(json_error_code(&error) != json_error_premature_end_of_input) + fail("json_loads returned incorrect error code"); +} + +static void run_tests() +{ + file_not_found(); + very_long_file_name(); + reject_duplicates(); + disable_eof_check(); + decode_any(); + decode_int_as_real(); + allow_nul(); + load_wrong_args(); + position(); + error_code(); +} diff --git a/3party/jansson/test/suites/api/test_load_callback.c b/3party/jansson/test/suites/api/test_load_callback.c new file mode 100644 index 0000000000..944952816c --- /dev/null +++ b/3party/jansson/test/suites/api/test_load_callback.c @@ -0,0 +1,75 @@ +/* + * Copyright (c) 2009-2011 Petri Lehtinen + * + * Jansson is free software; you can redistribute it and/or modify + * it under the terms of the MIT license. See LICENSE for details. + */ + +#include +#include +#include +#include "util.h" + +struct my_source { + const char *buf; + size_t off; + size_t cap; +}; + +static const char my_str[] = "[\"A\", {\"B\": \"C\", \"e\": false}, 1, null, \"foo\"]"; + +static size_t greedy_reader(void *buf, size_t buflen, void *arg) +{ + struct my_source *s = arg; + if (buflen > s->cap - s->off) + buflen = s->cap - s->off; + if (buflen > 0) { + memcpy(buf, s->buf + s->off, buflen); + s->off += buflen; + return buflen; + } else { + return 0; + } +} + +static void run_tests() +{ + struct my_source s; + json_t *json; + json_error_t error; + + s.off = 0; + s.cap = strlen(my_str); + s.buf = my_str; + + json = json_load_callback(greedy_reader, &s, 0, &error); + + if (!json) + fail("json_load_callback failed on a valid callback"); + json_decref(json); + + s.off = 0; + s.cap = strlen(my_str) - 1; + s.buf = my_str; + + json = json_load_callback(greedy_reader, &s, 0, &error); + if (json) { + json_decref(json); + fail("json_load_callback should have failed on an incomplete stream, but it didn't"); + } + if (strcmp(error.source, "") != 0) { + fail("json_load_callback returned an invalid error source"); + } + if (strcmp(error.text, "']' expected near end of file") != 0) { + fail("json_load_callback returned an invalid error message for an unclosed top-level array"); + } + + json = json_load_callback(NULL, NULL, 0, &error); + if (json) { + json_decref(json); + fail("json_load_callback should have failed on NULL load callback, but it didn't"); + } + if (strcmp(error.text, "wrong arguments") != 0) { + fail("json_load_callback returned an invalid error message for a NULL load callback"); + } +} diff --git a/3party/jansson/test/suites/api/test_loadb.c b/3party/jansson/test/suites/api/test_loadb.c new file mode 100644 index 0000000000..64e1fc568c --- /dev/null +++ b/3party/jansson/test/suites/api/test_loadb.c @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2009-2016 Petri Lehtinen + * + * Jansson is free software; you can redistribute it and/or modify + * it under the terms of the MIT license. See LICENSE for details. + */ + +#include +#include +#include "util.h" + +static void run_tests() +{ + json_t *json; + json_error_t error; + const char str[] = "[\"A\", {\"B\": \"C\"}, 1, 2, 3]garbage"; + size_t len = strlen(str) - strlen("garbage"); + + json = json_loadb(str, len, 0, &error); + if(!json) { + fail("json_loadb failed on a valid JSON buffer"); + } + json_decref(json); + + json = json_loadb(str, len - 1, 0, &error); + if (json) { + json_decref(json); + fail("json_loadb should have failed on an incomplete buffer, but it didn't"); + } + if(error.line != 1) { + fail("json_loadb returned an invalid line number on fail"); + } + if(strcmp(error.text, "']' expected near end of file") != 0) { + fail("json_loadb returned an invalid error message for an unclosed top-level array"); + } +} diff --git a/3party/jansson/test/suites/api/test_memory_funcs.c b/3party/jansson/test/suites/api/test_memory_funcs.c new file mode 100644 index 0000000000..02e450cd97 --- /dev/null +++ b/3party/jansson/test/suites/api/test_memory_funcs.c @@ -0,0 +1,137 @@ +#include +#include + +#include "util.h" + +static int malloc_called = 0; +static int free_called = 0; +static size_t malloc_used = 0; + +/* helpers */ +static void create_and_free_complex_object() +{ + json_t *obj; + + obj = json_pack("{s:i,s:n,s:b,s:b,s:{s:s},s:[i,i,i]}", + "foo", 42, + "bar", + "baz", 1, + "qux", 0, + "alice", "bar", "baz", + "bob", 9, 8, 7); + + json_decref(obj); +} + +static void create_and_free_object_with_oom() +{ + int i; + char key[4]; + json_t *obj = json_object(); + + for (i = 0; i < 10; i++) + { + snprintf(key, sizeof key, "%d", i); + json_object_set_new(obj, key, json_integer(i)); + } + + json_decref(obj); +} + +static void *my_malloc(size_t size) +{ + malloc_called = 1; + return malloc(size); +} + +static void my_free(void *ptr) +{ + free_called = 1; + free(ptr); +} + +static void test_simple() +{ + json_malloc_t mfunc = NULL; + json_free_t ffunc = NULL; + + json_set_alloc_funcs(my_malloc, my_free); + json_get_alloc_funcs(&mfunc, &ffunc); + create_and_free_complex_object(); + + if (malloc_called != 1 || free_called != 1 + || mfunc != my_malloc || ffunc != my_free) + fail("Custom allocation failed"); +} + + +static void *oom_malloc(size_t size) +{ + if (malloc_used + size > 800) + return NULL; + + malloc_used += size; + return malloc(size); +} + +static void oom_free(void *ptr) +{ + free_called++; + free(ptr); +} + +static void test_oom() +{ + free_called = 0; + json_set_alloc_funcs(oom_malloc, oom_free); + create_and_free_object_with_oom(); + + if (free_called == 0) + fail("Allocation with OOM failed"); +} + + +/* + Test the secure memory functions code given in the API reference + documentation, but by using plain memset instead of + guaranteed_memset(). +*/ + +static void *secure_malloc(size_t size) +{ + /* Store the memory area size in the beginning of the block */ + void *ptr = malloc(size + 8); + *((size_t *)ptr) = size; + return (char *)ptr + 8; +} + +static void secure_free(void *ptr) +{ + size_t size; + + ptr = (char *)ptr - 8; + size = *((size_t *)ptr); + + /*guaranteed_*/memset(ptr, 0, size + 8); + free(ptr); +} + +static void test_secure_funcs(void) +{ + json_set_alloc_funcs(secure_malloc, secure_free); + create_and_free_complex_object(); +} + +static void test_bad_args(void) +{ + /* The result of this test is not crashing. */ + json_get_alloc_funcs(NULL, NULL); +} + +static void run_tests() +{ + test_simple(); + test_secure_funcs(); + test_oom(); + test_bad_args(); +} diff --git a/3party/jansson/test/suites/api/test_number.c b/3party/jansson/test/suites/api/test_number.c new file mode 100644 index 0000000000..bf33aecc80 --- /dev/null +++ b/3party/jansson/test/suites/api/test_number.c @@ -0,0 +1,126 @@ +/* + * Copyright (c) 2009-2016 Petri Lehtinen + * + * Jansson is free software; you can redistribute it and/or modify + * it under the terms of the MIT license. See LICENSE for details. + */ + +#include +#include +#include "util.h" + +#ifdef INFINITY +// This test triggers "warning C4756: overflow in constant arithmetic" +// in Visual Studio. This warning is triggered here by design, so disable it. +// (This can only be done on function level so we keep these tests separate) +#ifdef _MSC_VER +#pragma warning(push) +#pragma warning (disable: 4756) +#endif +static void test_inifity() +{ + json_t *real = json_real(INFINITY); + if (real != NULL) + fail("could construct a real from Inf"); + + real = json_real(1.0); + if (json_real_set(real, INFINITY) != -1) + fail("could set a real to Inf"); + + if (json_real_value(real) != 1.0) + fail("real value changed unexpectedly"); + + json_decref(real); +#ifdef _MSC_VER +#pragma warning(pop) +#endif +} +#endif // INFINITY + +static void test_bad_args(void) +{ + json_t *txt = json_string("test"); + + if(json_integer_value(NULL) != 0) + fail("json_integer_value did not return 0 for non-integer"); + if(json_integer_value(txt) != 0) + fail("json_integer_value did not return 0 for non-integer"); + + if(!json_integer_set(NULL, 0)) + fail("json_integer_set did not return error for non-integer"); + if(!json_integer_set(txt, 0)) + fail("json_integer_set did not return error for non-integer"); + + if(json_real_value(NULL) != 0.0) + fail("json_real_value did not return 0.0 for non-real"); + if(json_real_value(txt) != 0.0) + fail("json_real_value did not return 0.0 for non-real"); + + if(!json_real_set(NULL, 0.0)) + fail("json_real_set did not return error for non-real"); + if(!json_real_set(txt, 0.0)) + fail("json_real_set did not return error for non-real"); + + if(json_number_value(NULL) != 0.0) + fail("json_number_value did not return 0.0 for non-numeric"); + if(json_number_value(txt) != 0.0) + fail("json_number_value did not return 0.0 for non-numeric"); + + if (txt->refcount != 1) + fail("unexpected reference count for txt"); + + json_decref(txt); +} + +static void run_tests() +{ + json_t *integer, *real; + json_int_t i; + double d; + + integer = json_integer(5); + real = json_real(100.1); + + if(!integer) + fail("unable to create integer"); + if(!real) + fail("unable to create real"); + + i = json_integer_value(integer); + if(i != 5) + fail("wrong integer value"); + + d = json_real_value(real); + if(d != 100.1) + fail("wrong real value"); + + d = json_number_value(integer); + if(d != 5.0) + fail("wrong number value"); + d = json_number_value(real); + if(d != 100.1) + fail("wrong number value"); + + json_decref(integer); + json_decref(real); + +#ifdef NAN + real = json_real(NAN); + if(real != NULL) + fail("could construct a real from NaN"); + + real = json_real(1.0); + if(json_real_set(real, NAN) != -1) + fail("could set a real to NaN"); + + if(json_real_value(real) != 1.0) + fail("real value changed unexpectedly"); + + json_decref(real); +#endif + +#ifdef INFINITY + test_inifity(); +#endif + test_bad_args(); +} diff --git a/3party/jansson/test/suites/api/test_object.c b/3party/jansson/test/suites/api/test_object.c new file mode 100644 index 0000000000..521ca81bdf --- /dev/null +++ b/3party/jansson/test/suites/api/test_object.c @@ -0,0 +1,677 @@ +/* + * Copyright (c) 2009-2016 Petri Lehtinen + * + * Jansson is free software; you can redistribute it and/or modify + * it under the terms of the MIT license. See LICENSE for details. + */ + +#include +#include +#include "util.h" + +static void test_clear() +{ + json_t *object, *ten; + + object = json_object(); + ten = json_integer(10); + + if(!object) + fail("unable to create object"); + if(!ten) + fail("unable to create integer"); + + if(json_object_set(object, "a", ten) || + json_object_set(object, "b", ten) || + json_object_set(object, "c", ten) || + json_object_set(object, "d", ten) || + json_object_set(object, "e", ten)) + fail("unable to set value"); + + if(json_object_size(object) != 5) + fail("invalid size"); + + json_object_clear(object); + + if(json_object_size(object) != 0) + fail("invalid size after clear"); + + json_decref(ten); + json_decref(object); +} + +static void test_update() +{ + json_t *object, *other, *nine, *ten; + + object = json_object(); + other = json_object(); + + nine = json_integer(9); + ten = json_integer(10); + + if(!object || !other) + fail("unable to create object"); + if(!nine || !ten) + fail("unable to create integer"); + + + /* update an empty object with an empty object */ + + if(json_object_update(object, other)) + fail("unable to update an emtpy object with an empty object"); + + if(json_object_size(object) != 0) + fail("invalid size after update"); + + if(json_object_size(other) != 0) + fail("invalid size for updater after update"); + + + /* update an empty object with a nonempty object */ + + if(json_object_set(other, "a", ten) || + json_object_set(other, "b", ten) || + json_object_set(other, "c", ten) || + json_object_set(other, "d", ten) || + json_object_set(other, "e", ten)) + fail("unable to set value"); + + if(json_object_update(object, other)) + fail("unable to update an empty object"); + + if(json_object_size(object) != 5) + fail("invalid size after update"); + + if(json_object_get(object, "a") != ten || + json_object_get(object, "b") != ten || + json_object_get(object, "c") != ten || + json_object_get(object, "d") != ten || + json_object_get(object, "e") != ten) + fail("update works incorrectly"); + + + /* perform the same update again */ + + if(json_object_update(object, other)) + fail("unable to update a non-empty object"); + + if(json_object_size(object) != 5) + fail("invalid size after update"); + + if(json_object_get(object, "a") != ten || + json_object_get(object, "b") != ten || + json_object_get(object, "c") != ten || + json_object_get(object, "d") != ten || + json_object_get(object, "e") != ten) + fail("update works incorrectly"); + + + /* update a nonempty object with a nonempty object with both old + and new keys */ + + if(json_object_clear(other)) + fail("clear failed"); + + if(json_object_set(other, "a", nine) || + json_object_set(other, "b", nine) || + json_object_set(other, "f", nine) || + json_object_set(other, "g", nine) || + json_object_set(other, "h", nine)) + fail("unable to set value"); + + if(json_object_update(object, other)) + fail("unable to update a nonempty object"); + + if(json_object_size(object) != 8) + fail("invalid size after update"); + + if(json_object_get(object, "a") != nine || + json_object_get(object, "b") != nine || + json_object_get(object, "f") != nine || + json_object_get(object, "g") != nine || + json_object_get(object, "h") != nine) + fail("update works incorrectly"); + + json_decref(nine); + json_decref(ten); + json_decref(other); + json_decref(object); +} + +static void test_set_many_keys() +{ + json_t *object, *value; + const char *keys = "abcdefghijklmnopqrstuvwxyz"; + char buf[2]; + size_t i; + + object = json_object(); + if (!object) + fail("unable to create object"); + + value = json_string("a"); + if (!value) + fail("unable to create string"); + + buf[1] = '\0'; + for (i = 0; i < strlen(keys); i++) { + buf[0] = keys[i]; + if (json_object_set(object, buf, value)) + fail("unable to set object key"); + } + + json_decref(object); + json_decref(value); +} + +static void test_conditional_updates() +{ + json_t *object, *other; + + object = json_pack("{sisi}", "foo", 1, "bar", 2); + other = json_pack("{sisi}", "foo", 3, "baz", 4); + + if(json_object_update_existing(object, other)) + fail("json_object_update_existing failed"); + + if(json_object_size(object) != 2) + fail("json_object_update_existing added new items"); + + if(json_integer_value(json_object_get(object, "foo")) != 3) + fail("json_object_update_existing failed to update existing key"); + + if(json_integer_value(json_object_get(object, "bar")) != 2) + fail("json_object_update_existing updated wrong key"); + + json_decref(object); + + object = json_pack("{sisi}", "foo", 1, "bar", 2); + + if(json_object_update_missing(object, other)) + fail("json_object_update_missing failed"); + + if(json_object_size(object) != 3) + fail("json_object_update_missing didn't add new items"); + + if(json_integer_value(json_object_get(object, "foo")) != 1) + fail("json_object_update_missing updated existing key"); + + if(json_integer_value(json_object_get(object, "bar")) != 2) + fail("json_object_update_missing updated wrong key"); + + if(json_integer_value(json_object_get(object, "baz")) != 4) + fail("json_object_update_missing didn't add new items"); + + json_decref(object); + json_decref(other); +} + +static void test_circular() +{ + json_t *object1, *object2; + + object1 = json_object(); + object2 = json_object(); + if(!object1 || !object2) + fail("unable to create object"); + + /* the simple case is checked */ + if(json_object_set(object1, "a", object1) == 0) + fail("able to set self"); + + /* create circular references */ + if(json_object_set(object1, "a", object2) || + json_object_set(object2, "a", object1)) + fail("unable to set value"); + + /* circularity is detected when dumping */ + if(json_dumps(object1, 0) != NULL) + fail("able to dump circulars"); + + /* decref twice to deal with the circular references */ + json_decref(object1); + json_decref(object2); + json_decref(object1); +} + +static void test_set_nocheck() +{ + json_t *object, *string; + + object = json_object(); + string = json_string("bar"); + + if(!object) + fail("unable to create object"); + if(!string) + fail("unable to create string"); + + if(json_object_set_nocheck(object, "foo", string)) + fail("json_object_set_nocheck failed"); + if(json_object_get(object, "foo") != string) + fail("json_object_get after json_object_set_nocheck failed"); + + /* invalid UTF-8 in key */ + if(json_object_set_nocheck(object, "a\xefz", string)) + fail("json_object_set_nocheck failed for invalid UTF-8"); + if(json_object_get(object, "a\xefz") != string) + fail("json_object_get after json_object_set_nocheck failed"); + + if(json_object_set_new_nocheck(object, "bax", json_integer(123))) + fail("json_object_set_new_nocheck failed"); + if(json_integer_value(json_object_get(object, "bax")) != 123) + fail("json_object_get after json_object_set_new_nocheck failed"); + + /* invalid UTF-8 in key */ + if(json_object_set_new_nocheck(object, "asdf\xfe", json_integer(321))) + fail("json_object_set_new_nocheck failed for invalid UTF-8"); + if(json_integer_value(json_object_get(object, "asdf\xfe")) != 321) + fail("json_object_get after json_object_set_new_nocheck failed"); + + json_decref(string); + json_decref(object); +} + +static void test_iterators() +{ + json_t *object, *foo, *bar, *baz; + void *iter; + + if(json_object_iter(NULL)) + fail("able to iterate over NULL"); + + if(json_object_iter_next(NULL, NULL)) + fail("able to increment an iterator on a NULL object"); + + object = json_object(); + foo = json_string("foo"); + bar = json_string("bar"); + baz = json_string("baz"); + if(!object || !foo || !bar || !baz) + fail("unable to create values"); + + if(json_object_iter_next(object, NULL)) + fail("able to increment a NULL iterator"); + + if(json_object_set(object, "a", foo) || + json_object_set(object, "b", bar) || + json_object_set(object, "c", baz)) + fail("unable to populate object"); + + iter = json_object_iter(object); + if(!iter) + fail("unable to get iterator"); + if (strcmp(json_object_iter_key(iter), "a") != 0) + fail("iterating doesn't yield keys in order"); + if (json_object_iter_value(iter) != foo) + fail("iterating doesn't yield values in order"); + + iter = json_object_iter_next(object, iter); + if(!iter) + fail("unable to increment iterator"); + if (strcmp(json_object_iter_key(iter), "b") != 0) + fail("iterating doesn't yield keys in order"); + if (json_object_iter_value(iter) != bar) + fail("iterating doesn't yield values in order"); + + iter = json_object_iter_next(object, iter); + if(!iter) + fail("unable to increment iterator"); + if (strcmp(json_object_iter_key(iter), "c") != 0) + fail("iterating doesn't yield keys in order"); + if (json_object_iter_value(iter) != baz) + fail("iterating doesn't yield values in order"); + + if(json_object_iter_next(object, iter) != NULL) + fail("able to iterate over the end"); + + if(json_object_iter_at(object, "foo")) + fail("json_object_iter_at() succeeds for non-existent key"); + + iter = json_object_iter_at(object, "b"); + if(!iter) + fail("json_object_iter_at() fails for an existing key"); + + if(strcmp(json_object_iter_key(iter), "b")) + fail("iterating failed: wrong key"); + if(json_object_iter_value(iter) != bar) + fail("iterating failed: wrong value"); + + if(json_object_iter_set(object, iter, baz)) + fail("unable to set value at iterator"); + + if(strcmp(json_object_iter_key(iter), "b")) + fail("json_object_iter_key() fails after json_object_iter_set()"); + if(json_object_iter_value(iter) != baz) + fail("json_object_iter_value() fails after json_object_iter_set()"); + if(json_object_get(object, "b") != baz) + fail("json_object_get() fails after json_object_iter_set()"); + + json_decref(object); + json_decref(foo); + json_decref(bar); + json_decref(baz); +} + +static void test_misc() +{ + json_t *object, *string, *other_string, *value; + + object = json_object(); + string = json_string("test"); + other_string = json_string("other"); + + if(!object) + fail("unable to create object"); + if(!string || !other_string) + fail("unable to create string"); + + if(json_object_get(object, "a")) + fail("value for nonexisting key"); + + if(json_object_set(object, "a", string)) + fail("unable to set value"); + + if(!json_object_set(object, NULL, string)) + fail("able to set NULL key"); + + if(json_object_del(object, "a")) + fail("unable to del the only key"); + + if(json_object_set(object, "a", string)) + fail("unable to set value"); + + if(!json_object_set(object, "a", NULL)) + fail("able to set NULL value"); + + /* invalid UTF-8 in key */ + if(!json_object_set(object, "a\xefz", string)) + fail("able to set invalid unicode key"); + + value = json_object_get(object, "a"); + if(!value) + fail("no value for existing key"); + if(value != string) + fail("got different value than what was added"); + + /* "a", "lp" and "px" collide in a five-bucket hashtable */ + if(json_object_set(object, "b", string) || + json_object_set(object, "lp", string) || + json_object_set(object, "px", string)) + fail("unable to set value"); + + value = json_object_get(object, "a"); + if(!value) + fail("no value for existing key"); + if(value != string) + fail("got different value than what was added"); + + if(json_object_set(object, "a", other_string)) + fail("unable to replace an existing key"); + + value = json_object_get(object, "a"); + if(!value) + fail("no value for existing key"); + if(value != other_string) + fail("got different value than what was set"); + + if(!json_object_del(object, "nonexisting")) + fail("able to delete a nonexisting key"); + + if(json_object_del(object, "px")) + fail("unable to delete an existing key"); + + if(json_object_del(object, "a")) + fail("unable to delete an existing key"); + + if(json_object_del(object, "lp")) + fail("unable to delete an existing key"); + + + /* add many keys to initiate rehashing */ + + if(json_object_set(object, "a", string)) + fail("unable to set value"); + + if(json_object_set(object, "lp", string)) + fail("unable to set value"); + + if(json_object_set(object, "px", string)) + fail("unable to set value"); + + if(json_object_set(object, "c", string)) + fail("unable to set value"); + + if(json_object_set(object, "d", string)) + fail("unable to set value"); + + if(json_object_set(object, "e", string)) + fail("unable to set value"); + + + if(json_object_set_new(object, "foo", json_integer(123))) + fail("unable to set new value"); + + value = json_object_get(object, "foo"); + if(!json_is_integer(value) || json_integer_value(value) != 123) + fail("json_object_set_new works incorrectly"); + + if(!json_object_set_new(object, NULL, json_integer(432))) + fail("able to set_new NULL key"); + + if(!json_object_set_new(object, "foo", NULL)) + fail("able to set_new NULL value"); + + json_decref(string); + json_decref(other_string); + json_decref(object); +} + +static void test_preserve_order() +{ + json_t *object; + char *result; + + const char *expected = "{\"foobar\": 1, \"bazquux\": 6, \"lorem ipsum\": 3, \"sit amet\": 5, \"helicopter\": 7}"; + + object = json_object(); + + json_object_set_new(object, "foobar", json_integer(1)); + json_object_set_new(object, "bazquux", json_integer(2)); + json_object_set_new(object, "lorem ipsum", json_integer(3)); + json_object_set_new(object, "dolor", json_integer(4)); + json_object_set_new(object, "sit amet", json_integer(5)); + + /* changing a value should preserve the order */ + json_object_set_new(object, "bazquux", json_integer(6)); + + /* deletion shouldn't change the order of others */ + json_object_del(object, "dolor"); + + /* add a new item just to make sure */ + json_object_set_new(object, "helicopter", json_integer(7)); + + result = json_dumps(object, JSON_PRESERVE_ORDER); + + if(strcmp(expected, result) != 0) { + fprintf(stderr, "%s != %s", expected, result); + fail("JSON_PRESERVE_ORDER doesn't work"); + } + + free(result); + json_decref(object); +} + +static void test_object_foreach() +{ + const char *key; + json_t *object1, *object2, *value; + + object1 = json_pack("{sisisi}", "foo", 1, "bar", 2, "baz", 3); + object2 = json_object(); + + json_object_foreach(object1, key, value) + json_object_set(object2, key, value); + + if(!json_equal(object1, object2)) + fail("json_object_foreach failed to iterate all key-value pairs"); + + json_decref(object1); + json_decref(object2); +} + +static void test_object_foreach_safe() +{ + const char *key; + void *tmp; + json_t *object, *value; + + object = json_pack("{sisisi}", "foo", 1, "bar", 2, "baz", 3); + + json_object_foreach_safe(object, tmp, key, value) { + json_object_del(object, key); + } + + if(json_object_size(object) != 0) + fail("json_object_foreach_safe failed to iterate all key-value pairs"); + + json_decref(object); +} + +static void test_bad_args(void) +{ + json_t *obj = json_object(); + json_t *num = json_integer(1); + void *iter; + + if (!obj || !num) + fail("failed to allocate test objects"); + + if (json_object_set(obj, "testkey", json_null())) + fail("failed to set testkey on object"); + + iter = json_object_iter(obj); + if (!iter) + fail("failed to retrieve test iterator"); + + if(json_object_size(NULL) != 0) + fail("json_object_size with non-object argument returned non-zero"); + if(json_object_size(num) != 0) + fail("json_object_size with non-object argument returned non-zero"); + + if(json_object_get(NULL, "test") != NULL) + fail("json_object_get with non-object argument returned non-NULL"); + if(json_object_get(num, "test") != NULL) + fail("json_object_get with non-object argument returned non-NULL"); + if(json_object_get(obj, NULL) != NULL) + fail("json_object_get with NULL key returned non-NULL"); + + if(!json_object_set_new_nocheck(NULL, "test", json_null())) + fail("json_object_set_new_nocheck with non-object argument did not return error"); + if(!json_object_set_new_nocheck(num, "test", json_null())) + fail("json_object_set_new_nocheck with non-object argument did not return error"); + if(!json_object_set_new_nocheck(obj, "test", json_incref(obj))) + fail("json_object_set_new_nocheck with object == value did not return error"); + if(!json_object_set_new_nocheck(obj, NULL, json_object())) + fail("json_object_set_new_nocheck with NULL key did not return error"); + + if(!json_object_del(NULL, "test")) + fail("json_object_del with non-object argument did not return error"); + if(!json_object_del(num, "test")) + fail("json_object_del with non-object argument did not return error"); + if(!json_object_del(obj, NULL)) + fail("json_object_del with NULL key did not return error"); + + if(!json_object_clear(NULL)) + fail("json_object_clear with non-object argument did not return error"); + if(!json_object_clear(num)) + fail("json_object_clear with non-object argument did not return error"); + + if(!json_object_update(NULL, obj)) + fail("json_object_update with non-object first argument did not return error"); + if(!json_object_update(num, obj)) + fail("json_object_update with non-object first argument did not return error"); + if(!json_object_update(obj, NULL)) + fail("json_object_update with non-object second argument did not return error"); + if(!json_object_update(obj, num)) + fail("json_object_update with non-object second argument did not return error"); + + if(!json_object_update_existing(NULL, obj)) + fail("json_object_update_existing with non-object first argument did not return error"); + if(!json_object_update_existing(num, obj)) + fail("json_object_update_existing with non-object first argument did not return error"); + if(!json_object_update_existing(obj, NULL)) + fail("json_object_update_existing with non-object second argument did not return error"); + if(!json_object_update_existing(obj, num)) + fail("json_object_update_existing with non-object second argument did not return error"); + + if(!json_object_update_missing(NULL, obj)) + fail("json_object_update_missing with non-object first argument did not return error"); + if(!json_object_update_missing(num, obj)) + fail("json_object_update_missing with non-object first argument did not return error"); + if(!json_object_update_missing(obj, NULL)) + fail("json_object_update_missing with non-object second argument did not return error"); + if(!json_object_update_missing(obj, num)) + fail("json_object_update_missing with non-object second argument did not return error"); + + if(json_object_iter(NULL) != NULL) + fail("json_object_iter with non-object argument returned non-NULL"); + if(json_object_iter(num) != NULL) + fail("json_object_iter with non-object argument returned non-NULL"); + + if(json_object_iter_at(NULL, "test") != NULL) + fail("json_object_iter_at with non-object argument returned non-NULL"); + if(json_object_iter_at(num, "test") != NULL) + fail("json_object_iter_at with non-object argument returned non-NULL"); + if(json_object_iter_at(obj, NULL) != NULL) + fail("json_object_iter_at with NULL iter returned non-NULL"); + + if(json_object_iter_next(obj, NULL) != NULL) + fail("json_object_iter_next with NULL iter returned non-NULL"); + if(json_object_iter_next(num, iter) != NULL) + fail("json_object_iter_next with non-object argument returned non-NULL"); + + if(json_object_iter_key(NULL) != NULL) + fail("json_object_iter_key with NULL iter returned non-NULL"); + + if(json_object_key_to_iter(NULL) != NULL) + fail("json_object_key_to_iter with NULL iter returned non-NULL"); + + if(json_object_iter_value(NULL) != NULL) + fail("json_object_iter_value with NULL iter returned non-NULL"); + + if(!json_object_iter_set_new(NULL, iter, json_incref(num))) + fail("json_object_iter_set_new with non-object argument did not return error"); + if(!json_object_iter_set_new(num, iter, json_incref(num))) + fail("json_object_iter_set_new with non-object argument did not return error"); + if(!json_object_iter_set_new(obj, NULL, json_incref(num))) + fail("json_object_iter_set_new with NULL iter did not return error"); + if(!json_object_iter_set_new(obj, iter, NULL)) + fail("json_object_iter_set_new with NULL value did not return error"); + + if (obj->refcount != 1) + fail("unexpected reference count for obj"); + + if (num->refcount != 1) + fail("unexpected reference count for num"); + + json_decref(obj); + json_decref(num); +} + +static void run_tests() +{ + test_misc(); + test_clear(); + test_update(); + test_set_many_keys(); + test_conditional_updates(); + test_circular(); + test_set_nocheck(); + test_iterators(); + test_preserve_order(); + test_object_foreach(); + test_object_foreach_safe(); + test_bad_args(); +} diff --git a/3party/jansson/test/suites/api/test_pack.c b/3party/jansson/test/suites/api/test_pack.c new file mode 100644 index 0000000000..084f170121 --- /dev/null +++ b/3party/jansson/test/suites/api/test_pack.c @@ -0,0 +1,518 @@ +/* + * Copyright (c) 2009-2016 Petri Lehtinen + * Copyright (c) 2010-2012 Graeme Smecher + * + * Jansson is free software; you can redistribute it and/or modify + * it under the terms of the MIT license. See LICENSE for details. + */ + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include + +#include +#include +#include +#include +#include "util.h" + +#ifdef INFINITY +// This test triggers "warning C4756: overflow in constant arithmetic" +// in Visual Studio. This warning is triggered here by design, so disable it. +// (This can only be done on function level so we keep these tests separate) +#ifdef _MSC_VER +#pragma warning(push) +#pragma warning (disable: 4756) +#endif +static void test_inifity() +{ + json_error_t error; + + if (json_pack_ex(&error, 0, "f", INFINITY)) + fail("json_pack infinity incorrectly succeeded"); + check_error(json_error_numeric_overflow, "Invalid floating point value", "", 1, 1, 1); + + if (json_pack_ex(&error, 0, "[f]", INFINITY)) + fail("json_pack infinity array element incorrectly succeeded"); + check_error(json_error_numeric_overflow, "Invalid floating point value", "", 1, 2, 2); + + if (json_pack_ex(&error, 0, "{s:f}", "key", INFINITY)) + fail("json_pack infinity object value incorrectly succeeded"); + check_error(json_error_numeric_overflow, "Invalid floating point value", "", 1, 4, 4); + +#ifdef _MSC_VER +#pragma warning(pop) +#endif +} +#endif // INFINITY + +static void run_tests() +{ + json_t *value; + int i; + char buffer[4] = {'t', 'e', 's', 't'}; + json_error_t error; + + /* + * Simple, valid json_pack cases + */ + /* true */ + value = json_pack("b", 1); + if(!json_is_true(value)) + fail("json_pack boolean failed"); + if(value->refcount != (size_t)-1) + fail("json_pack boolean refcount failed"); + json_decref(value); + + /* false */ + value = json_pack("b", 0); + if(!json_is_false(value)) + fail("json_pack boolean failed"); + if(value->refcount != (size_t)-1) + fail("json_pack boolean refcount failed"); + json_decref(value); + + /* null */ + value = json_pack("n"); + if(!json_is_null(value)) + fail("json_pack null failed"); + if(value->refcount != (size_t)-1) + fail("json_pack null refcount failed"); + json_decref(value); + + /* integer */ + value = json_pack("i", 1); + if(!json_is_integer(value) || json_integer_value(value) != 1) + fail("json_pack integer failed"); + if(value->refcount != (size_t)1) + fail("json_pack integer refcount failed"); + json_decref(value); + + /* integer from json_int_t */ + value = json_pack("I", (json_int_t)555555); + if(!json_is_integer(value) || json_integer_value(value) != 555555) + fail("json_pack json_int_t failed"); + if(value->refcount != (size_t)1) + fail("json_pack integer refcount failed"); + json_decref(value); + + /* real */ + value = json_pack("f", 1.0); + if(!json_is_real(value) || json_real_value(value) != 1.0) + fail("json_pack real failed"); + if(value->refcount != (size_t)1) + fail("json_pack real refcount failed"); + json_decref(value); + + /* string */ + value = json_pack("s", "test"); + if(!json_is_string(value) || strcmp("test", json_string_value(value))) + fail("json_pack string failed"); + if(value->refcount != (size_t)1) + fail("json_pack string refcount failed"); + json_decref(value); + + /* nullable string (defined case) */ + value = json_pack("s?", "test"); + if(!json_is_string(value) || strcmp("test", json_string_value(value))) + fail("json_pack nullable string (defined case) failed"); + if(value->refcount != (size_t)1) + fail("json_pack nullable string (defined case) refcount failed"); + json_decref(value); + + /* nullable string (NULL case) */ + value = json_pack("s?", NULL); + if(!json_is_null(value)) + fail("json_pack nullable string (NULL case) failed"); + if(value->refcount != (size_t)-1) + fail("json_pack nullable string (NULL case) refcount failed"); + json_decref(value); + + /* nullable string concatenation */ + if(json_pack_ex(&error, 0, "s?+", "test", "ing")) + fail("json_pack failed to catch invalid format 's?+'"); + check_error(json_error_invalid_format, "Cannot use '+' on optional strings", "", 1, 2, 2); + + /* nullable string with integer length */ + if(json_pack_ex(&error, 0, "s?#", "test", 4)) + fail("json_pack failed to catch invalid format 's?#'"); + check_error(json_error_invalid_format, "Cannot use '#' on optional strings", "", 1, 2, 2); + + /* string and length (int) */ + value = json_pack("s#", "test asdf", 4); + if(!json_is_string(value) || strcmp("test", json_string_value(value))) + fail("json_pack string and length failed"); + if(value->refcount != (size_t)1) + fail("json_pack string and length refcount failed"); + json_decref(value); + + /* string and length (size_t) */ + value = json_pack("s%", "test asdf", (size_t)4); + if(!json_is_string(value) || strcmp("test", json_string_value(value))) + fail("json_pack string and length failed"); + if(value->refcount != (size_t)1) + fail("json_pack string and length refcount failed"); + json_decref(value); + + /* string and length (int), non-NUL terminated string */ + value = json_pack("s#", buffer, 4); + if(!json_is_string(value) || strcmp("test", json_string_value(value))) + fail("json_pack string and length (int) failed"); + if(value->refcount != (size_t)1) + fail("json_pack string and length (int) refcount failed"); + json_decref(value); + + /* string and length (size_t), non-NUL terminated string */ + value = json_pack("s%", buffer, (size_t)4); + if(!json_is_string(value) || strcmp("test", json_string_value(value))) + fail("json_pack string and length (size_t) failed"); + if(value->refcount != (size_t)1) + fail("json_pack string and length (size_t) refcount failed"); + json_decref(value); + + /* string concatenation */ + if (json_pack("s+", "test", NULL)) + fail("json_pack string concatenation succeeded with NULL string"); + + value = json_pack("s++", "te", "st", "ing"); + if(!json_is_string(value) || strcmp("testing", json_string_value(value))) + fail("json_pack string concatenation failed"); + if(value->refcount != (size_t)1) + fail("json_pack string concatenation refcount failed"); + json_decref(value); + + /* string concatenation and length (int) */ + value = json_pack("s#+#+", "test", 1, "test", 2, "test"); + if(!json_is_string(value) || strcmp("ttetest", json_string_value(value))) + fail("json_pack string concatenation and length (int) failed"); + if(value->refcount != (size_t)1) + fail("json_pack string concatenation and length (int) refcount failed"); + json_decref(value); + + /* string concatenation and length (size_t) */ + value = json_pack("s%+%+", "test", (size_t)1, "test", (size_t)2, "test"); + if(!json_is_string(value) || strcmp("ttetest", json_string_value(value))) + fail("json_pack string concatenation and length (size_t) failed"); + if(value->refcount != (size_t)1) + fail("json_pack string concatenation and length (size_t) refcount failed"); + json_decref(value); + + /* empty object */ + value = json_pack("{}", 1.0); + if(!json_is_object(value) || json_object_size(value) != 0) + fail("json_pack empty object failed"); + if(value->refcount != (size_t)1) + fail("json_pack empty object refcount failed"); + json_decref(value); + + /* empty list */ + value = json_pack("[]", 1.0); + if(!json_is_array(value) || json_array_size(value) != 0) + fail("json_pack empty list failed"); + if(value->refcount != (size_t)1) + fail("json_pack empty list failed"); + json_decref(value); + + /* non-incref'd object */ + value = json_pack("o", json_integer(1)); + if(!json_is_integer(value) || json_integer_value(value) != 1) + fail("json_pack object failed"); + if(value->refcount != (size_t)1) + fail("json_pack integer refcount failed"); + json_decref(value); + + /* non-incref'd nullable object (defined case) */ + value = json_pack("o?", json_integer(1)); + if(!json_is_integer(value) || json_integer_value(value) != 1) + fail("json_pack nullable object (defined case) failed"); + if(value->refcount != (size_t)1) + fail("json_pack nullable object (defined case) refcount failed"); + json_decref(value); + + /* non-incref'd nullable object (NULL case) */ + value = json_pack("o?", NULL); + if(!json_is_null(value)) + fail("json_pack nullable object (NULL case) failed"); + if(value->refcount != (size_t)-1) + fail("json_pack nullable object (NULL case) refcount failed"); + json_decref(value); + + /* incref'd object */ + value = json_pack("O", json_integer(1)); + if(!json_is_integer(value) || json_integer_value(value) != 1) + fail("json_pack object failed"); + if(value->refcount != (size_t)2) + fail("json_pack integer refcount failed"); + json_decref(value); + json_decref(value); + + /* incref'd nullable object (defined case) */ + value = json_pack("O?", json_integer(1)); + if(!json_is_integer(value) || json_integer_value(value) != 1) + fail("json_pack incref'd nullable object (defined case) failed"); + if(value->refcount != (size_t)2) + fail("json_pack incref'd nullable object (defined case) refcount failed"); + json_decref(value); + json_decref(value); + + /* incref'd nullable object (NULL case) */ + value = json_pack("O?", NULL); + if(!json_is_null(value)) + fail("json_pack incref'd nullable object (NULL case) failed"); + if(value->refcount != (size_t)-1) + fail("json_pack incref'd nullable object (NULL case) refcount failed"); + + /* simple object */ + value = json_pack("{s:[]}", "foo"); + if(!json_is_object(value) || json_object_size(value) != 1) + fail("json_pack array failed"); + if(!json_is_array(json_object_get(value, "foo"))) + fail("json_pack array failed"); + if(json_object_get(value, "foo")->refcount != (size_t)1) + fail("json_pack object refcount failed"); + json_decref(value); + + /* object with complex key */ + value = json_pack("{s+#+: []}", "foo", "barbar", 3, "baz"); + if(!json_is_object(value) || json_object_size(value) != 1) + fail("json_pack array failed"); + if(!json_is_array(json_object_get(value, "foobarbaz"))) + fail("json_pack array failed"); + if(json_object_get(value, "foobarbaz")->refcount != (size_t)1) + fail("json_pack object refcount failed"); + json_decref(value); + + /* object with optional members */ + value = json_pack("{s:s,s:o,s:O}", "a", NULL, "b", NULL, "c", NULL); + if(value) + fail("json_pack object optional incorrectly succeeded"); + + value = json_pack("{s:**}", "a", NULL); + if(value) + fail("json_pack object optional invalid incorrectly succeeded"); + + if (json_pack_ex(&error, 0, "{s:i*}", "a", 1)) + fail("json_pack object optional invalid incorrectly succeeded"); + check_error(json_error_invalid_format, "Expected format 's', got '*'", "", 1, 5, 5); + + value = json_pack("{s:s*,s:o*,s:O*}", "a", NULL, "b", NULL, "c", NULL); + if(!json_is_object(value) || json_object_size(value) != 0) + fail("json_pack object optional failed"); + json_decref(value); + + value = json_pack("{s:s*}", "key", "\xff\xff"); + if(value) + fail("json_pack object optional with invalid UTF-8 incorrectly succeeded"); + + if(json_pack_ex(&error, 0, "{s: s*#}", "key", "test", 1)) + fail("json_pack failed to catch invalid format 's*#'"); + check_error(json_error_invalid_format, "Cannot use '#' on optional strings", "", 1, 6, 6); + + if(json_pack_ex(&error, 0, "{s: s*+}", "key", "test", "ing")) + fail("json_pack failed to catch invalid format 's*+'"); + check_error(json_error_invalid_format, "Cannot use '+' on optional strings", "", 1, 6, 6); + + /* simple array */ + value = json_pack("[i,i,i]", 0, 1, 2); + if(!json_is_array(value) || json_array_size(value) != 3) + fail("json_pack object failed"); + for(i=0; i<3; i++) + { + if(!json_is_integer(json_array_get(value, i)) || + json_integer_value(json_array_get(value, i)) != i) + + fail("json_pack integer array failed"); + } + json_decref(value); + + /* simple array with optional members */ + value = json_pack("[s,o,O]", NULL, NULL, NULL); + if(value) + fail("json_pack array optional incorrectly succeeded"); + + if (json_pack_ex(&error, 0, "[i*]", 1)) + fail("json_pack array optional invalid incorrectly succeeded"); + check_error(json_error_invalid_format, "Unexpected format character '*'", "", 1, 3, 3); + + value = json_pack("[**]", NULL); + if(value) + fail("json_pack array optional invalid incorrectly succeeded"); + value = json_pack("[s*,o*,O*]", NULL, NULL, NULL); + if(!json_is_array(value) || json_array_size(value) != 0) + fail("json_pack array optional failed"); + json_decref(value); + +#ifdef NAN + /* Invalid float values */ + if (json_pack_ex(&error, 0, "f", NAN)) + fail("json_pack NAN incorrectly succeeded"); + check_error(json_error_numeric_overflow, "Invalid floating point value", "", 1, 1, 1); + + if (json_pack_ex(&error, 0, "[f]", NAN)) + fail("json_pack NAN array element incorrectly succeeded"); + check_error(json_error_numeric_overflow, "Invalid floating point value", "", 1, 2, 2); + + if (json_pack_ex(&error, 0, "{s:f}", "key", NAN)) + fail("json_pack NAN object value incorrectly succeeded"); + check_error(json_error_numeric_overflow, "Invalid floating point value", "", 1, 4, 4); +#endif + +#ifdef INFINITY + test_inifity(); +#endif + + /* Whitespace; regular string */ + value = json_pack(" s\t ", "test"); + if(!json_is_string(value) || strcmp("test", json_string_value(value))) + fail("json_pack string (with whitespace) failed"); + json_decref(value); + + /* Whitespace; empty array */ + value = json_pack("[ ]"); + if(!json_is_array(value) || json_array_size(value) != 0) + fail("json_pack empty array (with whitespace) failed"); + json_decref(value); + + /* Whitespace; array */ + value = json_pack("[ i , i, i ] ", 1, 2, 3); + if(!json_is_array(value) || json_array_size(value) != 3) + fail("json_pack array (with whitespace) failed"); + json_decref(value); + + /* + * Invalid cases + */ + + /* newline in format string */ + if(json_pack_ex(&error, 0, "{\n\n1")) + fail("json_pack failed to catch invalid format '1'"); + check_error(json_error_invalid_format, "Expected format 's', got '1'", "", 3, 1, 4); + + /* mismatched open/close array/object */ + if(json_pack_ex(&error, 0, "[}")) + fail("json_pack failed to catch mismatched '}'"); + check_error(json_error_invalid_format, "Unexpected format character '}'", "", 1, 2, 2); + + if(json_pack_ex(&error, 0, "{]")) + fail("json_pack failed to catch mismatched ']'"); + check_error(json_error_invalid_format, "Expected format 's', got ']'", "", 1, 2, 2); + + /* missing close array */ + if(json_pack_ex(&error, 0, "[")) + fail("json_pack failed to catch missing ']'"); + check_error(json_error_invalid_format, "Unexpected end of format string", "", 1, 2, 2); + + /* missing close object */ + if(json_pack_ex(&error, 0, "{")) + fail("json_pack failed to catch missing '}'"); + check_error(json_error_invalid_format, "Unexpected end of format string", "", 1, 2, 2); + + /* garbage after format string */ + if(json_pack_ex(&error, 0, "[i]a", 42)) + fail("json_pack failed to catch garbage after format string"); + check_error(json_error_invalid_format, "Garbage after format string", "", 1, 4, 4); + + if(json_pack_ex(&error, 0, "ia", 42)) + fail("json_pack failed to catch garbage after format string"); + check_error(json_error_invalid_format, "Garbage after format string", "", 1, 2, 2); + + /* NULL string */ + if(json_pack_ex(&error, 0, "s", NULL)) + fail("json_pack failed to catch null argument string"); + check_error(json_error_null_value, "NULL string", "", 1, 1, 1); + + /* + on its own */ + if(json_pack_ex(&error, 0, "+", NULL)) + fail("json_pack failed to a lone +"); + check_error(json_error_invalid_format, "Unexpected format character '+'", "", 1, 1, 1); + + /* Empty format */ + if(json_pack_ex(&error, 0, "")) + fail("json_pack failed to catch empty format string"); + check_error(json_error_invalid_argument, "NULL or empty format string", "", -1, -1, 0); + + /* NULL format */ + if(json_pack_ex(&error, 0, NULL)) + fail("json_pack failed to catch NULL format string"); + check_error(json_error_invalid_argument, "NULL or empty format string", "", -1, -1, 0); + + /* NULL key */ + if(json_pack_ex(&error, 0, "{s:i}", NULL, 1)) + fail("json_pack failed to catch NULL key"); + check_error(json_error_null_value, "NULL object key", "", 1, 2, 2); + + /* NULL value followed by object still steals the object's ref */ + value = json_incref(json_object()); + if(json_pack_ex(&error, 0, "{s:s,s:o}", "badnull", NULL, "dontleak", value)) + fail("json_pack failed to catch NULL value"); + check_error(json_error_null_value, "NULL string", "", 1, 4, 4); + if(value->refcount != (size_t)1) + fail("json_pack failed to steal reference after error."); + json_decref(value); + + /* More complicated checks for row/columns */ + if(json_pack_ex(&error, 0, "{ {}: s }", "foo")) + fail("json_pack failed to catch object as key"); + check_error(json_error_invalid_format, "Expected format 's', got '{'", "", 1, 3, 3); + + /* Complex object */ + if(json_pack_ex(&error, 0, "{ s: {}, s:[ii{} }", "foo", "bar", 12, 13)) + fail("json_pack failed to catch missing ]"); + check_error(json_error_invalid_format, "Unexpected format character '}'", "", 1, 19, 19); + + /* Complex array */ + if(json_pack_ex(&error, 0, "[[[[[ [[[[[ [[[[ }]]]] ]]]] ]]]]]")) + fail("json_pack failed to catch extra }"); + check_error(json_error_invalid_format, "Unexpected format character '}'", "", 1, 21, 21); + + /* Invalid UTF-8 in object key */ + if(json_pack_ex(&error, 0, "{s:i}", "\xff\xff", 42)) + fail("json_pack failed to catch invalid UTF-8 in an object key"); + check_error(json_error_invalid_utf8, "Invalid UTF-8 object key", "", 1, 2, 2); + + /* Invalid UTF-8 in a string */ + if(json_pack_ex(&error, 0, "{s:s}", "foo", "\xff\xff")) + fail("json_pack failed to catch invalid UTF-8 in a string"); + check_error(json_error_invalid_utf8, "Invalid UTF-8 string", "", 1, 4, 4); + + /* Invalid UTF-8 in an optional '?' string */ + if(json_pack_ex(&error, 0, "{s:s?}", "foo", "\xff\xff")) + fail("json_pack failed to catch invalid UTF-8 in an optional '?' string"); + check_error(json_error_invalid_utf8, "Invalid UTF-8 string", "", 1, 5, 5); + + /* Invalid UTF-8 in an optional '*' string */ + if(json_pack_ex(&error, 0, "{s:s*}", "foo", "\xff\xff")) + fail("json_pack failed to catch invalid UTF-8 in an optional '*' string"); + check_error(json_error_invalid_utf8, "Invalid UTF-8 string", "", 1, 5, 5); + + /* Invalid UTF-8 in a concatenated key */ + if(json_pack_ex(&error, 0, "{s+:i}", "\xff\xff", "concat", 42)) + fail("json_pack failed to catch invalid UTF-8 in an object key"); + check_error(json_error_invalid_utf8, "Invalid UTF-8 object key", "", 1, 3, 3); + + if(json_pack_ex(&error, 0, "{s:o}", "foo", NULL)) + fail("json_pack failed to catch nullable object"); + check_error(json_error_null_value, "NULL object", "", 1, 4, 4); + + if(json_pack_ex(&error, 0, "{s:O}", "foo", NULL)) + fail("json_pack failed to catch nullable incref object"); + check_error(json_error_null_value, "NULL object", "", 1, 4, 4); + + if(json_pack_ex(&error, 0, "{s+:o}", "foo", "bar", NULL)) + fail("json_pack failed to catch non-nullable object value"); + check_error(json_error_null_value, "NULL object", "", 1, 5, 5); + + if(json_pack_ex(&error, 0, "[1s", "Hi")) + fail("json_pack failed to catch invalid format"); + check_error(json_error_invalid_format, "Unexpected format character '1'", "", 1, 2, 2); + + if(json_pack_ex(&error, 0, "[1s+", "Hi", "ya")) + fail("json_pack failed to catch invalid format"); + check_error(json_error_invalid_format, "Unexpected format character '1'", "", 1, 2, 2); + + if(json_pack_ex(&error, 0, "[so]", NULL, json_object())) + fail("json_pack failed to catch NULL value"); + check_error(json_error_null_value, "NULL string", "", 1, 2, 2); +} diff --git a/3party/jansson/test/suites/api/test_simple.c b/3party/jansson/test/suites/api/test_simple.c new file mode 100644 index 0000000000..82771873ff --- /dev/null +++ b/3party/jansson/test/suites/api/test_simple.c @@ -0,0 +1,292 @@ +/* + * Copyright (c) 2009-2016 Petri Lehtinen + * + * Jansson is free software; you can redistribute it and/or modify + * it under the terms of the MIT license. See LICENSE for details. + */ + +#include +#include +#include "util.h" + +static void test_bad_args(void) +{ + json_t *num = json_integer(1); + json_t *txt = json_string("test"); + + if (!num || !txt) + fail("failed to allocate test objects"); + + if(json_string_nocheck(NULL) != NULL) + fail("json_string_nocheck with NULL argument did not return NULL"); + if(json_stringn_nocheck(NULL, 0) != NULL) + fail("json_stringn_nocheck with NULL argument did not return NULL"); + if(json_string(NULL) != NULL) + fail("json_string with NULL argument did not return NULL"); + if(json_stringn(NULL, 0) != NULL) + fail("json_stringn with NULL argument did not return NULL"); + + if(json_string_length(NULL) != 0) + fail("json_string_length with non-string argument did not return 0"); + if(json_string_length(num) != 0) + fail("json_string_length with non-string argument did not return 0"); + + if(json_string_value(NULL) != NULL) + fail("json_string_value with non-string argument did not return NULL"); + if(json_string_value(num) != NULL) + fail("json_string_value with non-string argument did not return NULL"); + + if(!json_string_setn_nocheck(NULL, "", 0)) + fail("json_string_setn with non-string argument did not return error"); + if(!json_string_setn_nocheck(num, "", 0)) + fail("json_string_setn with non-string argument did not return error"); + if(!json_string_setn_nocheck(txt, NULL, 0)) + fail("json_string_setn_nocheck with NULL value did not return error"); + + if(!json_string_set_nocheck(txt, NULL)) + fail("json_string_set_nocheck with NULL value did not return error"); + if(!json_string_set(txt, NULL)) + fail("json_string_set with NULL value did not return error"); + if(!json_string_setn(txt, NULL, 0)) + fail("json_string_setn with NULL value did not return error"); + + if(num->refcount != 1) + fail("unexpected reference count for num"); + if(txt->refcount != 1) + fail("unexpected reference count for txt"); + + json_decref(num); + json_decref(txt); +} + +/* Call the simple functions not covered by other tests of the public API */ +static void run_tests() +{ + json_t *value; + + value = json_boolean(1); + if(!json_is_true(value)) + fail("json_boolean(1) failed"); + json_decref(value); + + value = json_boolean(-123); + if(!json_is_true(value)) + fail("json_boolean(-123) failed"); + json_decref(value); + + value = json_boolean(0); + if(!json_is_false(value)) + fail("json_boolean(0) failed"); + if(json_boolean_value(value) != 0) + fail("json_boolean_value failed"); + json_decref(value); + + + value = json_integer(1); + if(json_typeof(value) != JSON_INTEGER) + fail("json_typeof failed"); + + if(json_is_object(value)) + fail("json_is_object failed"); + + if(json_is_array(value)) + fail("json_is_array failed"); + + if(json_is_string(value)) + fail("json_is_string failed"); + + if(!json_is_integer(value)) + fail("json_is_integer failed"); + + if(json_is_real(value)) + fail("json_is_real failed"); + + if(!json_is_number(value)) + fail("json_is_number failed"); + + if(json_is_true(value)) + fail("json_is_true failed"); + + if(json_is_false(value)) + fail("json_is_false failed"); + + if(json_is_boolean(value)) + fail("json_is_boolean failed"); + + if(json_is_null(value)) + fail("json_is_null failed"); + + json_decref(value); + + + value = json_string("foo"); + if(!value) + fail("json_string failed"); + if(strcmp(json_string_value(value), "foo")) + fail("invalid string value"); + if (json_string_length(value) != 3) + fail("invalid string length"); + + if(json_string_set(value, "barr")) + fail("json_string_set failed"); + if(strcmp(json_string_value(value), "barr")) + fail("invalid string value"); + if (json_string_length(value) != 4) + fail("invalid string length"); + + if(json_string_setn(value, "hi\0ho", 5)) + fail("json_string_set failed"); + if(memcmp(json_string_value(value), "hi\0ho\0", 6)) + fail("invalid string value"); + if (json_string_length(value) != 5) + fail("invalid string length"); + + json_decref(value); + + value = json_string(NULL); + if(value) + fail("json_string(NULL) failed"); + + /* invalid UTF-8 */ + value = json_string("a\xefz"); + if(value) + fail("json_string() failed"); + + value = json_string_nocheck("foo"); + if(!value) + fail("json_string_nocheck failed"); + if(strcmp(json_string_value(value), "foo")) + fail("invalid string value"); + if (json_string_length(value) != 3) + fail("invalid string length"); + + if(json_string_set_nocheck(value, "barr")) + fail("json_string_set_nocheck failed"); + if(strcmp(json_string_value(value), "barr")) + fail("invalid string value"); + if (json_string_length(value) != 4) + fail("invalid string length"); + + if(json_string_setn_nocheck(value, "hi\0ho", 5)) + fail("json_string_set failed"); + if(memcmp(json_string_value(value), "hi\0ho\0", 6)) + fail("invalid string value"); + if (json_string_length(value) != 5) + fail("invalid string length"); + + json_decref(value); + + /* invalid UTF-8 */ + value = json_string_nocheck("qu\xff"); + if(!value) + fail("json_string_nocheck failed"); + if(strcmp(json_string_value(value), "qu\xff")) + fail("invalid string value"); + if (json_string_length(value) != 3) + fail("invalid string length"); + + if(json_string_set_nocheck(value, "\xfd\xfe\xff")) + fail("json_string_set_nocheck failed"); + if(strcmp(json_string_value(value), "\xfd\xfe\xff")) + fail("invalid string value"); + if (json_string_length(value) != 3) + fail("invalid string length"); + + json_decref(value); + + + value = json_integer(123); + if(!value) + fail("json_integer failed"); + if(json_integer_value(value) != 123) + fail("invalid integer value"); + if(json_number_value(value) != 123.0) + fail("invalid number value"); + + if(json_integer_set(value, 321)) + fail("json_integer_set failed"); + if(json_integer_value(value) != 321) + fail("invalid integer value"); + if(json_number_value(value) != 321.0) + fail("invalid number value"); + + json_decref(value); + + value = json_real(123.123); + if(!value) + fail("json_real failed"); + if(json_real_value(value) != 123.123) + fail("invalid integer value"); + if(json_number_value(value) != 123.123) + fail("invalid number value"); + + if(json_real_set(value, 321.321)) + fail("json_real_set failed"); + if(json_real_value(value) != 321.321) + fail("invalid real value"); + if(json_number_value(value) != 321.321) + fail("invalid number value"); + + json_decref(value); + + value = json_true(); + if(!value) + fail("json_true failed"); + json_decref(value); + + value = json_false(); + if(!value) + fail("json_false failed"); + json_decref(value); + + value = json_null(); + if(!value) + fail("json_null failed"); + json_decref(value); + + /* Test reference counting on singletons (true, false, null) */ + value = json_true(); + if(value->refcount != (size_t)-1) + fail("refcounting true works incorrectly"); + json_decref(value); + if(value->refcount != (size_t)-1) + fail("refcounting true works incorrectly"); + json_incref(value); + if(value->refcount != (size_t)-1) + fail("refcounting true works incorrectly"); + + value = json_false(); + if(value->refcount != (size_t)-1) + fail("refcounting false works incorrectly"); + json_decref(value); + if(value->refcount != (size_t)-1) + fail("refcounting false works incorrectly"); + json_incref(value); + if(value->refcount != (size_t)-1) + fail("refcounting false works incorrectly"); + + value = json_null(); + if(value->refcount != (size_t)-1) + fail("refcounting null works incorrectly"); + json_decref(value); + if(value->refcount != (size_t)-1) + fail("refcounting null works incorrectly"); + json_incref(value); + if(value->refcount != (size_t)-1) + fail("refcounting null works incorrectly"); + +#ifdef json_auto_t + value = json_string("foo"); + { + json_auto_t *test = json_incref(value); + /* Use test so GCC doesn't complain it is unused. */ + if(!json_is_string(test)) + fail("value type check failed"); + } + if(value->refcount != 1) + fail("automatic decrement failed"); + json_decref(value); +#endif + + test_bad_args(); +} diff --git a/3party/jansson/test/suites/api/test_sprintf.c b/3party/jansson/test/suites/api/test_sprintf.c new file mode 100644 index 0000000000..c0a4cf7af7 --- /dev/null +++ b/3party/jansson/test/suites/api/test_sprintf.c @@ -0,0 +1,34 @@ +#include +#include +#include "util.h" + + +static void test_sprintf() { + json_t *s = json_sprintf("foo bar %d", 42); + if (!s) + fail("json_sprintf returned NULL"); + if (!json_is_string(s)) + fail("json_sprintf didn't return a JSON string"); + if (strcmp(json_string_value(s), "foo bar 42")) + fail("json_sprintf generated an unexpected string"); + + json_decref(s); + + s = json_sprintf("%s", ""); + if (!s) + fail("json_sprintf returned NULL"); + if (!json_is_string(s)) + fail("json_sprintf didn't return a JSON string"); + if (json_string_length(s) != 0) + fail("string is not empty"); + json_decref(s); + + if (json_sprintf("%s", "\xff\xff")) + fail("json_sprintf unexpected success with invalid UTF"); +} + + +static void run_tests() +{ + test_sprintf(); +} diff --git a/3party/jansson/test/suites/api/test_unpack.c b/3party/jansson/test/suites/api/test_unpack.c new file mode 100644 index 0000000000..4516917e8c --- /dev/null +++ b/3party/jansson/test/suites/api/test_unpack.c @@ -0,0 +1,406 @@ +/* + * Copyright (c) 2009-2016 Petri Lehtinen + * Copyright (c) 2010-2012 Graeme Smecher + * + * Jansson is free software; you can redistribute it and/or modify + * it under the terms of the MIT license. See LICENSE for details. + */ + +#include +#include +#include +#include "util.h" + +static void run_tests() +{ + json_t *j, *j2; + int i1, i2, i3; + json_int_t I1; + int rv; + size_t z; + double f; + char *s; + + json_error_t error; + + /* + * Simple, valid json_pack cases + */ + + /* true */ + rv = json_unpack(json_true(), "b", &i1); + if(rv || !i1) + fail("json_unpack boolean failed"); + + /* false */ + rv = json_unpack(json_false(), "b", &i1); + if(rv || i1) + fail("json_unpack boolean failed"); + + /* null */ + if(json_unpack(json_null(), "n")) + fail("json_unpack null failed"); + + /* integer */ + j = json_integer(42); + rv = json_unpack(j, "i", &i1); + if(rv || i1 != 42) + fail("json_unpack integer failed"); + json_decref(j); + + /* json_int_t */ + j = json_integer(5555555); + rv = json_unpack(j, "I", &I1); + if(rv || I1 != 5555555) + fail("json_unpack json_int_t failed"); + json_decref(j); + + /* real */ + j = json_real(1.7); + rv = json_unpack(j, "f", &f); + if(rv || f != 1.7) + fail("json_unpack real failed"); + json_decref(j); + + /* number */ + j = json_integer(12345); + rv = json_unpack(j, "F", &f); + if(rv || f != 12345.0) + fail("json_unpack (real or) integer failed"); + json_decref(j); + + j = json_real(1.7); + rv = json_unpack(j, "F", &f); + if(rv || f != 1.7) + fail("json_unpack real (or integer) failed"); + json_decref(j); + + /* string */ + j = json_string("foo"); + rv = json_unpack(j, "s", &s); + if(rv || strcmp(s, "foo")) + fail("json_unpack string failed"); + json_decref(j); + + /* string with length (size_t) */ + j = json_string("foo"); + rv = json_unpack(j, "s%", &s, &z); + if(rv || strcmp(s, "foo") || z != 3) + fail("json_unpack string with length (size_t) failed"); + json_decref(j); + + /* empty object */ + j = json_object(); + if(json_unpack(j, "{}")) + fail("json_unpack empty object failed"); + json_decref(j); + + /* empty list */ + j = json_array(); + if(json_unpack(j, "[]")) + fail("json_unpack empty list failed"); + json_decref(j); + + /* non-incref'd object */ + j = json_object(); + rv = json_unpack(j, "o", &j2); + if(rv || j2 != j || j->refcount != 1) + fail("json_unpack object failed"); + json_decref(j); + + /* incref'd object */ + j = json_object(); + rv = json_unpack(j, "O", &j2); + if(rv || j2 != j || j->refcount != 2) + fail("json_unpack object failed"); + json_decref(j); + json_decref(j); + + /* simple object */ + j = json_pack("{s:i}", "foo", 42); + rv = json_unpack(j, "{s:i}", "foo", &i1); + if(rv || i1 != 42) + fail("json_unpack simple object failed"); + json_decref(j); + + /* simple array */ + j = json_pack("[iii]", 1, 2, 3); + rv = json_unpack(j, "[i,i,i]", &i1, &i2, &i3); + if(rv || i1 != 1 || i2 != 2 || i3 != 3) + fail("json_unpack simple array failed"); + json_decref(j); + + /* object with many items & strict checking */ + j = json_pack("{s:i, s:i, s:i}", "a", 1, "b", 2, "c", 3); + rv = json_unpack(j, "{s:i, s:i, s:i}", "a", &i1, "b", &i2, "c", &i3); + if(rv || i1 != 1 || i2 != 2 || i3 != 3) + fail("json_unpack object with many items failed"); + json_decref(j); + + /* + * Invalid cases + */ + + j = json_integer(42); + if(!json_unpack_ex(j, &error, 0, "z")) + fail("json_unpack succeeded with invalid format character"); + check_error(json_error_invalid_format, "Unexpected format character 'z'", "", 1, 1, 1); + + if(!json_unpack_ex(NULL, &error, 0, "[i]")) + fail("json_unpack succeeded with NULL root"); + check_error(json_error_null_value, "NULL root value", "", -1, -1, 0); + json_decref(j); + + /* mismatched open/close array/object */ + j = json_pack("[]"); + if(!json_unpack_ex(j, &error, 0, "[}")) + fail("json_unpack failed to catch mismatched ']'"); + check_error(json_error_invalid_format, "Unexpected format character '}'", "", 1, 2, 2); + json_decref(j); + + j = json_pack("{}"); + if(!json_unpack_ex(j, &error, 0, "{]")) + fail("json_unpack failed to catch mismatched '}'"); + check_error(json_error_invalid_format, "Expected format 's', got ']'", "", 1, 2, 2); + json_decref(j); + + /* missing close array */ + j = json_pack("[]"); + if(!json_unpack_ex(j, &error, 0, "[")) + fail("json_unpack failed to catch missing ']'"); + check_error(json_error_invalid_format, "Unexpected end of format string", "", 1, 2, 2); + json_decref(j); + + /* missing close object */ + j = json_pack("{}"); + if(!json_unpack_ex(j, &error, 0, "{")) + fail("json_unpack failed to catch missing '}'"); + check_error(json_error_invalid_format, "Unexpected end of format string", "", 1, 2, 2); + json_decref(j); + + /* garbage after format string */ + j = json_pack("[i]", 42); + if(!json_unpack_ex(j, &error, 0, "[i]a", &i1)) + fail("json_unpack failed to catch garbage after format string"); + check_error(json_error_invalid_format, "Garbage after format string", "", 1, 4, 4); + json_decref(j); + + j = json_integer(12345); + if(!json_unpack_ex(j, &error, 0, "ia", &i1)) + fail("json_unpack failed to catch garbage after format string"); + check_error(json_error_invalid_format, "Garbage after format string", "", 1, 2, 2); + json_decref(j); + + /* NULL format string */ + j = json_pack("[]"); + if(!json_unpack_ex(j, &error, 0, NULL)) + fail("json_unpack failed to catch null format string"); + check_error(json_error_invalid_argument, "NULL or empty format string", "", -1, -1, 0); + json_decref(j); + + /* NULL string pointer */ + j = json_string("foobie"); + if(!json_unpack_ex(j, &error, 0, "s", NULL)) + fail("json_unpack failed to catch null string pointer"); + check_error(json_error_null_value, "NULL string argument", "", 1, 1, 1); + json_decref(j); + + /* invalid types */ + j = json_integer(42); + j2 = json_string("foo"); + if(!json_unpack_ex(j, &error, 0, "s")) + fail("json_unpack failed to catch invalid type"); + check_error(json_error_wrong_type, "Expected string, got integer", "", 1, 1, 1); + + if(!json_unpack_ex(j, &error, 0, "n")) + fail("json_unpack failed to catch invalid type"); + check_error(json_error_wrong_type, "Expected null, got integer", "", 1, 1, 1); + + if(!json_unpack_ex(j, &error, 0, "b")) + fail("json_unpack failed to catch invalid type"); + check_error(json_error_wrong_type, "Expected true or false, got integer", "", 1, 1, 1); + + if(!json_unpack_ex(j2, &error, 0, "i")) + fail("json_unpack failed to catch invalid type"); + check_error(json_error_wrong_type, "Expected integer, got string", "", 1, 1, 1); + + if(!json_unpack_ex(j2, &error, 0, "I")) + fail("json_unpack failed to catch invalid type"); + check_error(json_error_wrong_type, "Expected integer, got string", "", 1, 1, 1); + + if(!json_unpack_ex(j, &error, 0, "f")) + fail("json_unpack failed to catch invalid type"); + check_error(json_error_wrong_type, "Expected real, got integer", "", 1, 1, 1); + + if(!json_unpack_ex(j2, &error, 0, "F")) + fail("json_unpack failed to catch invalid type"); + check_error(json_error_wrong_type, "Expected real or integer, got string", "", 1, 1, 1); + + if(!json_unpack_ex(j, &error, 0, "[i]")) + fail("json_unpack failed to catch invalid type"); + check_error(json_error_wrong_type, "Expected array, got integer", "", 1, 1, 1); + + if(!json_unpack_ex(j, &error, 0, "{si}", "foo")) + fail("json_unpack failed to catch invalid type"); + check_error(json_error_wrong_type, "Expected object, got integer", "", 1, 1, 1); + + json_decref(j); + json_decref(j2); + + /* Array index out of range */ + j = json_pack("[i]", 1); + if(!json_unpack_ex(j, &error, 0, "[ii]", &i1, &i2)) + fail("json_unpack failed to catch index out of array bounds"); + check_error(json_error_index_out_of_range, "Array index 1 out of range", "", 1, 3, 3); + json_decref(j); + + /* NULL object key */ + j = json_pack("{si}", "foo", 42); + if(!json_unpack_ex(j, &error, 0, "{si}", NULL, &i1)) + fail("json_unpack failed to catch null string pointer"); + check_error(json_error_null_value, "NULL object key", "", 1, 2, 2); + json_decref(j); + + /* Object key not found */ + j = json_pack("{si}", "foo", 42); + if(!json_unpack_ex(j, &error, 0, "{si}", "baz", &i1)) + fail("json_unpack failed to catch null string pointer"); + check_error(json_error_item_not_found, "Object item not found: baz", "", 1, 3, 3); + json_decref(j); + + /* + * Strict validation + */ + + j = json_pack("[iii]", 1, 2, 3); + rv = json_unpack(j, "[iii!]", &i1, &i2, &i3); + if(rv || i1 != 1 || i2 != 2 || i3 != 3) + fail("json_unpack array with strict validation failed"); + json_decref(j); + + j = json_pack("[iii]", 1, 2, 3); + if(!json_unpack_ex(j, &error, 0, "[ii!]", &i1, &i2)) + fail("json_unpack array with strict validation failed"); + check_error(json_error_end_of_input_expected, "1 array item(s) left unpacked", "", 1, 5, 5); + json_decref(j); + + /* Like above, but with JSON_STRICT instead of '!' format */ + j = json_pack("[iii]", 1, 2, 3); + if(!json_unpack_ex(j, &error, JSON_STRICT, "[ii]", &i1, &i2)) + fail("json_unpack array with strict validation failed"); + check_error(json_error_end_of_input_expected, "1 array item(s) left unpacked", "", 1, 4, 4); + json_decref(j); + + j = json_pack("{s:s, s:i}", "foo", "bar", "baz", 42); + rv = json_unpack(j, "{sssi!}", "foo", &s, "baz", &i1); + if(rv || strcmp(s, "bar") != 0 || i1 != 42) + fail("json_unpack object with strict validation failed"); + json_decref(j); + + /* Unpack the same item twice */ + j = json_pack("{s:s, s:i, s:b}", "foo", "bar", "baz", 42, "quux", 1); + if(!json_unpack_ex(j, &error, 0, "{s:s,s:s!}", "foo", &s, "foo", &s)) + fail("json_unpack object with strict validation failed"); + { + const char *possible_errors[] = { + "2 object item(s) left unpacked: baz, quux", + "2 object item(s) left unpacked: quux, baz" + }; + check_errors(json_error_end_of_input_expected, possible_errors, 2, "", 1, 10, 10); + } + json_decref(j); + + j = json_pack("[i,{s:i,s:n},[i,i]]", 1, "foo", 2, "bar", 3, 4); + if(json_unpack_ex(j, NULL, JSON_STRICT | JSON_VALIDATE_ONLY, + "[i{sisn}[ii]]", "foo", "bar")) + fail("json_unpack complex value with strict validation failed"); + json_decref(j); + + /* ! and * must be last */ + j = json_pack("[ii]", 1, 2); + if(!json_unpack_ex(j, &error, 0, "[i!i]", &i1, &i2)) + fail("json_unpack failed to catch ! in the middle of an array"); + check_error(json_error_invalid_format, "Expected ']' after '!', got 'i'", "", 1, 4, 4); + + if(!json_unpack_ex(j, &error, 0, "[i*i]", &i1, &i2)) + fail("json_unpack failed to catch * in the middle of an array"); + check_error(json_error_invalid_format, "Expected ']' after '*', got 'i'", "", 1, 4, 4); + json_decref(j); + + j = json_pack("{sssi}", "foo", "bar", "baz", 42); + if(!json_unpack_ex(j, &error, 0, "{ss!si}", "foo", &s, "baz", &i1)) + fail("json_unpack failed to catch ! in the middle of an object"); + check_error(json_error_invalid_format, "Expected '}' after '!', got 's'", "", 1, 5, 5); + + if(!json_unpack_ex(j, &error, 0, "{ss*si}", "foo", &s, "baz", &i1)) + fail("json_unpack failed to catch ! in the middle of an object"); + check_error(json_error_invalid_format, "Expected '}' after '*', got 's'", "", 1, 5, 5); + json_decref(j); + + /* Error in nested object */ + j = json_pack("{s{snsn}}", "foo", "bar", "baz"); + if(!json_unpack_ex(j, &error, 0, "{s{sn!}}", "foo", "bar")) + fail("json_unpack nested object with strict validation failed"); + check_error(json_error_end_of_input_expected, "1 object item(s) left unpacked: baz", "", 1, 7, 7); + json_decref(j); + + /* Error in nested array */ + j = json_pack("[[ii]]", 1, 2); + if(!json_unpack_ex(j, &error, 0, "[[i!]]", &i1)) + fail("json_unpack nested array with strict validation failed"); + check_error(json_error_end_of_input_expected, "1 array item(s) left unpacked", "", 1, 5, 5); + json_decref(j); + + /* Optional values */ + j = json_object(); + i1 = 0; + if(json_unpack(j, "{s?i}", "foo", &i1)) + fail("json_unpack failed for optional key"); + if(i1 != 0) + fail("json_unpack unpacked an optional key"); + json_decref(j); + + i1 = 0; + j = json_pack("{si}", "foo", 42); + if(json_unpack(j, "{s?i}", "foo", &i1)) + fail("json_unpack failed for an optional value"); + if(i1 != 42) + fail("json_unpack failed to unpack an optional value"); + json_decref(j); + + j = json_object(); + i1 = i2 = i3 = 0; + if(json_unpack(j, "{s?[ii]s?{s{si}}}", + "foo", &i1, &i2, + "bar", "baz", "quux", &i3)) + fail("json_unpack failed for complex optional values"); + if(i1 != 0 || i2 != 0 || i3 != 0) + fail("json_unpack unexpectedly unpacked something"); + json_decref(j); + + j = json_pack("{s{si}}", "foo", "bar", 42); + if(json_unpack(j, "{s?{s?i}}", "foo", "bar", &i1)) + fail("json_unpack failed for complex optional values"); + if(i1 != 42) + fail("json_unpack failed to unpack"); + json_decref(j); + + /* Combine ? and ! */ + j = json_pack("{si}", "foo", 42); + i1 = i2 = 0; + if(json_unpack(j, "{sis?i!}", "foo", &i1, "bar", &i2)) + fail("json_unpack failed for optional values with strict mode"); + if(i1 != 42) + fail("json_unpack failed to unpack"); + if(i2 != 0) + fail("json_unpack failed to unpack"); + json_decref(j); + + /* But don't compensate a missing key with an optional one. */ + j = json_pack("{sisi}", "foo", 42, "baz", 43); + i1 = i2 = i3 = 0; + if(!json_unpack_ex(j, &error, 0, "{sis?i!}", "foo", &i1, "bar", &i2)) + fail("json_unpack failed for optional values with strict mode and compensation"); + check_error(json_error_end_of_input_expected, "1 object item(s) left unpacked: baz", "", 1, 8, 8); + json_decref(j); +} diff --git a/3party/jansson/test/suites/api/util.h b/3party/jansson/test/suites/api/util.h new file mode 100644 index 0000000000..9b658e7895 --- /dev/null +++ b/3party/jansson/test/suites/api/util.h @@ -0,0 +1,97 @@ +/* + * Copyright (c) 2009-2016 Petri Lehtinen + * + * Jansson is free software; you can redistribute it and/or modify + * it under the terms of the MIT license. See LICENSE for details. + */ + +#ifndef UTIL_H +#define UTIL_H + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include +#include +#if HAVE_LOCALE_H +#include +#endif + +#include + +#define failhdr fprintf(stderr, "%s:%d: ", __FILE__, __LINE__) + +#define fail(msg) \ + do { \ + failhdr; \ + fprintf(stderr, "%s\n", msg); \ + exit(1); \ + } while(0) + +/* Assumes json_error_t error */ +#define check_errors(code_, texts_, num_, source_, \ + line_, column_, position_) \ + do { \ + int i_, found_ = 0; \ + if(json_error_code(&error) != code_) { \ + failhdr; \ + fprintf(stderr, "code: %d != %d\n", \ + json_error_code(&error), code_); \ + exit(1); \ + } \ + for(i_ = 0; i_ < num_; i_++) { \ + if(strcmp(error.text, texts_[i_]) == 0) { \ + found_ = 1; \ + break; \ + } \ + } \ + if (!found_) { \ + failhdr; \ + if (num_ == 1) { \ + fprintf(stderr, "text: \"%s\" != \"%s\"\n", error.text, texts_[0]); \ + } else { \ + fprintf(stderr, "text: \"%s\" does not match\n", error.text); \ + } \ + exit(1); \ + } \ + if(strcmp(error.source, source_) != 0) { \ + failhdr; \ + \ + fprintf(stderr, "source: \"%s\" != \"%s\"\n", error.source, source_); \ + exit(1); \ + } \ + if(error.line != line_) { \ + failhdr; \ + fprintf(stderr, "line: %d != %d\n", error.line, line_); \ + exit(1); \ + } \ + if(error.column != column_) { \ + failhdr; \ + fprintf(stderr, "column: %d != %d\n", error.column, column_); \ + exit(1); \ + } \ + if(error.position != position_) { \ + failhdr; \ + fprintf(stderr, "position: %d != %d\n", error.position, position_); \ + exit(1); \ + } \ + } while(0) + + +/* Assumes json_error_t error */ +#define check_error(code_, text_, source_, line_, column_, position_) \ + check_errors(code_, &text_, 1, source_, line_, column_, position_) + + +static void run_tests(); + +int main() { +#ifdef HAVE_SETLOCALE + setlocale(LC_ALL, ""); +#endif + run_tests(); + return 0; +} + +#endif diff --git a/3party/jansson/test/suites/encoding-flags/array/input b/3party/jansson/test/suites/encoding-flags/array/input new file mode 100644 index 0000000000..44e2ace7e5 --- /dev/null +++ b/3party/jansson/test/suites/encoding-flags/array/input @@ -0,0 +1 @@ +[1, 2] diff --git a/3party/jansson/test/suites/encoding-flags/array/output b/3party/jansson/test/suites/encoding-flags/array/output new file mode 100644 index 0000000000..fd8ef09578 --- /dev/null +++ b/3party/jansson/test/suites/encoding-flags/array/output @@ -0,0 +1 @@ +[1, 2] \ No newline at end of file diff --git a/3party/jansson/test/suites/encoding-flags/compact-array/env b/3party/jansson/test/suites/encoding-flags/compact-array/env new file mode 100644 index 0000000000..4474aaf143 --- /dev/null +++ b/3party/jansson/test/suites/encoding-flags/compact-array/env @@ -0,0 +1,2 @@ +JSON_COMPACT=1 +export JSON_COMPACT diff --git a/3party/jansson/test/suites/encoding-flags/compact-array/input b/3party/jansson/test/suites/encoding-flags/compact-array/input new file mode 100644 index 0000000000..44e2ace7e5 --- /dev/null +++ b/3party/jansson/test/suites/encoding-flags/compact-array/input @@ -0,0 +1 @@ +[1, 2] diff --git a/3party/jansson/test/suites/encoding-flags/compact-array/output b/3party/jansson/test/suites/encoding-flags/compact-array/output new file mode 100644 index 0000000000..3169929f69 --- /dev/null +++ b/3party/jansson/test/suites/encoding-flags/compact-array/output @@ -0,0 +1 @@ +[1,2] \ No newline at end of file diff --git a/3party/jansson/test/suites/encoding-flags/compact-object/env b/3party/jansson/test/suites/encoding-flags/compact-object/env new file mode 100644 index 0000000000..93cb33ddaf --- /dev/null +++ b/3party/jansson/test/suites/encoding-flags/compact-object/env @@ -0,0 +1,3 @@ +JSON_COMPACT=1 +HASHSEED=1 +export JSON_COMPACT HASHSEED diff --git a/3party/jansson/test/suites/encoding-flags/compact-object/input b/3party/jansson/test/suites/encoding-flags/compact-object/input new file mode 100644 index 0000000000..062e54fb49 --- /dev/null +++ b/3party/jansson/test/suites/encoding-flags/compact-object/input @@ -0,0 +1 @@ +{"a": 1, "b": 2} diff --git a/3party/jansson/test/suites/encoding-flags/compact-object/output b/3party/jansson/test/suites/encoding-flags/compact-object/output new file mode 100644 index 0000000000..73a5d70e33 --- /dev/null +++ b/3party/jansson/test/suites/encoding-flags/compact-object/output @@ -0,0 +1 @@ +{"a":1,"b":2} \ No newline at end of file diff --git a/3party/jansson/test/suites/encoding-flags/ensure-ascii/env b/3party/jansson/test/suites/encoding-flags/ensure-ascii/env new file mode 100644 index 0000000000..1b7b3e3f95 --- /dev/null +++ b/3party/jansson/test/suites/encoding-flags/ensure-ascii/env @@ -0,0 +1,2 @@ +JSON_ENSURE_ASCII=1 +export JSON_ENSURE_ASCII diff --git a/3party/jansson/test/suites/encoding-flags/ensure-ascii/input b/3party/jansson/test/suites/encoding-flags/ensure-ascii/input new file mode 100644 index 0000000000..69469cef58 --- /dev/null +++ b/3party/jansson/test/suites/encoding-flags/ensure-ascii/input @@ -0,0 +1,8 @@ +[ + "foo", + "Ã¥ ä ö", + "foo åä", + "åä foo", + "Ã¥ foo ä", + "clef g: ð„ž" +] diff --git a/3party/jansson/test/suites/encoding-flags/ensure-ascii/output b/3party/jansson/test/suites/encoding-flags/ensure-ascii/output new file mode 100644 index 0000000000..94fa79d2d2 --- /dev/null +++ b/3party/jansson/test/suites/encoding-flags/ensure-ascii/output @@ -0,0 +1 @@ +["foo", "\u00E5 \u00E4 \u00F6", "foo \u00E5\u00E4", "\u00E5\u00E4 foo", "\u00E5 foo \u00E4", "clef g: \uD834\uDD1E"] \ No newline at end of file diff --git a/3party/jansson/test/suites/encoding-flags/indent-array/env b/3party/jansson/test/suites/encoding-flags/indent-array/env new file mode 100644 index 0000000000..d220f837c3 --- /dev/null +++ b/3party/jansson/test/suites/encoding-flags/indent-array/env @@ -0,0 +1,2 @@ +JSON_INDENT=4 +export JSON_INDENT diff --git a/3party/jansson/test/suites/encoding-flags/indent-array/input b/3party/jansson/test/suites/encoding-flags/indent-array/input new file mode 100644 index 0000000000..44e2ace7e5 --- /dev/null +++ b/3party/jansson/test/suites/encoding-flags/indent-array/input @@ -0,0 +1 @@ +[1, 2] diff --git a/3party/jansson/test/suites/encoding-flags/indent-array/output b/3party/jansson/test/suites/encoding-flags/indent-array/output new file mode 100644 index 0000000000..c57d705ba8 --- /dev/null +++ b/3party/jansson/test/suites/encoding-flags/indent-array/output @@ -0,0 +1,4 @@ +[ + 1, + 2 +] \ No newline at end of file diff --git a/3party/jansson/test/suites/encoding-flags/indent-compact-array/env b/3party/jansson/test/suites/encoding-flags/indent-compact-array/env new file mode 100644 index 0000000000..78fbfcc2e7 --- /dev/null +++ b/3party/jansson/test/suites/encoding-flags/indent-compact-array/env @@ -0,0 +1,3 @@ +JSON_INDENT=4 +JSON_COMPACT=1 +export JSON_INDENT JSON_COMPACT diff --git a/3party/jansson/test/suites/encoding-flags/indent-compact-array/input b/3party/jansson/test/suites/encoding-flags/indent-compact-array/input new file mode 100644 index 0000000000..44e2ace7e5 --- /dev/null +++ b/3party/jansson/test/suites/encoding-flags/indent-compact-array/input @@ -0,0 +1 @@ +[1, 2] diff --git a/3party/jansson/test/suites/encoding-flags/indent-compact-array/output b/3party/jansson/test/suites/encoding-flags/indent-compact-array/output new file mode 100644 index 0000000000..c57d705ba8 --- /dev/null +++ b/3party/jansson/test/suites/encoding-flags/indent-compact-array/output @@ -0,0 +1,4 @@ +[ + 1, + 2 +] \ No newline at end of file diff --git a/3party/jansson/test/suites/encoding-flags/indent-compact-object/env b/3party/jansson/test/suites/encoding-flags/indent-compact-object/env new file mode 100644 index 0000000000..c73acc1792 --- /dev/null +++ b/3party/jansson/test/suites/encoding-flags/indent-compact-object/env @@ -0,0 +1,4 @@ +JSON_INDENT=4 +JSON_COMPACT=1 +HASHSEED=1 +export JSON_INDENT JSON_COMPACT HASHSEED diff --git a/3party/jansson/test/suites/encoding-flags/indent-compact-object/input b/3party/jansson/test/suites/encoding-flags/indent-compact-object/input new file mode 100644 index 0000000000..062e54fb49 --- /dev/null +++ b/3party/jansson/test/suites/encoding-flags/indent-compact-object/input @@ -0,0 +1 @@ +{"a": 1, "b": 2} diff --git a/3party/jansson/test/suites/encoding-flags/indent-compact-object/output b/3party/jansson/test/suites/encoding-flags/indent-compact-object/output new file mode 100644 index 0000000000..9cc42948d4 --- /dev/null +++ b/3party/jansson/test/suites/encoding-flags/indent-compact-object/output @@ -0,0 +1,4 @@ +{ + "a":1, + "b":2 +} \ No newline at end of file diff --git a/3party/jansson/test/suites/encoding-flags/indent-object/env b/3party/jansson/test/suites/encoding-flags/indent-object/env new file mode 100644 index 0000000000..961558ca23 --- /dev/null +++ b/3party/jansson/test/suites/encoding-flags/indent-object/env @@ -0,0 +1,3 @@ +JSON_INDENT=4 +HASHSEED=1 +export JSON_INDENT HASHSEED diff --git a/3party/jansson/test/suites/encoding-flags/indent-object/input b/3party/jansson/test/suites/encoding-flags/indent-object/input new file mode 100644 index 0000000000..062e54fb49 --- /dev/null +++ b/3party/jansson/test/suites/encoding-flags/indent-object/input @@ -0,0 +1 @@ +{"a": 1, "b": 2} diff --git a/3party/jansson/test/suites/encoding-flags/indent-object/output b/3party/jansson/test/suites/encoding-flags/indent-object/output new file mode 100644 index 0000000000..0fbddba449 --- /dev/null +++ b/3party/jansson/test/suites/encoding-flags/indent-object/output @@ -0,0 +1,4 @@ +{ + "a": 1, + "b": 2 +} \ No newline at end of file diff --git a/3party/jansson/test/suites/encoding-flags/object/env b/3party/jansson/test/suites/encoding-flags/object/env new file mode 100644 index 0000000000..9120b03514 --- /dev/null +++ b/3party/jansson/test/suites/encoding-flags/object/env @@ -0,0 +1,2 @@ +HASHSEED=1 +export HASHSEED diff --git a/3party/jansson/test/suites/encoding-flags/object/input b/3party/jansson/test/suites/encoding-flags/object/input new file mode 100644 index 0000000000..062e54fb49 --- /dev/null +++ b/3party/jansson/test/suites/encoding-flags/object/input @@ -0,0 +1 @@ +{"a": 1, "b": 2} diff --git a/3party/jansson/test/suites/encoding-flags/object/output b/3party/jansson/test/suites/encoding-flags/object/output new file mode 100644 index 0000000000..ecd219f72d --- /dev/null +++ b/3party/jansson/test/suites/encoding-flags/object/output @@ -0,0 +1 @@ +{"a": 1, "b": 2} \ No newline at end of file diff --git a/3party/jansson/test/suites/encoding-flags/preserve-order/env b/3party/jansson/test/suites/encoding-flags/preserve-order/env new file mode 100644 index 0000000000..4d9d206593 --- /dev/null +++ b/3party/jansson/test/suites/encoding-flags/preserve-order/env @@ -0,0 +1,2 @@ +JSON_PRESERVE_ORDER=1 +export JSON_PRESERVE_ORDER diff --git a/3party/jansson/test/suites/encoding-flags/preserve-order/input b/3party/jansson/test/suites/encoding-flags/preserve-order/input new file mode 100644 index 0000000000..27bcf18a07 --- /dev/null +++ b/3party/jansson/test/suites/encoding-flags/preserve-order/input @@ -0,0 +1 @@ +{"foo": 1, "bar": 2, "asdf": 3, "deadbeef": 4, "badc0ffee": 5, "qwerty": 6} diff --git a/3party/jansson/test/suites/encoding-flags/preserve-order/output b/3party/jansson/test/suites/encoding-flags/preserve-order/output new file mode 100644 index 0000000000..7a443f684c --- /dev/null +++ b/3party/jansson/test/suites/encoding-flags/preserve-order/output @@ -0,0 +1 @@ +{"foo": 1, "bar": 2, "asdf": 3, "deadbeef": 4, "badc0ffee": 5, "qwerty": 6} \ No newline at end of file diff --git a/3party/jansson/test/suites/encoding-flags/real-precision/env b/3party/jansson/test/suites/encoding-flags/real-precision/env new file mode 100644 index 0000000000..9c52cbcd67 --- /dev/null +++ b/3party/jansson/test/suites/encoding-flags/real-precision/env @@ -0,0 +1,2 @@ +JSON_REAL_PRECISION=4 +export JSON_REAL_PRECISION diff --git a/3party/jansson/test/suites/encoding-flags/real-precision/input b/3party/jansson/test/suites/encoding-flags/real-precision/input new file mode 100644 index 0000000000..e291165c15 --- /dev/null +++ b/3party/jansson/test/suites/encoding-flags/real-precision/input @@ -0,0 +1 @@ +[1.23456789, 1.0, 1.0000000000000002] diff --git a/3party/jansson/test/suites/encoding-flags/real-precision/output b/3party/jansson/test/suites/encoding-flags/real-precision/output new file mode 100644 index 0000000000..f273c73e5b --- /dev/null +++ b/3party/jansson/test/suites/encoding-flags/real-precision/output @@ -0,0 +1 @@ +[1.235, 1.0, 1.0] \ No newline at end of file diff --git a/3party/jansson/test/suites/encoding-flags/run b/3party/jansson/test/suites/encoding-flags/run new file mode 100755 index 0000000000..5db7d5e5c6 --- /dev/null +++ b/3party/jansson/test/suites/encoding-flags/run @@ -0,0 +1,32 @@ +#!/bin/sh +# +# Copyright (c) 2009-2016 Petri Lehtinen +# +# Jansson is free software; you can redistribute it and/or modify +# it under the terms of the MIT license. See LICENSE for details. + +is_test() { + test -d $test_path +} + +run_test() { + ( + if [ -f $test_path/env ]; then + . $test_path/env + fi + $json_process --env <$test_path/input >$test_log/stdout 2>$test_log/stderr + ) + valgrind_check $test_log/stderr || return 1 + cmp -s $test_path/output $test_log/stdout +} + +show_error() { + valgrind_show_error && return + + echo "EXPECTED OUTPUT:" + nl -bn $test_path/output + echo "ACTUAL OUTPUT:" + nl -bn $test_log/stdout +} + +. $top_srcdir/test/scripts/run-tests.sh diff --git a/3party/jansson/test/suites/encoding-flags/sort-keys/env b/3party/jansson/test/suites/encoding-flags/sort-keys/env new file mode 100644 index 0000000000..3ef24cb7b8 --- /dev/null +++ b/3party/jansson/test/suites/encoding-flags/sort-keys/env @@ -0,0 +1,2 @@ +JSON_SORT_KEYS=1 +export JSON_SORT_KEYS diff --git a/3party/jansson/test/suites/encoding-flags/sort-keys/input b/3party/jansson/test/suites/encoding-flags/sort-keys/input new file mode 100644 index 0000000000..66951d6b03 --- /dev/null +++ b/3party/jansson/test/suites/encoding-flags/sort-keys/input @@ -0,0 +1 @@ +{"foo": 1, "bar": 2, "baz": 3, "quux": 4} diff --git a/3party/jansson/test/suites/encoding-flags/sort-keys/output b/3party/jansson/test/suites/encoding-flags/sort-keys/output new file mode 100644 index 0000000000..132d9df312 --- /dev/null +++ b/3party/jansson/test/suites/encoding-flags/sort-keys/output @@ -0,0 +1 @@ +{"bar": 2, "baz": 3, "foo": 1, "quux": 4} \ No newline at end of file diff --git a/3party/jansson/test/suites/invalid-unicode/encoded-surrogate-half/error b/3party/jansson/test/suites/invalid-unicode/encoded-surrogate-half/error new file mode 100644 index 0000000000..762d2c4b17 --- /dev/null +++ b/3party/jansson/test/suites/invalid-unicode/encoded-surrogate-half/error @@ -0,0 +1,2 @@ +1 2 2 +unable to decode byte 0xed near '"' diff --git a/3party/jansson/test/suites/invalid-unicode/encoded-surrogate-half/input b/3party/jansson/test/suites/invalid-unicode/encoded-surrogate-half/input new file mode 100644 index 0000000000..515dd933ce --- /dev/null +++ b/3party/jansson/test/suites/invalid-unicode/encoded-surrogate-half/input @@ -0,0 +1 @@ +["í¢« <-- encoded surrogate half"] diff --git a/3party/jansson/test/suites/invalid-unicode/invalid-utf-8-after-backslash/error b/3party/jansson/test/suites/invalid-unicode/invalid-utf-8-after-backslash/error new file mode 100644 index 0000000000..b16dc171ee --- /dev/null +++ b/3party/jansson/test/suites/invalid-unicode/invalid-utf-8-after-backslash/error @@ -0,0 +1,2 @@ +1 3 3 +unable to decode byte 0xe5 near '"\' diff --git a/3party/jansson/test/suites/invalid-unicode/invalid-utf-8-after-backslash/input b/3party/jansson/test/suites/invalid-unicode/invalid-utf-8-after-backslash/input new file mode 100644 index 0000000000..57c8beef64 --- /dev/null +++ b/3party/jansson/test/suites/invalid-unicode/invalid-utf-8-after-backslash/input @@ -0,0 +1 @@ +["\å"] diff --git a/3party/jansson/test/suites/invalid-unicode/invalid-utf-8-in-array/error b/3party/jansson/test/suites/invalid-unicode/invalid-utf-8-in-array/error new file mode 100644 index 0000000000..be15386df0 --- /dev/null +++ b/3party/jansson/test/suites/invalid-unicode/invalid-utf-8-in-array/error @@ -0,0 +1,2 @@ +1 1 1 +unable to decode byte 0xe5 diff --git a/3party/jansson/test/suites/invalid-unicode/invalid-utf-8-in-array/input b/3party/jansson/test/suites/invalid-unicode/invalid-utf-8-in-array/input new file mode 100644 index 0000000000..ebefcd6f87 --- /dev/null +++ b/3party/jansson/test/suites/invalid-unicode/invalid-utf-8-in-array/input @@ -0,0 +1 @@ +[å] diff --git a/3party/jansson/test/suites/invalid-unicode/invalid-utf-8-in-bigger-int/error b/3party/jansson/test/suites/invalid-unicode/invalid-utf-8-in-bigger-int/error new file mode 100644 index 0000000000..01b4476392 --- /dev/null +++ b/3party/jansson/test/suites/invalid-unicode/invalid-utf-8-in-bigger-int/error @@ -0,0 +1,2 @@ +1 4 4 +unable to decode byte 0xe5 near '123' diff --git a/3party/jansson/test/suites/invalid-unicode/invalid-utf-8-in-bigger-int/input b/3party/jansson/test/suites/invalid-unicode/invalid-utf-8-in-bigger-int/input new file mode 100644 index 0000000000..e512f9ae08 --- /dev/null +++ b/3party/jansson/test/suites/invalid-unicode/invalid-utf-8-in-bigger-int/input @@ -0,0 +1 @@ +[123å] diff --git a/3party/jansson/test/suites/invalid-unicode/invalid-utf-8-in-escape/error b/3party/jansson/test/suites/invalid-unicode/invalid-utf-8-in-escape/error new file mode 100644 index 0000000000..c13583dd85 --- /dev/null +++ b/3party/jansson/test/suites/invalid-unicode/invalid-utf-8-in-escape/error @@ -0,0 +1,2 @@ +1 4 4 +unable to decode byte 0xe5 near '"\u' diff --git a/3party/jansson/test/suites/invalid-unicode/invalid-utf-8-in-escape/input b/3party/jansson/test/suites/invalid-unicode/invalid-utf-8-in-escape/input new file mode 100644 index 0000000000..2b271b82f3 --- /dev/null +++ b/3party/jansson/test/suites/invalid-unicode/invalid-utf-8-in-escape/input @@ -0,0 +1 @@ +["\uå"] diff --git a/3party/jansson/test/suites/invalid-unicode/invalid-utf-8-in-exponent/error b/3party/jansson/test/suites/invalid-unicode/invalid-utf-8-in-exponent/error new file mode 100644 index 0000000000..c7b20b7a2a --- /dev/null +++ b/3party/jansson/test/suites/invalid-unicode/invalid-utf-8-in-exponent/error @@ -0,0 +1,2 @@ +1 4 4 +unable to decode byte 0xe5 near '1e1' diff --git a/3party/jansson/test/suites/invalid-unicode/invalid-utf-8-in-exponent/input b/3party/jansson/test/suites/invalid-unicode/invalid-utf-8-in-exponent/input new file mode 100644 index 0000000000..d8e83c5954 --- /dev/null +++ b/3party/jansson/test/suites/invalid-unicode/invalid-utf-8-in-exponent/input @@ -0,0 +1 @@ +[1e1å] diff --git a/3party/jansson/test/suites/invalid-unicode/invalid-utf-8-in-identifier/error b/3party/jansson/test/suites/invalid-unicode/invalid-utf-8-in-identifier/error new file mode 100644 index 0000000000..33dfc23242 --- /dev/null +++ b/3party/jansson/test/suites/invalid-unicode/invalid-utf-8-in-identifier/error @@ -0,0 +1,2 @@ +1 2 2 +unable to decode byte 0xe5 near 'a' diff --git a/3party/jansson/test/suites/invalid-unicode/invalid-utf-8-in-identifier/input b/3party/jansson/test/suites/invalid-unicode/invalid-utf-8-in-identifier/input new file mode 100644 index 0000000000..ef038514a9 --- /dev/null +++ b/3party/jansson/test/suites/invalid-unicode/invalid-utf-8-in-identifier/input @@ -0,0 +1 @@ +[aå] diff --git a/3party/jansson/test/suites/invalid-unicode/invalid-utf-8-in-int/error b/3party/jansson/test/suites/invalid-unicode/invalid-utf-8-in-int/error new file mode 100644 index 0000000000..8f08970c12 --- /dev/null +++ b/3party/jansson/test/suites/invalid-unicode/invalid-utf-8-in-int/error @@ -0,0 +1,2 @@ +1 2 2 +unable to decode byte 0xe5 near '0' diff --git a/3party/jansson/test/suites/invalid-unicode/invalid-utf-8-in-int/input b/3party/jansson/test/suites/invalid-unicode/invalid-utf-8-in-int/input new file mode 100644 index 0000000000..371226e4cd --- /dev/null +++ b/3party/jansson/test/suites/invalid-unicode/invalid-utf-8-in-int/input @@ -0,0 +1 @@ +[0å] diff --git a/3party/jansson/test/suites/invalid-unicode/invalid-utf-8-in-real-after-e/error b/3party/jansson/test/suites/invalid-unicode/invalid-utf-8-in-real-after-e/error new file mode 100644 index 0000000000..b7660e327f --- /dev/null +++ b/3party/jansson/test/suites/invalid-unicode/invalid-utf-8-in-real-after-e/error @@ -0,0 +1,2 @@ +1 3 3 +unable to decode byte 0xe5 near '1e' diff --git a/3party/jansson/test/suites/invalid-unicode/invalid-utf-8-in-real-after-e/input b/3party/jansson/test/suites/invalid-unicode/invalid-utf-8-in-real-after-e/input new file mode 100644 index 0000000000..17fc29c90a --- /dev/null +++ b/3party/jansson/test/suites/invalid-unicode/invalid-utf-8-in-real-after-e/input @@ -0,0 +1 @@ +[1eå] diff --git a/3party/jansson/test/suites/invalid-unicode/invalid-utf-8-in-string/error b/3party/jansson/test/suites/invalid-unicode/invalid-utf-8-in-string/error new file mode 100644 index 0000000000..0b7039a520 --- /dev/null +++ b/3party/jansson/test/suites/invalid-unicode/invalid-utf-8-in-string/error @@ -0,0 +1,2 @@ +1 2 2 +unable to decode byte 0xe5 near '"' diff --git a/3party/jansson/test/suites/invalid-unicode/invalid-utf-8-in-string/input b/3party/jansson/test/suites/invalid-unicode/invalid-utf-8-in-string/input new file mode 100644 index 0000000000..00b79c0afa --- /dev/null +++ b/3party/jansson/test/suites/invalid-unicode/invalid-utf-8-in-string/input @@ -0,0 +1 @@ +["å <-- invalid UTF-8"] diff --git a/3party/jansson/test/suites/invalid-unicode/lone-invalid-utf-8/error b/3party/jansson/test/suites/invalid-unicode/lone-invalid-utf-8/error new file mode 100644 index 0000000000..8e9a511192 --- /dev/null +++ b/3party/jansson/test/suites/invalid-unicode/lone-invalid-utf-8/error @@ -0,0 +1,2 @@ +1 0 0 +unable to decode byte 0xe5 diff --git a/3party/jansson/test/suites/invalid-unicode/lone-invalid-utf-8/input b/3party/jansson/test/suites/invalid-unicode/lone-invalid-utf-8/input new file mode 100644 index 0000000000..eb8079699b --- /dev/null +++ b/3party/jansson/test/suites/invalid-unicode/lone-invalid-utf-8/input @@ -0,0 +1 @@ +å diff --git a/3party/jansson/test/suites/invalid-unicode/lone-utf-8-continuation-byte/error b/3party/jansson/test/suites/invalid-unicode/lone-utf-8-continuation-byte/error new file mode 100644 index 0000000000..86bbad3c80 --- /dev/null +++ b/3party/jansson/test/suites/invalid-unicode/lone-utf-8-continuation-byte/error @@ -0,0 +1,2 @@ +1 2 2 +unable to decode byte 0x81 near '"' diff --git a/3party/jansson/test/suites/invalid-unicode/lone-utf-8-continuation-byte/input b/3party/jansson/test/suites/invalid-unicode/lone-utf-8-continuation-byte/input new file mode 100644 index 0000000000..62a26b6fb8 --- /dev/null +++ b/3party/jansson/test/suites/invalid-unicode/lone-utf-8-continuation-byte/input @@ -0,0 +1 @@ +[""] diff --git a/3party/jansson/test/suites/invalid-unicode/not-in-unicode-range/error b/3party/jansson/test/suites/invalid-unicode/not-in-unicode-range/error new file mode 100644 index 0000000000..d07ccb3e5e --- /dev/null +++ b/3party/jansson/test/suites/invalid-unicode/not-in-unicode-range/error @@ -0,0 +1,2 @@ +1 2 2 +unable to decode byte 0xf4 near '"' diff --git a/3party/jansson/test/suites/invalid-unicode/not-in-unicode-range/input b/3party/jansson/test/suites/invalid-unicode/not-in-unicode-range/input new file mode 100644 index 0000000000..1216186a78 --- /dev/null +++ b/3party/jansson/test/suites/invalid-unicode/not-in-unicode-range/input @@ -0,0 +1 @@ +["ô¿¿¿"] diff --git a/3party/jansson/test/suites/invalid-unicode/overlong-3-byte-encoding/error b/3party/jansson/test/suites/invalid-unicode/overlong-3-byte-encoding/error new file mode 100644 index 0000000000..8a05abaed5 --- /dev/null +++ b/3party/jansson/test/suites/invalid-unicode/overlong-3-byte-encoding/error @@ -0,0 +1,2 @@ +1 2 2 +unable to decode byte 0xe0 near '"' diff --git a/3party/jansson/test/suites/invalid-unicode/overlong-3-byte-encoding/input b/3party/jansson/test/suites/invalid-unicode/overlong-3-byte-encoding/input new file mode 100644 index 0000000000..0bf909f7be --- /dev/null +++ b/3party/jansson/test/suites/invalid-unicode/overlong-3-byte-encoding/input @@ -0,0 +1 @@ +["à€¢ <-- overlong encoding"] diff --git a/3party/jansson/test/suites/invalid-unicode/overlong-4-byte-encoding/error b/3party/jansson/test/suites/invalid-unicode/overlong-4-byte-encoding/error new file mode 100644 index 0000000000..7e19c5fe48 --- /dev/null +++ b/3party/jansson/test/suites/invalid-unicode/overlong-4-byte-encoding/error @@ -0,0 +1,2 @@ +1 2 2 +unable to decode byte 0xf0 near '"' diff --git a/3party/jansson/test/suites/invalid-unicode/overlong-4-byte-encoding/input b/3party/jansson/test/suites/invalid-unicode/overlong-4-byte-encoding/input new file mode 100644 index 0000000000..c6b6313509 --- /dev/null +++ b/3party/jansson/test/suites/invalid-unicode/overlong-4-byte-encoding/input @@ -0,0 +1 @@ +["ð€€¢ <-- overlong encoding"] diff --git a/3party/jansson/test/suites/invalid-unicode/overlong-ascii-encoding/error b/3party/jansson/test/suites/invalid-unicode/overlong-ascii-encoding/error new file mode 100644 index 0000000000..1d382edd7a --- /dev/null +++ b/3party/jansson/test/suites/invalid-unicode/overlong-ascii-encoding/error @@ -0,0 +1,2 @@ +1 2 2 +unable to decode byte 0xc1 near '"' diff --git a/3party/jansson/test/suites/invalid-unicode/overlong-ascii-encoding/input b/3party/jansson/test/suites/invalid-unicode/overlong-ascii-encoding/input new file mode 100644 index 0000000000..ef6e10a342 --- /dev/null +++ b/3party/jansson/test/suites/invalid-unicode/overlong-ascii-encoding/input @@ -0,0 +1 @@ +["Á"] diff --git a/3party/jansson/test/suites/invalid-unicode/restricted-utf-8/error b/3party/jansson/test/suites/invalid-unicode/restricted-utf-8/error new file mode 100644 index 0000000000..d018f5ff3d --- /dev/null +++ b/3party/jansson/test/suites/invalid-unicode/restricted-utf-8/error @@ -0,0 +1,2 @@ +1 2 2 +unable to decode byte 0xfd near '"' diff --git a/3party/jansson/test/suites/invalid-unicode/restricted-utf-8/input b/3party/jansson/test/suites/invalid-unicode/restricted-utf-8/input new file mode 100644 index 0000000000..ba6017002c --- /dev/null +++ b/3party/jansson/test/suites/invalid-unicode/restricted-utf-8/input @@ -0,0 +1 @@ +["ý"] diff --git a/3party/jansson/test/suites/invalid-unicode/run b/3party/jansson/test/suites/invalid-unicode/run new file mode 100755 index 0000000000..369c43da52 --- /dev/null +++ b/3party/jansson/test/suites/invalid-unicode/run @@ -0,0 +1,27 @@ +#!/bin/sh +# +# Copyright (c) 2009-2016 Petri Lehtinen +# +# Jansson is free software; you can redistribute it and/or modify +# it under the terms of the MIT license. See LICENSE for details. + +is_test() { + test -d $test_path +} + +run_test() { + $json_process --env <$test_path/input >$test_log/stdout 2>$test_log/stderr + valgrind_check $test_log/stderr || return 1 + cmp -s $test_path/error $test_log/stderr +} + +show_error() { + valgrind_show_error && return + + echo "EXPECTED ERROR:" + nl -bn $test_path/error + echo "ACTUAL ERROR:" + nl -bn $test_log/stderr +} + +. $top_srcdir/test/scripts/run-tests.sh diff --git a/3party/jansson/test/suites/invalid-unicode/truncated-utf-8/error b/3party/jansson/test/suites/invalid-unicode/truncated-utf-8/error new file mode 100644 index 0000000000..8a05abaed5 --- /dev/null +++ b/3party/jansson/test/suites/invalid-unicode/truncated-utf-8/error @@ -0,0 +1,2 @@ +1 2 2 +unable to decode byte 0xe0 near '"' diff --git a/3party/jansson/test/suites/invalid-unicode/truncated-utf-8/input b/3party/jansson/test/suites/invalid-unicode/truncated-utf-8/input new file mode 100644 index 0000000000..bce9e18bf9 --- /dev/null +++ b/3party/jansson/test/suites/invalid-unicode/truncated-utf-8/input @@ -0,0 +1 @@ +["àÿ <-- truncated UTF-8"] diff --git a/3party/jansson/test/suites/invalid/apostrophe/error b/3party/jansson/test/suites/invalid/apostrophe/error new file mode 100644 index 0000000000..79bb2a0eb4 --- /dev/null +++ b/3party/jansson/test/suites/invalid/apostrophe/error @@ -0,0 +1,2 @@ +1 2 2 +invalid token near ''' diff --git a/3party/jansson/test/suites/invalid/apostrophe/input b/3party/jansson/test/suites/invalid/apostrophe/input new file mode 100644 index 0000000000..f2dd4d224d --- /dev/null +++ b/3party/jansson/test/suites/invalid/apostrophe/input @@ -0,0 +1 @@ +[' diff --git a/3party/jansson/test/suites/invalid/ascii-unicode-identifier/error b/3party/jansson/test/suites/invalid/ascii-unicode-identifier/error new file mode 100644 index 0000000000..a4d8142805 --- /dev/null +++ b/3party/jansson/test/suites/invalid/ascii-unicode-identifier/error @@ -0,0 +1,2 @@ +1 1 1 +'[' or '{' expected near 'a' diff --git a/3party/jansson/test/suites/invalid/ascii-unicode-identifier/input b/3party/jansson/test/suites/invalid/ascii-unicode-identifier/input new file mode 100644 index 0000000000..c2c0208eda --- /dev/null +++ b/3party/jansson/test/suites/invalid/ascii-unicode-identifier/input @@ -0,0 +1 @@ +aÃ¥ diff --git a/3party/jansson/test/suites/invalid/brace-comma/error b/3party/jansson/test/suites/invalid/brace-comma/error new file mode 100644 index 0000000000..ce046213cf --- /dev/null +++ b/3party/jansson/test/suites/invalid/brace-comma/error @@ -0,0 +1,2 @@ +1 2 2 +string or '}' expected near ',' diff --git a/3party/jansson/test/suites/invalid/brace-comma/input b/3party/jansson/test/suites/invalid/brace-comma/input new file mode 100644 index 0000000000..74a6628d44 --- /dev/null +++ b/3party/jansson/test/suites/invalid/brace-comma/input @@ -0,0 +1 @@ +{, diff --git a/3party/jansson/test/suites/invalid/bracket-comma/error b/3party/jansson/test/suites/invalid/bracket-comma/error new file mode 100644 index 0000000000..ce0a912bf2 --- /dev/null +++ b/3party/jansson/test/suites/invalid/bracket-comma/error @@ -0,0 +1,2 @@ +1 2 2 +unexpected token near ',' diff --git a/3party/jansson/test/suites/invalid/bracket-comma/input b/3party/jansson/test/suites/invalid/bracket-comma/input new file mode 100644 index 0000000000..5b911f11dc --- /dev/null +++ b/3party/jansson/test/suites/invalid/bracket-comma/input @@ -0,0 +1 @@ +[, diff --git a/3party/jansson/test/suites/invalid/bracket-one-comma/error.normal b/3party/jansson/test/suites/invalid/bracket-one-comma/error.normal new file mode 100644 index 0000000000..0248b114aa --- /dev/null +++ b/3party/jansson/test/suites/invalid/bracket-one-comma/error.normal @@ -0,0 +1,2 @@ +2 0 4 +']' expected near end of file diff --git a/3party/jansson/test/suites/invalid/bracket-one-comma/error.strip b/3party/jansson/test/suites/invalid/bracket-one-comma/error.strip new file mode 100644 index 0000000000..f89b38fcbf --- /dev/null +++ b/3party/jansson/test/suites/invalid/bracket-one-comma/error.strip @@ -0,0 +1,2 @@ +1 3 3 +']' expected near end of file diff --git a/3party/jansson/test/suites/invalid/bracket-one-comma/input b/3party/jansson/test/suites/invalid/bracket-one-comma/input new file mode 100644 index 0000000000..874691b1de --- /dev/null +++ b/3party/jansson/test/suites/invalid/bracket-one-comma/input @@ -0,0 +1 @@ +[1, diff --git a/3party/jansson/test/suites/invalid/empty/error b/3party/jansson/test/suites/invalid/empty/error new file mode 100644 index 0000000000..f45da6f820 --- /dev/null +++ b/3party/jansson/test/suites/invalid/empty/error @@ -0,0 +1,2 @@ +1 0 0 +'[' or '{' expected near end of file diff --git a/3party/jansson/test/suites/invalid/empty/input b/3party/jansson/test/suites/invalid/empty/input new file mode 100644 index 0000000000..e69de29bb2 diff --git a/3party/jansson/test/suites/invalid/extra-comma-in-array/error b/3party/jansson/test/suites/invalid/extra-comma-in-array/error new file mode 100644 index 0000000000..cae86c2460 --- /dev/null +++ b/3party/jansson/test/suites/invalid/extra-comma-in-array/error @@ -0,0 +1,2 @@ +1 4 4 +unexpected token near ']' diff --git a/3party/jansson/test/suites/invalid/extra-comma-in-array/input b/3party/jansson/test/suites/invalid/extra-comma-in-array/input new file mode 100644 index 0000000000..e8b1a170fd --- /dev/null +++ b/3party/jansson/test/suites/invalid/extra-comma-in-array/input @@ -0,0 +1 @@ +[1,] diff --git a/3party/jansson/test/suites/invalid/extra-comma-in-multiline-array/error b/3party/jansson/test/suites/invalid/extra-comma-in-multiline-array/error new file mode 100644 index 0000000000..5baeea4472 --- /dev/null +++ b/3party/jansson/test/suites/invalid/extra-comma-in-multiline-array/error @@ -0,0 +1,2 @@ +6 1 17 +unexpected token near ']' diff --git a/3party/jansson/test/suites/invalid/extra-comma-in-multiline-array/input b/3party/jansson/test/suites/invalid/extra-comma-in-multiline-array/input new file mode 100644 index 0000000000..bcb2a75260 --- /dev/null +++ b/3party/jansson/test/suites/invalid/extra-comma-in-multiline-array/input @@ -0,0 +1,6 @@ +[1, +2, +3, +4, +5, +] diff --git a/3party/jansson/test/suites/invalid/garbage-after-newline/error b/3party/jansson/test/suites/invalid/garbage-after-newline/error new file mode 100644 index 0000000000..5d2dec3749 --- /dev/null +++ b/3party/jansson/test/suites/invalid/garbage-after-newline/error @@ -0,0 +1,2 @@ +2 3 11 +end of file expected near 'foo' diff --git a/3party/jansson/test/suites/invalid/garbage-after-newline/input b/3party/jansson/test/suites/invalid/garbage-after-newline/input new file mode 100644 index 0000000000..3614ac78fe --- /dev/null +++ b/3party/jansson/test/suites/invalid/garbage-after-newline/input @@ -0,0 +1,2 @@ +[1,2,3] +foo diff --git a/3party/jansson/test/suites/invalid/garbage-at-the-end/error b/3party/jansson/test/suites/invalid/garbage-at-the-end/error new file mode 100644 index 0000000000..cdd8175728 --- /dev/null +++ b/3party/jansson/test/suites/invalid/garbage-at-the-end/error @@ -0,0 +1,2 @@ +1 10 10 +end of file expected near 'foo' diff --git a/3party/jansson/test/suites/invalid/garbage-at-the-end/input b/3party/jansson/test/suites/invalid/garbage-at-the-end/input new file mode 100644 index 0000000000..55aee53d22 --- /dev/null +++ b/3party/jansson/test/suites/invalid/garbage-at-the-end/input @@ -0,0 +1 @@ +[1,2,3]foo diff --git a/3party/jansson/test/suites/invalid/integer-starting-with-zero/error b/3party/jansson/test/suites/invalid/integer-starting-with-zero/error new file mode 100644 index 0000000000..64e0536aa6 --- /dev/null +++ b/3party/jansson/test/suites/invalid/integer-starting-with-zero/error @@ -0,0 +1,2 @@ +1 2 2 +invalid token near '0' diff --git a/3party/jansson/test/suites/invalid/integer-starting-with-zero/input b/3party/jansson/test/suites/invalid/integer-starting-with-zero/input new file mode 100644 index 0000000000..12f67e2c26 --- /dev/null +++ b/3party/jansson/test/suites/invalid/integer-starting-with-zero/input @@ -0,0 +1 @@ +[012] diff --git a/3party/jansson/test/suites/invalid/invalid-escape/error b/3party/jansson/test/suites/invalid/invalid-escape/error new file mode 100644 index 0000000000..d9863f73b3 --- /dev/null +++ b/3party/jansson/test/suites/invalid/invalid-escape/error @@ -0,0 +1,2 @@ +1 4 4 +invalid escape near '"\a' diff --git a/3party/jansson/test/suites/invalid/invalid-escape/input b/3party/jansson/test/suites/invalid/invalid-escape/input new file mode 100644 index 0000000000..64c7b70d98 --- /dev/null +++ b/3party/jansson/test/suites/invalid/invalid-escape/input @@ -0,0 +1 @@ +["\a <-- invalid escape"] diff --git a/3party/jansson/test/suites/invalid/invalid-identifier/error b/3party/jansson/test/suites/invalid/invalid-identifier/error new file mode 100644 index 0000000000..496c6aba25 --- /dev/null +++ b/3party/jansson/test/suites/invalid/invalid-identifier/error @@ -0,0 +1,2 @@ +1 5 5 +invalid token near 'troo' diff --git a/3party/jansson/test/suites/invalid/invalid-identifier/input b/3party/jansson/test/suites/invalid/invalid-identifier/input new file mode 100644 index 0000000000..3d2860da18 --- /dev/null +++ b/3party/jansson/test/suites/invalid/invalid-identifier/input @@ -0,0 +1 @@ +[troo diff --git a/3party/jansson/test/suites/invalid/invalid-negative-integer/error b/3party/jansson/test/suites/invalid/invalid-negative-integer/error new file mode 100644 index 0000000000..f2526c51e7 --- /dev/null +++ b/3party/jansson/test/suites/invalid/invalid-negative-integer/error @@ -0,0 +1,2 @@ +1 8 8 +']' expected near 'foo' diff --git a/3party/jansson/test/suites/invalid/invalid-negative-integer/input b/3party/jansson/test/suites/invalid/invalid-negative-integer/input new file mode 100644 index 0000000000..6196980ecc --- /dev/null +++ b/3party/jansson/test/suites/invalid/invalid-negative-integer/input @@ -0,0 +1 @@ +[-123foo] diff --git a/3party/jansson/test/suites/invalid/invalid-negative-real/error b/3party/jansson/test/suites/invalid/invalid-negative-real/error new file mode 100644 index 0000000000..933158ae5a --- /dev/null +++ b/3party/jansson/test/suites/invalid/invalid-negative-real/error @@ -0,0 +1,2 @@ +1 12 12 +']' expected near 'foo' diff --git a/3party/jansson/test/suites/invalid/invalid-negative-real/input b/3party/jansson/test/suites/invalid/invalid-negative-real/input new file mode 100644 index 0000000000..3c763d334e --- /dev/null +++ b/3party/jansson/test/suites/invalid/invalid-negative-real/input @@ -0,0 +1 @@ +[-123.123foo] diff --git a/3party/jansson/test/suites/invalid/invalid-second-surrogate/error b/3party/jansson/test/suites/invalid/invalid-second-surrogate/error new file mode 100644 index 0000000000..e5a2359e66 --- /dev/null +++ b/3party/jansson/test/suites/invalid/invalid-second-surrogate/error @@ -0,0 +1,2 @@ +1 62 62 +invalid Unicode '\uD888\u3210' diff --git a/3party/jansson/test/suites/invalid/invalid-second-surrogate/input b/3party/jansson/test/suites/invalid/invalid-second-surrogate/input new file mode 100644 index 0000000000..b21453f6f2 --- /dev/null +++ b/3party/jansson/test/suites/invalid/invalid-second-surrogate/input @@ -0,0 +1 @@ +["\uD888\u3210 (first surrogate and invalid second surrogate)"] diff --git a/3party/jansson/test/suites/invalid/invalid-unicode-escape/error b/3party/jansson/test/suites/invalid/invalid-unicode-escape/error new file mode 100644 index 0000000000..221c762eb0 --- /dev/null +++ b/3party/jansson/test/suites/invalid/invalid-unicode-escape/error @@ -0,0 +1,2 @@ +1 5 5 +invalid escape near '"\uq' diff --git a/3party/jansson/test/suites/invalid/invalid-unicode-escape/input b/3party/jansson/test/suites/invalid/invalid-unicode-escape/input new file mode 100644 index 0000000000..f381e85b8b --- /dev/null +++ b/3party/jansson/test/suites/invalid/invalid-unicode-escape/input @@ -0,0 +1 @@ +["\uqqqq <-- invalid unicode escape"] diff --git a/3party/jansson/test/suites/invalid/lone-open-brace/error.normal b/3party/jansson/test/suites/invalid/lone-open-brace/error.normal new file mode 100644 index 0000000000..00dc765b9c --- /dev/null +++ b/3party/jansson/test/suites/invalid/lone-open-brace/error.normal @@ -0,0 +1,2 @@ +2 0 2 +string or '}' expected near end of file diff --git a/3party/jansson/test/suites/invalid/lone-open-brace/error.strip b/3party/jansson/test/suites/invalid/lone-open-brace/error.strip new file mode 100644 index 0000000000..bb1c047456 --- /dev/null +++ b/3party/jansson/test/suites/invalid/lone-open-brace/error.strip @@ -0,0 +1,2 @@ +1 1 1 +string or '}' expected near end of file diff --git a/3party/jansson/test/suites/invalid/lone-open-brace/input b/3party/jansson/test/suites/invalid/lone-open-brace/input new file mode 100644 index 0000000000..98232c64fc --- /dev/null +++ b/3party/jansson/test/suites/invalid/lone-open-brace/input @@ -0,0 +1 @@ +{ diff --git a/3party/jansson/test/suites/invalid/lone-open-bracket/error.normal b/3party/jansson/test/suites/invalid/lone-open-bracket/error.normal new file mode 100644 index 0000000000..f463928f8a --- /dev/null +++ b/3party/jansson/test/suites/invalid/lone-open-bracket/error.normal @@ -0,0 +1,2 @@ +2 0 2 +']' expected near end of file diff --git a/3party/jansson/test/suites/invalid/lone-open-bracket/error.strip b/3party/jansson/test/suites/invalid/lone-open-bracket/error.strip new file mode 100644 index 0000000000..2bc07ea0c5 --- /dev/null +++ b/3party/jansson/test/suites/invalid/lone-open-bracket/error.strip @@ -0,0 +1,2 @@ +1 1 1 +']' expected near end of file diff --git a/3party/jansson/test/suites/invalid/lone-open-bracket/input b/3party/jansson/test/suites/invalid/lone-open-bracket/input new file mode 100644 index 0000000000..558ed37d93 --- /dev/null +++ b/3party/jansson/test/suites/invalid/lone-open-bracket/input @@ -0,0 +1 @@ +[ diff --git a/3party/jansson/test/suites/invalid/lone-second-surrogate/error b/3party/jansson/test/suites/invalid/lone-second-surrogate/error new file mode 100644 index 0000000000..bc5f34e11a --- /dev/null +++ b/3party/jansson/test/suites/invalid/lone-second-surrogate/error @@ -0,0 +1,2 @@ +1 40 40 +invalid Unicode '\uDFAA' diff --git a/3party/jansson/test/suites/invalid/lone-second-surrogate/input b/3party/jansson/test/suites/invalid/lone-second-surrogate/input new file mode 100644 index 0000000000..328e35c826 --- /dev/null +++ b/3party/jansson/test/suites/invalid/lone-second-surrogate/input @@ -0,0 +1 @@ +["\uDFAA (second surrogate on it's own)"] diff --git a/3party/jansson/test/suites/invalid/minus-sign-without-number/error b/3party/jansson/test/suites/invalid/minus-sign-without-number/error new file mode 100644 index 0000000000..b3a78b9781 --- /dev/null +++ b/3party/jansson/test/suites/invalid/minus-sign-without-number/error @@ -0,0 +1,2 @@ +1 2 2 +invalid token near '-' diff --git a/3party/jansson/test/suites/invalid/minus-sign-without-number/input b/3party/jansson/test/suites/invalid/minus-sign-without-number/input new file mode 100644 index 0000000000..0337883557 --- /dev/null +++ b/3party/jansson/test/suites/invalid/minus-sign-without-number/input @@ -0,0 +1 @@ +[-foo] diff --git a/3party/jansson/test/suites/invalid/negative-integer-starting-with-zero/error b/3party/jansson/test/suites/invalid/negative-integer-starting-with-zero/error new file mode 100644 index 0000000000..36adc34b4c --- /dev/null +++ b/3party/jansson/test/suites/invalid/negative-integer-starting-with-zero/error @@ -0,0 +1,2 @@ +1 3 3 +invalid token near '-0' diff --git a/3party/jansson/test/suites/invalid/negative-integer-starting-with-zero/input b/3party/jansson/test/suites/invalid/negative-integer-starting-with-zero/input new file mode 100644 index 0000000000..6fbb7a2f82 --- /dev/null +++ b/3party/jansson/test/suites/invalid/negative-integer-starting-with-zero/input @@ -0,0 +1 @@ +[-012] diff --git a/3party/jansson/test/suites/invalid/null-byte-in-object-key/error b/3party/jansson/test/suites/invalid/null-byte-in-object-key/error new file mode 100644 index 0000000000..3ec685b5d0 --- /dev/null +++ b/3party/jansson/test/suites/invalid/null-byte-in-object-key/error @@ -0,0 +1,2 @@ +1 15 15 +NUL byte in object key not supported near '"foo\u0000bar"' diff --git a/3party/jansson/test/suites/invalid/null-byte-in-object-key/input b/3party/jansson/test/suites/invalid/null-byte-in-object-key/input new file mode 100644 index 0000000000..593f0f67f9 --- /dev/null +++ b/3party/jansson/test/suites/invalid/null-byte-in-object-key/input @@ -0,0 +1 @@ +{"foo\u0000bar": 42} \ No newline at end of file diff --git a/3party/jansson/test/suites/invalid/null-byte-in-string/error b/3party/jansson/test/suites/invalid/null-byte-in-string/error new file mode 100644 index 0000000000..45f9bd8172 --- /dev/null +++ b/3party/jansson/test/suites/invalid/null-byte-in-string/error @@ -0,0 +1,2 @@ +1 12 12 +control character 0x0 near '"null byte ' diff --git a/3party/jansson/test/suites/invalid/null-byte-in-string/input b/3party/jansson/test/suites/invalid/null-byte-in-string/input new file mode 100644 index 0000000000..268d1f1943 Binary files /dev/null and b/3party/jansson/test/suites/invalid/null-byte-in-string/input differ diff --git a/3party/jansson/test/suites/invalid/null-byte-in-string/nostrip b/3party/jansson/test/suites/invalid/null-byte-in-string/nostrip new file mode 100644 index 0000000000..80f4bf761f --- /dev/null +++ b/3party/jansson/test/suites/invalid/null-byte-in-string/nostrip @@ -0,0 +1,2 @@ +The embedded NULL byte breaks json_loads(), which is used instead of +json_loadf() in the stripped tests. diff --git a/3party/jansson/test/suites/invalid/null-byte-outside-string/error b/3party/jansson/test/suites/invalid/null-byte-outside-string/error new file mode 100644 index 0000000000..44d4def924 --- /dev/null +++ b/3party/jansson/test/suites/invalid/null-byte-outside-string/error @@ -0,0 +1,2 @@ +1 2 2 +invalid token near end of file diff --git a/3party/jansson/test/suites/invalid/null-byte-outside-string/input b/3party/jansson/test/suites/invalid/null-byte-outside-string/input new file mode 100644 index 0000000000..aa550eb0cd Binary files /dev/null and b/3party/jansson/test/suites/invalid/null-byte-outside-string/input differ diff --git a/3party/jansson/test/suites/invalid/null-byte-outside-string/nostrip b/3party/jansson/test/suites/invalid/null-byte-outside-string/nostrip new file mode 100644 index 0000000000..80f4bf761f --- /dev/null +++ b/3party/jansson/test/suites/invalid/null-byte-outside-string/nostrip @@ -0,0 +1,2 @@ +The embedded NULL byte breaks json_loads(), which is used instead of +json_loadf() in the stripped tests. diff --git a/3party/jansson/test/suites/invalid/null-escape-in-string/error b/3party/jansson/test/suites/invalid/null-escape-in-string/error new file mode 100644 index 0000000000..3f5c8c6caf --- /dev/null +++ b/3party/jansson/test/suites/invalid/null-escape-in-string/error @@ -0,0 +1,2 @@ +1 33 33 +\u0000 is not allowed without JSON_ALLOW_NUL diff --git a/3party/jansson/test/suites/invalid/null-escape-in-string/input b/3party/jansson/test/suites/invalid/null-escape-in-string/input new file mode 100644 index 0000000000..dbc9c9a99f --- /dev/null +++ b/3party/jansson/test/suites/invalid/null-escape-in-string/input @@ -0,0 +1 @@ +["null escape \u0000 not allowed"] diff --git a/3party/jansson/test/suites/invalid/null/error b/3party/jansson/test/suites/invalid/null/error new file mode 100644 index 0000000000..1f5d46490d --- /dev/null +++ b/3party/jansson/test/suites/invalid/null/error @@ -0,0 +1,2 @@ +1 4 4 +'[' or '{' expected near 'null' diff --git a/3party/jansson/test/suites/invalid/null/input b/3party/jansson/test/suites/invalid/null/input new file mode 100644 index 0000000000..19765bd501 --- /dev/null +++ b/3party/jansson/test/suites/invalid/null/input @@ -0,0 +1 @@ +null diff --git a/3party/jansson/test/suites/invalid/object-apostrophes/error b/3party/jansson/test/suites/invalid/object-apostrophes/error new file mode 100644 index 0000000000..23fab01f65 --- /dev/null +++ b/3party/jansson/test/suites/invalid/object-apostrophes/error @@ -0,0 +1,2 @@ +1 2 2 +string or '}' expected near ''' diff --git a/3party/jansson/test/suites/invalid/object-apostrophes/input b/3party/jansson/test/suites/invalid/object-apostrophes/input new file mode 100644 index 0000000000..52b290574b --- /dev/null +++ b/3party/jansson/test/suites/invalid/object-apostrophes/input @@ -0,0 +1 @@ +{'a' diff --git a/3party/jansson/test/suites/invalid/object-garbage-at-end/error b/3party/jansson/test/suites/invalid/object-garbage-at-end/error new file mode 100644 index 0000000000..06c4ec1c22 --- /dev/null +++ b/3party/jansson/test/suites/invalid/object-garbage-at-end/error @@ -0,0 +1,2 @@ +1 12 12 +'}' expected near '123' diff --git a/3party/jansson/test/suites/invalid/object-garbage-at-end/input b/3party/jansson/test/suites/invalid/object-garbage-at-end/input new file mode 100644 index 0000000000..62c19d742b --- /dev/null +++ b/3party/jansson/test/suites/invalid/object-garbage-at-end/input @@ -0,0 +1 @@ +{"a":"a" 123} diff --git a/3party/jansson/test/suites/invalid/object-in-unterminated-array/error.normal b/3party/jansson/test/suites/invalid/object-in-unterminated-array/error.normal new file mode 100644 index 0000000000..0248b114aa --- /dev/null +++ b/3party/jansson/test/suites/invalid/object-in-unterminated-array/error.normal @@ -0,0 +1,2 @@ +2 0 4 +']' expected near end of file diff --git a/3party/jansson/test/suites/invalid/object-in-unterminated-array/error.strip b/3party/jansson/test/suites/invalid/object-in-unterminated-array/error.strip new file mode 100644 index 0000000000..f89b38fcbf --- /dev/null +++ b/3party/jansson/test/suites/invalid/object-in-unterminated-array/error.strip @@ -0,0 +1,2 @@ +1 3 3 +']' expected near end of file diff --git a/3party/jansson/test/suites/invalid/object-in-unterminated-array/input b/3party/jansson/test/suites/invalid/object-in-unterminated-array/input new file mode 100644 index 0000000000..ca9ec378e2 --- /dev/null +++ b/3party/jansson/test/suites/invalid/object-in-unterminated-array/input @@ -0,0 +1 @@ +[{} diff --git a/3party/jansson/test/suites/invalid/object-no-colon/error.normal b/3party/jansson/test/suites/invalid/object-no-colon/error.normal new file mode 100644 index 0000000000..78d84f7b7d --- /dev/null +++ b/3party/jansson/test/suites/invalid/object-no-colon/error.normal @@ -0,0 +1,2 @@ +2 0 5 +':' expected near end of file diff --git a/3party/jansson/test/suites/invalid/object-no-colon/error.strip b/3party/jansson/test/suites/invalid/object-no-colon/error.strip new file mode 100644 index 0000000000..528e266d27 --- /dev/null +++ b/3party/jansson/test/suites/invalid/object-no-colon/error.strip @@ -0,0 +1,2 @@ +1 4 4 +':' expected near end of file diff --git a/3party/jansson/test/suites/invalid/object-no-colon/input b/3party/jansson/test/suites/invalid/object-no-colon/input new file mode 100644 index 0000000000..107e6265c6 --- /dev/null +++ b/3party/jansson/test/suites/invalid/object-no-colon/input @@ -0,0 +1 @@ +{"a" diff --git a/3party/jansson/test/suites/invalid/object-no-value/error.normal b/3party/jansson/test/suites/invalid/object-no-value/error.normal new file mode 100644 index 0000000000..47ad902ddb --- /dev/null +++ b/3party/jansson/test/suites/invalid/object-no-value/error.normal @@ -0,0 +1,2 @@ +2 0 6 +unexpected token near end of file diff --git a/3party/jansson/test/suites/invalid/object-no-value/error.strip b/3party/jansson/test/suites/invalid/object-no-value/error.strip new file mode 100644 index 0000000000..b36c5e2bc6 --- /dev/null +++ b/3party/jansson/test/suites/invalid/object-no-value/error.strip @@ -0,0 +1,2 @@ +1 5 5 +unexpected token near end of file diff --git a/3party/jansson/test/suites/invalid/object-no-value/input b/3party/jansson/test/suites/invalid/object-no-value/input new file mode 100644 index 0000000000..f68f262696 --- /dev/null +++ b/3party/jansson/test/suites/invalid/object-no-value/input @@ -0,0 +1 @@ +{"a": diff --git a/3party/jansson/test/suites/invalid/object-unterminated-value/error.normal b/3party/jansson/test/suites/invalid/object-unterminated-value/error.normal new file mode 100644 index 0000000000..2ad76d4736 --- /dev/null +++ b/3party/jansson/test/suites/invalid/object-unterminated-value/error.normal @@ -0,0 +1,2 @@ +1 7 7 +unexpected newline near '"a' diff --git a/3party/jansson/test/suites/invalid/object-unterminated-value/error.strip b/3party/jansson/test/suites/invalid/object-unterminated-value/error.strip new file mode 100644 index 0000000000..385afb534c --- /dev/null +++ b/3party/jansson/test/suites/invalid/object-unterminated-value/error.strip @@ -0,0 +1,2 @@ +1 7 7 +premature end of input near '"a' diff --git a/3party/jansson/test/suites/invalid/object-unterminated-value/input b/3party/jansson/test/suites/invalid/object-unterminated-value/input new file mode 100644 index 0000000000..b854d7e184 --- /dev/null +++ b/3party/jansson/test/suites/invalid/object-unterminated-value/input @@ -0,0 +1 @@ +{"a":"a diff --git a/3party/jansson/test/suites/invalid/real-garbage-after-e/error b/3party/jansson/test/suites/invalid/real-garbage-after-e/error new file mode 100644 index 0000000000..b40ffa9b58 --- /dev/null +++ b/3party/jansson/test/suites/invalid/real-garbage-after-e/error @@ -0,0 +1,2 @@ +1 3 3 +invalid token near '1e' diff --git a/3party/jansson/test/suites/invalid/real-garbage-after-e/input b/3party/jansson/test/suites/invalid/real-garbage-after-e/input new file mode 100644 index 0000000000..6a945ac0f3 --- /dev/null +++ b/3party/jansson/test/suites/invalid/real-garbage-after-e/input @@ -0,0 +1 @@ +[1ea] diff --git a/3party/jansson/test/suites/invalid/real-negative-overflow/error b/3party/jansson/test/suites/invalid/real-negative-overflow/error new file mode 100644 index 0000000000..d7f8e412d4 --- /dev/null +++ b/3party/jansson/test/suites/invalid/real-negative-overflow/error @@ -0,0 +1,2 @@ +1 15 15 +real number overflow near '-123123e100000' diff --git a/3party/jansson/test/suites/invalid/real-negative-overflow/input b/3party/jansson/test/suites/invalid/real-negative-overflow/input new file mode 100644 index 0000000000..b5bd21c466 --- /dev/null +++ b/3party/jansson/test/suites/invalid/real-negative-overflow/input @@ -0,0 +1 @@ +[-123123e100000] diff --git a/3party/jansson/test/suites/invalid/real-positive-overflow/error b/3party/jansson/test/suites/invalid/real-positive-overflow/error new file mode 100644 index 0000000000..55883c981e --- /dev/null +++ b/3party/jansson/test/suites/invalid/real-positive-overflow/error @@ -0,0 +1,2 @@ +1 14 14 +real number overflow near '123123e100000' diff --git a/3party/jansson/test/suites/invalid/real-positive-overflow/input b/3party/jansson/test/suites/invalid/real-positive-overflow/input new file mode 100644 index 0000000000..524e53b316 --- /dev/null +++ b/3party/jansson/test/suites/invalid/real-positive-overflow/input @@ -0,0 +1 @@ +[123123e100000] diff --git a/3party/jansson/test/suites/invalid/real-truncated-at-e/error b/3party/jansson/test/suites/invalid/real-truncated-at-e/error new file mode 100644 index 0000000000..b40ffa9b58 --- /dev/null +++ b/3party/jansson/test/suites/invalid/real-truncated-at-e/error @@ -0,0 +1,2 @@ +1 3 3 +invalid token near '1e' diff --git a/3party/jansson/test/suites/invalid/real-truncated-at-e/input b/3party/jansson/test/suites/invalid/real-truncated-at-e/input new file mode 100644 index 0000000000..1d67b7b822 --- /dev/null +++ b/3party/jansson/test/suites/invalid/real-truncated-at-e/input @@ -0,0 +1 @@ +[1e] diff --git a/3party/jansson/test/suites/invalid/real-truncated-at-point/error b/3party/jansson/test/suites/invalid/real-truncated-at-point/error new file mode 100644 index 0000000000..db972e8e16 --- /dev/null +++ b/3party/jansson/test/suites/invalid/real-truncated-at-point/error @@ -0,0 +1,2 @@ +1 3 3 +invalid token near '1.' diff --git a/3party/jansson/test/suites/invalid/real-truncated-at-point/input b/3party/jansson/test/suites/invalid/real-truncated-at-point/input new file mode 100644 index 0000000000..b652b3fe02 --- /dev/null +++ b/3party/jansson/test/suites/invalid/real-truncated-at-point/input @@ -0,0 +1 @@ +[1.] diff --git a/3party/jansson/test/suites/invalid/recursion-depth/error b/3party/jansson/test/suites/invalid/recursion-depth/error new file mode 100644 index 0000000000..11e0537ff0 --- /dev/null +++ b/3party/jansson/test/suites/invalid/recursion-depth/error @@ -0,0 +1,2 @@ +1 2049 2049 +maximum parsing depth reached near '[' diff --git a/3party/jansson/test/suites/invalid/recursion-depth/input b/3party/jansson/test/suites/invalid/recursion-depth/input new file mode 100644 index 0000000000..bfa47d9d18 --- /dev/null +++ b/3party/jansson/test/suites/invalid/recursion-depth/input @@ -0,0 +1 @@ +[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[ diff --git a/3party/jansson/test/suites/invalid/run b/3party/jansson/test/suites/invalid/run new file mode 100755 index 0000000000..d1d490c63a --- /dev/null +++ b/3party/jansson/test/suites/invalid/run @@ -0,0 +1,57 @@ +#!/bin/sh +# +# Copyright (c) 2009-2016 Petri Lehtinen +# +# Jansson is free software; you can redistribute it and/or modify +# it under the terms of the MIT license. See LICENSE for details. + +is_test() { + test -d $test_path +} + +do_run() { + variant=$1 + s=".$1" + + strip=0 + if [ "$variant" = "strip" ]; then + # This test should not be stripped + [ -f $test_path/nostrip ] && return + strip=1 + fi + + STRIP=$strip $json_process --env \ + <$test_path/input >$test_log/stdout$s 2>$test_log/stderr$s + valgrind_check $test_log/stderr$s || return 1 + + ref=error + [ -f $test_path/error$s ] && ref=error$s + + if ! cmp -s $test_path/$ref $test_log/stderr$s; then + echo $variant > $test_log/variant + return 1 + fi +} + +run_test() { + do_run normal && do_run strip +} + +show_error() { + valgrind_show_error && return + + read variant < $test_log/variant + s=".$variant" + + echo "VARIANT: $variant" + + echo "EXPECTED ERROR:" + ref=error + [ -f $test_path/error$s ] && ref=error$s + nl -bn $test_path/$ref + + echo "ACTUAL ERROR:" + nl -bn $test_log/stderr$s +} + +. $top_srcdir/test/scripts/run-tests.sh diff --git a/3party/jansson/test/suites/invalid/tab-character-in-string/error b/3party/jansson/test/suites/invalid/tab-character-in-string/error new file mode 100644 index 0000000000..9e2f76ed23 --- /dev/null +++ b/3party/jansson/test/suites/invalid/tab-character-in-string/error @@ -0,0 +1,2 @@ +1 2 2 +control character 0x9 near '"' diff --git a/3party/jansson/test/suites/invalid/tab-character-in-string/input b/3party/jansson/test/suites/invalid/tab-character-in-string/input new file mode 100644 index 0000000000..3ebae0953c --- /dev/null +++ b/3party/jansson/test/suites/invalid/tab-character-in-string/input @@ -0,0 +1 @@ +[" <-- tab character"] diff --git a/3party/jansson/test/suites/invalid/too-big-negative-integer/error b/3party/jansson/test/suites/invalid/too-big-negative-integer/error new file mode 100644 index 0000000000..a0640b9a94 --- /dev/null +++ b/3party/jansson/test/suites/invalid/too-big-negative-integer/error @@ -0,0 +1,2 @@ +1 32 32 +too big negative integer diff --git a/3party/jansson/test/suites/invalid/too-big-negative-integer/input b/3party/jansson/test/suites/invalid/too-big-negative-integer/input new file mode 100644 index 0000000000..d6c26f1cf3 --- /dev/null +++ b/3party/jansson/test/suites/invalid/too-big-negative-integer/input @@ -0,0 +1 @@ +[-123123123123123123123123123123] diff --git a/3party/jansson/test/suites/invalid/too-big-positive-integer/error b/3party/jansson/test/suites/invalid/too-big-positive-integer/error new file mode 100644 index 0000000000..3bdbefd535 --- /dev/null +++ b/3party/jansson/test/suites/invalid/too-big-positive-integer/error @@ -0,0 +1,2 @@ +1 31 31 +too big integer diff --git a/3party/jansson/test/suites/invalid/too-big-positive-integer/input b/3party/jansson/test/suites/invalid/too-big-positive-integer/input new file mode 100644 index 0000000000..27c8553993 --- /dev/null +++ b/3party/jansson/test/suites/invalid/too-big-positive-integer/input @@ -0,0 +1 @@ +[123123123123123123123123123123] diff --git a/3party/jansson/test/suites/invalid/truncated-unicode-surrogate/error b/3party/jansson/test/suites/invalid/truncated-unicode-surrogate/error new file mode 100644 index 0000000000..1b99f061a2 --- /dev/null +++ b/3party/jansson/test/suites/invalid/truncated-unicode-surrogate/error @@ -0,0 +1,2 @@ +1 46 46 +invalid Unicode '\uDADA' diff --git a/3party/jansson/test/suites/invalid/truncated-unicode-surrogate/input b/3party/jansson/test/suites/invalid/truncated-unicode-surrogate/input new file mode 100644 index 0000000000..2b340f4ad4 --- /dev/null +++ b/3party/jansson/test/suites/invalid/truncated-unicode-surrogate/input @@ -0,0 +1 @@ +["\uDADA (first surrogate without the second)"] diff --git a/3party/jansson/test/suites/invalid/unicode-identifier/error b/3party/jansson/test/suites/invalid/unicode-identifier/error new file mode 100644 index 0000000000..178b0dd4d8 --- /dev/null +++ b/3party/jansson/test/suites/invalid/unicode-identifier/error @@ -0,0 +1,2 @@ +1 1 2 +'[' or '{' expected near 'Ã¥' diff --git a/3party/jansson/test/suites/invalid/unicode-identifier/input b/3party/jansson/test/suites/invalid/unicode-identifier/input new file mode 100644 index 0000000000..aad321caf7 --- /dev/null +++ b/3party/jansson/test/suites/invalid/unicode-identifier/input @@ -0,0 +1 @@ +Ã¥ diff --git a/3party/jansson/test/suites/invalid/unterminated-array-and-object/error.normal b/3party/jansson/test/suites/invalid/unterminated-array-and-object/error.normal new file mode 100644 index 0000000000..5b19804bc5 --- /dev/null +++ b/3party/jansson/test/suites/invalid/unterminated-array-and-object/error.normal @@ -0,0 +1,2 @@ +2 0 3 +string or '}' expected near end of file diff --git a/3party/jansson/test/suites/invalid/unterminated-array-and-object/error.strip b/3party/jansson/test/suites/invalid/unterminated-array-and-object/error.strip new file mode 100644 index 0000000000..da2bb22f15 --- /dev/null +++ b/3party/jansson/test/suites/invalid/unterminated-array-and-object/error.strip @@ -0,0 +1,2 @@ +1 2 2 +string or '}' expected near end of file diff --git a/3party/jansson/test/suites/invalid/unterminated-array-and-object/input b/3party/jansson/test/suites/invalid/unterminated-array-and-object/input new file mode 100644 index 0000000000..cd9dc64823 --- /dev/null +++ b/3party/jansson/test/suites/invalid/unterminated-array-and-object/input @@ -0,0 +1 @@ +[{ diff --git a/3party/jansson/test/suites/invalid/unterminated-array/error.normal b/3party/jansson/test/suites/invalid/unterminated-array/error.normal new file mode 100644 index 0000000000..8025ed1b02 --- /dev/null +++ b/3party/jansson/test/suites/invalid/unterminated-array/error.normal @@ -0,0 +1,2 @@ +2 0 5 +']' expected near end of file diff --git a/3party/jansson/test/suites/invalid/unterminated-array/error.strip b/3party/jansson/test/suites/invalid/unterminated-array/error.strip new file mode 100644 index 0000000000..495d0f7c43 --- /dev/null +++ b/3party/jansson/test/suites/invalid/unterminated-array/error.strip @@ -0,0 +1,2 @@ +1 4 4 +']' expected near end of file diff --git a/3party/jansson/test/suites/invalid/unterminated-array/input b/3party/jansson/test/suites/invalid/unterminated-array/input new file mode 100644 index 0000000000..727ee81063 --- /dev/null +++ b/3party/jansson/test/suites/invalid/unterminated-array/input @@ -0,0 +1 @@ +["a" diff --git a/3party/jansson/test/suites/invalid/unterminated-empty-key/error.normal b/3party/jansson/test/suites/invalid/unterminated-empty-key/error.normal new file mode 100644 index 0000000000..3d646abda3 --- /dev/null +++ b/3party/jansson/test/suites/invalid/unterminated-empty-key/error.normal @@ -0,0 +1,2 @@ +1 2 2 +unexpected newline near '"' diff --git a/3party/jansson/test/suites/invalid/unterminated-empty-key/error.strip b/3party/jansson/test/suites/invalid/unterminated-empty-key/error.strip new file mode 100644 index 0000000000..94f1947155 --- /dev/null +++ b/3party/jansson/test/suites/invalid/unterminated-empty-key/error.strip @@ -0,0 +1,2 @@ +1 2 2 +premature end of input near '"' diff --git a/3party/jansson/test/suites/invalid/unterminated-empty-key/input b/3party/jansson/test/suites/invalid/unterminated-empty-key/input new file mode 100644 index 0000000000..4117452de4 --- /dev/null +++ b/3party/jansson/test/suites/invalid/unterminated-empty-key/input @@ -0,0 +1 @@ +{" diff --git a/3party/jansson/test/suites/invalid/unterminated-key/error.normal b/3party/jansson/test/suites/invalid/unterminated-key/error.normal new file mode 100644 index 0000000000..5f09b77da8 --- /dev/null +++ b/3party/jansson/test/suites/invalid/unterminated-key/error.normal @@ -0,0 +1,2 @@ +1 3 3 +unexpected newline near '"a' diff --git a/3party/jansson/test/suites/invalid/unterminated-key/error.strip b/3party/jansson/test/suites/invalid/unterminated-key/error.strip new file mode 100644 index 0000000000..8b6bec430d --- /dev/null +++ b/3party/jansson/test/suites/invalid/unterminated-key/error.strip @@ -0,0 +1,2 @@ +1 3 3 +premature end of input near '"a' diff --git a/3party/jansson/test/suites/invalid/unterminated-key/input b/3party/jansson/test/suites/invalid/unterminated-key/input new file mode 100644 index 0000000000..705948c64e --- /dev/null +++ b/3party/jansson/test/suites/invalid/unterminated-key/input @@ -0,0 +1 @@ +{"a diff --git a/3party/jansson/test/suites/invalid/unterminated-object-and-array/error b/3party/jansson/test/suites/invalid/unterminated-object-and-array/error new file mode 100644 index 0000000000..ed97be73e3 --- /dev/null +++ b/3party/jansson/test/suites/invalid/unterminated-object-and-array/error @@ -0,0 +1,2 @@ +1 2 2 +string or '}' expected near '[' diff --git a/3party/jansson/test/suites/invalid/unterminated-object-and-array/input b/3party/jansson/test/suites/invalid/unterminated-object-and-array/input new file mode 100644 index 0000000000..da35a86207 --- /dev/null +++ b/3party/jansson/test/suites/invalid/unterminated-object-and-array/input @@ -0,0 +1 @@ +{[ diff --git a/3party/jansson/test/suites/invalid/unterminated-string/error.normal b/3party/jansson/test/suites/invalid/unterminated-string/error.normal new file mode 100644 index 0000000000..5f09b77da8 --- /dev/null +++ b/3party/jansson/test/suites/invalid/unterminated-string/error.normal @@ -0,0 +1,2 @@ +1 3 3 +unexpected newline near '"a' diff --git a/3party/jansson/test/suites/invalid/unterminated-string/error.strip b/3party/jansson/test/suites/invalid/unterminated-string/error.strip new file mode 100644 index 0000000000..8b6bec430d --- /dev/null +++ b/3party/jansson/test/suites/invalid/unterminated-string/error.strip @@ -0,0 +1,2 @@ +1 3 3 +premature end of input near '"a' diff --git a/3party/jansson/test/suites/invalid/unterminated-string/input b/3party/jansson/test/suites/invalid/unterminated-string/input new file mode 100644 index 0000000000..38ab6b04ca --- /dev/null +++ b/3party/jansson/test/suites/invalid/unterminated-string/input @@ -0,0 +1 @@ +["a diff --git a/3party/jansson/test/suites/valid/complex-array/env b/3party/jansson/test/suites/valid/complex-array/env new file mode 100644 index 0000000000..bd89eff9d9 --- /dev/null +++ b/3party/jansson/test/suites/valid/complex-array/env @@ -0,0 +1 @@ +JSON_SORT_KEYS=1 \ No newline at end of file diff --git a/3party/jansson/test/suites/valid/complex-array/input b/3party/jansson/test/suites/valid/complex-array/input new file mode 100644 index 0000000000..1b9bbb949f --- /dev/null +++ b/3party/jansson/test/suites/valid/complex-array/input @@ -0,0 +1,5 @@ +[1,2,3,4, +"a", "b", "c", +{"foo": "bar", "core": "dump"}, +true, false, true, true, null, false +] diff --git a/3party/jansson/test/suites/valid/complex-array/output b/3party/jansson/test/suites/valid/complex-array/output new file mode 100644 index 0000000000..7aefe5642c --- /dev/null +++ b/3party/jansson/test/suites/valid/complex-array/output @@ -0,0 +1 @@ +[1, 2, 3, 4, "a", "b", "c", {"core": "dump", "foo": "bar"}, true, false, true, true, null, false] \ No newline at end of file diff --git a/3party/jansson/test/suites/valid/empty-array/input b/3party/jansson/test/suites/valid/empty-array/input new file mode 100644 index 0000000000..fe51488c70 --- /dev/null +++ b/3party/jansson/test/suites/valid/empty-array/input @@ -0,0 +1 @@ +[] diff --git a/3party/jansson/test/suites/valid/empty-array/output b/3party/jansson/test/suites/valid/empty-array/output new file mode 100644 index 0000000000..0637a088a0 --- /dev/null +++ b/3party/jansson/test/suites/valid/empty-array/output @@ -0,0 +1 @@ +[] \ No newline at end of file diff --git a/3party/jansson/test/suites/valid/empty-object-in-array/input b/3party/jansson/test/suites/valid/empty-object-in-array/input new file mode 100644 index 0000000000..93d51406d6 --- /dev/null +++ b/3party/jansson/test/suites/valid/empty-object-in-array/input @@ -0,0 +1 @@ +[{}] diff --git a/3party/jansson/test/suites/valid/empty-object-in-array/output b/3party/jansson/test/suites/valid/empty-object-in-array/output new file mode 100644 index 0000000000..ee1aac42be --- /dev/null +++ b/3party/jansson/test/suites/valid/empty-object-in-array/output @@ -0,0 +1 @@ +[{}] \ No newline at end of file diff --git a/3party/jansson/test/suites/valid/empty-object/input b/3party/jansson/test/suites/valid/empty-object/input new file mode 100644 index 0000000000..0967ef424b --- /dev/null +++ b/3party/jansson/test/suites/valid/empty-object/input @@ -0,0 +1 @@ +{} diff --git a/3party/jansson/test/suites/valid/empty-object/output b/3party/jansson/test/suites/valid/empty-object/output new file mode 100644 index 0000000000..9e26dfeeb6 --- /dev/null +++ b/3party/jansson/test/suites/valid/empty-object/output @@ -0,0 +1 @@ +{} \ No newline at end of file diff --git a/3party/jansson/test/suites/valid/empty-string/input b/3party/jansson/test/suites/valid/empty-string/input new file mode 100644 index 0000000000..66a1e18560 --- /dev/null +++ b/3party/jansson/test/suites/valid/empty-string/input @@ -0,0 +1 @@ +[""] diff --git a/3party/jansson/test/suites/valid/empty-string/output b/3party/jansson/test/suites/valid/empty-string/output new file mode 100644 index 0000000000..93b6be2bcc --- /dev/null +++ b/3party/jansson/test/suites/valid/empty-string/output @@ -0,0 +1 @@ +[""] \ No newline at end of file diff --git a/3party/jansson/test/suites/valid/escaped-utf-control-char/input b/3party/jansson/test/suites/valid/escaped-utf-control-char/input new file mode 100644 index 0000000000..9a98545c00 --- /dev/null +++ b/3party/jansson/test/suites/valid/escaped-utf-control-char/input @@ -0,0 +1 @@ +["\u0012 escaped control character"] diff --git a/3party/jansson/test/suites/valid/escaped-utf-control-char/output b/3party/jansson/test/suites/valid/escaped-utf-control-char/output new file mode 100644 index 0000000000..07221b78d2 --- /dev/null +++ b/3party/jansson/test/suites/valid/escaped-utf-control-char/output @@ -0,0 +1 @@ +["\u0012 escaped control character"] \ No newline at end of file diff --git a/3party/jansson/test/suites/valid/false/input b/3party/jansson/test/suites/valid/false/input new file mode 100644 index 0000000000..4343652024 --- /dev/null +++ b/3party/jansson/test/suites/valid/false/input @@ -0,0 +1 @@ +[false] diff --git a/3party/jansson/test/suites/valid/false/output b/3party/jansson/test/suites/valid/false/output new file mode 100644 index 0000000000..67b2f07601 --- /dev/null +++ b/3party/jansson/test/suites/valid/false/output @@ -0,0 +1 @@ +[false] \ No newline at end of file diff --git a/3party/jansson/test/suites/valid/negative-int/input b/3party/jansson/test/suites/valid/negative-int/input new file mode 100644 index 0000000000..a96d5cdb31 --- /dev/null +++ b/3party/jansson/test/suites/valid/negative-int/input @@ -0,0 +1 @@ +[-123] diff --git a/3party/jansson/test/suites/valid/negative-int/output b/3party/jansson/test/suites/valid/negative-int/output new file mode 100644 index 0000000000..8e30f8bd96 --- /dev/null +++ b/3party/jansson/test/suites/valid/negative-int/output @@ -0,0 +1 @@ +[-123] \ No newline at end of file diff --git a/3party/jansson/test/suites/valid/negative-one/input b/3party/jansson/test/suites/valid/negative-one/input new file mode 100644 index 0000000000..2363a1ac08 --- /dev/null +++ b/3party/jansson/test/suites/valid/negative-one/input @@ -0,0 +1 @@ +[-1] diff --git a/3party/jansson/test/suites/valid/negative-one/output b/3party/jansson/test/suites/valid/negative-one/output new file mode 100644 index 0000000000..99d21a2a0f --- /dev/null +++ b/3party/jansson/test/suites/valid/negative-one/output @@ -0,0 +1 @@ +[-1] \ No newline at end of file diff --git a/3party/jansson/test/suites/valid/negative-zero/input b/3party/jansson/test/suites/valid/negative-zero/input new file mode 100644 index 0000000000..40fc49c715 --- /dev/null +++ b/3party/jansson/test/suites/valid/negative-zero/input @@ -0,0 +1 @@ +[-0] diff --git a/3party/jansson/test/suites/valid/negative-zero/output b/3party/jansson/test/suites/valid/negative-zero/output new file mode 100644 index 0000000000..6e7ea636ee --- /dev/null +++ b/3party/jansson/test/suites/valid/negative-zero/output @@ -0,0 +1 @@ +[0] \ No newline at end of file diff --git a/3party/jansson/test/suites/valid/null/input b/3party/jansson/test/suites/valid/null/input new file mode 100644 index 0000000000..62864b313d --- /dev/null +++ b/3party/jansson/test/suites/valid/null/input @@ -0,0 +1 @@ +[null] diff --git a/3party/jansson/test/suites/valid/null/output b/3party/jansson/test/suites/valid/null/output new file mode 100644 index 0000000000..500db4a86a --- /dev/null +++ b/3party/jansson/test/suites/valid/null/output @@ -0,0 +1 @@ +[null] \ No newline at end of file diff --git a/3party/jansson/test/suites/valid/one-byte-utf-8/input b/3party/jansson/test/suites/valid/one-byte-utf-8/input new file mode 100644 index 0000000000..8bda4685d4 --- /dev/null +++ b/3party/jansson/test/suites/valid/one-byte-utf-8/input @@ -0,0 +1 @@ +["\u002c one-byte UTF-8"] diff --git a/3party/jansson/test/suites/valid/one-byte-utf-8/output b/3party/jansson/test/suites/valid/one-byte-utf-8/output new file mode 100644 index 0000000000..c33d250ff7 --- /dev/null +++ b/3party/jansson/test/suites/valid/one-byte-utf-8/output @@ -0,0 +1 @@ +[", one-byte UTF-8"] \ No newline at end of file diff --git a/3party/jansson/test/suites/valid/real-capital-e-negative-exponent/input b/3party/jansson/test/suites/valid/real-capital-e-negative-exponent/input new file mode 100644 index 0000000000..1e9fa51537 --- /dev/null +++ b/3party/jansson/test/suites/valid/real-capital-e-negative-exponent/input @@ -0,0 +1 @@ +[1E-2] diff --git a/3party/jansson/test/suites/valid/real-capital-e-negative-exponent/output b/3party/jansson/test/suites/valid/real-capital-e-negative-exponent/output new file mode 100644 index 0000000000..75b9ef92cd --- /dev/null +++ b/3party/jansson/test/suites/valid/real-capital-e-negative-exponent/output @@ -0,0 +1 @@ +[0.01] \ No newline at end of file diff --git a/3party/jansson/test/suites/valid/real-capital-e-positive-exponent/input b/3party/jansson/test/suites/valid/real-capital-e-positive-exponent/input new file mode 100644 index 0000000000..6a6ab93371 --- /dev/null +++ b/3party/jansson/test/suites/valid/real-capital-e-positive-exponent/input @@ -0,0 +1 @@ +[1E+2] diff --git a/3party/jansson/test/suites/valid/real-capital-e-positive-exponent/output b/3party/jansson/test/suites/valid/real-capital-e-positive-exponent/output new file mode 100644 index 0000000000..d8ff702a11 --- /dev/null +++ b/3party/jansson/test/suites/valid/real-capital-e-positive-exponent/output @@ -0,0 +1 @@ +[100.0] \ No newline at end of file diff --git a/3party/jansson/test/suites/valid/real-capital-e/input b/3party/jansson/test/suites/valid/real-capital-e/input new file mode 100644 index 0000000000..e70322356c --- /dev/null +++ b/3party/jansson/test/suites/valid/real-capital-e/input @@ -0,0 +1 @@ +[1E22] diff --git a/3party/jansson/test/suites/valid/real-capital-e/output b/3party/jansson/test/suites/valid/real-capital-e/output new file mode 100644 index 0000000000..9a739f21fd --- /dev/null +++ b/3party/jansson/test/suites/valid/real-capital-e/output @@ -0,0 +1 @@ +[1e22] \ No newline at end of file diff --git a/3party/jansson/test/suites/valid/real-exponent/input b/3party/jansson/test/suites/valid/real-exponent/input new file mode 100644 index 0000000000..b2a69b9a35 --- /dev/null +++ b/3party/jansson/test/suites/valid/real-exponent/input @@ -0,0 +1 @@ +[123e45] diff --git a/3party/jansson/test/suites/valid/real-exponent/output b/3party/jansson/test/suites/valid/real-exponent/output new file mode 100644 index 0000000000..5ffc7196db --- /dev/null +++ b/3party/jansson/test/suites/valid/real-exponent/output @@ -0,0 +1 @@ +[1.2299999999999999e47] \ No newline at end of file diff --git a/3party/jansson/test/suites/valid/real-fraction-exponent/input b/3party/jansson/test/suites/valid/real-fraction-exponent/input new file mode 100644 index 0000000000..0c1660d1e9 --- /dev/null +++ b/3party/jansson/test/suites/valid/real-fraction-exponent/input @@ -0,0 +1 @@ +[123.456e78] diff --git a/3party/jansson/test/suites/valid/real-fraction-exponent/output b/3party/jansson/test/suites/valid/real-fraction-exponent/output new file mode 100644 index 0000000000..66a3c81864 --- /dev/null +++ b/3party/jansson/test/suites/valid/real-fraction-exponent/output @@ -0,0 +1 @@ +[1.23456e80] \ No newline at end of file diff --git a/3party/jansson/test/suites/valid/real-negative-exponent/input b/3party/jansson/test/suites/valid/real-negative-exponent/input new file mode 100644 index 0000000000..daa4af932b --- /dev/null +++ b/3party/jansson/test/suites/valid/real-negative-exponent/input @@ -0,0 +1 @@ +[1e-2] diff --git a/3party/jansson/test/suites/valid/real-negative-exponent/output b/3party/jansson/test/suites/valid/real-negative-exponent/output new file mode 100644 index 0000000000..75b9ef92cd --- /dev/null +++ b/3party/jansson/test/suites/valid/real-negative-exponent/output @@ -0,0 +1 @@ +[0.01] \ No newline at end of file diff --git a/3party/jansson/test/suites/valid/real-positive-exponent/input b/3party/jansson/test/suites/valid/real-positive-exponent/input new file mode 100644 index 0000000000..f3780773a9 --- /dev/null +++ b/3party/jansson/test/suites/valid/real-positive-exponent/input @@ -0,0 +1 @@ +[1e+2] diff --git a/3party/jansson/test/suites/valid/real-positive-exponent/output b/3party/jansson/test/suites/valid/real-positive-exponent/output new file mode 100644 index 0000000000..d8ff702a11 --- /dev/null +++ b/3party/jansson/test/suites/valid/real-positive-exponent/output @@ -0,0 +1 @@ +[100.0] \ No newline at end of file diff --git a/3party/jansson/test/suites/valid/real-subnormal-number/input b/3party/jansson/test/suites/valid/real-subnormal-number/input new file mode 100644 index 0000000000..df6065345c --- /dev/null +++ b/3party/jansson/test/suites/valid/real-subnormal-number/input @@ -0,0 +1 @@ +[1.8011670033376514e-308] diff --git a/3party/jansson/test/suites/valid/real-subnormal-number/output b/3party/jansson/test/suites/valid/real-subnormal-number/output new file mode 100644 index 0000000000..e6b0a58e8b --- /dev/null +++ b/3party/jansson/test/suites/valid/real-subnormal-number/output @@ -0,0 +1 @@ +[1.8011670033376514e-308] \ No newline at end of file diff --git a/3party/jansson/test/suites/valid/real-underflow/input b/3party/jansson/test/suites/valid/real-underflow/input new file mode 100644 index 0000000000..dc709960a1 --- /dev/null +++ b/3party/jansson/test/suites/valid/real-underflow/input @@ -0,0 +1 @@ +[123e-10000000] diff --git a/3party/jansson/test/suites/valid/real-underflow/output b/3party/jansson/test/suites/valid/real-underflow/output new file mode 100644 index 0000000000..92df1df1d1 --- /dev/null +++ b/3party/jansson/test/suites/valid/real-underflow/output @@ -0,0 +1 @@ +[0.0] \ No newline at end of file diff --git a/3party/jansson/test/suites/valid/run b/3party/jansson/test/suites/valid/run new file mode 100755 index 0000000000..d995489601 --- /dev/null +++ b/3party/jansson/test/suites/valid/run @@ -0,0 +1,56 @@ +#!/bin/sh +# +# Copyright (c) 2009-2016 Petri Lehtinen +# +# Jansson is free software; you can redistribute it and/or modify +# it under the terms of the MIT license. See LICENSE for details. + +JSON_SORT_KEYS=1 +export JSON_SORT_KEYS + +is_test() { + test -d $test_path +} + +do_run() { + variant=$1 + s=".$1" + + strip=0 + [ "$variant" = "strip" ] && strip=1 + + STRIP=$strip $json_process --env \ + <$test_path/input >$test_log/stdout$s 2>$test_log/stderr$s + valgrind_check $test_log/stderr$s || return 1 + + ref=output + [ -f $test_path/output$s ] && ref=output$s + + if ! cmp -s $test_path/$ref $test_log/stdout$s; then + echo $variant > $test_log/variant + return 1 + fi +} + +run_test() { + do_run normal && do_run strip +} + +show_error() { + valgrind_show_error && return + + read variant < $test_log/variant + s=".$variant" + + echo "VARIANT: $variant" + + echo "EXPECTED OUTPUT:" + ref=output + [ -f $test_path/output$s ] && ref=output$s + nl -bn $test_path/$ref + + echo "ACTUAL OUTPUT:" + nl -bn $test_log/stdout$s +} + +. $top_srcdir/test/scripts/run-tests.sh diff --git a/3party/jansson/test/suites/valid/short-string/input b/3party/jansson/test/suites/valid/short-string/input new file mode 100644 index 0000000000..0c3426d4c2 --- /dev/null +++ b/3party/jansson/test/suites/valid/short-string/input @@ -0,0 +1 @@ +["a"] diff --git a/3party/jansson/test/suites/valid/short-string/output b/3party/jansson/test/suites/valid/short-string/output new file mode 100644 index 0000000000..eac5f7b46e --- /dev/null +++ b/3party/jansson/test/suites/valid/short-string/output @@ -0,0 +1 @@ +["a"] \ No newline at end of file diff --git a/3party/jansson/test/suites/valid/simple-ascii-string/input b/3party/jansson/test/suites/valid/simple-ascii-string/input new file mode 100644 index 0000000000..929b215c17 --- /dev/null +++ b/3party/jansson/test/suites/valid/simple-ascii-string/input @@ -0,0 +1 @@ +["abcdefghijklmnopqrstuvwxyz1234567890 "] diff --git a/3party/jansson/test/suites/valid/simple-ascii-string/output b/3party/jansson/test/suites/valid/simple-ascii-string/output new file mode 100644 index 0000000000..90358ab703 --- /dev/null +++ b/3party/jansson/test/suites/valid/simple-ascii-string/output @@ -0,0 +1 @@ +["abcdefghijklmnopqrstuvwxyz1234567890 "] \ No newline at end of file diff --git a/3party/jansson/test/suites/valid/simple-int-0/input b/3party/jansson/test/suites/valid/simple-int-0/input new file mode 100644 index 0000000000..111bb86865 --- /dev/null +++ b/3party/jansson/test/suites/valid/simple-int-0/input @@ -0,0 +1 @@ +[0] diff --git a/3party/jansson/test/suites/valid/simple-int-0/output b/3party/jansson/test/suites/valid/simple-int-0/output new file mode 100644 index 0000000000..6e7ea636ee --- /dev/null +++ b/3party/jansson/test/suites/valid/simple-int-0/output @@ -0,0 +1 @@ +[0] \ No newline at end of file diff --git a/3party/jansson/test/suites/valid/simple-int-1/input b/3party/jansson/test/suites/valid/simple-int-1/input new file mode 100644 index 0000000000..7660873d10 --- /dev/null +++ b/3party/jansson/test/suites/valid/simple-int-1/input @@ -0,0 +1 @@ +[1] diff --git a/3party/jansson/test/suites/valid/simple-int-1/output b/3party/jansson/test/suites/valid/simple-int-1/output new file mode 100644 index 0000000000..bace2a0be1 --- /dev/null +++ b/3party/jansson/test/suites/valid/simple-int-1/output @@ -0,0 +1 @@ +[1] \ No newline at end of file diff --git a/3party/jansson/test/suites/valid/simple-int-123/input b/3party/jansson/test/suites/valid/simple-int-123/input new file mode 100644 index 0000000000..3214bfe58c --- /dev/null +++ b/3party/jansson/test/suites/valid/simple-int-123/input @@ -0,0 +1 @@ +[123] diff --git a/3party/jansson/test/suites/valid/simple-int-123/output b/3party/jansson/test/suites/valid/simple-int-123/output new file mode 100644 index 0000000000..e47f69afcf --- /dev/null +++ b/3party/jansson/test/suites/valid/simple-int-123/output @@ -0,0 +1 @@ +[123] \ No newline at end of file diff --git a/3party/jansson/test/suites/valid/simple-object/input b/3party/jansson/test/suites/valid/simple-object/input new file mode 100644 index 0000000000..a34fb4907e --- /dev/null +++ b/3party/jansson/test/suites/valid/simple-object/input @@ -0,0 +1 @@ +{"a":[]} diff --git a/3party/jansson/test/suites/valid/simple-object/output b/3party/jansson/test/suites/valid/simple-object/output new file mode 100644 index 0000000000..982abe8262 --- /dev/null +++ b/3party/jansson/test/suites/valid/simple-object/output @@ -0,0 +1 @@ +{"a": []} \ No newline at end of file diff --git a/3party/jansson/test/suites/valid/simple-real/input b/3party/jansson/test/suites/valid/simple-real/input new file mode 100644 index 0000000000..0fed7df36a --- /dev/null +++ b/3party/jansson/test/suites/valid/simple-real/input @@ -0,0 +1 @@ +[123.456789] diff --git a/3party/jansson/test/suites/valid/simple-real/output b/3party/jansson/test/suites/valid/simple-real/output new file mode 100644 index 0000000000..b02878e5fc --- /dev/null +++ b/3party/jansson/test/suites/valid/simple-real/output @@ -0,0 +1 @@ +[123.456789] \ No newline at end of file diff --git a/3party/jansson/test/suites/valid/string-escapes/input b/3party/jansson/test/suites/valid/string-escapes/input new file mode 100644 index 0000000000..d994564d3f --- /dev/null +++ b/3party/jansson/test/suites/valid/string-escapes/input @@ -0,0 +1 @@ +["\"\\\/\b\f\n\r\t"] diff --git a/3party/jansson/test/suites/valid/string-escapes/output b/3party/jansson/test/suites/valid/string-escapes/output new file mode 100644 index 0000000000..ca5c1c6583 --- /dev/null +++ b/3party/jansson/test/suites/valid/string-escapes/output @@ -0,0 +1 @@ +["\"\\/\b\f\n\r\t"] \ No newline at end of file diff --git a/3party/jansson/test/suites/valid/three-byte-utf-8/input b/3party/jansson/test/suites/valid/three-byte-utf-8/input new file mode 100644 index 0000000000..ccc0bfa572 --- /dev/null +++ b/3party/jansson/test/suites/valid/three-byte-utf-8/input @@ -0,0 +1 @@ +["\u0821 three-byte UTF-8"] diff --git a/3party/jansson/test/suites/valid/three-byte-utf-8/output b/3party/jansson/test/suites/valid/three-byte-utf-8/output new file mode 100644 index 0000000000..c44d124e75 --- /dev/null +++ b/3party/jansson/test/suites/valid/three-byte-utf-8/output @@ -0,0 +1 @@ +["à ¡ three-byte UTF-8"] \ No newline at end of file diff --git a/3party/jansson/test/suites/valid/true/input b/3party/jansson/test/suites/valid/true/input new file mode 100644 index 0000000000..29513c4917 --- /dev/null +++ b/3party/jansson/test/suites/valid/true/input @@ -0,0 +1 @@ +[true] diff --git a/3party/jansson/test/suites/valid/true/output b/3party/jansson/test/suites/valid/true/output new file mode 100644 index 0000000000..de601e305f --- /dev/null +++ b/3party/jansson/test/suites/valid/true/output @@ -0,0 +1 @@ +[true] \ No newline at end of file diff --git a/3party/jansson/test/suites/valid/two-byte-utf-8/input b/3party/jansson/test/suites/valid/two-byte-utf-8/input new file mode 100644 index 0000000000..05ae854b52 --- /dev/null +++ b/3party/jansson/test/suites/valid/two-byte-utf-8/input @@ -0,0 +1 @@ +["\u0123 two-byte UTF-8"] diff --git a/3party/jansson/test/suites/valid/two-byte-utf-8/output b/3party/jansson/test/suites/valid/two-byte-utf-8/output new file mode 100644 index 0000000000..1f0988d945 --- /dev/null +++ b/3party/jansson/test/suites/valid/two-byte-utf-8/output @@ -0,0 +1 @@ +["Ä£ two-byte UTF-8"] \ No newline at end of file diff --git a/3party/jansson/test/suites/valid/utf-8-string/input b/3party/jansson/test/suites/valid/utf-8-string/input new file mode 100644 index 0000000000..20dc64a45c --- /dev/null +++ b/3party/jansson/test/suites/valid/utf-8-string/input @@ -0,0 +1 @@ +["€þıœəßð some utf-8 ĸʒ×ŋµåäöð„ž"] diff --git a/3party/jansson/test/suites/valid/utf-8-string/output b/3party/jansson/test/suites/valid/utf-8-string/output new file mode 100644 index 0000000000..53728650da --- /dev/null +++ b/3party/jansson/test/suites/valid/utf-8-string/output @@ -0,0 +1 @@ +["€þıœəßð some utf-8 ĸʒ×ŋµåäöð„ž"] \ No newline at end of file diff --git a/3party/jansson/test/suites/valid/utf-surrogate-four-byte-encoding/input b/3party/jansson/test/suites/valid/utf-surrogate-four-byte-encoding/input new file mode 100644 index 0000000000..c598b41723 --- /dev/null +++ b/3party/jansson/test/suites/valid/utf-surrogate-four-byte-encoding/input @@ -0,0 +1 @@ +["\uD834\uDD1E surrogate, four-byte UTF-8"] diff --git a/3party/jansson/test/suites/valid/utf-surrogate-four-byte-encoding/output b/3party/jansson/test/suites/valid/utf-surrogate-four-byte-encoding/output new file mode 100644 index 0000000000..fa806d2544 --- /dev/null +++ b/3party/jansson/test/suites/valid/utf-surrogate-four-byte-encoding/output @@ -0,0 +1 @@ +["ð„ž surrogate, four-byte UTF-8"] \ No newline at end of file diff --git a/3party/liboauthcpp/src/SHA1.cpp b/3party/liboauthcpp/src/SHA1.cpp index b6ac955227..ce1ba683e6 100644 --- a/3party/liboauthcpp/src/SHA1.cpp +++ b/3party/liboauthcpp/src/SHA1.cpp @@ -246,23 +246,23 @@ void CSHA1::ReportHash(char *szReport, unsigned char uReportType) if(uReportType == REPORT_HEX) { - snprintf(szTemp, sizeof(szTemp), "%02X", m_digest[0]); + sprintf(szTemp, "%02X", m_digest[0]); strcat(szReport, szTemp); for(i = 1; i < 20; i++) { - snprintf(szTemp, sizeof(szTemp), " %02X", m_digest[i]); + sprintf(szTemp, " %02X", m_digest[i]); strcat(szReport, szTemp); } } else if(uReportType == REPORT_DIGIT) { - snprintf(szTemp, sizeof(szTemp), "%u", m_digest[0]); + sprintf(szTemp, "%u", m_digest[0]); strcat(szReport, szTemp); for(i = 1; i < 20; i++) { - snprintf(szTemp, sizeof(szTemp), " %u", m_digest[i]); + sprintf(szTemp, " %u", m_digest[i]); strcat(szReport, szTemp); } } diff --git a/3party/liboauthcpp/src/liboauthcpp.cpp b/3party/liboauthcpp/src/liboauthcpp.cpp index 8850b7f25f..c269100b6e 100644 --- a/3party/liboauthcpp/src/liboauthcpp.cpp +++ b/3party/liboauthcpp/src/liboauthcpp.cpp @@ -235,8 +235,8 @@ void Client::generateNonceTimeStamp() // both values makes life easier because generating a signature is // idempotent -- otherwise using macros can cause double evaluation and // incorrect results because of repeated calls to rand(). - snprintf( szRand, sizeof(szRand), "%x", ((testingTimestamp != 0) ? testingNonce : rand()) ); - snprintf( szTime, sizeof(szTime), "%ld", ((testingTimestamp != 0) ? testingTimestamp : time( NULL )) ); + sprintf( szRand, "%x", ((testingTimestamp != 0) ? testingNonce : rand()) ); + sprintf( szTime, "%ld", ((testingTimestamp != 0) ? testingTimestamp : time( NULL )) ); m_nonce.assign( szTime ); m_nonce.append( szRand ); diff --git a/3party/opening_hours/opening_hours_integration_tests/CMakeLists.txt b/3party/opening_hours/opening_hours_integration_tests/CMakeLists.txt index 86c37a89a9..f099d549a1 100644 --- a/3party/opening_hours/opening_hours_integration_tests/CMakeLists.txt +++ b/3party/opening_hours/opening_hours_integration_tests/CMakeLists.txt @@ -5,11 +5,7 @@ set(SRC opening_hours_integration_tests.cpp) omim_add_executable(${PROJECT_NAME} ${SRC}) target_link_libraries(${PROJECT_NAME} opening_hours) -# Silence boost::test warnings. -target_compile_options(${PROJECT_NAME} PRIVATE - $<$:-Wno-deprecated-declarations> - $<$:-Wno-unused-but-set-variable> -) + if(${CMAKE_SYSTEM_NAME} MATCHES "Linux") set(COPY_CMD cp -u) diff --git a/3party/opening_hours/opening_hours_supported_features_tests/CMakeLists.txt b/3party/opening_hours/opening_hours_supported_features_tests/CMakeLists.txt index 5b2ca661e6..5a9dc48611 100644 --- a/3party/opening_hours/opening_hours_supported_features_tests/CMakeLists.txt +++ b/3party/opening_hours/opening_hours_supported_features_tests/CMakeLists.txt @@ -5,8 +5,3 @@ set(SRC opening_hours_supported_features_tests.cpp) omim_add_executable(${PROJECT_NAME} ${SRC}) target_link_libraries(${PROJECT_NAME} opening_hours) -# Silence boost::test warnings. -target_compile_options(${PROJECT_NAME} PRIVATE - $<$:-Wno-deprecated-declarations> - $<$:-Wno-unused-but-set-variable> -) diff --git a/3party/opening_hours/opening_hours_tests/CMakeLists.txt b/3party/opening_hours/opening_hours_tests/CMakeLists.txt index 66369a779a..0de6e64410 100644 --- a/3party/opening_hours/opening_hours_tests/CMakeLists.txt +++ b/3party/opening_hours/opening_hours_tests/CMakeLists.txt @@ -5,8 +5,3 @@ set(SRC opening_hours_tests.cpp) omim_add_executable(${PROJECT_NAME} ${SRC}) target_link_libraries(${PROJECT_NAME} opening_hours) -# Silence boost::test warnings. -target_compile_options(${PROJECT_NAME} PRIVATE - $<$:-Wno-deprecated-declarations> - $<$:-Wno-unused-but-set-variable> -) diff --git a/3party/protobuf/CMakeLists.txt b/3party/protobuf/CMakeLists.txt index 58e6a1d0bb..c31682f0c2 100644 --- a/3party/protobuf/CMakeLists.txt +++ b/3party/protobuf/CMakeLists.txt @@ -38,6 +38,5 @@ endif () target_compile_options(${PROJECT_NAME} PRIVATE $<$:-Wno-shorten-64-to-32> - $<$:-Wno-deprecated-declarations> - $<$>:-Wno-sign-compare> + -Wno-sign-compare ) diff --git a/3party/pugixml/CMakeLists.txt b/3party/pugixml/CMakeLists.txt index 6284a90516..d49d17cb44 100644 --- a/3party/pugixml/CMakeLists.txt +++ b/3party/pugixml/CMakeLists.txt @@ -4,8 +4,7 @@ set(SRC pugixml/src/pugiconfig.hpp pugixml/src/pugixml.cpp pugixml/src/pugixml.hpp + utils.hpp ) add_library(${PROJECT_NAME} ${SRC}) - -target_include_directories(${PROJECT_NAME} PUBLIC pugixml/src) diff --git a/3party/pugixml/pugixml b/3party/pugixml/pugixml index a0e0643363..effc46f0ed 160000 --- a/3party/pugixml/pugixml +++ b/3party/pugixml/pugixml @@ -1 +1 @@ -Subproject commit a0e064336317c9347a91224112af9933598714e9 +Subproject commit effc46f0ed35a70a53db7f56e37141ae3cb3a92a diff --git a/3party/pugixml/utils.hpp b/3party/pugixml/utils.hpp new file mode 100644 index 0000000000..7d53b88a22 --- /dev/null +++ b/3party/pugixml/utils.hpp @@ -0,0 +1,28 @@ +#pragma once + +#include "pugixml/src/pugixml.hpp" + +#include +#include +#include + +namespace pugi +{ +template +inline std::string XMLToString(pugi::xml_node const & n, Args &&... args) +{ + std::ostringstream sstr; + n.print(sstr, std::forward(args)...); + return sstr.str(); +} + +inline std::string DebugPrint(pugi::xml_node const & n) +{ + return XMLToString(n); +} + +inline std::string DebugPrint(pugi::xml_document const & n) +{ + return DebugPrint(dynamic_cast(n)); +} +} // namespace pugi diff --git a/3party/stb_image/stb_image_write.h b/3party/stb_image/stb_image_write.h index 151eacaacd..e4b32ed1bc 100644 --- a/3party/stb_image/stb_image_write.h +++ b/3party/stb_image/stb_image_write.h @@ -773,7 +773,7 @@ static int stbi_write_hdr_core(stbi__write_context *s, int x, int y, int comp, f #ifdef __STDC_LIB_EXT1__ len = sprintf_s(buffer, sizeof(buffer), "EXPOSURE= 1.0000000000000\n\n-Y %d +X %d\n", y, x); #else - len = snprintf(buffer, sizeof(buffer), "EXPOSURE= 1.0000000000000\n\n-Y %d +X %d\n", y, x); + len = sprintf(buffer, "EXPOSURE= 1.0000000000000\n\n-Y %d +X %d\n", y, x); #endif s->func(s->context, buffer, len); diff --git a/CMakeLists.txt b/CMakeLists.txt index 2fc9a7f12a..47c02e373f 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -20,39 +20,22 @@ if (APPLE AND NOT ("${CMAKE_SYSTEM_NAME}" STREQUAL Android)) set(CMAKE_OBJCXX_FLAGS -fobjc-arc) endif() -message(STATUS "Using compiler ${CMAKE_CXX_COMPILER_ID} ${CMAKE_CXX_COMPILER_VERSION}") +message("Using compiler ${CMAKE_CXX_COMPILER_ID} ${CMAKE_CXX_COMPILER_VERSION}") option(UNITY_DISABLE "Disable unity build" OFF) -if (NOT UNITY_DISABLE AND NOT DEFINED ENV{UNITY_DISABLE}) + +if (NOT UNITY_DISABLE) + message("Using unity builds, pass -DUNITY_DISABLE=ON to disable it.") set(CMAKE_UNITY_BUILD ON) - if (DEFINED ENV{UNITY_BUILD_BATCH_SIZE}) - set(CMAKE_UNITY_BUILD_BATCH_SIZE $ENV{UNITY_BUILD_BATCH_SIZE}) - else() - set(CMAKE_UNITY_BUILD_BATCH_SIZE 50) - endif() - message(STATUS "Using Unity Build with batch ${CMAKE_UNITY_BUILD_BATCH_SIZE}, export UNITY_DISABLE=1 or use -DUNITY_DISABLE=ON to disable it.") + set(CMAKE_UNITY_BUILD_BATCH_SIZE 50) endif() -option(CCACHE_DISABLE "Disable ccache" OFF) -if (NOT CCACHE_DISABLE AND NOT DEFINED ENV{CCACHE_DISABLE}) - find_program(CCACHE_PROGRAM ccache HINTS /usr/local/bin/) - if (CCACHE_PROGRAM) - message(STATUS "Using ccache, export CCACHE_DISABLE=1 or use -DCCACHE_DISABLE=ON to disable it.") - set_property(GLOBAL PROPERTY RULE_LAUNCH_COMPILE "${CCACHE_PROGRAM}") - set_property(GLOBAL PROPERTY RULE_LAUNCH_LINK "${CCACHE_PROGRAM}") - set(CMAKE_C_COMPILER_LAUNCHER "${CCACHE_PROGRAM}") - set(CMAKE_CXX_COMPILER_LAUNCHER "${CCACHE_PROGRAM}") - endif() -endif() - -option(COLORS_DISABLE "Disable colored compiler output" OFF) -if (NOT DEFINED ENV{COLORS_DISABLE} AND CMAKE_CXX_COMPILER_ID MATCHES "GNU|Clang") - message(STATUS "export COLORS_DISABLE=1 or use -DCOLORS_DISABLE=ON to disable colored compiler output.") +if (NOT (DEFINED ENV{COLORS_DISABLE}) AND CMAKE_CXX_COMPILER_ID MATCHES "GNU|Clang") + message("export COLORS_DISABLE=1 to disable colored compiler output.") add_compile_options($<$:-fdiagnostics-color=always> $<$:-fcolor-diagnostics>) add_link_options($<$:-fdiagnostics-color=always> $<$:-fcolor-diagnostics>) endif() -option(WITH_SYSTEM_PROVIDED_3PARTY "Enable compilation with system provided dependencies" OFF) set(OMIM_ROOT ${CMAKE_SOURCE_DIR}) set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${OMIM_ROOT}/cmake") @@ -115,7 +98,7 @@ else() message(FATAL_ERROR "Unknown build type: " ${CMAKE_BUILD_TYPE}) endif() -message(STATUS "Build type: " ${CMAKE_BUILD_TYPE}) +message("Build type: " ${CMAKE_BUILD_TYPE}) # End of setting build type # Options @@ -123,7 +106,7 @@ message(STATUS "Build type: " ${CMAKE_BUILD_TYPE}) # Call `make package` after cmake to build design tool. option(BUILD_DESIGNER "Build application as design tool" OFF) if (BUILD_DESIGNER) - message(STATUS "Designer tool building is enabled") + message("Designer tool building is enabled") add_definitions(-DBUILD_DESIGNER) endif() @@ -138,7 +121,7 @@ option(USE_PCH "Use precompiled headers" OFF) option(NJOBS "Number of parallel processes" OFF) if (NJOBS) - message(STATUS "Number of parallel processes: ${NJOBS}") + message("Number of parallel processes: ${NJOBS}") set(CMAKE_JOB_POOLS custom=${NJOBS}) set(CMAKE_JOB_POOL_COMPILE custom) set(CMAKE_JOB_POOL_LINK custom) @@ -163,11 +146,11 @@ if (PLATFORM_LINUX) endif() if (USE_ASAN) - message(STATUS "Address Sanitizer is enabled") + message("Address Sanitizer is enabled") endif() if (USE_TSAN) - message(STATUS "Thread Sanitizer is enabled") + message("Thread Sanitizer is enabled") endif() if (USE_ASAN AND USE_TSAN) @@ -175,16 +158,16 @@ if (USE_ASAN AND USE_TSAN) endif() if (USE_LIBFUZZER) - message(STATUS "LibFuzzer is enabled") + message("LibFuzzer is enabled") endif() if (USE_PPROF) - message(STATUS "Google Profiler is enabled") + message("Google Profiler is enabled") add_definitions(-DUSE_PPROF) endif() if (USE_HEAPPROF) - message(STATUS "Heap Profiler is enabled") + message("Heap Profiler is enabled") endif() set(CMAKE_POSITION_INDEPENDENT_CODE ON) @@ -193,6 +176,17 @@ set(CMAKE_POSITION_INDEPENDENT_CODE ON) set(EXECUTABLE_OUTPUT_PATH ${CMAKE_CURRENT_BINARY_DIR}) set(LIBRARY_OUTPUT_PATH ${CMAKE_CURRENT_BINARY_DIR}) +if (NOT (DEFINED ENV{CCACHE_DISABLE})) + find_program(CCACHE_PROGRAM ccache HINTS /usr/local/bin/) + if (CCACHE_PROGRAM) + message("Using ccache, export CCACHE_DISABLE=1 to disable it.") + set_property(GLOBAL PROPERTY RULE_LAUNCH_COMPILE "${CCACHE_PROGRAM}") + set_property(GLOBAL PROPERTY RULE_LAUNCH_LINK "${CCACHE_PROGRAM}") + set(CMAKE_C_COMPILER_LAUNCHER "${CCACHE_PROGRAM}") + set(CMAKE_CXX_COMPILER_LAUNCHER "${CCACHE_PROGRAM}") + endif() +endif() + if (PLATFORM_LINUX OR PLATFORM_ANDROID) find_program(LLD_FOUND ld.lld) if (LLD_FOUND) @@ -240,13 +234,8 @@ if (NOT PLATFORM_IPHONE AND NOT PLATFORM_ANDROID) if (NOT SKIP_DESKTOP) list(APPEND qt_components Gui Xml Svg) endif() - if (DEFINED ENV{HOMEBREW_PREFIX}) - set(HOMEBREW_PREFIX $ENV{HOMEBREW_PREFIX}) - else() - set(HOMEBREW_PREFIX /opt/homebrew) - endif() # PATHS are hard-coded hints where to look for qt5 in addition to other places. - find_package(Qt5 COMPONENTS REQUIRED ${qt_components} PATHS $ENV{QT_PATH} ${HOMEBREW_PREFIX}/opt/qt@5 /usr/local/opt/qt@5 /usr/lib/x86_64-linux-gnu/qt5) + find_package(Qt5 COMPONENTS REQUIRED ${qt_components} PATHS $ENV{QT_PATH} /opt/homebrew/opt/qt@5 /usr/local/opt/qt@5 /usr/lib/x86_64-linux-gnu/qt5) if (Qt5_VERSION VERSION_LESS 5.5.0) message(FATAL_ERROR "Minimum supported Qt5 version is 5.5") endif() @@ -283,7 +272,7 @@ if (USE_LIBFUZZER) endif() if (USE_PCH) - message(STATUS "Precompiled headers are ON") + message("Precompiled headers are ON") set(OMIM_PCH_TARGET_NAME "omim_pch") add_precompiled_headers( ${OMIM_ROOT}/precompiled_headers.hpp @@ -292,41 +281,22 @@ if (USE_PCH) endif() # Include 3party dependencies. -if (NOT WITH_SYSTEM_PROVIDED_3PARTY) - # Configure expat library. - # Suppress "Policy CMP0077 is not set: option() honors normal variables" - # for the expat options below. - set(CMAKE_POLICY_DEFAULT_CMP0077 NEW) - set(EXPAT_BUILD_TOOLS OFF) - set(EXPAT_BUILD_EXAMPLES OFF) - set(EXPAT_BUILD_TESTS OFF) - set(EXPAT_BUILD_DOCS OFF) - set(EXPAT_BUILD_PKGCONFIG OFF) - set(EXPAT_ENABLE_INSTALL OFF) - set(EXPAT_SHARED_LIBS OFF) - add_subdirectory(3party/expat/expat) - - # Configure Jansson library. - set(JANSSON_BUILD_DOCS OFF) - set(JANSSON_BUILD_MAN OFF) - set(JANSSON_EXAMPLES OFF) - set(JANSSON_INSTALL OFF) - set(JANSSON_WITHOUT_TESTS ON) - add_subdirectory(3party/jansson/jansson/) - target_include_directories(jansson INTERFACE "${PROJECT_BINARY_DIR}/3party/jansson/jansson/include") - - # Add pugixml library. - add_subdirectory(3party/pugixml) - - # Add protobuf library. - add_subdirectory(${OMIM_ROOT}/3party/protobuf) -endif() - +# Configure expat library. +# Suppress "Policy CMP0077 is not set: option() honors normal variables" +# for the expat options below. +set(CMAKE_POLICY_DEFAULT_CMP0077 NEW) +set(EXPAT_BUILD_TOOLS OFF) +set(EXPAT_BUILD_EXAMPLES OFF) +set(EXPAT_BUILD_TESTS OFF) +set(EXPAT_BUILD_DOCS OFF) +set(EXPAT_BUILD_PKGCONFIG OFF) +set(EXPAT_ENABLE_INSTALL OFF) +set(EXPAT_SHARED_LIBS OFF) +add_subdirectory(3party/expat/expat) add_subdirectory(3party/agg) add_subdirectory(3party/bsdiff-courgette) add_subdirectory(3party/gflags) -target_compile_options(gflags_nothreads_static PRIVATE $<$:-Wno-subobject-linkage>) # Not needed for the usual build process, but it fixes QtCreator editor, # that doesn't see gflags/gflags.h in binary dir (gflags has tricky cmake configuration). if (PLATFORM_DESKTOP) @@ -340,10 +310,11 @@ else() add_subdirectory(3party/freetype) add_subdirectory(3party/icu) endif() - +add_subdirectory(3party/jansson) add_subdirectory(3party/liboauthcpp) add_subdirectory(3party/minizip) add_subdirectory(3party/opening_hours) +add_subdirectory(3party/pugixml) add_subdirectory(3party/sdf_image) add_subdirectory(3party/stb_image) add_subdirectory(3party/succinct) @@ -354,9 +325,15 @@ if (PLATFORM_DESKTOP) add_subdirectory(3party/libtess2) endif() +# Only options related to warnings should be placed here. +# Other options should be set before all add_subdirectory calls. +add_compile_options( + "-Wall" +) + find_package(Python3 COMPONENTS Interpreter) if (Python3_Interpreter_FOUND) - message(STATUS "Found python to use in qt/, shaders/ and 3party/: ${Python3_EXECUTABLE}") + message("Found python to use in qt/, shaders/ and 3party/: ${Python3_EXECUTABLE}") else() message(FATAL_ERROR "Could not find python3 to use in qt/, shaders/ and 3party/.") endif() @@ -373,7 +350,6 @@ add_subdirectory(geometry) add_subdirectory(indexer) add_subdirectory(kml) add_subdirectory(map) -add_subdirectory(cppjansson) add_subdirectory(platform) add_subdirectory(routing) add_subdirectory(routing_common) diff --git a/CONTRIBUTORS b/CONTRIBUTORS index 67838d9f8b..28433b4209 100644 --- a/CONTRIBUTORS +++ b/CONTRIBUTORS @@ -64,8 +64,6 @@ Strings and translations: Karina Kordon Konstantin Pastbin Metehan Özyürek - Joan Montané - Luna Rose Project management: Alexander Matveenko diff --git a/README.md b/README.md index 3bd2cbe752..fa33cc7d2f 100644 --- a/README.md +++ b/README.md @@ -2,9 +2,7 @@ -[Organic Maps](https://organicmaps.app) is a free Android & iOS offline maps app for travelers, tourists, drivers, hikers, and cyclists. -It uses crowd-sourced [OpenStreetMap](https://www.openstreetmap.org) data and is developed with love by creators of **MapsWithMe** app (later renamed to **Maps.Me**) and by our community. -No ads, no tracking, no data collection, no crapware. Your [donations](https://organicmaps.app/donate/) and positive reviews motivate and inspire us, thanks â¤ï¸! +[Organic Maps](https://organicmaps.app) is a free Android & iOS offline maps app for travelers, tourists, hikers, and cyclists. It uses crowd-sourced OpenStreetMap data and is developed with love by **MapsWithMe** (**MapsMe**) founders and our community. No ads, no tracking, no data collection, no crapware. Your [donations](https://organicmaps.app/donate/) and positive reviews motivate and inspire us, thanks â¤ï¸!

@@ -117,8 +115,7 @@ See [GOVERNANCE](docs/GOVERNANCE.md). ## Contributing -If you want to build the project, check [docs/INSTALL.md](docs/INSTALL.md). If you want to help the project, -see [docs/CONTRIBUTING.md](docs/CONTRIBUTING.md) and read everything in the [docs folder](docs/) of the repository. +See [CONTRIBUTING](docs/CONTRIBUTING.md) and read everything in the [docs folder](docs/) of the repository. ## Beta @@ -139,10 +136,7 @@ and [Google Play](https://play.google.com/store/apps/details?id=app.organicmaps) - ПриÑоединÑйтеÑÑŒ к нашей [руÑÑкоÑзычной группе в Telegram](https://t.me/OrganicMapsRu) Ð´Ð»Ñ Ð¾Ð±Ñ€Ð°Ñ‚Ð½Ð¾Ð¹ ÑвÑзи и помощи. - DiÄŸer kullanıcılarla tartışmak için [Telegram Grubumuza](https://t.me/OrganicMapsTR) katılın. - Contact us by [email](mailto:hello@organicmaps.app). -- Follow our updates in -[Mastodon](https://fosstodon.org/@organicmaps), -[Facebook](https://facebook.com/OrganicMaps), -[Twitter](https://twitter.com/OrganicMapsApp), +- Follow our updates in [Facebook](https://facebook.com/OrganicMaps), [Twitter](https://twitter.com/OrganicMapsApp), [Instagram](https://instagram.com/organicmaps.app/). - Güncellemelerimizi [Instagram](https://instagram.com/organicmapstr/) üzerinden takip edin. diff --git a/android/AndroidManifest.xml b/android/AndroidManifest.xml index 1463b1d67d..a6f668f580 100644 --- a/android/AndroidManifest.xml +++ b/android/AndroidManifest.xml @@ -1,7 +1,7 @@ + @@ -58,16 +59,16 @@ android:dataExtractionRules="@xml/backup_content_v31" android:icon="@mipmap/ic_launcher" android:label="@string/app_name" - android:localeConfig="@xml/locales_config" android:theme="@style/MwmTheme" android:supportsRtl="true" - android:networkSecurityConfig="@xml/network_security_config" - tools:targetApi="t"> + android:networkSecurityConfig="@xml/network_security_config"> + @@ -75,6 +76,14 @@ + + + + + + + + @@ -85,9 +94,8 @@ - + - @@ -96,9 +104,8 @@ - + - @@ -551,9 +558,24 @@ - - - + + + + + + + + + + + + + + @@ -569,14 +591,22 @@ - - - - - - - - + + + + + + + + + + + + @@ -584,47 +614,69 @@ - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -633,90 +685,90 @@ + android:parentActivityName="com.mapswithme.maps.MwmActivity" /> - + + android:name="com.mapswithme.maps.editor.ProfileActivity" + android:parentActivityName="com.mapswithme.maps.settings.SettingsActivity" /> + android:name="com.mapswithme.maps.editor.FeatureCategoryActivity" + android:parentActivityName="com.mapswithme.maps.MwmActivity" /> + android:name="com.mapswithme.maps.editor.ReportActivity" + android:parentActivityName="com.mapswithme.maps.MwmActivity" /> + android:name="com.mapswithme.maps.editor.OsmLoginActivity" + android:parentActivityName="com.mapswithme.maps.MwmActivity" /> diff --git a/android/build.gradle b/android/build.gradle index 9aab4e47f5..b496f39967 100644 --- a/android/build.gradle +++ b/android/build.gradle @@ -26,7 +26,8 @@ buildscript { ext.googleFirebaseServicesEnabled = project.hasProperty('firebase') ?: googleFirebaseServicesDefault dependencies { - classpath 'com.android.tools.build:gradle:7.3.1' + classpath 'com.android.tools:r8:3.3.28' + classpath 'com.android.tools.build:gradle:7.2.1' if (googleMobileServicesEnabled) { println("Building with Google Mobile Services") @@ -44,7 +45,7 @@ buildscript { } classpath("com.github.triplet.gradle:play-publisher:3.7.0") - classpath("ru.cian:huawei-publish-gradle-plugin:1.3.5") + classpath("ru.cian:huawei-publish-gradle-plugin:1.3.3") } } @@ -69,42 +70,32 @@ apply plugin: 'ru.cian.huawei-publish-gradle-plugin' dependencies { // Google Mobile Services if (googleMobileServicesEnabled) { - implementation 'com.google.android.gms:play-services-location:21.0.1' + implementation 'com.google.android.gms:play-services-location:19.0.1' } // Google Firebase Services if (googleFirebaseServicesEnabled) { - // Import the BoM for the Firebase platform - implementation platform('com.google.firebase:firebase-bom:30.5.0') - // Add the dependencies for the Crashlytics and Analytics libraries - // When using the BoM, you don't specify versions in Firebase library dependencies - implementation 'com.google.firebase:firebase-crashlytics' - implementation 'com.google.firebase:firebase-crashlytics-ndk' + implementation 'com.google.firebase:firebase-crashlytics:18.2.6' + implementation 'com.google.firebase:firebase-crashlytics-ndk:18.2.6' } - implementation 'androidx.annotation:annotation:1.5.0' - implementation 'androidx.appcompat:appcompat:1.7.0-alpha01' + implementation 'androidx.annotation:annotation:1.3.0' + implementation 'androidx.appcompat:appcompat:1.4.2' implementation 'androidx.constraintlayout:constraintlayout:2.1.4' - implementation 'androidx.fragment:fragment:1.5.4' - // Lifecycle is added as a workaround for duplicate classes error caused by some outdated dependency: - // > A failure occurred while executing com.android.build.gradle.internal.tasks.CheckDuplicatesRunnable - // > Duplicate class androidx.lifecycle.ViewModelLazy found in modules jetified-lifecycle-viewmodel-ktx-2.3.1-runtime (androidx.lifecycle:lifecycle-viewmodel-ktx:2.3.1) and lifecycle-viewmodel-2.5.1-runtime (androidx.lifecycle:lifecycle-viewmodel:2.5.1) - // Duplicate class androidx.lifecycle.ViewTreeViewModelKt found in modules jetified-lifecycle-viewmodel-ktx-2.3.1-runtime (androidx.lifecycle:lifecycle-viewmodel-ktx:2.3.1) and lifecycle-viewmodel-2.5.1-runtime (androidx.lifecycle:lifecycle-viewmodel:2.5.1) - implementation 'androidx.lifecycle:lifecycle-viewmodel:2.5.1' - implementation 'androidx.lifecycle:lifecycle-viewmodel-ktx:2.5.1' + implementation 'androidx.fragment:fragment:1.4.1' implementation 'androidx.preference:preference:1.2.0' implementation 'androidx.recyclerview:recyclerview:1.2.1' implementation 'androidx.work:work-runtime:2.7.1' - implementation 'com.google.android.material:material:1.8.0-alpha02' - implementation 'com.google.code.gson:gson:2.10' + implementation 'com.google.android.material:material:1.7.0-alpha02' + implementation 'com.google.code.gson:gson:2.9.0' implementation 'com.timehop.stickyheadersrecyclerview:library:0.4.3@aar' implementation 'com.github.devnullorthrow:MPAndroidChart:3.2.0-alpha' implementation 'net.jcip:jcip-annotations:1.0' // Test Dependencies testImplementation 'junit:junit:4.13.2' - testImplementation 'org.mockito:mockito-core:4.8.1' - testImplementation 'org.mockito:mockito-inline:4.8.1' + testImplementation 'org.mockito:mockito-core:4.6.0' + testImplementation 'org.mockito:mockito-inline:4.6.0' } def run(cmd) { @@ -116,8 +107,6 @@ def run(cmd) { return stdout.toString() } - -import com.github.triplet.gradle.androidpublisher.ReleaseStatus import org.gradle.nativeplatform.platform.internal.DefaultNativePlatform def getVersion() { @@ -125,7 +114,7 @@ def getVersion() { def bash = isWindows ? 'C:\\Program Files\\Git\\bin\\bash.exe' : 'bash' def versionCode = Integer.parseInt(run([bash, '../tools/unix/version.sh', 'android_code']).trim()) def versionName = run([bash, '../tools/unix/version.sh', 'android_name']).trim() - return new Tuple2(versionCode, versionName) + return new groovy.lang.Tuple2(versionCode, versionName) } def getCommitMessage() { @@ -138,8 +127,6 @@ project.ext.appId = 'app.organicmaps' project.ext.appName = 'Organic Maps' android { - namespace 'app.organicmaps' - buildFeatures { dataBinding = true } @@ -147,23 +134,21 @@ android { compileSdkVersion propCompileSdkVersion.toInteger() buildToolsVersion propBuildToolsVersion - ndkVersion '25.1.8937393' + ndkVersion '24.0.8215888' defaultConfig { // Default package name is taken from the manifest and should be app.organicmaps def ver = getVersion() - versionCode = ver.V1 - versionName = ver.V2 - println('Version: ' + versionName) - println('VersionCode: ' + versionCode) + println('Version: ' + ver.second) + println('VersionCode: ' + ver.first) + versionCode = ver.first + versionName = ver.second minSdkVersion propMinSdkVersion.toInteger() targetSdkVersion propTargetSdkVersion.toInteger() applicationId project.ext.appId buildConfigField 'String', 'SUPPORT_MAIL', '"android@organicmaps.app"' - // Should be customized in flavors. - buildConfigField 'String', 'REVIEW_URL', '""' - - resConfigs project.ext.supportedLocalizations + buildConfigField 'String', 'REVIEW_URL', '"https://organicmaps.app/donate/"' + buildConfigField 'int', 'RATING_THRESHOLD', '5' multiDexEnabled true multiDexKeepFile file('multidex-config.txt') @@ -236,7 +221,7 @@ android { res.srcDirs = ['tests/resources'] } - flavorDimensions 'default' + flavorDimensions "default" productFlavors { // 01 is a historical artefact, sorry. @@ -289,26 +274,16 @@ android { universalApk true } + // TODO: Fix a lot of lint errors in our code lint { - disable 'MissingTranslation' - // https://github.com/organicmaps/organicmaps/issues/3551 - disable 'MissingQuantity', 'UnusedQuantity' - // https://github.com/organicmaps/organicmaps/issues/3550 - disable 'ByteOrderMark' - // https://github.com/organicmaps/organicmaps/issues/1077 - disable 'CustomSplashScreen' - // https://github.com/organicmaps/organicmaps/issues/3610 - disable 'InsecureBaseConfiguration' - // https://github.com/organicmaps/organicmaps/issues/3608 - disable 'UnusedResources' - abortOnError true + abortOnError false } gradle.projectsEvaluated { android.applicationVariants.all { variant -> def task = variant.name.capitalize() project.task(type: Exec, "run${task}", dependsOn: "install${task}") { - commandLine android.getAdbExe(), 'shell', 'am', 'start', '-n', "${applicationId}/app.organicmaps.SplashActivity" + commandLine android.getAdbExe(), 'shell', 'am', 'start', '-n', "${applicationId}/com.mapswithme.maps.SplashActivity" } } } @@ -342,8 +317,6 @@ android { ndk.debugSymbolLevel = 'none' if (googleFirebaseServicesEnabled) { - // Keep debug symbols for test lab. - ndk.debugSymbolLevel = 'symbol_table' firebaseCrashlytics { nativeSymbolUploadEnabled true } @@ -401,7 +374,7 @@ android { externalNativeBuild { cmake { - version "3.22.1+" + version "3.18.0+" buildStagingDirectory "./nativeOutputs" path "../CMakeLists.txt" } @@ -432,10 +405,6 @@ android { } } -tasks.withType(JavaCompile) { - options.compilerArgs << '-Xlint:unchecked' << '-Xlint:deprecation' -} - android.buildTypes.all { buildType -> def suffix = applicationIdSuffix != null ? applicationIdSuffix : "" def authorityValue = android.defaultConfig.applicationId + suffix + ".provider" @@ -444,32 +413,7 @@ android.buildTypes.all { buildType -> manifestPlaceholders += [FILE_PROVIDER_PLACEHOLDER : authorityValue] } -task prepareGoogleReleaseListing { - // Prepares Google Play metainfo from F-Droid metainfo. - final sourceFlavor = 'fdroid' - final targetFlavor = 'google' - doLast { - final sourceDir = new File("${projectDir}/src/$sourceFlavor/play/listings") - final targetDir = new File("${projectDir}/src/$targetFlavor/play/listings") - final sourceFiles = fileTree(dir: sourceDir, - include: "**/*.txt", exclude: "**/*-${targetFlavor}.txt") - sourceFiles.each { File sourceFile -> - final path = sourceFile.getPath() - final locale = sourceFile.parentFile.getName() - final targetLocaleDir = new File(targetDir, locale) - if (!targetLocaleDir.isDirectory()) - targetLocaleDir.mkdirs() - final targetFile = new File(targetLocaleDir, sourceFile.getName()) - // Override Google-specific values by using ${name}-google.txt files. - final overrideFile = new File(sourceFile.getPath().replace(".txt", "-${targetFlavor}.txt")) - targetFile.text = overrideFile.exists() ? overrideFile.text : sourceFile.text - } - copy { - from "${projectDir}/../screenshots/android" - into targetDir - } - } -} +import com.github.triplet.gradle.androidpublisher.ReleaseStatus play { enabled.set(false) @@ -484,28 +428,9 @@ huaweiPublish { instances { huaweiRelease { credentialsPath = "$rootDir/huawei-appgallery.json" - buildFormat = 'aab' - deployType = 'draft' // confirm manually - releaseNotes = [] - def localeOverride = [ - 'am' : 'am-ET', - 'gu': 'gu_IN', - 'iw-IL': 'he_IL', - 'kn-IN': 'kn_IN', - 'ml-IN': 'ml_IN', - 'mn-MN': 'mn_MN', - 'mr-IN': 'mr_IN', - 'ta-IN': 'ta_IN', - 'te-IN': 'te_IN', - ] - def files = fileTree(dir: "$projectDir/src/fdroid/play/listings", - include: '**/release-notes.txt') - files.each { File file -> - def path = file.getPath() - def locale = file.parentFile.getName() - locale = localeOverride.get(locale, locale) - releaseNotes.add(new ru.cian.huawei.publish.ReleaseNote(locale, path)) - } + buildFormat = "aab" + // https://github.com/cianru/huawei-publish-gradle-plugin/issues/32 + deployType = 'draft' } } } diff --git a/android/flavors/firebase-disabled/app/organicmaps/util/CrashlyticsUtils.java b/android/flavors/firebase-disabled/com/mapswithme/util/CrashlyticsUtils.java similarity index 88% rename from android/flavors/firebase-disabled/app/organicmaps/util/CrashlyticsUtils.java rename to android/flavors/firebase-disabled/com/mapswithme/util/CrashlyticsUtils.java index 8e077c866b..4335da8085 100644 --- a/android/flavors/firebase-disabled/app/organicmaps/util/CrashlyticsUtils.java +++ b/android/flavors/firebase-disabled/com/mapswithme/util/CrashlyticsUtils.java @@ -1,9 +1,9 @@ -package app.organicmaps.util; +package com.mapswithme.util; import android.content.Context; -import app.organicmaps.MwmApplication; -import app.organicmaps.base.Initializable; +import com.mapswithme.maps.MwmApplication; +import com.mapswithme.maps.base.Initializable; import androidx.annotation.NonNull; import androidx.annotation.Nullable; diff --git a/android/flavors/firebase-enabled/com/mapswithme/util/CrashlyticsUtils.java b/android/flavors/firebase-enabled/com/mapswithme/util/CrashlyticsUtils.java index f1cf88f8e4..dad0a4061a 100644 --- a/android/flavors/firebase-enabled/com/mapswithme/util/CrashlyticsUtils.java +++ b/android/flavors/firebase-enabled/com/mapswithme/util/CrashlyticsUtils.java @@ -1,12 +1,12 @@ -package app.organicmaps.util; +package com.mapswithme.util; import android.content.Context; import android.util.Log; import com.google.firebase.crashlytics.FirebaseCrashlytics; -import app.organicmaps.MwmApplication; -import app.organicmaps.base.Initializable; -import app.organicmaps.util.log.Logger; +import com.mapswithme.maps.MwmApplication; +import com.mapswithme.maps.base.Initializable; +import com.mapswithme.util.log.Logger; import androidx.annotation.NonNull; import androidx.annotation.Nullable; diff --git a/android/flavors/gms-disabled/com/mapswithme/maps/location/LocationProviderFactory.java b/android/flavors/gms-disabled/com/mapswithme/maps/location/LocationProviderFactory.java index 23c31b675a..f761a4a087 100644 --- a/android/flavors/gms-disabled/com/mapswithme/maps/location/LocationProviderFactory.java +++ b/android/flavors/gms-disabled/com/mapswithme/maps/location/LocationProviderFactory.java @@ -1,4 +1,4 @@ -package app.organicmaps.location; +package com.mapswithme.maps.location; import android.content.Context; diff --git a/android/flavors/gms-enabled/app/organicmaps/location/GoogleFusedLocationProvider.java b/android/flavors/gms-enabled/app/organicmaps/location/GoogleFusedLocationProvider.java deleted file mode 100644 index d4256276c1..0000000000 --- a/android/flavors/gms-enabled/app/organicmaps/location/GoogleFusedLocationProvider.java +++ /dev/null @@ -1,148 +0,0 @@ -package app.organicmaps.location; - -import static app.organicmaps.util.concurrency.UiThread.runLater; - -import android.app.PendingIntent; -import android.content.Context; -import android.location.Location; -import android.os.Looper; - -import androidx.annotation.NonNull; - -import com.google.android.gms.common.api.ApiException; -import com.google.android.gms.common.api.ResolvableApiException; -import com.google.android.gms.location.FusedLocationProviderClient; -import com.google.android.gms.location.Granularity; -import com.google.android.gms.location.LocationAvailability; -import com.google.android.gms.location.LocationCallback; -import com.google.android.gms.location.LocationRequest; -import com.google.android.gms.location.LocationResult; -import com.google.android.gms.location.LocationServices; -import com.google.android.gms.location.LocationSettingsRequest; -import com.google.android.gms.location.LocationSettingsStatusCodes; -import com.google.android.gms.location.Priority; -import com.google.android.gms.location.SettingsClient; - -import app.organicmaps.util.LocationUtils; -import app.organicmaps.util.log.Logger; - -class GoogleFusedLocationProvider extends BaseLocationProvider -{ - private static final String TAG = GoogleFusedLocationProvider.class.getSimpleName(); - @NonNull - private final FusedLocationProviderClient mFusedLocationClient; - @NonNull - private final SettingsClient mSettingsClient; - @NonNull - private final Context mContext; - - private class GoogleLocationCallback extends LocationCallback - { - @Override - public void onLocationResult(@NonNull LocationResult result) - { - final Location location = result.getLastLocation(); - if (location != null) - mListener.onLocationChanged(location); - } - - @Override - public void onLocationAvailability(@NonNull LocationAvailability availability) - { - if (!availability.isLocationAvailable()) { - Logger.w(TAG, "isLocationAvailable returned false"); - } - } - } - - private final GoogleLocationCallback mCallback = new GoogleLocationCallback(); - - GoogleFusedLocationProvider(@NonNull Context context, @NonNull BaseLocationProvider.Listener listener) - { - super(listener); - mFusedLocationClient = LocationServices.getFusedLocationProviderClient(context); - mSettingsClient = LocationServices.getSettingsClient(context); - mContext = context; - } - - @SuppressWarnings("MissingPermission") - // A permission is checked externally - @Override - public void start(long interval) - { - Logger.d(TAG); - - final LocationRequest locationRequest = new LocationRequest.Builder(Priority.PRIORITY_HIGH_ACCURACY, interval) - // Wait a few seconds for accurate locations initially, when accurate locations could not be computed on the device immediately. - // https://github.com/organicmaps/organicmaps/issues/2149 - .setWaitForAccurateLocation(true) - // The desired location granularity should correspond to the client permission level. The client will be - // delivered fine locations while it has the Manifest.permission.ACCESS_FINE_LOCATION permission, coarse - // locations while it has only the Manifest.permission.ACCESS_COARSE_LOCATION permission, and no location - // if it lacks either. - .setGranularity(Granularity.GRANULARITY_PERMISSION_LEVEL) - // Sets the maximum age of an initial historical location delivered for this request. - .setMaxUpdateAgeMillis(60 * 60 * 1000L) // 1 hour - .build(); - - LocationSettingsRequest.Builder builder = new LocationSettingsRequest.Builder(); - builder.addLocationRequest(locationRequest); - builder.setAlwaysShow(true); // improves the wording/appearance of the dialog - final LocationSettingsRequest locationSettingsRequest = builder.build(); - - mSettingsClient.checkLocationSettings(locationSettingsRequest).addOnSuccessListener(locationSettingsResponse -> { - Logger.d(TAG, "Service is available"); - mFusedLocationClient.requestLocationUpdates(locationRequest, mCallback, Looper.myLooper()); - }).addOnFailureListener(e -> { - try - { - int statusCode = ((ApiException) e).getStatusCode(); - if (statusCode == LocationSettingsStatusCodes.RESOLUTION_REQUIRED) - { - // This case happens if at least one of the following system settings is off: - // 1. Location Services a.k.a GPS; - // 2. Google Location Accuracy a.k.a High Accuracy; - // 3. Both Wi-Fi && Mobile Data together (needed for 2). - // - // PendingIntent below will show a special Google "For better experience... enable (1) and/or (2) and/or (3)" - // dialog. This system dialog can change system settings if "Yes" is pressed. We can't do it from our app. - // However, we don't want to annoy a user who disabled (2) or (3) intentionally. GPS (1) is mandatory to - // continue, while (2) and (3) are not dealbreakers here. - // - // See https://github.com/organicmaps/organicmaps/issues/3846 - // - if (LocationUtils.areLocationServicesTurnedOn(mContext)) - { - Logger.d(TAG, "Don't show 'location resolution' dialog because location services are already on"); - mFusedLocationClient.requestLocationUpdates(locationRequest, mCallback, Looper.myLooper()); - return; - } - Logger.d(TAG, "Requesting 'location resolution' dialog"); - final ResolvableApiException resolvable = (ResolvableApiException) e; - final PendingIntent pendingIntent = resolvable.getResolution(); - // Call this callback in the next event loop to allow LocationHelper::start() to finish. - runLater(() -> mListener.onLocationResolutionRequired(pendingIntent)); - return; - } - } - catch (ClassCastException ex) - { - // Ignore, should be an impossible error. - // https://developers.google.com/android/reference/com/google/android/gms/location/SettingsClient - Logger.e(TAG, "An error that should be impossible: " + ex); - } - // Location settings are not satisfied. However, we have no way to fix the - // settings so we won't show the dialog. - Logger.e(TAG, "Service is not available: " + e); - // Call this callback in the next event loop to allow LocationHelper::start() to finish. - runLater(mListener::onFusedLocationUnsupported); - }); - } - - @Override - protected void stop() - { - Logger.d(TAG); - mFusedLocationClient.removeLocationUpdates(mCallback); - } -} diff --git a/android/flavors/gms-enabled/com/mapswithme/maps/location/GoogleFusedLocationProvider.java b/android/flavors/gms-enabled/com/mapswithme/maps/location/GoogleFusedLocationProvider.java new file mode 100644 index 0000000000..b90050f799 --- /dev/null +++ b/android/flavors/gms-enabled/com/mapswithme/maps/location/GoogleFusedLocationProvider.java @@ -0,0 +1,115 @@ +package com.mapswithme.maps.location; + +import android.content.Context; +import android.location.Location; +import android.os.Looper; + +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import com.google.android.gms.location.FusedLocationProviderClient; +import com.google.android.gms.location.LocationAvailability; +import com.google.android.gms.location.LocationCallback; +import com.google.android.gms.location.LocationRequest; +import com.google.android.gms.location.LocationResult; +import com.google.android.gms.location.LocationServices; +import com.google.android.gms.location.LocationSettingsRequest; +import com.google.android.gms.location.SettingsClient; +import com.mapswithme.util.log.Logger; + +import static com.mapswithme.maps.location.LocationHelper.ERROR_NOT_SUPPORTED; + +class GoogleFusedLocationProvider extends BaseLocationProvider +{ + private static final String TAG = GoogleFusedLocationProvider.class.getSimpleName(); + @NonNull + private final FusedLocationProviderClient mFusedLocationClient; + @NonNull + private final SettingsClient mSettingsClient; + + private class GoogleLocationCallback extends LocationCallback + { + @Override + public void onLocationResult(@NonNull LocationResult result) + { + final Location location = result.getLastLocation(); + // Documentation is inconsistent with the code: "returns null if no locations are available". + // https://developers.google.com/android/reference/com/google/android/gms/location/LocationResult#getLastLocation() + //noinspection ConstantConditions + if (location != null) + mListener.onLocationChanged(location); + } + + @Override + public void onLocationAvailability(@NonNull LocationAvailability availability) + { + if (!availability.isLocationAvailable()) { + Logger.w(TAG, "isLocationAvailable returned false"); + //mListener.onLocationError(ERROR_GPS_OFF); + } + } + } + + @Nullable + private final GoogleLocationCallback mCallback = new GoogleLocationCallback(); + + private boolean mActive = false; + + GoogleFusedLocationProvider(@NonNull Context context, @NonNull BaseLocationProvider.Listener listener) + { + super(listener); + mFusedLocationClient = LocationServices.getFusedLocationProviderClient(context); + mSettingsClient = LocationServices.getSettingsClient(context); + } + + @SuppressWarnings("MissingPermission") + // A permission is checked externally + @Override + public void start(long interval) + { + Logger.d(TAG, "start()"); + if (mActive) + throw new IllegalStateException("Already subscribed"); + mActive = true; + + final LocationRequest locationRequest = LocationRequest.create(); + locationRequest.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY); + locationRequest.setInterval(interval); + // Wait a few seconds for accurate locations initially, when accurate locations could not be computed on the device immediately. + // https://github.com/organicmaps/organicmaps/issues/2149 + locationRequest.setWaitForAccurateLocation(true); + Logger.d(TAG, "Request Google fused provider to provide locations at this interval = " + + interval + " ms"); + locationRequest.setFastestInterval(interval / 2); + + LocationSettingsRequest.Builder builder = new LocationSettingsRequest.Builder(); + builder.addLocationRequest(locationRequest); + final LocationSettingsRequest locationSettingsRequest = builder.build(); + + mSettingsClient.checkLocationSettings(locationSettingsRequest).addOnSuccessListener(locationSettingsResponse -> { + Logger.d(TAG, "Service is available"); + mFusedLocationClient.requestLocationUpdates(locationRequest, mCallback, Looper.myLooper()); + }).addOnFailureListener(e -> { + Logger.e(TAG, "Service is not available: " + e); + mListener.onLocationError(ERROR_NOT_SUPPORTED); + }); + + // onLocationResult() may not always be called regularly, however the device location is known. + mFusedLocationClient.getLastLocation().addOnSuccessListener(location -> { + Logger.d(TAG, "onLastLocation, location = " + location); + if (location == null) + return; + mListener.onLocationChanged(location); + }); + } + + @Override + protected void stop() + { + Logger.d(TAG, "stop()"); + mFusedLocationClient.removeLocationUpdates(mCallback); + mActive = false; + } + + @Override + protected boolean trustFusedLocations() { return true; } +} diff --git a/android/flavors/gms-enabled/app/organicmaps/location/LocationProviderFactory.java b/android/flavors/gms-enabled/com/mapswithme/maps/location/LocationProviderFactory.java similarity index 89% rename from android/flavors/gms-enabled/app/organicmaps/location/LocationProviderFactory.java rename to android/flavors/gms-enabled/com/mapswithme/maps/location/LocationProviderFactory.java index 5b802eb036..ae10e402f8 100644 --- a/android/flavors/gms-enabled/app/organicmaps/location/LocationProviderFactory.java +++ b/android/flavors/gms-enabled/com/mapswithme/maps/location/LocationProviderFactory.java @@ -1,12 +1,12 @@ -package app.organicmaps.location; +package com.mapswithme.maps.location; import android.content.Context; import androidx.annotation.NonNull; import com.google.android.gms.common.ConnectionResult; import com.google.android.gms.common.GoogleApiAvailability; -import app.organicmaps.util.Config; -import app.organicmaps.util.log.Logger; +import com.mapswithme.util.Config; +import com.mapswithme.util.log.Logger; public class LocationProviderFactory { diff --git a/android/gradle.properties b/android/gradle.properties index c9cf2e5f8f..f0911ada49 100644 --- a/android/gradle.properties +++ b/android/gradle.properties @@ -1,12 +1,10 @@ propMinSdkVersion=21 -propTargetSdkVersion=33 -propCompileSdkVersion=33 -propBuildToolsVersion=33.0.0 +propTargetSdkVersion=31 +propCompileSdkVersion=31 +propBuildToolsVersion=32.0.0 org.gradle.caching=true org.gradle.jvmargs=-Xmx1024m -Xms256m android.useAndroidX=true android.enableJetifier=true android.native.buildOutput=verbose -# Autogenerated by tools/unix/generate_localizations.sh -supportedLocalizations=ar,be,bg,ca,cs,da,de,el,en,en_GB,es,es_MX,et,eu,fa,fi,fr,fr_CA,he,hi,hu,id,in,it,ja,ko,mr,nb,ne,nl,pl,pt,pt_BR,ro,ru,sk,sv,sw,th,tr,uk,vi,zh_Hans,zh_Hant diff --git a/android/gradle/wrapper/gradle-wrapper.jar b/android/gradle/wrapper/gradle-wrapper.jar index 249e5832f0..41d9927a4d 100644 Binary files a/android/gradle/wrapper/gradle-wrapper.jar and b/android/gradle/wrapper/gradle-wrapper.jar differ diff --git a/android/gradle/wrapper/gradle-wrapper.properties b/android/gradle/wrapper/gradle-wrapper.properties index ae04661ee7..aa991fceae 100644 --- a/android/gradle/wrapper/gradle-wrapper.properties +++ b/android/gradle/wrapper/gradle-wrapper.properties @@ -1,5 +1,5 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-7.5.1-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-7.4.2-bin.zip zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists diff --git a/android/gradlew b/android/gradlew index a69d9cb6c2..1b6c787337 100755 --- a/android/gradlew +++ b/android/gradlew @@ -205,12 +205,6 @@ set -- \ org.gradle.wrapper.GradleWrapperMain \ "$@" -# Stop when "xargs" is not available. -if ! command -v xargs >/dev/null 2>&1 -then - die "xargs is not available" -fi - # Use "xargs" to parse quoted args. # # With -n1 it outputs one arg per line, with the quotes and backslashes removed. diff --git a/android/gradlew.bat b/android/gradlew.bat index f127cfd49d..107acd32c4 100644 --- a/android/gradlew.bat +++ b/android/gradlew.bat @@ -14,7 +14,7 @@ @rem limitations under the License. @rem -@if "%DEBUG%"=="" @echo off +@if "%DEBUG%" == "" @echo off @rem ########################################################################## @rem @rem Gradle startup script for Windows @@ -25,7 +25,7 @@ if "%OS%"=="Windows_NT" setlocal set DIRNAME=%~dp0 -if "%DIRNAME%"=="" set DIRNAME=. +if "%DIRNAME%" == "" set DIRNAME=. set APP_BASE_NAME=%~n0 set APP_HOME=%DIRNAME% @@ -40,7 +40,7 @@ if defined JAVA_HOME goto findJavaFromJavaHome set JAVA_EXE=java.exe %JAVA_EXE% -version >NUL 2>&1 -if %ERRORLEVEL% equ 0 goto execute +if "%ERRORLEVEL%" == "0" goto execute echo. echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. @@ -75,15 +75,13 @@ set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar :end @rem End local scope for the variables with windows NT shell -if %ERRORLEVEL% equ 0 goto mainEnd +if "%ERRORLEVEL%"=="0" goto mainEnd :fail rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of rem the _cmd.exe /c_ return code! -set EXIT_CODE=%ERRORLEVEL% -if %EXIT_CODE% equ 0 set EXIT_CODE=1 -if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE% -exit /b %EXIT_CODE% +if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 +exit /b 1 :mainEnd if "%OS%"=="Windows_NT" endlocal diff --git a/android/jni/CMakeLists.txt b/android/jni/CMakeLists.txt index c4cc9d4799..e82a603256 100644 --- a/android/jni/CMakeLists.txt +++ b/android/jni/CMakeLists.txt @@ -1,72 +1,72 @@ -cmake_minimum_required(VERSION 3.22.1) +cmake_minimum_required(VERSION 3.18) project(organicmaps C CXX) set(SRC # JNI headers ../../private.h - app/organicmaps/core/jni_helper.hpp - app/organicmaps/core/logging.hpp - app/organicmaps/core/ScopedEnv.hpp - app/organicmaps/core/ScopedLocalRef.hpp - app/organicmaps/Framework.hpp - app/organicmaps/opengl/android_gl_utils.hpp - app/organicmaps/opengl/androidoglcontext.hpp - app/organicmaps/opengl/androidoglcontextfactory.hpp - app/organicmaps/opengl/gl3stub.h - app/organicmaps/platform/GuiThread.hpp - app/organicmaps/platform/Platform.hpp - app/organicmaps/util/FeatureIdBuilder.hpp - app/organicmaps/vulkan/android_vulkan_context_factory.hpp + com/mapswithme/core/jni_helper.hpp + com/mapswithme/core/logging.hpp + com/mapswithme/core/ScopedEnv.hpp + com/mapswithme/core/ScopedLocalRef.hpp + com/mapswithme/maps/Framework.hpp + com/mapswithme/opengl/android_gl_utils.hpp + com/mapswithme/opengl/androidoglcontext.hpp + com/mapswithme/opengl/androidoglcontextfactory.hpp + com/mapswithme/opengl/gl3stub.h + com/mapswithme/platform/GuiThread.hpp + com/mapswithme/platform/Platform.hpp + com/mapswithme/util/FeatureIdBuilder.hpp + com/mapswithme/vulkan/android_vulkan_context_factory.hpp # JNI sources - app/organicmaps/core/jni_helper.cpp - app/organicmaps/core/logging.cpp - app/organicmaps/bookmarks/data/BookmarkManager.cpp - app/organicmaps/DisplayedCategories.cpp - app/organicmaps/DownloadResourcesLegacyActivity.cpp - app/organicmaps/editor/Editor.cpp - app/organicmaps/editor/OpeningHours.cpp - app/organicmaps/editor/OsmOAuth.cpp - app/organicmaps/Framework.cpp - app/organicmaps/isolines/IsolinesManager.cpp - app/organicmaps/LocationHelper.cpp - app/organicmaps/LocationState.cpp - app/organicmaps/Map.cpp - app/organicmaps/MapManager.cpp - app/organicmaps/MwmApplication.cpp - app/organicmaps/routing/RoutingOptions.cpp - app/organicmaps/SearchEngine.cpp - app/organicmaps/SearchRecents.cpp - app/organicmaps/settings/UnitLocale.cpp - app/organicmaps/sound/tts.cpp - app/organicmaps/subway/SubwayManager.cpp - app/organicmaps/TrackRecorder.cpp - app/organicmaps/TrafficState.cpp - app/organicmaps/UserMarkHelper.cpp - app/organicmaps/opengl/android_gl_utils.cpp - app/organicmaps/opengl/androidoglcontext.cpp - app/organicmaps/opengl/androidoglcontextfactory.cpp - app/organicmaps/opengl/gl3stub.c - app/organicmaps/platform/GuiThread.cpp - app/organicmaps/platform/HttpThread.cpp - app/organicmaps/platform/Language.cpp - app/organicmaps/platform/Localization.cpp - app/organicmaps/platform/Platform.cpp - app/organicmaps/platform/PThreadImpl.cpp - app/organicmaps/platform/SecureStorage.cpp - app/organicmaps/platform/SocketImpl.cpp - app/organicmaps/util/Config.cpp - app/organicmaps/util/GeoUtils.cpp - app/organicmaps/util/HttpBackgroundUploader.cpp - app/organicmaps/util/HttpClient.cpp - app/organicmaps/util/HttpUploader.cpp - app/organicmaps/util/HttpUploaderUtils.cpp - app/organicmaps/util/Language.cpp - app/organicmaps/util/LogsManager.cpp - app/organicmaps/util/NetworkPolicy.cpp - app/organicmaps/util/StringUtils.cpp - app/organicmaps/vulkan/android_vulkan_context_factory.cpp + com/mapswithme/core/jni_helper.cpp + com/mapswithme/core/logging.cpp + com/mapswithme/maps/bookmarks/data/BookmarkManager.cpp + com/mapswithme/maps/DisplayedCategories.cpp + com/mapswithme/maps/DownloadResourcesLegacyActivity.cpp + com/mapswithme/maps/editor/Editor.cpp + com/mapswithme/maps/editor/OpeningHours.cpp + com/mapswithme/maps/editor/OsmOAuth.cpp + com/mapswithme/maps/Framework.cpp + com/mapswithme/maps/isolines/IsolinesManager.cpp + com/mapswithme/maps/LocationHelper.cpp + com/mapswithme/maps/LocationState.cpp + com/mapswithme/maps/MapFragment.cpp + com/mapswithme/maps/MapManager.cpp + com/mapswithme/maps/MwmApplication.cpp + com/mapswithme/maps/routing/RoutingOptions.cpp + com/mapswithme/maps/SearchEngine.cpp + com/mapswithme/maps/SearchRecents.cpp + com/mapswithme/maps/settings/UnitLocale.cpp + com/mapswithme/maps/sound/tts.cpp + com/mapswithme/maps/subway/SubwayManager.cpp + com/mapswithme/maps/TrackRecorder.cpp + com/mapswithme/maps/TrafficState.cpp + com/mapswithme/maps/UserMarkHelper.cpp + com/mapswithme/opengl/android_gl_utils.cpp + com/mapswithme/opengl/androidoglcontext.cpp + com/mapswithme/opengl/androidoglcontextfactory.cpp + com/mapswithme/opengl/gl3stub.c + com/mapswithme/platform/GuiThread.cpp + com/mapswithme/platform/HttpThread.cpp + com/mapswithme/platform/Language.cpp + com/mapswithme/platform/Localization.cpp + com/mapswithme/platform/Platform.cpp + com/mapswithme/platform/PThreadImpl.cpp + com/mapswithme/platform/SecureStorage.cpp + com/mapswithme/platform/SocketImpl.cpp + com/mapswithme/util/Config.cpp + com/mapswithme/util/GeoUtils.cpp + com/mapswithme/util/HttpBackgroundUploader.cpp + com/mapswithme/util/HttpClient.cpp + com/mapswithme/util/HttpUploader.cpp + com/mapswithme/util/HttpUploaderUtils.cpp + com/mapswithme/util/Language.cpp + com/mapswithme/util/LogsManager.cpp + com/mapswithme/util/NetworkPolicy.cpp + com/mapswithme/util/StringUtils.cpp + com/mapswithme/vulkan/android_vulkan_context_factory.cpp ) omim_add_library(${PROJECT_NAME} SHARED ${SRC}) @@ -103,7 +103,7 @@ target_link_libraries(${PROJECT_NAME} # expat # freetype # minizip - # cppjansson + # jansson # protobuf # succinct # stb_image diff --git a/android/jni/app/organicmaps/DisplayedCategories.cpp b/android/jni/app/organicmaps/DisplayedCategories.cpp deleted file mode 100644 index 3fc3674401..0000000000 --- a/android/jni/app/organicmaps/DisplayedCategories.cpp +++ /dev/null @@ -1,16 +0,0 @@ -#include "app/organicmaps/Framework.hpp" -#include "app/organicmaps/core/jni_helper.hpp" - -#include "search/displayed_categories.hpp" - -extern "C" -{ -JNIEXPORT jobjectArray JNICALL -Java_app_organicmaps_search_DisplayedCategories_nativeGetKeys(JNIEnv * env, jclass clazz) -{ - ::Framework * fr = g_framework->NativeFramework(); - ASSERT(fr, ()); - search::DisplayedCategories categories = fr->GetDisplayedCategories(); - return jni::ToJavaStringArray(env, categories.GetKeys()); -} -} // extern "C" diff --git a/android/jni/app/organicmaps/LocationHelper.cpp b/android/jni/app/organicmaps/LocationHelper.cpp deleted file mode 100644 index 985ab8b5de..0000000000 --- a/android/jni/app/organicmaps/LocationHelper.cpp +++ /dev/null @@ -1,44 +0,0 @@ -#include "Framework.hpp" -#include "map/gps_tracker.hpp" - -extern "C" -{ - JNIEXPORT void JNICALL - Java_app_organicmaps_location_LocationHelper_nativeOnLocationError(JNIEnv * env, jclass clazz, int errorCode) - { - ASSERT(g_framework, ()); - g_framework->OnLocationError(errorCode); - } - - JNIEXPORT void JNICALL - Java_app_organicmaps_location_LocationHelper_nativeLocationUpdated(JNIEnv * env, jclass clazz, jlong time, - jdouble lat, jdouble lon, jfloat accuracy, - jdouble altitude, jfloat speed, jfloat bearing) - { - ASSERT(g_framework, ()); - location::GpsInfo info; - info.m_source = location::EAndroidNative; - - info.m_timestamp = static_cast(time) / 1000.0; - info.m_latitude = lat; - info.m_longitude = lon; - - if (accuracy > 0.0) - info.m_horizontalAccuracy = accuracy; - - if (altitude != 0.0) - { - info.m_altitude = altitude; - info.m_verticalAccuracy = accuracy; - } - - if (bearing > 0.0) - info.m_bearing = bearing; - - if (speed > 0.0) - info.m_speedMpS = speed; - - g_framework->OnLocationUpdated(info); - GpsTracker::Instance().OnLocationUpdated(info); - } -} diff --git a/android/jni/app/organicmaps/LocationState.cpp b/android/jni/app/organicmaps/LocationState.cpp deleted file mode 100644 index 53c34d0f27..0000000000 --- a/android/jni/app/organicmaps/LocationState.cpp +++ /dev/null @@ -1,75 +0,0 @@ -#include "Framework.hpp" - -#include "app/organicmaps/core/jni_helper.hpp" - -#include "app/organicmaps/platform/Platform.hpp" - -extern "C" -{ - -static void LocationStateModeChanged(location::EMyPositionMode mode, - std::shared_ptr const & listener) -{ - JNIEnv * env = jni::GetEnv(); - env->CallVoidMethod(*listener, jni::GetMethodID(env, *listener.get(), - "onMyPositionModeChanged", "(I)V"), static_cast(mode)); -} - -static void LocationPendingTimeout(std::shared_ptr const & listener) -{ - JNIEnv * env = jni::GetEnv(); - env->CallVoidMethod(*listener, jni::GetMethodID(env, *listener.get(), - "onLocationPendingTimeout", "()V")); -} - -// public static void nativeSwitchToNextMode(); -JNIEXPORT void JNICALL -Java_app_organicmaps_location_LocationState_nativeSwitchToNextMode(JNIEnv * env, jclass clazz) -{ - ASSERT(g_framework, ()); - g_framework->SwitchMyPositionNextMode(); -} - -// private static int nativeGetMode(); -JNIEXPORT jint JNICALL -Java_app_organicmaps_location_LocationState_nativeGetMode(JNIEnv * env, jclass clazz) -{ - ASSERT(g_framework, ()); - return g_framework->GetMyPositionMode(); -} - -// public static void nativeSetListener(ModeChangeListener listener); -JNIEXPORT void JNICALL -Java_app_organicmaps_location_LocationState_nativeSetListener(JNIEnv * env, jclass clazz, - jobject listener) -{ - ASSERT(g_framework, ()); - g_framework->SetMyPositionModeListener(std::bind(&LocationStateModeChanged, std::placeholders::_1, - jni::make_global_ref(listener))); -} - -// public static void nativeRemoveListener(); -JNIEXPORT void JNICALL -Java_app_organicmaps_location_LocationState_nativeRemoveListener(JNIEnv * env, jclass clazz) -{ - ASSERT(g_framework, ()); - g_framework->SetMyPositionModeListener(location::TMyPositionModeChanged()); -} - -JNIEXPORT void JNICALL -Java_app_organicmaps_location_LocationState_nativeSetLocationPendingTimeoutListener( - JNIEnv * env, jclass clazz, jobject listener) -{ - ASSERT(g_framework, ()); - g_framework->NativeFramework()->SetMyPositionPendingTimeoutListener( - std::bind(&LocationPendingTimeout, jni::make_global_ref(listener))); -} - -JNIEXPORT void JNICALL -Java_app_organicmaps_location_LocationState_nativeRemoveLocationPendingTimeoutListener( - JNIEnv * env, jclass) -{ - ASSERT(g_framework, ()); - g_framework->NativeFramework()->SetMyPositionPendingTimeoutListener(nullptr); -} -} // extern "C" diff --git a/android/jni/app/organicmaps/Map.cpp b/android/jni/app/organicmaps/Map.cpp deleted file mode 100644 index 616b5dbb5b..0000000000 --- a/android/jni/app/organicmaps/Map.cpp +++ /dev/null @@ -1,177 +0,0 @@ -#include "Framework.hpp" - -#include "app/organicmaps/core/jni_helper.hpp" - -#include "app/organicmaps/platform/Platform.hpp" - -#include "storage/storage_defines.hpp" - -#include "base/logging.hpp" - -#include "platform/settings.hpp" - -namespace -{ -void OnRenderingInitializationFinished(std::shared_ptr const & listener) -{ - JNIEnv * env = jni::GetEnv(); - env->CallVoidMethod(*listener, jni::GetMethodID(env, *listener.get(), - "onRenderingInitializationFinished", "()V")); -} -} // namespace - -extern "C" -{ -JNIEXPORT jboolean JNICALL -Java_app_organicmaps_Map_nativeCreateEngine(JNIEnv * env, jclass, - jobject surface, jint density, - jboolean firstLaunch, - jboolean isLaunchByDeepLink, - jint appVersionCode) -{ - return g_framework->CreateDrapeEngine(env, surface, density, firstLaunch, isLaunchByDeepLink, - base::asserted_cast(appVersionCode)); -} - -JNIEXPORT jboolean JNICALL -Java_app_organicmaps_Map_nativeIsEngineCreated(JNIEnv *, jclass) -{ - return g_framework->IsDrapeEngineCreated(); -} - -JNIEXPORT jboolean JNICALL -Java_app_organicmaps_Map_nativeShowMapForUrl(JNIEnv * env, jclass, jstring url) -{ - return g_framework->ShowMapForURL(jni::ToNativeString(env, url)); -} - -JNIEXPORT void JNICALL -Java_app_organicmaps_Map_nativeSetRenderingInitializationFinishedListener( - JNIEnv *, jclass, jobject listener) -{ - if (listener) - { - g_framework->NativeFramework()->SetGraphicsContextInitializationHandler( - std::bind(&OnRenderingInitializationFinished, jni::make_global_ref(listener))); - } - else - { - g_framework->NativeFramework()->SetGraphicsContextInitializationHandler(nullptr); - } -} - -JNIEXPORT jboolean JNICALL -Java_app_organicmaps_Map_nativeAttachSurface(JNIEnv * env, jclass, jobject surface) -{ - return g_framework->AttachSurface(env, surface); -} - -JNIEXPORT void JNICALL -Java_app_organicmaps_Map_nativeDetachSurface(JNIEnv *, jclass, jboolean destroySurface) -{ - g_framework->DetachSurface(destroySurface); -} - -JNIEXPORT void JNICALL -Java_app_organicmaps_Map_nativeSurfaceChanged(JNIEnv * env, jclass, jobject surface, jint w, jint h) -{ - g_framework->Resize(env, surface, w, h); -} - -JNIEXPORT jboolean JNICALL -Java_app_organicmaps_Map_nativeDestroySurfaceOnDetach(JNIEnv *, jclass) -{ - return g_framework->DestroySurfaceOnDetach(); -} - -JNIEXPORT void JNICALL -Java_app_organicmaps_Map_nativePauseSurfaceRendering(JNIEnv *, jclass) -{ - g_framework->PauseSurfaceRendering(); -} - -JNIEXPORT void JNICALL -Java_app_organicmaps_Map_nativeResumeSurfaceRendering(JNIEnv *, jclass) -{ - g_framework->ResumeSurfaceRendering(); -} - -JNIEXPORT void JNICALL -Java_app_organicmaps_Map_nativeApplyWidgets(JNIEnv *, jclass) -{ - g_framework->ApplyWidgets(); -} - -JNIEXPORT void JNICALL -Java_app_organicmaps_Map_nativeCleanWidgets(JNIEnv *, jclass) -{ - g_framework->CleanWidgets(); -} - -JNIEXPORT void JNICALL -Java_app_organicmaps_Map_nativeSetupWidget( - JNIEnv *, jclass, jint widget, jfloat x, jfloat y, jint anchor) -{ - g_framework->SetupWidget(static_cast(widget), x, y, static_cast(anchor)); -} - -JNIEXPORT void JNICALL -Java_app_organicmaps_Map_nativeCompassUpdated(JNIEnv *, jclass, jdouble north, jboolean forceRedraw) -{ - location::CompassInfo info; - info.m_bearing = north; - - g_framework->OnCompassUpdated(info, forceRedraw); -} - -JNIEXPORT void JNICALL -Java_app_organicmaps_Map_nativeMove( - JNIEnv *, jclass, jdouble factorX, jdouble factorY, jboolean isAnim) -{ - g_framework->Move(factorX, factorY, isAnim); -} - -JNIEXPORT void JNICALL -Java_app_organicmaps_Map_nativeScalePlus(JNIEnv *, jclass) -{ - g_framework->Scale(::Framework::SCALE_MAG); -} - -JNIEXPORT void JNICALL -Java_app_organicmaps_Map_nativeScaleMinus(JNIEnv *, jclass) -{ - g_framework->Scale(::Framework::SCALE_MIN); -} - -JNIEXPORT void JNICALL -Java_app_organicmaps_Map_nativeScale( - JNIEnv *, jclass, jdouble factor, jdouble focusX, jdouble focusY, jboolean isAnim) -{ - g_framework->Scale(factor, {focusX, focusY}, isAnim); -} - -JNIEXPORT void JNICALL -Java_app_organicmaps_Map_nativeOnTouch(JNIEnv *, jclass, jint action, - jint id1, jfloat x1, jfloat y1, - jint id2, jfloat x2, jfloat y2, - jint maskedPointer) -{ - g_framework->Touch(action, - android::Framework::Finger(id1, x1, y1), - android::Framework::Finger(id2, x2, y2), maskedPointer); -} - -JNIEXPORT void JNICALL -Java_app_organicmaps_Map_nativeStorageConnected(JNIEnv *, jclass) -{ - android::Platform::Instance().OnExternalStorageStatusChanged(true); - g_framework->AddLocalMaps(); -} - -JNIEXPORT void JNICALL -Java_app_organicmaps_Map_nativeStorageDisconnected(JNIEnv *, jclass) -{ - android::Platform::Instance().OnExternalStorageStatusChanged(false); - g_framework->RemoveLocalMaps(); -} -} // extern "C" diff --git a/android/jni/app/organicmaps/MwmApplication.cpp b/android/jni/app/organicmaps/MwmApplication.cpp deleted file mode 100644 index bddbc37af0..0000000000 --- a/android/jni/app/organicmaps/MwmApplication.cpp +++ /dev/null @@ -1,61 +0,0 @@ -#include "app/organicmaps/Framework.hpp" - -#include "app/organicmaps/platform/GuiThread.hpp" -#include "app/organicmaps/platform/Platform.hpp" - -#include "app/organicmaps/core/jni_helper.hpp" - -extern "C" -{ - // static void nativeSetSettingsDir(String settingsPath); - JNIEXPORT void JNICALL - Java_app_organicmaps_MwmApplication_nativeSetSettingsDir(JNIEnv * env, jclass clazz, jstring settingsPath) - { - android::Platform::Instance().SetSettingsDir(jni::ToNativeString(env, settingsPath)); - } - - // void nativeInitPlatform(String apkPath, String storagePath, String privatePath, String tmpPath, - // String flavorName, String buildType, boolean isTablet); - JNIEXPORT void JNICALL - Java_app_organicmaps_MwmApplication_nativeInitPlatform(JNIEnv * env, jobject thiz, - jstring apkPath, jstring writablePath, - jstring privatePath, jstring tmpPath, - jstring flavorName, jstring buildType, - jboolean isTablet) - { - android::Platform::Instance().Initialize(env, thiz, apkPath, writablePath, privatePath, tmpPath, - flavorName, buildType, isTablet); - } - - // static void nativeInitFramework(); - JNIEXPORT void JNICALL - Java_app_organicmaps_MwmApplication_nativeInitFramework(JNIEnv * env, jclass clazz) - { - if (!g_framework) - g_framework = std::make_unique(); - } - - // static void nativeProcessTask(long taskPointer); - JNIEXPORT void JNICALL - Java_app_organicmaps_MwmApplication_nativeProcessTask(JNIEnv * env, jclass clazz, jlong taskPointer) - { - android::GuiThread::ProcessTask(taskPointer); - } - - // static void nativeAddLocalization(String name, String value); - JNIEXPORT void JNICALL - Java_app_organicmaps_MwmApplication_nativeAddLocalization(JNIEnv * env, jclass clazz, jstring name, jstring value) - { - g_framework->AddString(jni::ToNativeString(env, name), - jni::ToNativeString(env, value)); - } - - JNIEXPORT void JNICALL - Java_app_organicmaps_MwmApplication_nativeOnTransit(JNIEnv *, jclass, jboolean foreground) - { - if (static_cast(foreground)) - g_framework->NativeFramework()->EnterForeground(); - else - g_framework->NativeFramework()->EnterBackground(); - } -} diff --git a/android/jni/app/organicmaps/TrackRecorder.cpp b/android/jni/app/organicmaps/TrackRecorder.cpp deleted file mode 100644 index 7cf0dfed6a..0000000000 --- a/android/jni/app/organicmaps/TrackRecorder.cpp +++ /dev/null @@ -1,39 +0,0 @@ -#include "Framework.hpp" - -#include "map/gps_tracker.hpp" - -#include - -extern "C" -{ - JNIEXPORT void JNICALL - Java_app_organicmaps_location_TrackRecorder_nativeSetEnabled(JNIEnv * env, jclass clazz, jboolean enable) - { - GpsTracker::Instance().SetEnabled(enable); - Framework * const f = frm(); - if (f == nullptr) - return; - if (enable) - f->ConnectToGpsTracker(); - else - f->DisconnectFromGpsTracker(); - } - - JNIEXPORT jboolean JNICALL - Java_app_organicmaps_location_TrackRecorder_nativeIsEnabled(JNIEnv * env, jclass clazz) - { - return GpsTracker::Instance().IsEnabled(); - } - - JNIEXPORT void JNICALL - Java_app_organicmaps_location_TrackRecorder_nativeSetDuration(JNIEnv * env, jclass clazz, jint durationHours) - { - GpsTracker::Instance().SetDuration(std::chrono::hours(durationHours)); - } - - JNIEXPORT jint JNICALL - Java_app_organicmaps_location_TrackRecorder_nativeGetDuration(JNIEnv * env, jclass clazz) - { - return static_cast(GpsTracker::Instance().GetDuration().count()); - } -} diff --git a/android/jni/app/organicmaps/TrafficState.cpp b/android/jni/app/organicmaps/TrafficState.cpp deleted file mode 100644 index 94ec80fcfc..0000000000 --- a/android/jni/app/organicmaps/TrafficState.cpp +++ /dev/null @@ -1,49 +0,0 @@ -#include "Framework.hpp" - -#include "app/organicmaps/core/jni_helper.hpp" - -#include "app/organicmaps/platform/Platform.hpp" - -extern "C" -{ -static void TrafficStateChanged(TrafficManager::TrafficState state, std::shared_ptr const & listener) -{ - JNIEnv * env = jni::GetEnv(); - env->CallVoidMethod(*listener, jni::GetMethodID(env, *listener, "onTrafficStateChanged", "(I)V"), static_cast(state)); -} - -JNIEXPORT void JNICALL -Java_app_organicmaps_maplayer_traffic_TrafficState_nativeSetListener(JNIEnv * env, jclass clazz, jobject listener) -{ - CHECK(g_framework, ("Framework isn't created yet!")); - g_framework->SetTrafficStateListener(std::bind(&TrafficStateChanged, std::placeholders::_1, jni::make_global_ref(listener))); -} - -JNIEXPORT void JNICALL -Java_app_organicmaps_maplayer_traffic_TrafficState_nativeRemoveListener(JNIEnv * env, jclass clazz) -{ - CHECK(g_framework, ("Framework isn't created yet!")); - g_framework->SetTrafficStateListener(TrafficManager::TrafficStateChangedFn()); -} - -JNIEXPORT void JNICALL -Java_app_organicmaps_maplayer_traffic_TrafficState_nativeEnable(JNIEnv * env, jclass clazz) -{ - CHECK(g_framework, ("Framework isn't created yet!")); - g_framework->EnableTraffic(); -} - -JNIEXPORT jboolean JNICALL -Java_app_organicmaps_maplayer_traffic_TrafficState_nativeIsEnabled(JNIEnv * env, jclass clazz) -{ - CHECK(g_framework, ("Framework isn't created yet!")); - return static_cast(g_framework->IsTrafficEnabled()); -} - -JNIEXPORT void JNICALL -Java_app_organicmaps_maplayer_traffic_TrafficState_nativeDisable(JNIEnv * env, jclass clazz) -{ - CHECK(g_framework, ("Framework isn't created yet!")); - g_framework->DisableTraffic(); -} -} // extern "C" diff --git a/android/jni/app/organicmaps/editor/Editor.cpp b/android/jni/app/organicmaps/editor/Editor.cpp deleted file mode 100644 index cbe58bb013..0000000000 --- a/android/jni/app/organicmaps/editor/Editor.cpp +++ /dev/null @@ -1,531 +0,0 @@ -#include - -#include "app/organicmaps/core/jni_helper.hpp" -#include "app/organicmaps/Framework.hpp" - -#include "editor/osm_editor.hpp" - -#include "indexer/cuisines.hpp" -#include "indexer/editable_map_object.hpp" -#include "indexer/validate_and_format_contacts.hpp" - -#include "coding/string_utf8_multilang.hpp" - -#include "base/assert.hpp" -#include "base/logging.hpp" -#include "base/string_utils.hpp" - -#include "std/target_os.hpp" - -#include -#include -#include - -namespace -{ -using TCuisine = std::pair; -osm::EditableMapObject g_editableMapObject; - -jclass g_localNameClazz; -jmethodID g_localNameCtor; -jfieldID g_localNameFieldCode; -jfieldID g_localNameFieldName; -jclass g_localStreetClazz; -jmethodID g_localStreetCtor; -jfieldID g_localStreetFieldDef; -jfieldID g_localStreetFieldLoc; -jclass g_namesDataSourceClassID; -jmethodID g_namesDataSourceConstructorID; - -jobject ToJavaName(JNIEnv * env, osm::LocalizedName const & name) -{ - jni::TScopedLocalRef jName(env, jni::ToJavaString(env, name.m_name)); - jni::TScopedLocalRef jLang(env, jni::ToJavaString(env, name.m_lang)); - jni::TScopedLocalRef jLangName(env, jni::ToJavaString(env, name.m_langName)); - return env->NewObject(g_localNameClazz, g_localNameCtor, name.m_code, - jName.get(), jLang.get(), jLangName.get()); -} - -jobject ToJavaStreet(JNIEnv * env, osm::LocalizedStreet const & street) -{ - return env->NewObject(g_localStreetClazz, g_localStreetCtor, - jni::TScopedLocalRef(env, jni::ToJavaString(env, street.m_defaultName)).get(), - jni::TScopedLocalRef(env, jni::ToJavaString(env, street.m_localizedName)).get()); -} - -osm::NewFeatureCategories & GetFeatureCategories() -{ - static osm::NewFeatureCategories categories = g_framework->NativeFramework()->GetEditorCategories(); - return categories; -} -} // namespace - -extern "C" -{ -using osm::Editor; - -JNIEXPORT void JNICALL -Java_app_organicmaps_editor_Editor_nativeInit(JNIEnv * env, jclass) -{ - g_localNameClazz = jni::GetGlobalClassRef(env, "app/organicmaps/editor/data/LocalizedName"); - // LocalizedName(int code, @NonNull String name, @NonNull String lang, @NonNull String langName) - g_localNameCtor = jni::GetConstructorID(env, g_localNameClazz, "(ILjava/lang/String;Ljava/lang/String;Ljava/lang/String;)V"); - g_localNameFieldCode = env->GetFieldID(g_localNameClazz, "code", "I"); - g_localNameFieldName = env->GetFieldID(g_localNameClazz, "name", "Ljava/lang/String;"); - - g_localStreetClazz = jni::GetGlobalClassRef(env, "app/organicmaps/editor/data/LocalizedStreet"); - // LocalizedStreet(@NonNull String defaultName, @NonNull String localizedName) - g_localStreetCtor = jni::GetConstructorID(env, g_localStreetClazz, "(Ljava/lang/String;Ljava/lang/String;)V"); - g_localStreetFieldDef = env->GetFieldID(g_localStreetClazz, "defaultName", "Ljava/lang/String;"); - g_localStreetFieldLoc = env->GetFieldID(g_localStreetClazz, "localizedName", "Ljava/lang/String;"); - - g_namesDataSourceClassID = jni::GetGlobalClassRef(env, "app/organicmaps/editor/data/NamesDataSource"); - g_namesDataSourceConstructorID = jni::GetConstructorID(env, g_namesDataSourceClassID, "([Lapp/organicmaps/editor/data/LocalizedName;I)V"); -} - -JNIEXPORT jstring JNICALL -Java_app_organicmaps_editor_Editor_nativeGetOpeningHours(JNIEnv * env, jclass) -{ - return jni::ToJavaString(env, g_editableMapObject.GetOpeningHours()); -} - -JNIEXPORT void JNICALL -Java_app_organicmaps_editor_Editor_nativeSetOpeningHours(JNIEnv * env, jclass, jstring value) -{ - g_editableMapObject.SetOpeningHours(jni::ToNativeString(env, value)); -} - -JNIEXPORT jstring JNICALL -Java_app_organicmaps_editor_Editor_nativeGetMetadata(JNIEnv * env, jclass, jint id) -{ - auto const metaID = static_cast(id); - ASSERT_LESS(metaID, osm::MapObject::MetadataID::FMD_COUNT, ()); - return jni::ToJavaString(env, g_editableMapObject.GetMetadata(metaID)); -} - -JNIEXPORT jboolean JNICALL -Java_app_organicmaps_editor_Editor_nativeIsMetadataValid(JNIEnv * env, jclass, jint id, jstring value) -{ - auto const metaID = static_cast(id); - ASSERT_LESS(metaID, osm::MapObject::MetadataID::FMD_COUNT, ()); - return osm::EditableMapObject::IsValidMetadata(metaID, jni::ToNativeString(env, value)); -} - -JNIEXPORT void JNICALL -Java_app_organicmaps_editor_Editor_nativeSetMetadata(JNIEnv * env, jclass, jint id, jstring value) -{ - auto const metaID = static_cast(id); - ASSERT_LESS(metaID, osm::MapObject::MetadataID::FMD_COUNT, ()); - g_editableMapObject.SetMetadata(metaID, jni::ToNativeString(env, value)); -} - -JNIEXPORT jint JNICALL -Java_app_organicmaps_editor_Editor_nativeGetStars(JNIEnv * env, jclass) -{ - return g_editableMapObject.GetStars(); -} - -JNIEXPORT jint JNICALL -Java_app_organicmaps_editor_Editor_nativeGetMaxEditableBuildingLevels(JNIEnv *, jclass) -{ - return osm::EditableMapObject::kMaximumLevelsEditableByUsers; -} - -JNIEXPORT jboolean JNICALL -Java_app_organicmaps_editor_Editor_nativeHasWifi(JNIEnv *, jclass) -{ - return g_editableMapObject.GetInternet() == osm::Internet::Wlan; -} - -JNIEXPORT void JNICALL -Java_app_organicmaps_editor_Editor_nativeSetHasWifi(JNIEnv *, jclass, jboolean hasWifi) -{ - g_editableMapObject.SetInternet(hasWifi ? osm::Internet::Wlan : osm::Internet::Unknown); -} - -JNIEXPORT jboolean JNICALL -Java_app_organicmaps_editor_Editor_nativeSaveEditedFeature(JNIEnv *, jclass) -{ - switch (g_framework->NativeFramework()->SaveEditedMapObject(g_editableMapObject)) - { - case osm::Editor::SaveResult::NothingWasChanged: - case osm::Editor::SaveResult::SavedSuccessfully: - return true; - case osm::Editor::SaveResult::NoFreeSpaceError: - case osm::Editor::SaveResult::NoUnderlyingMapError: - case osm::Editor::SaveResult::SavingError: - return false; - } -} - -JNIEXPORT jboolean JNICALL -Java_app_organicmaps_editor_Editor_nativeShouldShowEditPlace(JNIEnv *, jclass) -{ - ::Framework * frm = g_framework->NativeFramework(); - if (!frm->HasPlacePageInfo()) - return static_cast(false); - - return g_framework->GetPlacePageInfo().ShouldShowEditPlace(); -} - -JNIEXPORT jboolean JNICALL -Java_app_organicmaps_editor_Editor_nativeShouldShowAddPlace(JNIEnv *, jclass) -{ - ::Framework * frm = g_framework->NativeFramework(); - if (!frm->HasPlacePageInfo()) - return static_cast(false); - - return g_framework->GetPlacePageInfo().ShouldShowAddPlace(); -} - -JNIEXPORT jboolean JNICALL -Java_app_organicmaps_editor_Editor_nativeShouldShowAddBusiness(JNIEnv *, jclass) -{ - ::Framework * frm = g_framework->NativeFramework(); - if (!frm->HasPlacePageInfo()) - return static_cast(false); - - return g_framework->GetPlacePageInfo().ShouldShowAddBusiness(); -} - -JNIEXPORT jintArray JNICALL -Java_app_organicmaps_editor_Editor_nativeGetEditableProperties(JNIEnv * env, jclass clazz) -{ - auto const & editable = g_editableMapObject.GetEditableProperties(); - size_t const size = editable.size(); - jintArray jEditableFields = env->NewIntArray(static_cast(size)); - jint * arr = env->GetIntArrayElements(jEditableFields, 0); - for (size_t i = 0; i < size; ++i) - arr[i] = base::Underlying(editable[i]); - env->ReleaseIntArrayElements(jEditableFields, arr, 0); - - return jEditableFields; -} - -JNIEXPORT jboolean JNICALL -Java_app_organicmaps_editor_Editor_nativeIsAddressEditable(JNIEnv * env, jclass clazz) -{ - return g_editableMapObject.IsAddressEditable(); -} - -JNIEXPORT jboolean JNICALL -Java_app_organicmaps_editor_Editor_nativeIsNameEditable(JNIEnv * env, jclass clazz) -{ - return g_editableMapObject.IsNameEditable(); -} - -JNIEXPORT jboolean JNICALL -Java_app_organicmaps_editor_Editor_nativeIsPointType(JNIEnv * env, jclass clazz) -{ - return g_editableMapObject.IsPointType(); -} - -JNIEXPORT jboolean JNICALL -Java_app_organicmaps_editor_Editor_nativeIsBuilding(JNIEnv * env, jclass clazz) -{ - return g_editableMapObject.IsBuilding(); -} - -JNIEXPORT jobject JNICALL -Java_app_organicmaps_editor_Editor_nativeGetNamesDataSource(JNIEnv * env, jclass, jboolean needFakes) -{ - auto const namesDataSource = g_editableMapObject.GetNamesDataSource(needFakes); - - jobjectArray names = jni::ToJavaArray(env, g_localNameClazz, namesDataSource.names, ToJavaName); - jsize const mandatoryNamesCount = static_cast(namesDataSource.mandatoryNamesCount); - - return env->NewObject(g_namesDataSourceClassID, g_namesDataSourceConstructorID, names, mandatoryNamesCount); -} - -JNIEXPORT jstring JNICALL -Java_app_organicmaps_editor_Editor_nativeGetDefaultName(JNIEnv * env, jclass) -{ - return jni::ToJavaString(env, g_editableMapObject.GetDefaultName()); -} - -JNIEXPORT void JNICALL -Java_app_organicmaps_editor_Editor_nativeEnableNamesAdvancedMode(JNIEnv *, jclass) -{ - g_editableMapObject.EnableNamesAdvancedMode(); -} - -JNIEXPORT void JNICALL -Java_app_organicmaps_editor_Editor_nativeSetNames(JNIEnv * env, jclass, jobjectArray names) -{ - int const length = env->GetArrayLength(names); - for (int i = 0; i < length; i++) - { - auto jName = env->GetObjectArrayElement(names, i); - g_editableMapObject.SetName(jni::ToNativeString(env, static_cast(env->GetObjectField(jName, g_localNameFieldName))), - env->GetIntField(jName, g_localNameFieldCode)); - } -} - -JNIEXPORT jobject JNICALL -Java_app_organicmaps_editor_Editor_nativeGetStreet(JNIEnv * env, jclass) -{ - return ToJavaStreet(env, g_editableMapObject.GetStreet()); -} - -JNIEXPORT void JNICALL -Java_app_organicmaps_editor_Editor_nativeSetStreet(JNIEnv * env, jclass, jobject street) -{ - g_editableMapObject.SetStreet({jni::ToNativeString(env, (jstring) env->GetObjectField(street, g_localStreetFieldDef)), - jni::ToNativeString(env, (jstring) env->GetObjectField(street, g_localStreetFieldLoc))}); -} -JNIEXPORT jobjectArray JNICALL -Java_app_organicmaps_editor_Editor_nativeGetNearbyStreets(JNIEnv * env, jclass clazz) -{ - return jni::ToJavaArray(env, g_localStreetClazz, g_editableMapObject.GetNearbyStreets(), ToJavaStreet); -} - -JNIEXPORT jobjectArray JNICALL -Java_app_organicmaps_editor_Editor_nativeGetSupportedLanguages(JNIEnv * env, jclass clazz) -{ - using TLang = StringUtf8Multilang::Lang; - //public Language(@NonNull String code, @NonNull String name) - static jclass const langClass = jni::GetGlobalClassRef(env, "app/organicmaps/editor/data/Language"); - static jmethodID const langCtor = jni::GetConstructorID(env, langClass, "(Ljava/lang/String;Ljava/lang/String;)V"); - - return jni::ToJavaArray(env, langClass, StringUtf8Multilang::GetSupportedLanguages(), - [](JNIEnv * env, TLang const & lang) - { - jni::TScopedLocalRef const code(env, jni::ToJavaString(env, lang.m_code)); - jni::TScopedLocalRef const name(env, jni::ToJavaString(env, lang.m_name)); - return env->NewObject(langClass, langCtor, code.get(), name.get()); - }); -} - -JNIEXPORT jstring JNICALL -Java_app_organicmaps_editor_Editor_nativeGetHouseNumber(JNIEnv * env, jclass) -{ - return jni::ToJavaString(env, g_editableMapObject.GetHouseNumber()); -} - -JNIEXPORT void JNICALL -Java_app_organicmaps_editor_Editor_nativeSetHouseNumber(JNIEnv * env, jclass, jstring houseNumber) -{ - g_editableMapObject.SetHouseNumber(jni::ToNativeString(env, houseNumber)); -} - -JNIEXPORT jboolean JNICALL -Java_app_organicmaps_editor_Editor_nativeHasSomethingToUpload(JNIEnv * env, jclass clazz) -{ - return Editor::Instance().HaveMapEditsOrNotesToUpload(); -} - -JNIEXPORT void JNICALL -Java_app_organicmaps_editor_Editor_nativeUploadChanges(JNIEnv * env, jclass clazz, jstring token, jstring secret, - jstring appVersion, jstring appId) -{ - // TODO: Handle upload status in callback - Editor::Instance().UploadChanges(jni::ToNativeString(env, token), jni::ToNativeString(env, secret), - {{"created_by", "Organic Maps " OMIM_OS_NAME " " + jni::ToNativeString(env, appVersion)}, - {"bundle_id", jni::ToNativeString(env, appId)}}, nullptr); -} - -JNIEXPORT jlongArray JNICALL -Java_app_organicmaps_editor_Editor_nativeGetStats(JNIEnv * env, jclass clazz) -{ - auto const stats = Editor::Instance().GetStats(); - jlongArray result = env->NewLongArray(3); - jlong buf[] = {static_cast(stats.m_edits.size()), static_cast(stats.m_uploadedCount), - stats.m_lastUploadTimestamp}; - env->SetLongArrayRegion(result, 0, 3, buf); - return result; -} - -JNIEXPORT void JNICALL -Java_app_organicmaps_editor_Editor_nativeClearLocalEdits(JNIEnv * env, jclass clazz) -{ - Editor::Instance().ClearAllLocalEdits(); -} - -JNIEXPORT void JNICALL -Java_app_organicmaps_editor_Editor_nativeStartEdit(JNIEnv *, jclass) -{ - ::Framework * frm = g_framework->NativeFramework(); - if (!frm->HasPlacePageInfo()) - return; - - place_page::Info const & info = g_framework->GetPlacePageInfo(); - CHECK(frm->GetEditableMapObject(info.GetID(), g_editableMapObject), ("Invalid feature in the place page.")); -} - -JNIEXPORT void JNICALL -Java_app_organicmaps_editor_Editor_nativeCreateMapObject(JNIEnv * env, jclass, - jstring featureType) -{ - ::Framework * frm = g_framework->NativeFramework(); - auto const type = classif().GetTypeByReadableObjectName(jni::ToNativeString(env, featureType)); - CHECK(frm->CreateMapObject(frm->GetViewportCenter(), type, g_editableMapObject), - ("Couldn't create mapobject, wrong coordinates of missing mwm")); -} - -// static void nativeCreateNote(String text); -JNIEXPORT void JNICALL -Java_app_organicmaps_editor_Editor_nativeCreateNote(JNIEnv * env, jclass clazz, jstring text) -{ - g_framework->NativeFramework()->CreateNote( - g_editableMapObject, osm::Editor::NoteProblemType::General, jni::ToNativeString(env, text)); -} - -// static void nativePlaceDoesNotExist(String comment); -JNIEXPORT void JNICALL -Java_app_organicmaps_editor_Editor_nativePlaceDoesNotExist(JNIEnv * env, jclass clazz, jstring comment) -{ - g_framework->NativeFramework()->CreateNote(g_editableMapObject, - osm::Editor::NoteProblemType::PlaceDoesNotExist, - jni::ToNativeString(env, comment)); -} - -JNIEXPORT void JNICALL -Java_app_organicmaps_editor_Editor_nativeRollbackMapObject(JNIEnv * env, jclass clazz) -{ - g_framework->NativeFramework()->RollBackChanges(g_editableMapObject.GetID()); -} - -JNIEXPORT jobjectArray JNICALL -Java_app_organicmaps_editor_Editor_nativeGetAllCreatableFeatureTypes(JNIEnv * env, jclass clazz, - jstring jLang) -{ - std::string const & lang = jni::ToNativeString(env, jLang); - GetFeatureCategories().AddLanguage(lang); - return jni::ToJavaStringArray(env, GetFeatureCategories().GetAllCreatableTypeNames()); -} - -JNIEXPORT jobjectArray JNICALL -Java_app_organicmaps_editor_Editor_nativeSearchCreatableFeatureTypes(JNIEnv * env, jclass clazz, - jstring query, - jstring jLang) -{ - std::string const & lang = jni::ToNativeString(env, jLang); - GetFeatureCategories().AddLanguage(lang); - return jni::ToJavaStringArray(env, - GetFeatureCategories().Search(jni::ToNativeString(env, query))); -} - -JNIEXPORT jobjectArray JNICALL -Java_app_organicmaps_editor_Editor_nativeGetCuisines(JNIEnv * env, jclass clazz) -{ - osm::AllCuisines const & cuisines = osm::Cuisines::Instance().AllSupportedCuisines(); - std::vector keys; - keys.reserve(cuisines.size()); - for (TCuisine const & cuisine : cuisines) - keys.push_back(cuisine.first); - return jni::ToJavaStringArray(env, keys); -} - -JNIEXPORT jobjectArray JNICALL -Java_app_organicmaps_editor_Editor_nativeGetSelectedCuisines(JNIEnv * env, jclass clazz) -{ - return jni::ToJavaStringArray(env, g_editableMapObject.GetCuisines()); -} - -JNIEXPORT jobjectArray JNICALL -Java_app_organicmaps_editor_Editor_nativeFilterCuisinesKeys(JNIEnv * env, jclass thiz, jstring jSubstr) -{ - std::string const substr = jni::ToNativeString(env, jSubstr); - bool const noFilter = substr.length() == 0; - osm::AllCuisines const & cuisines = osm::Cuisines::Instance().AllSupportedCuisines(); - std::vector keys; - keys.reserve(cuisines.size()); - - for (TCuisine const & cuisine : cuisines) - { - std::string const & key = cuisine.first; - std::string const & label = cuisine.second; - if (noFilter || search::ContainsNormalized(key, substr) || search::ContainsNormalized(label, substr)) - keys.push_back(key); - } - - return jni::ToJavaStringArray(env, keys); -} - -JNIEXPORT jobjectArray JNICALL -Java_app_organicmaps_editor_Editor_nativeTranslateCuisines(JNIEnv * env, jclass clazz, jobjectArray jKeys) -{ - int const length = env->GetArrayLength(jKeys); - auto const & cuisines = osm::Cuisines::Instance(); - std::vector translations; - translations.reserve(length); - for (int i = 0; i < length; i++) - { - std::string const key = jni::ToNativeString(env, static_cast(env->GetObjectArrayElement(jKeys, i))); - translations.push_back(cuisines.Translate(key)); - } - return jni::ToJavaStringArray(env, translations); -} - -JNIEXPORT void JNICALL -Java_app_organicmaps_editor_Editor_nativeSetSelectedCuisines(JNIEnv * env, jclass clazz, jobjectArray jKeys) -{ - int const length = env->GetArrayLength(jKeys); - std::vector cuisines; - cuisines.reserve(length); - for (int i = 0; i < length; i++) - cuisines.push_back(jni::ToNativeString(env, static_cast(env->GetObjectArrayElement(jKeys, i)))); - g_editableMapObject.SetCuisines(cuisines); -} - -JNIEXPORT jstring JNICALL -Java_app_organicmaps_editor_Editor_nativeGetFormattedCuisine(JNIEnv * env, jclass clazz) -{ - return jni::ToJavaString(env, g_editableMapObject.FormatCuisines()); -} - -JNIEXPORT jstring JNICALL -Java_app_organicmaps_editor_Editor_nativeGetMwmName(JNIEnv * env, jclass clazz) -{ - return jni::ToJavaString(env, g_editableMapObject.GetID().GetMwmName()); -} - -JNIEXPORT jlong JNICALL -Java_app_organicmaps_editor_Editor_nativeGetMwmVersion(JNIEnv * env, jclass clazz) -{ - return g_editableMapObject.GetID().GetMwmVersion(); -} - -// static boolean nativeIsHouseValid(String houseNumber); -JNIEXPORT jboolean JNICALL -Java_app_organicmaps_editor_Editor_nativeIsHouseValid(JNIEnv * env, jclass clazz, jstring houseNumber) -{ - return osm::EditableMapObject::ValidateHouseNumber(jni::ToNativeString(env, houseNumber)); -} - -JNIEXPORT jboolean JNICALL -Java_app_organicmaps_editor_Editor_nativeIsNameValid(JNIEnv * env, jclass clazz, jstring name) -{ - return osm::EditableMapObject::ValidateName(jni::ToNativeString(env, name)); -} - -JNIEXPORT jstring JNICALL -Java_app_organicmaps_editor_Editor_nativeGetCategory(JNIEnv * env, jclass clazz) -{ - auto types = g_editableMapObject.GetTypes(); - types.SortBySpec(); - return jni::ToJavaString(env, classif().GetReadableObjectName(*types.begin())); -} - -// @FeatureStatus -// static native int nativeGetMapObjectStatus(); -JNIEXPORT jint JNICALL -Java_app_organicmaps_editor_Editor_nativeGetMapObjectStatus(JNIEnv * env, jclass clazz) -{ - return static_cast(osm::Editor::Instance().GetFeatureStatus(g_editableMapObject.GetID())); -} - -JNIEXPORT jboolean JNICALL -Java_app_organicmaps_editor_Editor_nativeIsMapObjectUploaded(JNIEnv * env, jclass clazz) -{ - return osm::Editor::Instance().IsFeatureUploaded(g_editableMapObject.GetID().m_mwmId, g_editableMapObject.GetID().m_index); -} - -// static nativeMakeLocalizedName(String langCode, String name); -JNIEXPORT jobject JNICALL -Java_app_organicmaps_editor_Editor_nativeMakeLocalizedName(JNIEnv * env, jclass clazz, jstring code, jstring name) -{ - osm::LocalizedName localizedName(jni::ToNativeString(env, code), jni::ToNativeString(env, name)); - return ToJavaName(env, localizedName); -} -} // extern "C" diff --git a/android/jni/app/organicmaps/isolines/IsolinesManager.cpp b/android/jni/app/organicmaps/isolines/IsolinesManager.cpp deleted file mode 100644 index ee4bebe7c7..0000000000 --- a/android/jni/app/organicmaps/isolines/IsolinesManager.cpp +++ /dev/null @@ -1,47 +0,0 @@ -#include -#include "app/organicmaps/Framework.hpp" -#include "app/organicmaps/core/jni_helper.hpp" -#include "app/organicmaps/platform/Platform.hpp" - -using namespace std::placeholders; - -extern "C" -{ -static void IsolinesStateChanged(IsolinesManager::IsolinesState state, - std::shared_ptr const & listener) -{ - LOG(LINFO, (static_cast(state))); - JNIEnv * env = jni::GetEnv(); - env->CallVoidMethod(*listener, - jni::GetMethodID(env, *listener, "onStateChanged", "(I)V"), - static_cast(state)); -} - - -JNIEXPORT void JNICALL -Java_app_organicmaps_maplayer_isolines_IsolinesManager_nativeAddListener(JNIEnv *env, jclass clazz, jobject listener) -{ - CHECK(g_framework, ("Framework isn't created yet!")); - g_framework->SetIsolinesListener(std::bind(&IsolinesStateChanged, - std::placeholders::_1, - jni::make_global_ref(listener))); -} - -JNIEXPORT void JNICALL -Java_app_organicmaps_maplayer_isolines_IsolinesManager_nativeRemoveListener(JNIEnv * env, jclass clazz) -{ - CHECK(g_framework, ("Framework isn't created yet!")); - g_framework->SetIsolinesListener(nullptr); -} - -JNIEXPORT jboolean JNICALL -Java_app_organicmaps_maplayer_isolines_IsolinesManager_nativeShouldShowNotification(JNIEnv *env, - jclass clazz) -{ - CHECK(g_framework, ("Framework isn't created yet!")); - auto const &manager = g_framework->NativeFramework()->GetIsolinesManager(); - auto const visible = manager.IsVisible(); - auto const enabled = manager.GetState() == IsolinesManager::IsolinesState::Enabled; - return static_cast(!visible && enabled); -} -} diff --git a/android/jni/app/organicmaps/platform/Language.cpp b/android/jni/app/organicmaps/platform/Language.cpp deleted file mode 100644 index 17142a4b69..0000000000 --- a/android/jni/app/organicmaps/platform/Language.cpp +++ /dev/null @@ -1,57 +0,0 @@ -#include "android/jni/app/organicmaps/core/jni_helper.hpp" -#include "android/jni/app/organicmaps/core/ScopedLocalRef.hpp" - -#include "platform/locale.hpp" - -#include "base/assert.hpp" -#include "base/logging.hpp" -#include "base/string_utils.hpp" - -#include - -/// This function is called from native c++ code -std::string GetAndroidSystemLanguage() -{ - static char const * DEFAULT_LANG = "en"; - - JNIEnv * env = jni::GetEnv(); - if (!env) - { - LOG(LWARNING, ("Can't get JNIEnv")); - return DEFAULT_LANG; - } - - static jclass const languageClass = jni::GetGlobalClassRef(env, "app/organicmaps/util/Language"); - static jmethodID const getDefaultLocaleId = jni::GetStaticMethodID(env, languageClass, "getDefaultLocale", "()Ljava/lang/String;"); - - jni::TScopedLocalRef localeRef(env, env->CallStaticObjectMethod(languageClass, getDefaultLocaleId)); - - std::string res = jni::ToNativeString(env, (jstring) localeRef.get()); - if (res.empty()) - res = DEFAULT_LANG; - - return res; -} - -namespace platform -{ -Locale GetCurrentLocale() -{ - JNIEnv * env = jni::GetEnv(); - static jmethodID const getLanguageCodeId = jni::GetStaticMethodID(env, g_utilsClazz, "getLanguageCode", - "()Ljava/lang/String;"); - jni::ScopedLocalRef languageCode(env, env->CallStaticObjectMethod(g_utilsClazz, getLanguageCodeId)); - - static jmethodID const getCountryCodeId = jni::GetStaticMethodID(env, g_utilsClazz, "getCountryCode", - "()Ljava/lang/String;"); - jni::ScopedLocalRef countryCode(env, env->CallStaticObjectMethod(g_utilsClazz, getCountryCodeId)); - - static jmethodID const getCurrencyCodeId = jni::GetStaticMethodID(env, g_utilsClazz, "getCurrencyCode", - "()Ljava/lang/String;"); - jni::ScopedLocalRef currencyCode(env, env->CallStaticObjectMethod(g_utilsClazz, getCurrencyCodeId)); - - return {jni::ToNativeString(env, static_cast(languageCode.get())), - jni::ToNativeString(env, static_cast(countryCode.get())), - currencyCode.get() ? jni::ToNativeString(env, static_cast(currencyCode.get())) : ""}; -} -} // namespace platform diff --git a/android/jni/app/organicmaps/settings/UnitLocale.cpp b/android/jni/app/organicmaps/settings/UnitLocale.cpp deleted file mode 100644 index 7214bff662..0000000000 --- a/android/jni/app/organicmaps/settings/UnitLocale.cpp +++ /dev/null @@ -1,23 +0,0 @@ -#include "app/organicmaps/Framework.hpp" - -#include "platform/measurement_utils.hpp" -#include "platform/settings.hpp" - -extern "C" -{ - JNIEXPORT void JNICALL - Java_app_organicmaps_settings_UnitLocale_setCurrentUnits(JNIEnv * env, jobject thiz, jint units) - { - measurement_utils::Units const u = static_cast(units); - settings::Set(settings::kMeasurementUnits, u); - g_framework->SetupMeasurementSystem(); - } - - JNIEXPORT jint JNICALL - Java_app_organicmaps_settings_UnitLocale_getCurrentUnits(JNIEnv * env, jobject thiz) - { - measurement_utils::Units u; - return static_cast( - settings::Get(settings::kMeasurementUnits, u) ? u : measurement_utils::Units::Metric); - } -} diff --git a/android/jni/app/organicmaps/sound/tts.cpp b/android/jni/app/organicmaps/sound/tts.cpp deleted file mode 100644 index 1c25d18287..0000000000 --- a/android/jni/app/organicmaps/sound/tts.cpp +++ /dev/null @@ -1,30 +0,0 @@ -#include "app/organicmaps/Framework.hpp" - -#include "app/organicmaps/core/jni_helper.hpp" - -extern "C" -{ - JNIEXPORT void JNICALL - Java_app_organicmaps_sound_TtsPlayer_nativeEnableTurnNotifications(JNIEnv *, jclass, jboolean enable) - { - return frm()->GetRoutingManager().EnableTurnNotifications(static_cast(enable)); - } - - JNIEXPORT jboolean JNICALL - Java_app_organicmaps_sound_TtsPlayer_nativeAreTurnNotificationsEnabled(JNIEnv *, jclass) - { - return static_cast(frm()->GetRoutingManager().AreTurnNotificationsEnabled()); - } - - JNIEXPORT void JNICALL - Java_app_organicmaps_sound_TtsPlayer_nativeSetTurnNotificationsLocale(JNIEnv * env, jclass, jstring jLocale) - { - frm()->GetRoutingManager().SetTurnNotificationsLocale(jni::ToNativeString(env, jLocale)); - } - - JNIEXPORT jstring JNICALL - Java_app_organicmaps_sound_TtsPlayer_nativeGetTurnNotificationsLocale(JNIEnv * env, jclass) - { - return jni::ToJavaString(env, frm()->GetRoutingManager().GetTurnNotificationsLocale()); - } -} // extern "C" diff --git a/android/jni/app/organicmaps/subway/SubwayManager.cpp b/android/jni/app/organicmaps/subway/SubwayManager.cpp deleted file mode 100644 index c495bf572f..0000000000 --- a/android/jni/app/organicmaps/subway/SubwayManager.cpp +++ /dev/null @@ -1,32 +0,0 @@ -#include -#include -#include "app/organicmaps/core/jni_helper.hpp" -#include "app/organicmaps/platform/Platform.hpp" - -extern "C" -{ -static void TransitSchemeStateChanged(TransitReadManager::TransitSchemeState state, - std::shared_ptr const & listener) -{ - JNIEnv * env = jni::GetEnv(); - env->CallVoidMethod(*listener, - jni::GetMethodID(env, *listener, "onTransitStateChanged", "(I)V"), - static_cast(state)); -} - -JNIEXPORT void JNICALL -Java_app_organicmaps_maplayer_subway_SubwayManager_nativeAddListener(JNIEnv *env, jclass clazz, jobject listener) -{ - CHECK(g_framework, ("Framework isn't created yet!")); - g_framework->SetTransitSchemeListener(std::bind(&TransitSchemeStateChanged, - std::placeholders::_1, - jni::make_global_ref(listener))); -} - -JNIEXPORT void JNICALL -Java_app_organicmaps_maplayer_subway_SubwayManager_nativeRemoveListener(JNIEnv * env, jclass clazz) -{ - CHECK(g_framework, ("Framework isn't created yet!")); - g_framework->SetTransitSchemeListener(TransitReadManager::TransitStateChangedFn()); -} -} diff --git a/android/jni/app/organicmaps/util/Config.cpp b/android/jni/app/organicmaps/util/Config.cpp deleted file mode 100644 index 6c92610c20..0000000000 --- a/android/jni/app/organicmaps/util/Config.cpp +++ /dev/null @@ -1,114 +0,0 @@ -#include "app/organicmaps/core/jni_helper.hpp" -#include "app/organicmaps/Framework.hpp" -#include "platform/settings.hpp" - -extern "C" -{ - JNIEXPORT jboolean JNICALL - Java_app_organicmaps_util_Config_nativeGetBoolean(JNIEnv * env, jclass thiz, jstring name, jboolean defaultVal) - { - bool val; - if (settings::Get(jni::ToNativeString(env, name), val)) - return static_cast(val); - - return defaultVal; - } - - JNIEXPORT void JNICALL - Java_app_organicmaps_util_Config_nativeSetBoolean(JNIEnv * env, jclass thiz, jstring name, jboolean val) - { - (void)settings::Set(jni::ToNativeString(env, name), static_cast(val)); - } - - JNIEXPORT jint JNICALL - Java_app_organicmaps_util_Config_nativeGetInt(JNIEnv * env, jclass thiz, jstring name, jint defaultValue) - { - int32_t value; - if (settings::Get(jni::ToNativeString(env, name), value)) - return static_cast(value); - - return defaultValue; - } - - JNIEXPORT void JNICALL - Java_app_organicmaps_util_Config_nativeSetInt(JNIEnv * env, jclass thiz, jstring name, jint value) - { - (void)settings::Set(jni::ToNativeString(env, name), static_cast(value)); - } - - JNIEXPORT jlong JNICALL - Java_app_organicmaps_util_Config_nativeGetLong(JNIEnv * env, jclass thiz, jstring name, jlong defaultValue) - { - int64_t value; - if (settings::Get(jni::ToNativeString(env, name), value)) - return static_cast(value); - - return defaultValue; - } - - JNIEXPORT void JNICALL - Java_app_organicmaps_util_Config_nativeSetLong(JNIEnv * env, jclass thiz, jstring name, jlong value) - { - (void)settings::Set(jni::ToNativeString(env, name), static_cast(value)); - } - - JNIEXPORT jdouble JNICALL - Java_app_organicmaps_util_Config_nativeGetDouble(JNIEnv * env, jclass thiz, jstring name, jdouble defaultValue) - { - double value; - if (settings::Get(jni::ToNativeString(env, name), value)) - return static_cast(value); - - return defaultValue; - } - - JNIEXPORT void JNICALL - Java_app_organicmaps_util_Config_nativeSetDouble(JNIEnv * env, jclass thiz, jstring name, jdouble value) - { - (void)settings::Set(jni::ToNativeString(env, name), static_cast(value)); - } - - JNIEXPORT jstring JNICALL - Java_app_organicmaps_util_Config_nativeGetString(JNIEnv * env, jclass thiz, jstring name, jstring defaultValue) - { - std::string value; - if (settings::Get(jni::ToNativeString(env, name), value)) - return jni::ToJavaString(env, value); - - return defaultValue; - } - - JNIEXPORT void JNICALL - Java_app_organicmaps_util_Config_nativeSetString(JNIEnv * env, jclass thiz, jstring name, jstring value) - { - (void)settings::Set(jni::ToNativeString(env, name), jni::ToNativeString(env, value)); - } - - JNIEXPORT jboolean JNICALL - Java_app_organicmaps_util_Config_nativeGetLargeFontsSize(JNIEnv * env, jclass thiz) - { - return frm()->LoadLargeFontsSize(); - } - - JNIEXPORT void JNICALL - Java_app_organicmaps_util_Config_nativeSetLargeFontsSize(JNIEnv * env, jclass thiz, - jboolean value) - { - frm()->SaveLargeFontsSize(value); - frm()->SetLargeFontsSize(value); - } - - JNIEXPORT jboolean JNICALL - Java_app_organicmaps_util_Config_nativeGetTransliteration(JNIEnv * env, jclass thiz) - { - return frm()->LoadTransliteration(); - } - - JNIEXPORT void JNICALL - Java_app_organicmaps_util_Config_nativeSetTransliteration(JNIEnv * env, jclass thiz, - jboolean value) - { - frm()->SaveTransliteration(value); - frm()->AllowTransliteration(value); - } -} // extern "C" diff --git a/android/jni/app/organicmaps/util/Language.cpp b/android/jni/app/organicmaps/util/Language.cpp deleted file mode 100644 index f574e00f44..0000000000 --- a/android/jni/app/organicmaps/util/Language.cpp +++ /dev/null @@ -1,12 +0,0 @@ -#include "android/jni/app/organicmaps/core/jni_helper.hpp" -#include "platform/preferred_languages.hpp" - -extern "C" -{ -JNIEXPORT jstring JNICALL -Java_app_organicmaps_util_Language_nativeNormalize(JNIEnv *env, jclass type, jstring lang) -{ - std::string locale = languages::Normalize(jni::ToNativeString(env, lang)); - return jni::ToJavaString(env, locale); -} -} diff --git a/android/jni/app/organicmaps/util/LogsManager.cpp b/android/jni/app/organicmaps/util/LogsManager.cpp deleted file mode 100644 index 802221ebcd..0000000000 --- a/android/jni/app/organicmaps/util/LogsManager.cpp +++ /dev/null @@ -1,11 +0,0 @@ -#include -#include "app/organicmaps/core/logging.hpp" - -extern "C" { -JNIEXPORT void JNICALL -Java_app_organicmaps_util_log_LogsManager_nativeToggleCoreDebugLogs( - JNIEnv * /*env*/, jclass /*clazz*/, jboolean enabled) -{ - jni::ToggleDebugLogs(enabled); -} -} // extern "C" diff --git a/android/jni/app/organicmaps/util/StringUtils.cpp b/android/jni/app/organicmaps/util/StringUtils.cpp deleted file mode 100644 index 6c561530fa..0000000000 --- a/android/jni/app/organicmaps/util/StringUtils.cpp +++ /dev/null @@ -1,102 +0,0 @@ -#include "app/organicmaps/core/jni_helper.hpp" - -#include "indexer/search_string_utils.hpp" - -#include "platform/localization.hpp" -#include "platform/measurement_utils.hpp" -#include "platform/settings.hpp" - -#include - -namespace -{ -jobject MakeJavaPair(JNIEnv * env, std::string const & first, std::string const & second) -{ - static jclass const pairClass = jni::GetGlobalClassRef(env, "android/util/Pair"); - static jmethodID const pairCtor = - jni::GetConstructorID(env, pairClass, "(Ljava/lang/Object;Ljava/lang/Object;)V"); - return env->NewObject(pairClass, pairCtor, jni::ToJavaString(env, first), - jni::ToJavaString(env, second)); -} -} // namespace - -extern "C" -{ -JNIEXPORT jboolean JNICALL -Java_app_organicmaps_util_StringUtils_nativeIsHtml(JNIEnv * env, jclass thiz, jstring text) -{ - return strings::IsHTML(jni::ToNativeString(env, text)); -} - -JNIEXPORT jboolean JNICALL -Java_app_organicmaps_util_StringUtils_nativeContainsNormalized(JNIEnv * env, jclass thiz, jstring str, jstring substr) -{ - return search::ContainsNormalized(jni::ToNativeString(env, str), jni::ToNativeString(env, substr)); -} - -JNIEXPORT jobjectArray JNICALL -Java_app_organicmaps_util_StringUtils_nativeFilterContainsNormalized(JNIEnv * env, jclass thiz, jobjectArray src, jstring jSubstr) -{ - std::string const substr = jni::ToNativeString(env, jSubstr); - int const length = env->GetArrayLength(src); - std::vector filtered; - filtered.reserve(length); - for (int i = 0; i < length; i++) - { - std::string const str = jni::ToNativeString(env, static_cast(env->GetObjectArrayElement(src, i))); - if (search::ContainsNormalized(str, substr)) - filtered.push_back(str); - } - - return jni::ToJavaStringArray(env, filtered); -} - -JNIEXPORT jobject JNICALL Java_app_organicmaps_util_StringUtils_nativeFormatSpeedAndUnits( - JNIEnv * env, jclass thiz, jdouble metersPerSecond) -{ - auto const units = measurement_utils::GetMeasurementUnits(); - return MakeJavaPair(env, measurement_utils::FormatSpeedNumeric(metersPerSecond, units), - platform::GetLocalizedSpeedUnits(units)); -} - -JNIEXPORT jstring JNICALL -Java_app_organicmaps_util_StringUtils_nativeFormatDistance(JNIEnv * env, jclass thiz, - jdouble distanceInMeters) -{ - auto const localizedUnits = platform::GetLocalizedDistanceUnits(); - return jni::ToJavaString(env, measurement_utils::FormatDistanceWithLocalization(distanceInMeters, - localizedUnits.m_high, - localizedUnits.m_low)); -} - -JNIEXPORT jstring JNICALL -Java_app_organicmaps_util_StringUtils_nativeFormatDistanceWithLocalization(JNIEnv * env, jclass, - jdouble distanceInMeters, - jstring high, - jstring low) -{ - auto const distance = measurement_utils::FormatDistanceWithLocalization( - distanceInMeters, jni::ToNativeString(env, high), jni::ToNativeString(env, low)); - return jni::ToJavaString(env, distance); -} - -JNIEXPORT jobject JNICALL -Java_app_organicmaps_util_StringUtils_nativeGetLocalizedDistanceUnits(JNIEnv * env, jclass) -{ - auto const localizedUnits = platform::GetLocalizedDistanceUnits(); - return MakeJavaPair(env, localizedUnits.m_high, localizedUnits.m_low); -} - -JNIEXPORT jobject JNICALL -Java_app_organicmaps_util_StringUtils_nativeGetLocalizedAltitudeUnits(JNIEnv * env, jclass) -{ - auto const localizedUnits = platform::GetLocalizedAltitudeUnits(); - return MakeJavaPair(env, localizedUnits.m_high, localizedUnits.m_low); -} - -JNIEXPORT jstring JNICALL -Java_app_organicmaps_util_StringUtils_nativeGetLocalizedSpeedUnits(JNIEnv * env, jclass) -{ - return jni::ToJavaString(env, platform::GetLocalizedSpeedUnits()); -} -} // extern "C" diff --git a/android/jni/app/organicmaps/core/ScopedEnv.hpp b/android/jni/com/mapswithme/core/ScopedEnv.hpp similarity index 100% rename from android/jni/app/organicmaps/core/ScopedEnv.hpp rename to android/jni/com/mapswithme/core/ScopedEnv.hpp diff --git a/android/jni/app/organicmaps/core/ScopedLocalRef.hpp b/android/jni/com/mapswithme/core/ScopedLocalRef.hpp similarity index 100% rename from android/jni/app/organicmaps/core/ScopedLocalRef.hpp rename to android/jni/com/mapswithme/core/ScopedLocalRef.hpp diff --git a/android/jni/app/organicmaps/core/jni_helper.cpp b/android/jni/com/mapswithme/core/jni_helper.cpp similarity index 85% rename from android/jni/app/organicmaps/core/jni_helper.cpp rename to android/jni/com/mapswithme/core/jni_helper.cpp index 05e770dceb..96f06c6281 100644 --- a/android/jni/app/organicmaps/core/jni_helper.cpp +++ b/android/jni/com/mapswithme/core/jni_helper.cpp @@ -41,23 +41,23 @@ JNI_OnLoad(JavaVM * jvm, void *) jni::InitAssertLog(); JNIEnv * env = jni::GetEnv(); - g_mapObjectClazz = jni::GetGlobalClassRef(env, "app/organicmaps/bookmarks/data/MapObject"); - g_featureIdClazz = jni::GetGlobalClassRef(env, "app/organicmaps/bookmarks/data/FeatureId"); - g_bookmarkClazz = jni::GetGlobalClassRef(env, "app/organicmaps/bookmarks/data/Bookmark"); - g_httpClientClazz = jni::GetGlobalClassRef(env, "app/organicmaps/util/HttpClient"); - g_httpParamsClazz = jni::GetGlobalClassRef(env, "app/organicmaps/util/HttpClient$Params"); - g_platformSocketClazz = jni::GetGlobalClassRef(env, "app/organicmaps/location/PlatformSocket"); - g_utilsClazz = jni::GetGlobalClassRef(env, "app/organicmaps/util/Utils"); - g_loggerClazz = jni::GetGlobalClassRef(env, "app/organicmaps/util/log/Logger"); - g_keyValueClazz = jni::GetGlobalClassRef(env, "app/organicmaps/util/KeyValue"); - g_httpUploaderClazz = jni::GetGlobalClassRef(env, "app/organicmaps/util/HttpUploader"); - g_httpPayloadClazz = jni::GetGlobalClassRef(env, "app/organicmaps/util/HttpPayload"); + g_mapObjectClazz = jni::GetGlobalClassRef(env, "com/mapswithme/maps/bookmarks/data/MapObject"); + g_featureIdClazz = jni::GetGlobalClassRef(env, "com/mapswithme/maps/bookmarks/data/FeatureId"); + g_bookmarkClazz = jni::GetGlobalClassRef(env, "com/mapswithme/maps/bookmarks/data/Bookmark"); + g_httpClientClazz = jni::GetGlobalClassRef(env, "com/mapswithme/util/HttpClient"); + g_httpParamsClazz = jni::GetGlobalClassRef(env, "com/mapswithme/util/HttpClient$Params"); + g_platformSocketClazz = jni::GetGlobalClassRef(env, "com/mapswithme/maps/location/PlatformSocket"); + g_utilsClazz = jni::GetGlobalClassRef(env, "com/mapswithme/util/Utils"); + g_loggerClazz = jni::GetGlobalClassRef(env, "com/mapswithme/util/log/Logger"); + g_keyValueClazz = jni::GetGlobalClassRef(env, "com/mapswithme/util/KeyValue"); + g_httpUploaderClazz = jni::GetGlobalClassRef(env, "com/mapswithme/util/HttpUploader"); + g_httpPayloadClazz = jni::GetGlobalClassRef(env, "com/mapswithme/util/HttpPayload"); g_httpBackgroundUploaderClazz = - jni::GetGlobalClassRef(env, "app/organicmaps/util/HttpBackgroundUploader"); - g_httpUploaderResultClazz = jni::GetGlobalClassRef(env, "app/organicmaps/util/HttpUploader$Result"); - g_networkPolicyClazz = jni::GetGlobalClassRef(env, "app/organicmaps/util/NetworkPolicy"); - g_elevationInfoClazz = jni::GetGlobalClassRef(env, "app/organicmaps/bookmarks/data/ElevationInfo"); - g_parsingResultClazz = jni::GetGlobalClassRef(env, "app/organicmaps/api/ParsingResult"); + jni::GetGlobalClassRef(env, "com/mapswithme/util/HttpBackgroundUploader"); + g_httpUploaderResultClazz = jni::GetGlobalClassRef(env, "com/mapswithme/util/HttpUploader$Result"); + g_networkPolicyClazz = jni::GetGlobalClassRef(env, "com/mapswithme/util/NetworkPolicy"); + g_elevationInfoClazz = jni::GetGlobalClassRef(env, "com/mapswithme/maps/bookmarks/data/ElevationInfo"); + g_parsingResultClazz = jni::GetGlobalClassRef(env, "com/mapswithme/maps/api/ParsingResult"); return JNI_VERSION_1_6; } @@ -107,7 +107,6 @@ JavaVM * GetJVM() jmethodID GetMethodID(JNIEnv * env, jobject obj, char const * name, char const * signature) { - // GetObjectClass may hang in WaitHoldingLocks. TScopedLocalClassRef clazz(env, env->GetObjectClass(obj)); ASSERT(clazz.get(), ("Can't get class: ", DescribeException())); @@ -256,7 +255,7 @@ std::string DescribeException() jobject GetNewParcelablePointD(JNIEnv * env, m2::PointD const & point) { - jclass klass = env->FindClass("app/organicmaps/bookmarks/data/ParcelablePointD"); + jclass klass = env->FindClass("com/mapswithme/maps/bookmarks/data/ParcelablePointD"); ASSERT ( klass, () ); jmethodID methodID = GetConstructorID(env, klass, "(DD)V"); diff --git a/android/jni/app/organicmaps/core/jni_helper.hpp b/android/jni/com/mapswithme/core/jni_helper.hpp similarity index 100% rename from android/jni/app/organicmaps/core/jni_helper.hpp rename to android/jni/com/mapswithme/core/jni_helper.hpp diff --git a/android/jni/app/organicmaps/core/logging.cpp b/android/jni/com/mapswithme/core/logging.cpp similarity index 92% rename from android/jni/app/organicmaps/core/logging.cpp rename to android/jni/com/mapswithme/core/logging.cpp index abe1fcbd23..7a34b839cd 100644 --- a/android/jni/app/organicmaps/core/logging.cpp +++ b/android/jni/com/mapswithme/core/logging.cpp @@ -3,9 +3,9 @@ #include "base/exception.hpp" #include "base/logging.hpp" -#include "app/organicmaps/core/jni_helper.hpp" -#include "app/organicmaps/core/logging.hpp" -#include "app/organicmaps/core/ScopedEnv.hpp" +#include "com/mapswithme/core/jni_helper.hpp" +#include "com/mapswithme/core/logging.hpp" +#include "com/mapswithme/core/ScopedEnv.hpp" #include #include diff --git a/android/jni/app/organicmaps/core/logging.hpp b/android/jni/com/mapswithme/core/logging.hpp similarity index 100% rename from android/jni/app/organicmaps/core/logging.hpp rename to android/jni/com/mapswithme/core/logging.hpp diff --git a/android/jni/app/organicmaps/core/render_context.cpp b/android/jni/com/mapswithme/core/render_context.cpp similarity index 100% rename from android/jni/app/organicmaps/core/render_context.cpp rename to android/jni/com/mapswithme/core/render_context.cpp diff --git a/android/jni/app/organicmaps/core/render_context.hpp b/android/jni/com/mapswithme/core/render_context.hpp similarity index 100% rename from android/jni/app/organicmaps/core/render_context.hpp rename to android/jni/com/mapswithme/core/render_context.hpp diff --git a/android/jni/com/mapswithme/maps/DisplayedCategories.cpp b/android/jni/com/mapswithme/maps/DisplayedCategories.cpp new file mode 100644 index 0000000000..56d88ef84a --- /dev/null +++ b/android/jni/com/mapswithme/maps/DisplayedCategories.cpp @@ -0,0 +1,16 @@ +#include "com/mapswithme/maps/Framework.hpp" +#include "com/mapswithme/core/jni_helper.hpp" + +#include "search/displayed_categories.hpp" + +extern "C" +{ +JNIEXPORT jobjectArray JNICALL +Java_com_mapswithme_maps_search_DisplayedCategories_nativeGetKeys(JNIEnv * env, jclass clazz) +{ + ::Framework * fr = g_framework->NativeFramework(); + ASSERT(fr, ()); + search::DisplayedCategories categories = fr->GetDisplayedCategories(); + return jni::ToJavaStringArray(env, categories.GetKeys()); +} +} // extern "C" diff --git a/android/jni/app/organicmaps/DownloadResourcesLegacyActivity.cpp b/android/jni/com/mapswithme/maps/DownloadResourcesLegacyActivity.cpp similarity index 92% rename from android/jni/app/organicmaps/DownloadResourcesLegacyActivity.cpp rename to android/jni/com/mapswithme/maps/DownloadResourcesLegacyActivity.cpp index 748368a633..be8cce17ab 100644 --- a/android/jni/app/organicmaps/DownloadResourcesLegacyActivity.cpp +++ b/android/jni/com/mapswithme/maps/DownloadResourcesLegacyActivity.cpp @@ -16,7 +16,7 @@ #include "base/logging.hpp" #include "base/string_utils.hpp" -#include "app/organicmaps/core/jni_helper.hpp" +#include "com/mapswithme/core/jni_helper.hpp" #include #include @@ -70,7 +70,7 @@ extern "C" } JNIEXPORT jint JNICALL - Java_app_organicmaps_DownloadResourcesLegacyActivity_nativeGetBytesToDownload(JNIEnv * env, jclass clazz) + Java_com_mapswithme_maps_DownloadResourcesLegacyActivity_nativeGetBytesToDownload(JNIEnv * env, jclass clazz) { // clear all g_filesToDownload.clear(); @@ -149,7 +149,7 @@ extern "C" } JNIEXPORT jint JNICALL - Java_app_organicmaps_DownloadResourcesLegacyActivity_nativeStartNextFileDownload(JNIEnv * env, jclass clazz, jobject listener) + Java_com_mapswithme_maps_DownloadResourcesLegacyActivity_nativeStartNextFileDownload(JNIEnv * env, jclass clazz, jobject listener) { if (g_filesToDownload.empty()) return ERR_NO_MORE_FILES; @@ -178,7 +178,7 @@ extern "C" } JNIEXPORT void JNICALL - Java_app_organicmaps_DownloadResourcesLegacyActivity_nativeCancelCurrentFile(JNIEnv * env, jclass clazz) + Java_com_mapswithme_maps_DownloadResourcesLegacyActivity_nativeCancelCurrentFile(JNIEnv * env, jclass clazz) { LOG(LDEBUG, ("cancelCurrentFile, currentRequest=", g_currentRequest)); g_currentRequest.reset(); diff --git a/android/jni/app/organicmaps/Framework.cpp b/android/jni/com/mapswithme/maps/Framework.cpp similarity index 80% rename from android/jni/app/organicmaps/Framework.cpp rename to android/jni/com/mapswithme/maps/Framework.cpp index ad17613965..fa612abe0c 100644 --- a/android/jni/app/organicmaps/Framework.cpp +++ b/android/jni/com/mapswithme/maps/Framework.cpp @@ -1,12 +1,12 @@ -#include "app/organicmaps/Framework.hpp" +#include "com/mapswithme/maps/Framework.hpp" -#include "app/organicmaps/core/jni_helper.hpp" -#include "app/organicmaps/UserMarkHelper.hpp" -#include "app/organicmaps/opengl/androidoglcontextfactory.hpp" -#include "app/organicmaps/platform/Platform.hpp" -#include "app/organicmaps/util/FeatureIdBuilder.hpp" -#include "app/organicmaps/util/NetworkPolicy.hpp" -#include "app/organicmaps/vulkan/android_vulkan_context_factory.hpp" +#include "com/mapswithme/core/jni_helper.hpp" +#include "com/mapswithme/maps/UserMarkHelper.hpp" +#include "com/mapswithme/opengl/androidoglcontextfactory.hpp" +#include "com/mapswithme/platform/Platform.hpp" +#include "com/mapswithme/util/FeatureIdBuilder.hpp" +#include "com/mapswithme/util/NetworkPolicy.hpp" +#include "com/mapswithme/vulkan/android_vulkan_context_factory.hpp" #include "map/bookmark_helpers.hpp" #include "map/chart_generator.hpp" @@ -278,6 +278,9 @@ void Framework::Resize(JNIEnv * env, jobject jSurface, int w, int h) m_oglContextFactory->CastFactory()->UpdateSurfaceSize(w, h); } m_work.OnSize(w, h); + + //TODO: remove after correct visible rect calculation. + frm()->SetVisibleViewport(m2::RectD(0, 0, w, h)); } void Framework::DetachSurface(bool destroySurface) @@ -471,16 +474,6 @@ void Framework::ShowNode(CountryId const & idx, bool zoomToDownloadButton) } } -void Framework::Scale(double factor, m2::PointD const & pxPoint, bool isAnim) -{ - m_work.Scale(factor, pxPoint, isAnim); -} - -void Framework::Move(double factorX, double factorY, bool isAnim) -{ - m_work.Move(factorX, factorY, isAnim); -} - void Framework::Touch(int action, Finger const & f1, Finger const & f2, uint8_t maskedPointer) { MultiTouchAction eventType = static_cast(action); @@ -733,7 +726,7 @@ FeatureID Framework::BuildFeatureId(JNIEnv * env, jobject featureId) } } // namespace android -//============ GLUE CODE for app.organicmaps.Framework class =============// +//============ GLUE CODE for com.mapswithme.maps.Framework class =============// /* ____ * _ |||| _ * \\ // @@ -780,20 +773,20 @@ RoutingManager::LoadRouteHandler g_loadRouteHandler; /// @name JNI EXPORTS JNIEXPORT jstring JNICALL -Java_app_organicmaps_Framework_nativeGetAddress(JNIEnv * env, jclass clazz, jdouble lat, jdouble lon) +Java_com_mapswithme_maps_Framework_nativeGetAddress(JNIEnv * env, jclass clazz, jdouble lat, jdouble lon) { auto const info = frm()->GetAddressAtPoint(mercator::FromLatLon(lat, lon)); return jni::ToJavaString(env, info.FormatAddress()); } JNIEXPORT void JNICALL -Java_app_organicmaps_Framework_nativeClearApiPoints(JNIEnv * env, jclass clazz) +Java_com_mapswithme_maps_Framework_nativeClearApiPoints(JNIEnv * env, jclass clazz) { frm()->GetBookmarkManager().GetEditSession().ClearGroup(UserMark::Type::API); } JNIEXPORT jobject JNICALL -Java_app_organicmaps_Framework_nativeParseAndSetApiUrl(JNIEnv * env, jclass clazz, jstring url) +Java_com_mapswithme_maps_Framework_nativeParseAndSetApiUrl(JNIEnv * env, jclass clazz, jstring url) { static jmethodID const resultConstructor = jni::GetConstructorID(env, g_parsingResultClazz, "(IZ)V"); auto const result = frm()->ParseAndSetApiURL(jni::ToNativeString(env, url)); @@ -802,16 +795,16 @@ Java_app_organicmaps_Framework_nativeParseAndSetApiUrl(JNIEnv * env, jclass claz } JNIEXPORT jobject JNICALL -Java_app_organicmaps_Framework_nativeGetParsedRoutingData(JNIEnv * env, jclass clazz) +Java_com_mapswithme_maps_Framework_nativeGetParsedRoutingData(JNIEnv * env, jclass clazz) { using namespace url_scheme; - static jclass const pointClazz = jni::GetGlobalClassRef(env, "app/organicmaps/api/RoutePoint"); + static jclass const pointClazz = jni::GetGlobalClassRef(env, "com/mapswithme/maps/api/RoutePoint"); // Java signature : RoutePoint(double lat, double lon, String name) static jmethodID const pointConstructor = jni::GetConstructorID(env, pointClazz, "(DDLjava/lang/String;)V"); - static jclass const routeDataClazz = jni::GetGlobalClassRef(env, "app/organicmaps/api/ParsedRoutingData"); + static jclass const routeDataClazz = jni::GetGlobalClassRef(env, "com/mapswithme/maps/api/ParsedRoutingData"); // Java signature : ParsedRoutingData(RoutePoint[] points, int routerType) { - static jmethodID const routeDataConstructor = jni::GetConstructorID(env, routeDataClazz, "([Lapp/organicmaps/api/RoutePoint;I)V"); + static jmethodID const routeDataConstructor = jni::GetConstructorID(env, routeDataClazz, "([Lcom/mapswithme/maps/api/RoutePoint;I)V"); auto const & routingData = frm()->GetParsedRoutingData(); jobjectArray points = jni::ToJavaArray(env, pointClazz, routingData.m_points, @@ -827,37 +820,24 @@ Java_app_organicmaps_Framework_nativeGetParsedRoutingData(JNIEnv * env, jclass c } JNIEXPORT jobject JNICALL -Java_app_organicmaps_Framework_nativeGetParsedSearchRequest(JNIEnv * env, jclass clazz) +Java_com_mapswithme_maps_Framework_nativeGetParsedSearchRequest(JNIEnv * env, jclass clazz) { using namespace url_scheme; - static jclass const cl = jni::GetGlobalClassRef(env, "app/organicmaps/api/ParsedSearchRequest"); + static jclass const cl = jni::GetGlobalClassRef(env, "com/mapswithme/maps/api/ParsedSearchRequest"); // Java signature : ParsedSearchRequest(String query, String locale, double lat, double lon, boolean isSearchOnMap) static jmethodID const ctor = jni::GetConstructorID(env, cl, "(Ljava/lang/String;Ljava/lang/String;DDZ)V"); auto const & r = frm()->GetParsedSearchRequest(); - ms::LatLon const center = frm()->GetParsedCenterLatLon(); - return env->NewObject(cl, ctor, jni::ToJavaString(env, r.m_query), jni::ToJavaString(env, r.m_locale), center.m_lat, center.m_lon, r.m_isSearchOnMap); + return env->NewObject(cl, ctor, jni::ToJavaString(env, r.m_query), jni::ToJavaString(env, r.m_locale), r.m_centerLat, r.m_centerLon, r.m_isSearchOnMap); } JNIEXPORT jstring JNICALL -Java_app_organicmaps_Framework_nativeGetParsedAppName(JNIEnv * env, jclass) +Java_com_mapswithme_maps_Framework_nativeGetParsedAppName(JNIEnv * env, jclass) { return jni::ToJavaString(env, frm()->GetParsedAppName()); } -JNIEXPORT jdoubleArray JNICALL -Java_app_organicmaps_Framework_nativeGetParsedCenterLatLon(JNIEnv * env, jclass) -{ - ms::LatLon const center = frm()->GetParsedCenterLatLon(); - - double latlon[] = {center.m_lat, center.m_lon}; - jdoubleArray jLatLon = env->NewDoubleArray(2); - env->SetDoubleArrayRegion(jLatLon, 0, 2, latlon); - - return jLatLon; -} - JNIEXPORT void JNICALL -Java_app_organicmaps_Framework_nativePlacePageActivationListener(JNIEnv *env, jclass clazz, +Java_com_mapswithme_maps_Framework_nativePlacePageActivationListener(JNIEnv *env, jclass clazz, jobject jListener) { LOG(LINFO, ("Set global map object listener")); @@ -865,7 +845,7 @@ Java_app_organicmaps_Framework_nativePlacePageActivationListener(JNIEnv *env, jc // void onPlacePageActivated(MapObject object); jmethodID const activatedId = jni::GetMethodID(env, g_placePageActivationListener, "onPlacePageActivated", - "(Lapp/organicmaps/widget/placepage/PlacePageData;)V"); + "(Lcom/mapswithme/maps/widget/placepage/PlacePageData;)V"); // void onPlacePageDeactivated(boolean switchFullScreenMode); jmethodID const deactivateId = jni::GetMethodID(env, g_placePageActivationListener, "onPlacePageDeactivated", "(Z)V"); @@ -894,7 +874,7 @@ Java_app_organicmaps_Framework_nativePlacePageActivationListener(JNIEnv *env, jc } JNIEXPORT void JNICALL -Java_app_organicmaps_Framework_nativeRemovePlacePageActivationListener(JNIEnv *env, jclass) +Java_com_mapswithme_maps_Framework_nativeRemovePlacePageActivationListener(JNIEnv *env, jclass) { if (g_placePageActivationListener == nullptr) return; @@ -906,7 +886,7 @@ Java_app_organicmaps_Framework_nativeRemovePlacePageActivationListener(JNIEnv *e } JNIEXPORT jstring JNICALL -Java_app_organicmaps_Framework_nativeGetGe0Url(JNIEnv * env, jclass, jdouble lat, jdouble lon, jdouble zoomLevel, jstring name) +Java_com_mapswithme_maps_Framework_nativeGetGe0Url(JNIEnv * env, jclass, jdouble lat, jdouble lon, jdouble zoomLevel, jstring name) { ::Framework * fr = frm(); double const scale = (zoomLevel > 0 ? zoomLevel : fr->GetDrawScale()); @@ -915,14 +895,14 @@ Java_app_organicmaps_Framework_nativeGetGe0Url(JNIEnv * env, jclass, jdouble lat } JNIEXPORT jobject JNICALL -Java_app_organicmaps_Framework_nativeGetDistanceAndAzimuth( +Java_com_mapswithme_maps_Framework_nativeGetDistanceAndAzimuth( JNIEnv * env, jclass, jdouble merX, jdouble merY, jdouble cLat, jdouble cLon, jdouble north) { string distance; double azimut = -1.0; frm()->GetDistanceAndAzimut(m2::PointD(merX, merY), cLat, cLon, north, distance, azimut); - static jclass const daClazz = jni::GetGlobalClassRef(env, "app/organicmaps/bookmarks/data/DistanceAndAzimut"); + static jclass const daClazz = jni::GetGlobalClassRef(env, "com/mapswithme/maps/bookmarks/data/DistanceAndAzimut"); // Java signature : DistanceAndAzimut(String distance, double azimuth) static jmethodID const methodID = jni::GetConstructorID(env, daClazz, "(Ljava/lang/String;D)V"); @@ -932,16 +912,16 @@ Java_app_organicmaps_Framework_nativeGetDistanceAndAzimuth( } JNIEXPORT jobject JNICALL -Java_app_organicmaps_Framework_nativeGetDistanceAndAzimuthFromLatLon( +Java_com_mapswithme_maps_Framework_nativeGetDistanceAndAzimuthFromLatLon( JNIEnv * env, jclass clazz, jdouble lat, jdouble lon, jdouble cLat, jdouble cLon, jdouble north) { double const merY = mercator::LatToY(lat); double const merX = mercator::LonToX(lon); - return Java_app_organicmaps_Framework_nativeGetDistanceAndAzimuth(env, clazz, merX, merY, cLat, cLon, north); + return Java_com_mapswithme_maps_Framework_nativeGetDistanceAndAzimuth(env, clazz, merX, merY, cLat, cLon, north); } JNIEXPORT jstring JNICALL -Java_app_organicmaps_Framework_nativeFormatLatLon(JNIEnv * env, jclass, jdouble lat, jdouble lon, int coordsFormat) +Java_com_mapswithme_maps_Framework_nativeFormatLatLon(JNIEnv * env, jclass, jdouble lat, jdouble lon, int coordsFormat) { switch (static_cast(coordsFormat)) { @@ -958,29 +938,27 @@ Java_app_organicmaps_Framework_nativeFormatLatLon(JNIEnv * env, jclass, jdouble } JNIEXPORT jstring JNICALL -Java_app_organicmaps_Framework_nativeFormatAltitude(JNIEnv * env, jclass, jdouble alt) +Java_com_mapswithme_maps_Framework_nativeFormatAltitude(JNIEnv * env, jclass, jdouble alt) { auto const localizedUnits = platform::GetLocalizedAltitudeUnits(); return jni::ToJavaString(env, measurement_utils::FormatAltitudeWithLocalization(alt, localizedUnits.m_low)); } JNIEXPORT jstring JNICALL -Java_app_organicmaps_Framework_nativeFormatSpeed(JNIEnv * env, jclass, jdouble speed) +Java_com_mapswithme_maps_Framework_nativeFormatSpeed(JNIEnv * env, jclass, jdouble speed) { - auto const units = measurement_utils::GetMeasurementUnits(); - return jni::ToJavaString(env, measurement_utils::FormatSpeedNumeric(speed, units) + " " + - platform::GetLocalizedSpeedUnits(units)); + return jni::ToJavaString(env, measurement_utils::FormatSpeed(speed)); } /* JNIEXPORT jobject JNICALL -Java_app_organicmaps_Framework_nativeGetOutdatedCountriesString(JNIEnv * env, jclass) +Java_com_mapswithme_maps_Framework_nativeGetOutdatedCountriesString(JNIEnv * env, jclass) { return jni::ToJavaString(env, g_framework->GetOutdatedCountriesString()); } JNIEXPORT jobjectArray JNICALL -Java_app_organicmaps_Framework_nativeGetOutdatedCountries(JNIEnv * env, jclass) +Java_com_mapswithme_maps_Framework_nativeGetOutdatedCountries(JNIEnv * env, jclass) { vector countries; Storage const & storage = g_framework->GetStorage(); @@ -994,44 +972,44 @@ Java_app_organicmaps_Framework_nativeGetOutdatedCountries(JNIEnv * env, jclass) } JNIEXPORT jint JNICALL -Java_app_organicmaps_Framework_nativeToDoAfterUpdate(JNIEnv * env, jclass) +Java_com_mapswithme_maps_Framework_nativeToDoAfterUpdate(JNIEnv * env, jclass) { return g_framework->ToDoAfterUpdate(); } JNIEXPORT jboolean JNICALL -Java_app_organicmaps_Framework_nativeIsDataVersionChanged(JNIEnv * env, jclass) +Java_com_mapswithme_maps_Framework_nativeIsDataVersionChanged(JNIEnv * env, jclass) { return frm()->IsDataVersionUpdated() ? JNI_TRUE : JNI_FALSE; } JNIEXPORT void JNICALL -Java_app_organicmaps_Framework_nativeUpdateSavedDataVersion(JNIEnv * env, jclass) +Java_com_mapswithme_maps_Framework_nativeUpdateSavedDataVersion(JNIEnv * env, jclass) { frm()->UpdateSavedDataVersion(); } */ JNIEXPORT jlong JNICALL -Java_app_organicmaps_Framework_nativeGetDataVersion(JNIEnv * env, jclass) +Java_com_mapswithme_maps_Framework_nativeGetDataVersion(JNIEnv * env, jclass) { return frm()->GetCurrentDataVersion(); } JNIEXPORT jint JNICALL -Java_app_organicmaps_Framework_nativeGetDrawScale(JNIEnv * env, jclass) +Java_com_mapswithme_maps_Framework_nativeGetDrawScale(JNIEnv * env, jclass) { return static_cast(frm()->GetDrawScale()); } JNIEXPORT void JNICALL -Java_app_organicmaps_Framework_nativePokeSearchInViewport(JNIEnv * env, jclass) +Java_com_mapswithme_maps_Framework_nativePokeSearchInViewport(JNIEnv * env, jclass) { frm()->GetSearchAPI().PokeSearchInViewport(); } JNIEXPORT jdoubleArray JNICALL -Java_app_organicmaps_Framework_nativeGetScreenRectCenter(JNIEnv * env, jclass) +Java_com_mapswithme_maps_Framework_nativeGetScreenRectCenter(JNIEnv * env, jclass) { m2::PointD const center = frm()->GetViewportCenter(); @@ -1043,37 +1021,37 @@ Java_app_organicmaps_Framework_nativeGetScreenRectCenter(JNIEnv * env, jclass) } JNIEXPORT void JNICALL -Java_app_organicmaps_Framework_nativeShowTrackRect(JNIEnv * env, jclass, jlong track) +Java_com_mapswithme_maps_Framework_nativeShowTrackRect(JNIEnv * env, jclass, jlong track) { frm()->ShowTrack(static_cast(track)); } JNIEXPORT jstring JNICALL -Java_app_organicmaps_Framework_nativeGetBookmarkDir(JNIEnv * env, jclass) +Java_com_mapswithme_maps_Framework_nativeGetBookmarkDir(JNIEnv * env, jclass) { return jni::ToJavaString(env, GetPlatform().SettingsDir().c_str()); } JNIEXPORT jstring JNICALL -Java_app_organicmaps_Framework_nativeGetWritableDir(JNIEnv * env, jclass) +Java_com_mapswithme_maps_Framework_nativeGetWritableDir(JNIEnv * env, jclass) { return jni::ToJavaString(env, GetPlatform().WritableDir().c_str()); } JNIEXPORT jstring JNICALL -Java_app_organicmaps_Framework_nativeGetSettingsDir(JNIEnv * env, jclass) +Java_com_mapswithme_maps_Framework_nativeGetSettingsDir(JNIEnv * env, jclass) { return jni::ToJavaString(env, GetPlatform().SettingsDir().c_str()); } JNIEXPORT jstring JNICALL -Java_app_organicmaps_Framework_nativeGetDataFileExt(JNIEnv * env, jclass) +Java_com_mapswithme_maps_Framework_nativeGetDataFileExt(JNIEnv * env, jclass) { return jni::ToJavaString(env, DATA_FILE_EXTENSION); } JNIEXPORT jobjectArray JNICALL -Java_app_organicmaps_Framework_nativeGetMovableFilesExts(JNIEnv * env, jclass) +Java_com_mapswithme_maps_Framework_nativeGetMovableFilesExts(JNIEnv * env, jclass) { vector exts = { DATA_FILE_EXTENSION, FONT_FILE_EXTENSION }; platform::CountryIndexes::GetIndexesExts(exts); @@ -1081,14 +1059,14 @@ Java_app_organicmaps_Framework_nativeGetMovableFilesExts(JNIEnv * env, jclass) } JNIEXPORT jobjectArray JNICALL -Java_app_organicmaps_Framework_nativeGetBookmarksFilesExts(JNIEnv * env, jclass) +Java_com_mapswithme_maps_Framework_nativeGetBookmarksFilesExts(JNIEnv * env, jclass) { const vector exts = { kKmzExtension, kKmlExtension, kKmbExtension }; return jni::ToJavaStringArray(env, exts); } JNIEXPORT void JNICALL -Java_app_organicmaps_Framework_nativeChangeWritableDir(JNIEnv * env, jclass, jstring jNewPath) +Java_com_mapswithme_maps_Framework_nativeChangeWritableDir(JNIEnv * env, jclass, jstring jNewPath) { string newPath = jni::ToNativeString(env, jNewPath); g_framework->RemoveLocalMaps(); @@ -1097,55 +1075,55 @@ Java_app_organicmaps_Framework_nativeChangeWritableDir(JNIEnv * env, jclass, jst } JNIEXPORT jboolean JNICALL -Java_app_organicmaps_Framework_nativeIsRoutingActive(JNIEnv * env, jclass) +Java_com_mapswithme_maps_Framework_nativeIsRoutingActive(JNIEnv * env, jclass) { return frm()->GetRoutingManager().IsRoutingActive(); } JNIEXPORT jboolean JNICALL -Java_app_organicmaps_Framework_nativeIsRouteBuilding(JNIEnv * env, jclass) +Java_com_mapswithme_maps_Framework_nativeIsRouteBuilding(JNIEnv * env, jclass) { return frm()->GetRoutingManager().IsRouteBuilding(); } JNIEXPORT jboolean JNICALL -Java_app_organicmaps_Framework_nativeIsRouteBuilt(JNIEnv * env, jclass) +Java_com_mapswithme_maps_Framework_nativeIsRouteBuilt(JNIEnv * env, jclass) { return frm()->GetRoutingManager().IsRouteBuilt(); } JNIEXPORT void JNICALL -Java_app_organicmaps_Framework_nativeCloseRouting(JNIEnv * env, jclass) +Java_com_mapswithme_maps_Framework_nativeCloseRouting(JNIEnv * env, jclass) { frm()->GetRoutingManager().CloseRouting(true /* remove route points */); } JNIEXPORT void JNICALL -Java_app_organicmaps_Framework_nativeBuildRoute(JNIEnv * env, jclass) +Java_com_mapswithme_maps_Framework_nativeBuildRoute(JNIEnv * env, jclass) { frm()->GetRoutingManager().BuildRoute(); } JNIEXPORT void JNICALL -Java_app_organicmaps_Framework_nativeRemoveRoute(JNIEnv * env, jclass) +Java_com_mapswithme_maps_Framework_nativeRemoveRoute(JNIEnv * env, jclass) { frm()->GetRoutingManager().RemoveRoute(false /* deactivateFollowing */); } JNIEXPORT void JNICALL -Java_app_organicmaps_Framework_nativeFollowRoute(JNIEnv * env, jclass) +Java_com_mapswithme_maps_Framework_nativeFollowRoute(JNIEnv * env, jclass) { frm()->GetRoutingManager().FollowRoute(); } JNIEXPORT void JNICALL -Java_app_organicmaps_Framework_nativeDisableFollowing(JNIEnv * env, jclass) +Java_com_mapswithme_maps_Framework_nativeDisableFollowing(JNIEnv * env, jclass) { frm()->GetRoutingManager().DisableFollowMode(); } JNIEXPORT jobjectArray JNICALL -Java_app_organicmaps_Framework_nativeGenerateNotifications(JNIEnv * env, jclass) +Java_com_mapswithme_maps_Framework_nativeGenerateNotifications(JNIEnv * env, jclass) { ::Framework * fr = frm(); if (!fr->GetRoutingManager().IsRoutingActive()) @@ -1160,20 +1138,20 @@ Java_app_organicmaps_Framework_nativeGenerateNotifications(JNIEnv * env, jclass) } JNIEXPORT void JNICALL -Java_app_organicmaps_Framework_nativeSetSpeedCamManagerMode(JNIEnv * env, jclass, jint mode) +Java_com_mapswithme_maps_Framework_nativeSetSpeedCamManagerMode(JNIEnv * env, jclass, jint mode) { frm()->GetRoutingManager().GetSpeedCamManager().SetMode( static_cast(mode)); } JNIEXPORT jint JNICALL -Java_app_organicmaps_Framework_nativeGetSpeedCamManagerMode(JNIEnv * env, jclass) +Java_com_mapswithme_maps_Framework_nativeGetSpeedCamManagerMode(JNIEnv * env, jclass) { return static_cast(frm()->GetRoutingManager().GetSpeedCamManager().GetMode()); } JNIEXPORT jobject JNICALL -Java_app_organicmaps_Framework_nativeGetRouteFollowingInfo(JNIEnv * env, jclass) +Java_com_mapswithme_maps_Framework_nativeGetRouteFollowingInfo(JNIEnv * env, jclass) { ::Framework * fr = frm(); if (!fr->GetRoutingManager().IsRoutingActive()) @@ -1184,7 +1162,7 @@ Java_app_organicmaps_Framework_nativeGetRouteFollowingInfo(JNIEnv * env, jclass) if (!info.IsValid()) return nullptr; - static jclass const klass = jni::GetGlobalClassRef(env, "app/organicmaps/routing/RoutingInfo"); + static jclass const klass = jni::GetGlobalClassRef(env, "com/mapswithme/maps/routing/RoutingInfo"); // Java signature : RoutingInfo(String distToTarget, String units, String distTurn, String // turnSuffix, String currentStreet, String nextStreet, // double completionPercent, int vehicleTurnOrdinal, int @@ -1195,13 +1173,13 @@ Java_app_organicmaps_Framework_nativeGetRouteFollowingInfo(JNIEnv * env, jclass) "(Ljava/lang/String;Ljava/lang/String;" "Ljava/lang/String;Ljava/lang/String;" "Ljava/lang/String;Ljava/lang/String;DIIIII" - "[Lapp/organicmaps/routing/SingleLaneInfo;ZZ)V"); + "[Lcom/mapswithme/maps/routing/SingleLaneInfo;ZZ)V"); vector const & lanes = info.m_lanes; jobjectArray jLanes = nullptr; if (!lanes.empty()) { - static jclass const laneClass = jni::GetGlobalClassRef(env, "app/organicmaps/routing/SingleLaneInfo"); + static jclass const laneClass = jni::GetGlobalClassRef(env, "com/mapswithme/maps/routing/SingleLaneInfo"); auto const lanesSize = static_cast(lanes.size()); jLanes = env->NewObjectArray(lanesSize, laneClass, nullptr); ASSERT(jLanes, (jni::DescribeException())); @@ -1237,39 +1215,33 @@ Java_app_organicmaps_Framework_nativeGetRouteFollowingInfo(JNIEnv * env, jclass) } JNIEXPORT jintArray JNICALL -Java_app_organicmaps_Framework_nativeGenerateRouteAltitudeChartBits(JNIEnv * env, jclass, jint width, jint height, jobject routeAltitudeLimits) +Java_com_mapswithme_maps_Framework_nativeGenerateRouteAltitudeChartBits(JNIEnv * env, jclass, jint width, jint height, jobject routeAltitudeLimits) { - RoutingManager::DistanceAltitude altitudes; - if (!frm()->GetRoutingManager().GetRouteAltitudesAndDistancesM(altitudes)) + ::Framework * fr = frm(); + ASSERT(fr, ()); + + geometry::Altitudes altitudes; + vector routePointDistanceM; + if (!fr->GetRoutingManager().GetRouteAltitudesAndDistancesM(routePointDistanceM, altitudes)) { LOG(LWARNING, ("Can't get distance to route points and altitude.")); return nullptr; } - altitudes.Simplify(); - vector imageRGBAData; - if (!altitudes.GenerateRouteAltitudeChart(width, height, imageRGBAData)) + uint32_t totalAscent = 0; + uint32_t totalDescent = 0; + measurement_utils::Units units = measurement_utils::Units::Metric; + if (!fr->GetRoutingManager().GenerateRouteAltitudeChart( + width, height, altitudes, routePointDistanceM, imageRGBAData, + totalAscent, totalDescent, units)) { LOG(LWARNING, ("Can't generate route altitude image.")); return nullptr; } - uint32_t totalAscent, totalDescent; - altitudes.CalculateAscentDescent(totalAscent, totalDescent); - - // Android platform code has specific result string formatting, so make conversion here. - using namespace measurement_utils; - auto units = Units::Metric; - if (settings::Get(settings::kMeasurementUnits, units) && units == Units::Imperial) - { - totalAscent = measurement_utils::MetersToFeet(totalAscent); - totalDescent = measurement_utils::MetersToFeet(totalDescent); - } - // Passing route limits. - // Do not use jni::GetGlobalClassRef, because this class is used only to init static fieldId vars. - static jclass const routeAltitudeLimitsClass = env->GetObjectClass(routeAltitudeLimits); + jclass const routeAltitudeLimitsClass = env->GetObjectClass(routeAltitudeLimits); ASSERT(routeAltitudeLimitsClass, ()); static jfieldID const totalAscentField = env->GetFieldID(routeAltitudeLimitsClass, "totalAscent", "I"); @@ -1282,7 +1254,7 @@ Java_app_organicmaps_Framework_nativeGenerateRouteAltitudeChartBits(JNIEnv * env static jfieldID const isMetricUnitsField = env->GetFieldID(routeAltitudeLimitsClass, "isMetricUnits", "Z"); ASSERT(isMetricUnitsField, ()); - env->SetBooleanField(routeAltitudeLimits, isMetricUnitsField, units == Units::Metric); + env->SetBooleanField(routeAltitudeLimits, isMetricUnitsField, units == measurement_utils::Units::Metric); size_t const imageRGBADataSize = imageRGBAData.size(); ASSERT_NOT_EQUAL(imageRGBADataSize, 0, ("GenerateRouteAltitudeChart returns true but the vector with altitude image bits is empty.")); @@ -1315,13 +1287,13 @@ Java_app_organicmaps_Framework_nativeGenerateRouteAltitudeChartBits(JNIEnv * env } JNIEXPORT void JNICALL -Java_app_organicmaps_Framework_nativeShowCountry(JNIEnv * env, jclass, jstring countryId, jboolean zoomToDownloadButton) +Java_com_mapswithme_maps_Framework_nativeShowCountry(JNIEnv * env, jclass, jstring countryId, jboolean zoomToDownloadButton) { g_framework->ShowNode(jni::ToNativeString(env, countryId), (bool) zoomToDownloadButton); } JNIEXPORT void JNICALL -Java_app_organicmaps_Framework_nativeSetRoutingListener(JNIEnv * env, jclass, jobject listener) +Java_com_mapswithme_maps_Framework_nativeSetRoutingListener(JNIEnv * env, jclass, jobject listener) { CHECK(g_framework, ("Framework isn't created yet!")); auto rf = jni::make_global_ref(listener); @@ -1332,7 +1304,7 @@ Java_app_organicmaps_Framework_nativeSetRoutingListener(JNIEnv * env, jclass, jo } JNIEXPORT void JNICALL -Java_app_organicmaps_Framework_nativeSetRouteProgressListener(JNIEnv * env, jclass, jobject listener) +Java_com_mapswithme_maps_Framework_nativeSetRouteProgressListener(JNIEnv * env, jclass, jobject listener) { CHECK(g_framework, ("Framework isn't created yet!")); frm()->GetRoutingManager().SetRouteProgressListener( @@ -1340,7 +1312,7 @@ Java_app_organicmaps_Framework_nativeSetRouteProgressListener(JNIEnv * env, jcla } JNIEXPORT void JNICALL -Java_app_organicmaps_Framework_nativeSetRoutingRecommendationListener(JNIEnv * env, jclass, +Java_com_mapswithme_maps_Framework_nativeSetRoutingRecommendationListener(JNIEnv * env, jclass, jobject listener) { CHECK(g_framework, ("Framework isn't created yet!")); @@ -1349,7 +1321,7 @@ Java_app_organicmaps_Framework_nativeSetRoutingRecommendationListener(JNIEnv * e } JNIEXPORT void JNICALL -Java_app_organicmaps_Framework_nativeSetRoutingLoadPointsListener( +Java_com_mapswithme_maps_Framework_nativeSetRoutingLoadPointsListener( JNIEnv *, jclass, jobject listener) { CHECK(g_framework, ("Framework isn't created yet!")); @@ -1360,13 +1332,13 @@ Java_app_organicmaps_Framework_nativeSetRoutingLoadPointsListener( } JNIEXPORT void JNICALL -Java_app_organicmaps_Framework_nativeDeactivatePopup(JNIEnv * env, jclass) +Java_com_mapswithme_maps_Framework_nativeDeactivatePopup(JNIEnv * env, jclass) { return g_framework->DeactivatePopup(); } JNIEXPORT void JNICALL -Java_app_organicmaps_Framework_nativeSetMapStyle(JNIEnv * env, jclass, jint mapStyle) +Java_com_mapswithme_maps_Framework_nativeSetMapStyle(JNIEnv * env, jclass, jint mapStyle) { MapStyle const val = static_cast(mapStyle); if (val != g_framework->GetMapStyle()) @@ -1374,13 +1346,13 @@ Java_app_organicmaps_Framework_nativeSetMapStyle(JNIEnv * env, jclass, jint mapS } JNIEXPORT jint JNICALL -Java_app_organicmaps_Framework_nativeGetMapStyle(JNIEnv * env, jclass) +Java_com_mapswithme_maps_Framework_nativeGetMapStyle(JNIEnv * env, jclass) { return g_framework->GetMapStyle(); } JNIEXPORT void JNICALL -Java_app_organicmaps_Framework_nativeMarkMapStyle(JNIEnv * env, jclass, jint mapStyle) +Java_com_mapswithme_maps_Framework_nativeMarkMapStyle(JNIEnv * env, jclass, jint mapStyle) { MapStyle const val = static_cast(mapStyle); if (val != g_framework->GetMapStyle()) @@ -1388,7 +1360,7 @@ Java_app_organicmaps_Framework_nativeMarkMapStyle(JNIEnv * env, jclass, jint map } JNIEXPORT void JNICALL -Java_app_organicmaps_Framework_nativeSetRouter(JNIEnv * env, jclass, jint routerType) +Java_com_mapswithme_maps_Framework_nativeSetRouter(JNIEnv * env, jclass, jint routerType) { using Type = routing::RouterType; Type type = Type::Vehicle; @@ -1404,19 +1376,19 @@ Java_app_organicmaps_Framework_nativeSetRouter(JNIEnv * env, jclass, jint router } JNIEXPORT jint JNICALL -Java_app_organicmaps_Framework_nativeGetRouter(JNIEnv * env, jclass) +Java_com_mapswithme_maps_Framework_nativeGetRouter(JNIEnv * env, jclass) { return static_cast(g_framework->GetRoutingManager().GetRouter()); } JNIEXPORT jint JNICALL -Java_app_organicmaps_Framework_nativeGetLastUsedRouter(JNIEnv * env, jclass) +Java_com_mapswithme_maps_Framework_nativeGetLastUsedRouter(JNIEnv * env, jclass) { return static_cast(g_framework->GetRoutingManager().GetLastUsedRouter()); } JNIEXPORT jint JNICALL -Java_app_organicmaps_Framework_nativeGetBestRouter(JNIEnv * env, jclass, +Java_com_mapswithme_maps_Framework_nativeGetBestRouter(JNIEnv * env, jclass, jdouble srcLat, jdouble srcLon, jdouble dstLat, jdouble dstLon) { @@ -1425,7 +1397,7 @@ Java_app_organicmaps_Framework_nativeGetBestRouter(JNIEnv * env, jclass, } JNIEXPORT void JNICALL -Java_app_organicmaps_Framework_nativeAddRoutePoint(JNIEnv * env, jclass, jstring title, +Java_com_mapswithme_maps_Framework_nativeAddRoutePoint(JNIEnv * env, jclass, jstring title, jstring subtitle, jint markType, jint intermediateIndex, jboolean isMyPosition, @@ -1443,7 +1415,7 @@ Java_app_organicmaps_Framework_nativeAddRoutePoint(JNIEnv * env, jclass, jstring } JNIEXPORT void JNICALL -Java_app_organicmaps_Framework_nativeRemoveRoutePoint(JNIEnv * env, jclass, +Java_com_mapswithme_maps_Framework_nativeRemoveRoutePoint(JNIEnv * env, jclass, jint markType, jint intermediateIndex) { frm()->GetRoutingManager().RemoveRoutePoint(static_cast(markType), @@ -1451,24 +1423,24 @@ Java_app_organicmaps_Framework_nativeRemoveRoutePoint(JNIEnv * env, jclass, } JNIEXPORT void JNICALL -Java_app_organicmaps_Framework_nativeRemoveIntermediateRoutePoints(JNIEnv * env, jclass) +Java_com_mapswithme_maps_Framework_nativeRemoveIntermediateRoutePoints(JNIEnv * env, jclass) { frm()->GetRoutingManager().RemoveIntermediateRoutePoints(); } JNIEXPORT jboolean JNICALL -Java_app_organicmaps_Framework_nativeCouldAddIntermediatePoint(JNIEnv * env, jclass) +Java_com_mapswithme_maps_Framework_nativeCouldAddIntermediatePoint(JNIEnv * env, jclass) { return frm()->GetRoutingManager().CouldAddIntermediatePoint(); } JNIEXPORT jobjectArray JNICALL -Java_app_organicmaps_Framework_nativeGetRoutePoints(JNIEnv * env, jclass) +Java_com_mapswithme_maps_Framework_nativeGetRoutePoints(JNIEnv * env, jclass) { auto const points = frm()->GetRoutingManager().GetRoutePoints(); static jclass const pointClazz = jni::GetGlobalClassRef(env, - "app/organicmaps/routing/RouteMarkData"); + "com/mapswithme/maps/routing/RouteMarkData"); // Java signature : RouteMarkData(String title, String subtitle, // @RoutePointInfo.RouteMarkType int pointType, // int intermediateIndex, boolean isVisible, boolean isMyPosition, @@ -1492,12 +1464,12 @@ Java_app_organicmaps_Framework_nativeGetRoutePoints(JNIEnv * env, jclass) } JNIEXPORT jobject JNICALL -Java_app_organicmaps_Framework_nativeGetTransitRouteInfo(JNIEnv * env, jclass) +Java_com_mapswithme_maps_Framework_nativeGetTransitRouteInfo(JNIEnv * env, jclass) { auto const routeInfo = frm()->GetRoutingManager().GetTransitRouteInfo(); static jclass const transitStepClass = jni::GetGlobalClassRef(env, - "app/organicmaps/routing/TransitStepInfo"); + "com/mapswithme/maps/routing/TransitStepInfo"); // Java signature : TransitStepInfo(@TransitType int type, @Nullable String distance, @Nullable String distanceUnits, // int timeInSec, @Nullable String number, int color, int intermediateIndex) static jmethodID const transitStepConstructor = jni::GetConstructorID(env, transitStepClass, @@ -1521,14 +1493,14 @@ Java_app_organicmaps_Framework_nativeGetTransitRouteInfo(JNIEnv * env, jclass) })); static jclass const transitRouteInfoClass = jni::GetGlobalClassRef(env, - "app/organicmaps/routing/TransitRouteInfo"); + "com/mapswithme/maps/routing/TransitRouteInfo"); // Java signature : TransitRouteInfo(@NonNull String totalDistance, @NonNull String totalDistanceUnits, int totalTimeInSec, // @NonNull String totalPedestrianDistance, @NonNull String totalPedestrianDistanceUnits, // int totalPedestrianTimeInSec, @NonNull TransitStepInfo[] steps) static jmethodID const transitRouteInfoConstructor = jni::GetConstructorID(env, transitRouteInfoClass, "(Ljava/lang/String;Ljava/lang/String;I" "Ljava/lang/String;Ljava/lang/String;I" - "[Lapp/organicmaps/routing/TransitStepInfo;)V"); + "[Lcom/mapswithme/maps/routing/TransitStepInfo;)V"); jni::TScopedLocalRef const distance(env, jni::ToJavaString(env, routeInfo.m_totalDistanceStr)); jni::TScopedLocalRef const distanceUnits(env, jni::ToJavaString(env, routeInfo.m_totalDistanceUnitsSuffix)); jni::TScopedLocalRef const distancePedestrian(env, jni::ToJavaString(env, routeInfo.m_totalPedestrianDistanceStr)); @@ -1540,20 +1512,20 @@ Java_app_organicmaps_Framework_nativeGetTransitRouteInfo(JNIEnv * env, jclass) } JNIEXPORT void JNICALL -Java_app_organicmaps_Framework_nativeReloadWorldMaps(JNIEnv * env, jclass) +Java_com_mapswithme_maps_Framework_nativeReloadWorldMaps(JNIEnv * env, jclass) { g_framework->ReloadWorldMaps(); } JNIEXPORT jboolean JNICALL -Java_app_organicmaps_Framework_nativeIsDayTime(JNIEnv * env, jclass, jlong utcTimeSeconds, jdouble lat, jdouble lon) +Java_com_mapswithme_maps_Framework_nativeIsDayTime(JNIEnv * env, jclass, jlong utcTimeSeconds, jdouble lat, jdouble lon) { DayTimeType const dt = GetDayTime(static_cast(utcTimeSeconds), lat, lon); return (dt == DayTimeType::Day || dt == DayTimeType::PolarDay); } JNIEXPORT void JNICALL -Java_app_organicmaps_Framework_nativeSet3dMode(JNIEnv * env, jclass, jboolean allow, jboolean allowBuildings) +Java_com_mapswithme_maps_Framework_nativeSet3dMode(JNIEnv * env, jclass, jboolean allow, jboolean allowBuildings) { bool const allow3d = static_cast(allow); bool const allow3dBuildings = static_cast(allowBuildings); @@ -1563,13 +1535,13 @@ Java_app_organicmaps_Framework_nativeSet3dMode(JNIEnv * env, jclass, jboolean al } JNIEXPORT void JNICALL -Java_app_organicmaps_Framework_nativeGet3dMode(JNIEnv * env, jclass, jobject result) +Java_com_mapswithme_maps_Framework_nativeGet3dMode(JNIEnv * env, jclass, jobject result) { bool enabled; bool buildings; g_framework->Get3dMode(enabled, buildings); - static jclass const resultClass = env->GetObjectClass(result); + jclass const resultClass = env->GetObjectClass(result); static jfieldID const enabledField = env->GetFieldID(resultClass, "enabled", "Z"); env->SetBooleanField(result, enabledField, enabled); @@ -1579,7 +1551,7 @@ Java_app_organicmaps_Framework_nativeGet3dMode(JNIEnv * env, jclass, jobject res } JNIEXPORT void JNICALL -Java_app_organicmaps_Framework_nativeSetAutoZoomEnabled(JNIEnv * env, jclass, jboolean enabled) +Java_com_mapswithme_maps_Framework_nativeSetAutoZoomEnabled(JNIEnv * env, jclass, jboolean enabled) { bool const autoZoomEnabled = static_cast(enabled); frm()->SaveAutoZoom(autoZoomEnabled); @@ -1587,19 +1559,19 @@ Java_app_organicmaps_Framework_nativeSetAutoZoomEnabled(JNIEnv * env, jclass, jb } JNIEXPORT void JNICALL -Java_app_organicmaps_Framework_nativeSetTransitSchemeEnabled(JNIEnv * env, jclass, jboolean enabled) +Java_com_mapswithme_maps_Framework_nativeSetTransitSchemeEnabled(JNIEnv * env, jclass, jboolean enabled) { frm()->GetTransitManager().EnableTransitSchemeMode(static_cast(enabled)); } JNIEXPORT jboolean JNICALL -Java_app_organicmaps_Framework_nativeIsTransitSchemeEnabled(JNIEnv * env, jclass) +Java_com_mapswithme_maps_Framework_nativeIsTransitSchemeEnabled(JNIEnv * env, jclass) { return static_cast(frm()->LoadTransitSchemeEnabled()); } JNIEXPORT void JNICALL -Java_app_organicmaps_Framework_nativeSetIsolinesLayerEnabled(JNIEnv * env, jclass, jboolean enabled) +Java_com_mapswithme_maps_Framework_nativeSetIsolinesLayerEnabled(JNIEnv * env, jclass, jboolean enabled) { auto const isolinesEnabled = static_cast(enabled); frm()->GetIsolinesManager().SetEnabled(isolinesEnabled); @@ -1607,32 +1579,32 @@ Java_app_organicmaps_Framework_nativeSetIsolinesLayerEnabled(JNIEnv * env, jclas } JNIEXPORT jboolean JNICALL -Java_app_organicmaps_Framework_nativeIsIsolinesLayerEnabled(JNIEnv * env, jclass) +Java_com_mapswithme_maps_Framework_nativeIsIsolinesLayerEnabled(JNIEnv * env, jclass) { return static_cast(frm()->LoadIsolinesEnabled()); } JNIEXPORT void JNICALL -Java_app_organicmaps_Framework_nativeSaveSettingSchemeEnabled(JNIEnv * env, jclass, jboolean enabled) +Java_com_mapswithme_maps_Framework_nativeSaveSettingSchemeEnabled(JNIEnv * env, jclass, jboolean enabled) { frm()->SaveTransitSchemeEnabled(static_cast(enabled)); } JNIEXPORT jboolean JNICALL -Java_app_organicmaps_Framework_nativeGetAutoZoomEnabled(JNIEnv *, jclass) +Java_com_mapswithme_maps_Framework_nativeGetAutoZoomEnabled(JNIEnv *, jclass) { return frm()->LoadAutoZoom(); } // static void nativeZoomToPoint(double lat, double lon, int zoom, boolean animate); JNIEXPORT void JNICALL -Java_app_organicmaps_Framework_nativeZoomToPoint(JNIEnv * env, jclass, jdouble lat, jdouble lon, jint zoom, jboolean animate) +Java_com_mapswithme_maps_Framework_nativeZoomToPoint(JNIEnv * env, jclass, jdouble lat, jdouble lon, jint zoom, jboolean animate) { g_framework->Scale(m2::PointD(mercator::FromLatLon(lat, lon)), zoom, animate); } JNIEXPORT jobject JNICALL -Java_app_organicmaps_Framework_nativeDeleteBookmarkFromMapObject(JNIEnv * env, jclass) +Java_com_mapswithme_maps_Framework_nativeDeleteBookmarkFromMapObject(JNIEnv * env, jclass) { if (!frm()->HasPlacePageInfo()) return nullptr; @@ -1651,7 +1623,7 @@ Java_app_organicmaps_Framework_nativeDeleteBookmarkFromMapObject(JNIEnv * env, j } JNIEXPORT void JNICALL -Java_app_organicmaps_Framework_nativeTurnOnChoosePositionMode(JNIEnv *, jclass, jboolean isBusiness, jboolean applyPosition) +Java_com_mapswithme_maps_Framework_nativeTurnOnChoosePositionMode(JNIEnv *, jclass, jboolean isBusiness, jboolean applyPosition) { auto const pos = applyPosition && frm()->HasPlacePageInfo() ? g_framework->GetPlacePageInfo().GetMercator() @@ -1660,26 +1632,26 @@ Java_app_organicmaps_Framework_nativeTurnOnChoosePositionMode(JNIEnv *, jclass, } JNIEXPORT void JNICALL -Java_app_organicmaps_Framework_nativeTurnOffChoosePositionMode(JNIEnv *, jclass) +Java_com_mapswithme_maps_Framework_nativeTurnOffChoosePositionMode(JNIEnv *, jclass) { g_framework->SetChoosePositionMode(false, false, false, m2::PointD()); } JNIEXPORT jboolean JNICALL -Java_app_organicmaps_Framework_nativeIsInChoosePositionMode(JNIEnv *, jclass) +Java_com_mapswithme_maps_Framework_nativeIsInChoosePositionMode(JNIEnv *, jclass) { return g_framework->GetChoosePositionMode(); } JNIEXPORT jboolean JNICALL -Java_app_organicmaps_Framework_nativeIsDownloadedMapAtScreenCenter(JNIEnv *, jclass) +Java_com_mapswithme_maps_Framework_nativeIsDownloadedMapAtScreenCenter(JNIEnv *, jclass) { ::Framework * fr = frm(); return storage::IsPointCoveredByDownloadedMaps(fr->GetViewportCenter(), fr->GetStorage(), fr->GetCountryInfoGetter()); } JNIEXPORT jstring JNICALL -Java_app_organicmaps_Framework_nativeGetActiveObjectFormattedCuisine(JNIEnv * env, jclass) +Java_com_mapswithme_maps_Framework_nativeGetActiveObjectFormattedCuisine(JNIEnv * env, jclass) { ::Framework * frm = g_framework->NativeFramework(); if (!frm->HasPlacePageInfo()) @@ -1689,75 +1661,75 @@ Java_app_organicmaps_Framework_nativeGetActiveObjectFormattedCuisine(JNIEnv * en } JNIEXPORT void JNICALL -Java_app_organicmaps_Framework_nativeSetVisibleRect(JNIEnv * env, jclass, jint left, jint top, jint right, jint bottom) +Java_com_mapswithme_maps_Framework_nativeSetVisibleRect(JNIEnv * env, jclass, jint left, jint top, jint right, jint bottom) { frm()->SetVisibleViewport(m2::RectD(left, top, right, bottom)); } JNIEXPORT jboolean JNICALL -Java_app_organicmaps_Framework_nativeIsRouteFinished(JNIEnv * env, jclass) +Java_com_mapswithme_maps_Framework_nativeIsRouteFinished(JNIEnv * env, jclass) { return frm()->GetRoutingManager().IsRouteFinished(); } JNIEXPORT void JNICALL -Java_app_organicmaps_Framework_nativeRunFirstLaunchAnimation(JNIEnv * env, jclass) +Java_com_mapswithme_maps_Framework_nativeRunFirstLaunchAnimation(JNIEnv * env, jclass) { frm()->RunFirstLaunchAnimation(); } JNIEXPORT jint JNICALL -Java_app_organicmaps_Framework_nativeOpenRoutePointsTransaction(JNIEnv * env, jclass) +Java_com_mapswithme_maps_Framework_nativeOpenRoutePointsTransaction(JNIEnv * env, jclass) { return frm()->GetRoutingManager().OpenRoutePointsTransaction(); } JNIEXPORT void JNICALL -Java_app_organicmaps_Framework_nativeApplyRoutePointsTransaction(JNIEnv * env, jclass, +Java_com_mapswithme_maps_Framework_nativeApplyRoutePointsTransaction(JNIEnv * env, jclass, jint transactionId) { frm()->GetRoutingManager().ApplyRoutePointsTransaction(transactionId); } JNIEXPORT void JNICALL -Java_app_organicmaps_Framework_nativeCancelRoutePointsTransaction(JNIEnv * env, jclass, +Java_com_mapswithme_maps_Framework_nativeCancelRoutePointsTransaction(JNIEnv * env, jclass, jint transactionId) { frm()->GetRoutingManager().CancelRoutePointsTransaction(transactionId); } JNIEXPORT jint JNICALL -Java_app_organicmaps_Framework_nativeInvalidRoutePointsTransactionId(JNIEnv * env, jclass) +Java_com_mapswithme_maps_Framework_nativeInvalidRoutePointsTransactionId(JNIEnv * env, jclass) { return frm()->GetRoutingManager().InvalidRoutePointsTransactionId(); } JNIEXPORT jboolean JNICALL -Java_app_organicmaps_Framework_nativeHasSavedRoutePoints(JNIEnv *, jclass) +Java_com_mapswithme_maps_Framework_nativeHasSavedRoutePoints(JNIEnv *, jclass) { return frm()->GetRoutingManager().HasSavedRoutePoints(); } JNIEXPORT void JNICALL -Java_app_organicmaps_Framework_nativeLoadRoutePoints(JNIEnv *, jclass) +Java_com_mapswithme_maps_Framework_nativeLoadRoutePoints(JNIEnv *, jclass) { frm()->GetRoutingManager().LoadRoutePoints(g_loadRouteHandler); } JNIEXPORT void JNICALL -Java_app_organicmaps_Framework_nativeSaveRoutePoints(JNIEnv *, jclass) +Java_com_mapswithme_maps_Framework_nativeSaveRoutePoints(JNIEnv *, jclass) { frm()->GetRoutingManager().SaveRoutePoints(); } JNIEXPORT void JNICALL -Java_app_organicmaps_Framework_nativeDeleteSavedRoutePoints(JNIEnv *, jclass) +Java_com_mapswithme_maps_Framework_nativeDeleteSavedRoutePoints(JNIEnv *, jclass) { frm()->GetRoutingManager().DeleteSavedRoutePoints(); } JNIEXPORT void JNICALL -Java_app_organicmaps_Framework_nativeShowFeature(JNIEnv * env, jclass, jobject featureId) +Java_com_mapswithme_maps_Framework_nativeShowFeature(JNIEnv * env, jclass, jobject featureId) { auto const f = g_framework->BuildFeatureId(env, featureId); @@ -1766,13 +1738,13 @@ Java_app_organicmaps_Framework_nativeShowFeature(JNIEnv * env, jclass, jobject f } JNIEXPORT void JNICALL -Java_app_organicmaps_Framework_nativeMakeCrash(JNIEnv *env, jclass type) +Java_com_mapswithme_maps_Framework_nativeMakeCrash(JNIEnv *env, jclass type) { CHECK(false, ("Diagnostic native crash!")); } JNIEXPORT void JNICALL -Java_app_organicmaps_Framework_nativeSetPowerManagerFacility(JNIEnv *, jclass, +Java_com_mapswithme_maps_Framework_nativeSetPowerManagerFacility(JNIEnv *, jclass, jint facilityType, jboolean state) { frm()->GetPowerManager().SetFacility(static_cast(facilityType), @@ -1780,32 +1752,34 @@ Java_app_organicmaps_Framework_nativeSetPowerManagerFacility(JNIEnv *, jclass, } JNIEXPORT jint JNICALL -Java_app_organicmaps_Framework_nativeGetPowerManagerScheme(JNIEnv *, jclass) +Java_com_mapswithme_maps_Framework_nativeGetPowerManagerScheme(JNIEnv *, jclass) { return static_cast(frm()->GetPowerManager().GetScheme()); } JNIEXPORT void JNICALL -Java_app_organicmaps_Framework_nativeSetPowerManagerScheme(JNIEnv *, jclass, jint schemeType) +Java_com_mapswithme_maps_Framework_nativeSetPowerManagerScheme(JNIEnv *, jclass, jint schemeType) { frm()->GetPowerManager().SetScheme(static_cast(schemeType)); } JNIEXPORT void JNICALL -Java_app_organicmaps_Framework_nativeSetViewportCenter(JNIEnv *, jclass, jdouble lat, jdouble lon, jint zoom) +Java_com_mapswithme_maps_Framework_nativeSetViewportCenter(JNIEnv *, jclass, jdouble lat, + jdouble lon, jint zoom, jboolean isAnim) { - // isAnim = true because of previous nativeTurnOnChoosePositionMode animations. - frm()->SetViewportCenter(mercator::FromLatLon(lat, lon), static_cast(zoom), true /* isAnim */); + auto const center = mercator::FromLatLon(static_cast(lat), + static_cast(lon)); + frm()->SetViewportCenter(center, static_cast(zoom), static_cast(isAnim)); } JNIEXPORT void JNICALL -Java_app_organicmaps_Framework_nativeStopLocationFollow(JNIEnv *, jclass) +Java_com_mapswithme_maps_Framework_nativeStopLocationFollow(JNIEnv *, jclass) { frm()->StopLocationFollow(); } JNIEXPORT void JNICALL -Java_app_organicmaps_Framework_nativeSetSearchViewport(JNIEnv *, jclass, jdouble lat, +Java_com_mapswithme_maps_Framework_nativeSetSearchViewport(JNIEnv *, jclass, jdouble lat, jdouble lon, jint zoom) { auto const center = mercator::FromLatLon(static_cast(lat), @@ -1815,7 +1789,7 @@ Java_app_organicmaps_Framework_nativeSetSearchViewport(JNIEnv *, jclass, jdouble } JNIEXPORT jboolean JNICALL -Java_app_organicmaps_Framework_nativeHasPlacePageInfo(JNIEnv *, jclass) +Java_com_mapswithme_maps_Framework_nativeHasPlacePageInfo(JNIEnv *, jclass) { return static_cast(frm()->HasPlacePageInfo()); } diff --git a/android/jni/app/organicmaps/Framework.hpp b/android/jni/com/mapswithme/maps/Framework.hpp similarity index 96% rename from android/jni/app/organicmaps/Framework.hpp rename to android/jni/com/mapswithme/maps/Framework.hpp index 9cc3d5e265..69974af199 100644 --- a/android/jni/app/organicmaps/Framework.hpp +++ b/android/jni/com/mapswithme/maps/Framework.hpp @@ -39,7 +39,7 @@ struct EverywhereSearchParams; namespace android { - enum CoordinatesFormat // See Java enum app.organicmaps.widget.placepage.CoordinatesFormat for all possible values. + enum CoordinatesFormat // See Java enum com.mapswithme.maps.widget.placepage.CoordinatesFormat for all possible values. { LatLonDMS = 0, // Latitude, Longitude in degrees minutes seconds format, comma separated LatLonDecimal = 1, // Latitude, Longitude in decimal format, comma separated @@ -127,10 +127,6 @@ namespace android float m_x, m_y; }; - void Scale(double factor, m2::PointD const & pxPoint, bool isAnim); - - void Move(double factorX, double factorY, bool isAnim); - void Touch(int action, Finger const & f1, Finger const & f2, uint8_t maskedPointer); bool Search(search::EverywhereSearchParams const & params); diff --git a/android/jni/com/mapswithme/maps/LocationHelper.cpp b/android/jni/com/mapswithme/maps/LocationHelper.cpp new file mode 100644 index 0000000000..d7a759d230 --- /dev/null +++ b/android/jni/com/mapswithme/maps/LocationHelper.cpp @@ -0,0 +1,43 @@ +#include "Framework.hpp" +#include "map/gps_tracker.hpp" + +extern "C" +{ + JNIEXPORT void JNICALL + Java_com_mapswithme_maps_location_LocationHelper_nativeOnLocationError(JNIEnv * env, jclass clazz, int errorCode) + { + g_framework->OnLocationError(errorCode); + } + + JNIEXPORT void JNICALL + Java_com_mapswithme_maps_location_LocationHelper_nativeLocationUpdated(JNIEnv * env, jclass clazz, jlong time, + jdouble lat, jdouble lon, jfloat accuracy, + jdouble altitude, jfloat speed, jfloat bearing) + { + location::GpsInfo info; + info.m_source = location::EAndroidNative; + + info.m_timestamp = static_cast(time) / 1000.0; + info.m_latitude = lat; + info.m_longitude = lon; + + if (accuracy > 0.0) + info.m_horizontalAccuracy = accuracy; + + if (altitude != 0.0) + { + info.m_altitude = altitude; + info.m_verticalAccuracy = accuracy; + } + + if (bearing > 0.0) + info.m_bearing = bearing; + + if (speed > 0.0) + info.m_speedMpS = speed; + + if (g_framework) + g_framework->OnLocationUpdated(info); + GpsTracker::Instance().OnLocationUpdated(info); + } +} diff --git a/android/jni/com/mapswithme/maps/LocationState.cpp b/android/jni/com/mapswithme/maps/LocationState.cpp new file mode 100644 index 0000000000..7d8e4b851d --- /dev/null +++ b/android/jni/com/mapswithme/maps/LocationState.cpp @@ -0,0 +1,69 @@ +#include "Framework.hpp" + +#include "com/mapswithme/core/jni_helper.hpp" + +#include "com/mapswithme/platform/Platform.hpp" + +extern "C" +{ + +static void LocationStateModeChanged(location::EMyPositionMode mode, + std::shared_ptr const & listener) +{ + JNIEnv * env = jni::GetEnv(); + env->CallVoidMethod(*listener, jni::GetMethodID(env, *listener.get(), + "onMyPositionModeChanged", "(I)V"), static_cast(mode)); +} + +static void LocationPendingTimeout(std::shared_ptr const & listener) +{ + JNIEnv * env = jni::GetEnv(); + env->CallVoidMethod(*listener, jni::GetMethodID(env, *listener.get(), + "onLocationPendingTimeout", "()V")); +} + +// public static void nativeSwitchToNextMode(); +JNIEXPORT void JNICALL +Java_com_mapswithme_maps_location_LocationState_nativeSwitchToNextMode(JNIEnv * env, jclass clazz) +{ + g_framework->SwitchMyPositionNextMode(); +} + +// private static int nativeGetMode(); +JNIEXPORT jint JNICALL +Java_com_mapswithme_maps_location_LocationState_nativeGetMode(JNIEnv * env, jclass clazz) +{ + return g_framework->GetMyPositionMode(); +} + +// public static void nativeSetListener(ModeChangeListener listener); +JNIEXPORT void JNICALL +Java_com_mapswithme_maps_location_LocationState_nativeSetListener(JNIEnv * env, jclass clazz, + jobject listener) +{ + g_framework->SetMyPositionModeListener(std::bind(&LocationStateModeChanged, std::placeholders::_1, + jni::make_global_ref(listener))); +} + +// public static void nativeRemoveListener(); +JNIEXPORT void JNICALL +Java_com_mapswithme_maps_location_LocationState_nativeRemoveListener(JNIEnv * env, jclass clazz) +{ + g_framework->SetMyPositionModeListener(location::TMyPositionModeChanged()); +} + +JNIEXPORT void JNICALL +Java_com_mapswithme_maps_location_LocationState_nativeSetLocationPendingTimeoutListener( + JNIEnv * env, jclass clazz, jobject listener) +{ + g_framework->NativeFramework()->SetMyPositionPendingTimeoutListener( + std::bind(&LocationPendingTimeout, jni::make_global_ref(listener))); +} + +JNIEXPORT void JNICALL +Java_com_mapswithme_maps_location_LocationState_nativeRemoveLocationPendingTimeoutListener( + JNIEnv * env, jclass) +{ + g_framework->NativeFramework()->SetMyPositionPendingTimeoutListener(nullptr); +} +} // extern "C" diff --git a/android/jni/com/mapswithme/maps/MapFragment.cpp b/android/jni/com/mapswithme/maps/MapFragment.cpp new file mode 100644 index 0000000000..885621e72c --- /dev/null +++ b/android/jni/com/mapswithme/maps/MapFragment.cpp @@ -0,0 +1,168 @@ +#include "Framework.hpp" + +#include "com/mapswithme/core/jni_helper.hpp" + +#include "com/mapswithme/platform/Platform.hpp" + +#include "storage/storage_defines.hpp" + +#include "base/logging.hpp" + +#include "platform/settings.hpp" + +namespace +{ +void OnRenderingInitializationFinished(std::shared_ptr const & listener) +{ + JNIEnv * env = jni::GetEnv(); + env->CallVoidMethod(*listener, jni::GetMethodID(env, *listener.get(), + "onRenderingInitializationFinished", "()V")); +} +} // namespace + +extern "C" +{ +using namespace storage; + +JNIEXPORT void JNICALL +Java_com_mapswithme_maps_MapFragment_nativeCompassUpdated(JNIEnv * env, jclass clazz, jdouble north, jboolean forceRedraw) +{ + location::CompassInfo info; + info.m_bearing = north; + + g_framework->OnCompassUpdated(info, forceRedraw); +} + +JNIEXPORT void JNICALL +Java_com_mapswithme_maps_MapFragment_nativeStorageConnected(JNIEnv * env, jclass clazz) +{ + android::Platform::Instance().OnExternalStorageStatusChanged(true); + g_framework->AddLocalMaps(); +} + +JNIEXPORT void JNICALL +Java_com_mapswithme_maps_MapFragment_nativeStorageDisconnected(JNIEnv * env, jclass clazz) +{ + android::Platform::Instance().OnExternalStorageStatusChanged(false); + g_framework->RemoveLocalMaps(); +} + +JNIEXPORT void JNICALL +Java_com_mapswithme_maps_MapFragment_nativeScalePlus(JNIEnv * env, jclass clazz) +{ + g_framework->Scale(::Framework::SCALE_MAG); +} + +JNIEXPORT void JNICALL +Java_com_mapswithme_maps_MapFragment_nativeScaleMinus(JNIEnv * env, jclass clazz) +{ + g_framework->Scale(::Framework::SCALE_MIN); +} + +JNIEXPORT jboolean JNICALL +Java_com_mapswithme_maps_MapFragment_nativeShowMapForUrl(JNIEnv * env, jclass clazz, jstring url) +{ + return g_framework->ShowMapForURL(jni::ToNativeString(env, url)); +} + +JNIEXPORT jboolean JNICALL +Java_com_mapswithme_maps_MapFragment_nativeCreateEngine(JNIEnv * env, jclass clazz, + jobject surface, jint density, + jboolean firstLaunch, + jboolean isLaunchByDeepLink, + jint appVersionCode) +{ + return g_framework->CreateDrapeEngine(env, surface, density, firstLaunch, isLaunchByDeepLink, + base::asserted_cast(appVersionCode)); +} + +JNIEXPORT jboolean JNICALL +Java_com_mapswithme_maps_MapFragment_nativeIsEngineCreated(JNIEnv * env, jclass clazz) +{ + return g_framework->IsDrapeEngineCreated(); +} + +JNIEXPORT jboolean JNICALL +Java_com_mapswithme_maps_MapFragment_nativeDestroySurfaceOnDetach(JNIEnv * env, jclass clazz) +{ + return g_framework->DestroySurfaceOnDetach(); +} + +JNIEXPORT jboolean JNICALL +Java_com_mapswithme_maps_MapFragment_nativeAttachSurface(JNIEnv * env, jclass clazz, + jobject surface) +{ + return g_framework->AttachSurface(env, surface); +} + +JNIEXPORT void JNICALL +Java_com_mapswithme_maps_MapFragment_nativeDetachSurface(JNIEnv * env, jclass clazz, + jboolean destroySurface) +{ + g_framework->DetachSurface(destroySurface); +} + +JNIEXPORT void JNICALL +Java_com_mapswithme_maps_MapFragment_nativePauseSurfaceRendering(JNIEnv *, jclass) +{ + g_framework->PauseSurfaceRendering(); +} + +JNIEXPORT void JNICALL +Java_com_mapswithme_maps_MapFragment_nativeResumeSurfaceRendering(JNIEnv *, jclass) +{ + g_framework->ResumeSurfaceRendering(); +} + +JNIEXPORT void JNICALL +Java_com_mapswithme_maps_MapFragment_nativeSurfaceChanged(JNIEnv * env, jclass, jobject surface, + jint w, jint h) +{ + g_framework->Resize(env, surface, w, h); +} + +JNIEXPORT void JNICALL +Java_com_mapswithme_maps_MapFragment_nativeOnTouch(JNIEnv * env, jclass clazz, jint action, + jint id1, jfloat x1, jfloat y1, + jint id2, jfloat x2, jfloat y2, + jint maskedPointer) +{ + g_framework->Touch(action, + android::Framework::Finger(id1, x1, y1), + android::Framework::Finger(id2, x2, y2), maskedPointer); +} + +JNIEXPORT void JNICALL +Java_com_mapswithme_maps_MapFragment_nativeSetupWidget( + JNIEnv * env, jclass clazz, jint widget, jfloat x, jfloat y, jint anchor) +{ + g_framework->SetupWidget(static_cast(widget), x, y, static_cast(anchor)); +} + +JNIEXPORT void JNICALL +Java_com_mapswithme_maps_MapFragment_nativeApplyWidgets(JNIEnv * env, jclass clazz) +{ + g_framework->ApplyWidgets(); +} + +JNIEXPORT void JNICALL +Java_com_mapswithme_maps_MapFragment_nativeCleanWidgets(JNIEnv * env, jclass clazz) +{ + g_framework->CleanWidgets(); +} + +JNIEXPORT void JNICALL +Java_com_mapswithme_maps_MapFragment_nativeSetRenderingInitializationFinishedListener( + JNIEnv * env, jclass clazz, jobject listener) +{ + if (listener) + { + g_framework->NativeFramework()->SetGraphicsContextInitializationHandler( + std::bind(&OnRenderingInitializationFinished, jni::make_global_ref(listener))); + } + else + { + g_framework->NativeFramework()->SetGraphicsContextInitializationHandler(nullptr); + } +} +} // extern "C" diff --git a/android/jni/app/organicmaps/MapManager.cpp b/android/jni/com/mapswithme/maps/MapManager.cpp similarity index 84% rename from android/jni/app/organicmaps/MapManager.cpp rename to android/jni/com/mapswithme/maps/MapManager.cpp index f6c773e59e..ff97f3cc9b 100644 --- a/android/jni/app/organicmaps/MapManager.cpp +++ b/android/jni/com/mapswithme/maps/MapManager.cpp @@ -1,6 +1,6 @@ #include "Framework.hpp" -#include "app/organicmaps/core/jni_helper.hpp" +#include "com/mapswithme/core/jni_helper.hpp" #include "coding/internal/file_data.hpp" @@ -72,7 +72,7 @@ void CacheListClassRefs(JNIEnv * env) jclass listClass = env->FindClass("java/util/List"); g_listAddMethod = env->GetMethodID(listClass, "add", "(Ljava/lang/Object;)Z"); - g_countryItemClass = jni::GetGlobalClassRef(env, "app/organicmaps/downloader/CountryItem"); + g_countryItemClass = jni::GetGlobalClassRef(env, "com/mapswithme/maps/downloader/CountryItem"); } static CountryId const GetRootId(JNIEnv * env, jstring root) @@ -86,55 +86,55 @@ extern "C" // static String nativeGetRoot(); JNIEXPORT jstring JNICALL -Java_app_organicmaps_downloader_MapManager_nativeGetRoot(JNIEnv * env, jclass clazz) +Java_com_mapswithme_maps_downloader_MapManager_nativeGetRoot(JNIEnv * env, jclass clazz) { return jni::ToJavaString(env, GetStorage().GetRootId()); } // static boolean nativeMoveFile(String oldFile, String newFile); JNIEXPORT jboolean JNICALL -Java_app_organicmaps_downloader_MapManager_nativeMoveFile(JNIEnv * env, jclass clazz, jstring oldFile, jstring newFile) +Java_com_mapswithme_maps_downloader_MapManager_nativeMoveFile(JNIEnv * env, jclass clazz, jstring oldFile, jstring newFile) { return base::MoveFileX(jni::ToNativeString(env, oldFile), jni::ToNativeString(env, newFile)); } // static boolean nativeHasSpaceToDownloadAmount(long bytes); JNIEXPORT jboolean JNICALL -Java_app_organicmaps_downloader_MapManager_nativeHasSpaceToDownloadAmount(JNIEnv * env, jclass clazz, jlong bytes) +Java_com_mapswithme_maps_downloader_MapManager_nativeHasSpaceToDownloadAmount(JNIEnv * env, jclass clazz, jlong bytes) { return IsEnoughSpaceForDownload(bytes); } // static boolean nativeHasSpaceToDownloadCountry(String root); JNIEXPORT jboolean JNICALL -Java_app_organicmaps_downloader_MapManager_nativeHasSpaceToDownloadCountry(JNIEnv * env, jclass clazz, jstring root) +Java_com_mapswithme_maps_downloader_MapManager_nativeHasSpaceToDownloadCountry(JNIEnv * env, jclass clazz, jstring root) { return IsEnoughSpaceForDownload(jni::ToNativeString(env, root), GetStorage()); } // static boolean nativeHasSpaceToUpdate(String root); JNIEXPORT jboolean JNICALL -Java_app_organicmaps_downloader_MapManager_nativeHasSpaceToUpdate(JNIEnv * env, jclass clazz, jstring root) +Java_com_mapswithme_maps_downloader_MapManager_nativeHasSpaceToUpdate(JNIEnv * env, jclass clazz, jstring root) { return IsEnoughSpaceForUpdate(jni::ToNativeString(env, root), GetStorage()); } // static int nativeGetDownloadedCount(); JNIEXPORT jint JNICALL -Java_app_organicmaps_downloader_MapManager_nativeGetDownloadedCount(JNIEnv * env, jclass clazz) +Java_com_mapswithme_maps_downloader_MapManager_nativeGetDownloadedCount(JNIEnv * env, jclass clazz) { return static_cast(GetStorage().GetDownloadedFilesCount()); } // static @Nullable UpdateInfo nativeGetUpdateInfo(@Nullable String root); JNIEXPORT jobject JNICALL -Java_app_organicmaps_downloader_MapManager_nativeGetUpdateInfo(JNIEnv * env, jclass clazz, jstring root) +Java_com_mapswithme_maps_downloader_MapManager_nativeGetUpdateInfo(JNIEnv * env, jclass clazz, jstring root) { Storage::UpdateInfo info; if (!GetStorage().GetUpdateInfo(GetRootId(env, root), info)) return nullptr; - static jclass const infoClass = jni::GetGlobalClassRef(env, "app/organicmaps/downloader/UpdateInfo"); + static jclass const infoClass = jni::GetGlobalClassRef(env, "com/mapswithme/maps/downloader/UpdateInfo"); ASSERT(infoClass, (jni::DescribeException())); static jmethodID const ctor = jni::GetConstructorID(env, infoClass, "(IJ)V"); ASSERT(ctor, (jni::DescribeException())); @@ -266,7 +266,7 @@ static void PutItemsToList( // static void nativeListItems(@Nullable String root, double lat, double lon, boolean hasLocation, boolean myMapsMode, List result); JNIEXPORT void JNICALL -Java_app_organicmaps_downloader_MapManager_nativeListItems(JNIEnv * env, jclass clazz, jstring parent, jdouble lat, jdouble lon, jboolean hasLocation, jboolean myMapsMode, jobject result) +Java_com_mapswithme_maps_downloader_MapManager_nativeListItems(JNIEnv * env, jclass clazz, jstring parent, jdouble lat, jdouble lon, jboolean hasLocation, jboolean myMapsMode, jobject result) { CacheListClassRefs(env); @@ -291,7 +291,7 @@ Java_app_organicmaps_downloader_MapManager_nativeListItems(JNIEnv * env, jclass // static void nativeUpdateItem(CountryItem item); JNIEXPORT void JNICALL -Java_app_organicmaps_downloader_MapManager_nativeGetAttributes(JNIEnv * env, jclass, jobject item) +Java_com_mapswithme_maps_downloader_MapManager_nativeGetAttributes(JNIEnv * env, jclass, jobject item) { CacheListClassRefs(env); @@ -306,7 +306,7 @@ Java_app_organicmaps_downloader_MapManager_nativeGetAttributes(JNIEnv * env, jcl // static void nativeGetStatus(String root); JNIEXPORT jint JNICALL -Java_app_organicmaps_downloader_MapManager_nativeGetStatus(JNIEnv * env, jclass clazz, jstring root) +Java_com_mapswithme_maps_downloader_MapManager_nativeGetStatus(JNIEnv * env, jclass clazz, jstring root) { NodeStatuses ns; GetStorage().GetNodeStatuses(jni::ToNativeString(env, root), ns); @@ -315,7 +315,7 @@ Java_app_organicmaps_downloader_MapManager_nativeGetStatus(JNIEnv * env, jclass // static void nativeGetError(String root); JNIEXPORT jint JNICALL -Java_app_organicmaps_downloader_MapManager_nativeGetError(JNIEnv * env, jclass clazz, jstring root) +Java_com_mapswithme_maps_downloader_MapManager_nativeGetError(JNIEnv * env, jclass clazz, jstring root) { NodeStatuses ns; GetStorage().GetNodeStatuses(jni::ToNativeString(env, root), ns); @@ -324,21 +324,21 @@ Java_app_organicmaps_downloader_MapManager_nativeGetError(JNIEnv * env, jclass c // static String nativeGetName(String root); JNIEXPORT jstring JNICALL -Java_app_organicmaps_downloader_MapManager_nativeGetName(JNIEnv * env, jclass clazz, jstring root) +Java_com_mapswithme_maps_downloader_MapManager_nativeGetName(JNIEnv * env, jclass clazz, jstring root) { return jni::ToJavaString(env, GetStorage().GetNodeLocalName(jni::ToNativeString(env, root))); } // static @Nullable String nativeFindCountry(double lat, double lon); JNIEXPORT jstring JNICALL -Java_app_organicmaps_downloader_MapManager_nativeFindCountry(JNIEnv * env, jclass clazz, jdouble lat, jdouble lon) +Java_com_mapswithme_maps_downloader_MapManager_nativeFindCountry(JNIEnv * env, jclass clazz, jdouble lat, jdouble lon) { return jni::ToJavaString(env, g_framework->NativeFramework()->GetCountryInfoGetter().GetRegionCountryId(mercator::FromLatLon(lat, lon))); } // static boolean nativeIsDownloading(); JNIEXPORT jboolean JNICALL -Java_app_organicmaps_downloader_MapManager_nativeIsDownloading(JNIEnv * env, jclass clazz) +Java_com_mapswithme_maps_downloader_MapManager_nativeIsDownloading(JNIEnv * env, jclass clazz) { return static_cast(GetStorage().IsDownloadInProgress()); } @@ -368,7 +368,7 @@ static void EndBatchingCallbacks(JNIEnv * env) for (TBatchedData const & dataItem : key.second) { // Create StorageCallbackData instance… - static jclass batchDataClass = jni::GetGlobalClassRef(env, "app/organicmaps/downloader/MapManager$StorageCallbackData"); + static jclass batchDataClass = jni::GetGlobalClassRef(env, "com/mapswithme/maps/downloader/MapManager$StorageCallbackData"); static jmethodID batchDataCtor = jni::GetConstructorID(env, batchDataClass, "(Ljava/lang/String;IIZ)V"); jni::TScopedLocalRef const id(env, jni::ToJavaString(env, dataItem.m_countryId)); @@ -391,7 +391,7 @@ static void EndBatchingCallbacks(JNIEnv * env) // static void nativeDownload(String root); JNIEXPORT void JNICALL -Java_app_organicmaps_downloader_MapManager_nativeDownload(JNIEnv * env, jclass clazz, jstring root) +Java_com_mapswithme_maps_downloader_MapManager_nativeDownload(JNIEnv * env, jclass clazz, jstring root) { StartBatchingCallbacks(); GetStorage().DownloadNode(jni::ToNativeString(env, root)); @@ -400,7 +400,7 @@ Java_app_organicmaps_downloader_MapManager_nativeDownload(JNIEnv * env, jclass c // static boolean nativeRetry(String root); JNIEXPORT void JNICALL -Java_app_organicmaps_downloader_MapManager_nativeRetry(JNIEnv * env, jclass clazz, jstring root) +Java_com_mapswithme_maps_downloader_MapManager_nativeRetry(JNIEnv * env, jclass clazz, jstring root) { StartBatchingCallbacks(); GetStorage().RetryDownloadNode(jni::ToNativeString(env, root)); @@ -409,7 +409,7 @@ Java_app_organicmaps_downloader_MapManager_nativeRetry(JNIEnv * env, jclass claz // static void nativeUpdate(String root); JNIEXPORT void JNICALL -Java_app_organicmaps_downloader_MapManager_nativeUpdate(JNIEnv * env, jclass clazz, jstring root) +Java_com_mapswithme_maps_downloader_MapManager_nativeUpdate(JNIEnv * env, jclass clazz, jstring root) { StartBatchingCallbacks(); GetStorage().UpdateNode(GetRootId(env, root)); @@ -418,7 +418,7 @@ Java_app_organicmaps_downloader_MapManager_nativeUpdate(JNIEnv * env, jclass cla // static void nativeCancel(String root); JNIEXPORT void JNICALL -Java_app_organicmaps_downloader_MapManager_nativeCancel(JNIEnv * env, jclass clazz, jstring root) +Java_com_mapswithme_maps_downloader_MapManager_nativeCancel(JNIEnv * env, jclass clazz, jstring root) { StartBatchingCallbacks(); GetStorage().CancelDownloadNode(GetRootId(env, root)); @@ -427,7 +427,7 @@ Java_app_organicmaps_downloader_MapManager_nativeCancel(JNIEnv * env, jclass cla // static void nativeDelete(String root); JNIEXPORT void JNICALL -Java_app_organicmaps_downloader_MapManager_nativeDelete(JNIEnv * env, jclass clazz, jstring root) +Java_com_mapswithme_maps_downloader_MapManager_nativeDelete(JNIEnv * env, jclass clazz, jstring root) { StartBatchingCallbacks(); auto const countryId = jni::ToNativeString(env, root); @@ -460,7 +460,7 @@ static void ProgressChangedCallback(std::shared_ptr const & listenerRef // static int nativeSubscribe(StorageCallback listener); JNIEXPORT jint JNICALL -Java_app_organicmaps_downloader_MapManager_nativeSubscribe(JNIEnv * env, jclass clazz, jobject listener) +Java_com_mapswithme_maps_downloader_MapManager_nativeSubscribe(JNIEnv * env, jclass clazz, jobject listener) { CacheListClassRefs(env); return GetStorage().Subscribe(std::bind(&StatusChangedCallback, jni::make_global_ref(listener), _1), @@ -469,14 +469,14 @@ Java_app_organicmaps_downloader_MapManager_nativeSubscribe(JNIEnv * env, jclass // static void nativeUnsubscribe(int slot); JNIEXPORT void JNICALL -Java_app_organicmaps_downloader_MapManager_nativeUnsubscribe(JNIEnv * env, jclass clazz, jint slot) +Java_com_mapswithme_maps_downloader_MapManager_nativeUnsubscribe(JNIEnv * env, jclass clazz, jint slot) { GetStorage().Unsubscribe(slot); } // static void nativeSubscribeOnCountryChanged(CurrentCountryChangedListener listener); JNIEXPORT void JNICALL -Java_app_organicmaps_downloader_MapManager_nativeSubscribeOnCountryChanged(JNIEnv * env, jclass clazz, jobject listener) +Java_com_mapswithme_maps_downloader_MapManager_nativeSubscribeOnCountryChanged(JNIEnv * env, jclass clazz, jobject listener) { ASSERT(!g_countryChangedListener, ()); g_countryChangedListener = env->NewGlobalRef(listener); @@ -496,7 +496,7 @@ Java_app_organicmaps_downloader_MapManager_nativeSubscribeOnCountryChanged(JNIEn // static void nativeUnsubscribeOnCountryChanged(); JNIEXPORT void JNICALL -Java_app_organicmaps_downloader_MapManager_nativeUnsubscribeOnCountryChanged(JNIEnv * env, jclass clazz) +Java_com_mapswithme_maps_downloader_MapManager_nativeUnsubscribeOnCountryChanged(JNIEnv * env, jclass clazz) { g_framework->NativeFramework()->SetCurrentCountryChangedListener(nullptr); @@ -507,14 +507,14 @@ Java_app_organicmaps_downloader_MapManager_nativeUnsubscribeOnCountryChanged(JNI // static boolean nativeHasUnsavedEditorChanges(String root); JNIEXPORT jboolean JNICALL -Java_app_organicmaps_downloader_MapManager_nativeHasUnsavedEditorChanges(JNIEnv * env, jclass clazz, jstring root) +Java_com_mapswithme_maps_downloader_MapManager_nativeHasUnsavedEditorChanges(JNIEnv * env, jclass clazz, jstring root) { return g_framework->NativeFramework()->HasUnsavedEdits(jni::ToNativeString(env, root)); } // static void nativeGetPathTo(String root, List result); JNIEXPORT void JNICALL -Java_app_organicmaps_downloader_MapManager_nativeGetPathTo(JNIEnv * env, jclass clazz, jstring root, jobject result) +Java_com_mapswithme_maps_downloader_MapManager_nativeGetPathTo(JNIEnv * env, jclass clazz, jstring root, jobject result) { CountriesVec path; GetStorage().GetGroupNodePathToRoot(jni::ToNativeString(env, root), path); @@ -524,7 +524,7 @@ Java_app_organicmaps_downloader_MapManager_nativeGetPathTo(JNIEnv * env, jclass // static int nativeGetOverallProgress(String[] countries); JNIEXPORT jint JNICALL -Java_app_organicmaps_downloader_MapManager_nativeGetOverallProgress(JNIEnv * env, jclass clazz, jobjectArray jcountries) +Java_com_mapswithme_maps_downloader_MapManager_nativeGetOverallProgress(JNIEnv * env, jclass clazz, jobjectArray jcountries) { int const size = env->GetArrayLength(jcountries); CountriesVec countries; @@ -547,28 +547,28 @@ Java_app_organicmaps_downloader_MapManager_nativeGetOverallProgress(JNIEnv * env // static boolean nativeIsAutoretryFailed(); JNIEXPORT jboolean JNICALL -Java_app_organicmaps_downloader_MapManager_nativeIsAutoretryFailed(JNIEnv * env, jclass clazz) +Java_com_mapswithme_maps_downloader_MapManager_nativeIsAutoretryFailed(JNIEnv * env, jclass clazz) { return g_framework->IsAutoRetryDownloadFailed(); } // static boolean nativeIsDownloadOn3gEnabled(); JNIEXPORT jboolean JNICALL -Java_app_organicmaps_downloader_MapManager_nativeIsDownloadOn3gEnabled(JNIEnv * env, jclass clazz) +Java_com_mapswithme_maps_downloader_MapManager_nativeIsDownloadOn3gEnabled(JNIEnv * env, jclass clazz) { return g_framework->IsDownloadOn3gEnabled(); } // static void nativeEnableDownloadOn3g(); JNIEXPORT void JNICALL -Java_app_organicmaps_downloader_MapManager_nativeEnableDownloadOn3g(JNIEnv * env, jclass clazz) +Java_com_mapswithme_maps_downloader_MapManager_nativeEnableDownloadOn3g(JNIEnv * env, jclass clazz) { g_framework->EnableDownloadOn3g(); } // static @Nullable String nativeGetSelectedCountry(); JNIEXPORT jstring JNICALL -Java_app_organicmaps_downloader_MapManager_nativeGetSelectedCountry(JNIEnv * env, jclass clazz) +Java_com_mapswithme_maps_downloader_MapManager_nativeGetSelectedCountry(JNIEnv * env, jclass clazz) { if (!g_framework->NativeFramework()->HasPlacePageInfo()) return nullptr; diff --git a/android/jni/com/mapswithme/maps/MwmApplication.cpp b/android/jni/com/mapswithme/maps/MwmApplication.cpp new file mode 100644 index 0000000000..2f7efe3091 --- /dev/null +++ b/android/jni/com/mapswithme/maps/MwmApplication.cpp @@ -0,0 +1,61 @@ +#include "com/mapswithme/maps/Framework.hpp" + +#include "com/mapswithme/platform/GuiThread.hpp" +#include "com/mapswithme/platform/Platform.hpp" + +#include "com/mapswithme/core/jni_helper.hpp" + +extern "C" +{ + // static void nativeSetSettingsDir(String settingsPath); + JNIEXPORT void JNICALL + Java_com_mapswithme_maps_MwmApplication_nativeSetSettingsDir(JNIEnv * env, jclass clazz, jstring settingsPath) + { + android::Platform::Instance().SetSettingsDir(jni::ToNativeString(env, settingsPath)); + } + + // void nativeInitPlatform(String apkPath, String storagePath, String privatePath, String tmpPath, + // String flavorName, String buildType, boolean isTablet); + JNIEXPORT void JNICALL + Java_com_mapswithme_maps_MwmApplication_nativeInitPlatform(JNIEnv * env, jobject thiz, + jstring apkPath, jstring writablePath, + jstring privatePath, jstring tmpPath, + jstring flavorName, jstring buildType, + jboolean isTablet) + { + android::Platform::Instance().Initialize(env, thiz, apkPath, writablePath, privatePath, tmpPath, + flavorName, buildType, isTablet); + } + + // static void nativeInitFramework(); + JNIEXPORT void JNICALL + Java_com_mapswithme_maps_MwmApplication_nativeInitFramework(JNIEnv * env, jclass clazz) + { + if (!g_framework) + g_framework = std::make_unique(); + } + + // static void nativeProcessTask(long taskPointer); + JNIEXPORT void JNICALL + Java_com_mapswithme_maps_MwmApplication_nativeProcessTask(JNIEnv * env, jclass clazz, jlong taskPointer) + { + android::GuiThread::ProcessTask(taskPointer); + } + + // static void nativeAddLocalization(String name, String value); + JNIEXPORT void JNICALL + Java_com_mapswithme_maps_MwmApplication_nativeAddLocalization(JNIEnv * env, jclass clazz, jstring name, jstring value) + { + g_framework->AddString(jni::ToNativeString(env, name), + jni::ToNativeString(env, value)); + } + + JNIEXPORT void JNICALL + Java_com_mapswithme_maps_MwmApplication_nativeOnTransit(JNIEnv *, jclass, jboolean foreground) + { + if (static_cast(foreground)) + g_framework->NativeFramework()->EnterForeground(); + else + g_framework->NativeFramework()->EnterBackground(); + } +} diff --git a/android/jni/app/organicmaps/SearchEngine.cpp b/android/jni/com/mapswithme/maps/SearchEngine.cpp similarity index 81% rename from android/jni/app/organicmaps/SearchEngine.cpp rename to android/jni/com/mapswithme/maps/SearchEngine.cpp index 67c5bc7c65..71e3ee4331 100644 --- a/android/jni/app/organicmaps/SearchEngine.cpp +++ b/android/jni/com/mapswithme/maps/SearchEngine.cpp @@ -1,6 +1,6 @@ -#include "app/organicmaps/Framework.hpp" -#include "app/organicmaps/UserMarkHelper.hpp" -#include "app/organicmaps/platform/Platform.hpp" +#include "com/mapswithme/maps/Framework.hpp" +#include "com/mapswithme/maps/UserMarkHelper.hpp" +#include "com/mapswithme/platform/Platform.hpp" #include "map/bookmarks_search_params.hpp" #include "map/everywhere_search_params.hpp" @@ -82,26 +82,34 @@ jobject ToJavaResult(Result const & result, search::ProductInfo const & productI env->ReleaseIntArrayElements(ranges.get(), rawArr, 0); ms::LatLon ll = ms::LatLon::Zero(); + string distance; + double distanceInMeters = 0.0; + if (result.HasPoint()) - ll = mercator::ToLatLon(result.GetFeatureCenter()); + { + auto const center = result.GetFeatureCenter(); + ll = mercator::ToLatLon(center); + if (hasPosition) + { + distanceInMeters = ms::DistanceOnEarth(lat, lon, + mercator::YToLat(center.y), + mercator::XToLon(center.x)); + distance = measurement_utils::FormatDistance(distanceInMeters); + } + } + + bool popularityHasHigherPriority = PopularityHasHigherPriority(hasPosition, distanceInMeters); if (result.IsSuggest()) { jni::TScopedLocalRef name(env, jni::ToJavaString(env, result.GetString())); jni::TScopedLocalRef suggest(env, jni::ToJavaString(env, result.GetSuggestionString())); - return env->NewObject(g_resultClass, g_suggestConstructor, name.get(), suggest.get(), ll.m_lat, ll.m_lon, ranges.get()); + jobject ret = env->NewObject(g_resultClass, g_suggestConstructor, name.get(), suggest.get(), ll.m_lat, ll.m_lon, ranges.get()); + ASSERT(ret, ()); + return ret; } - string distance; - double distanceInMeters = 0.0; - if (result.HasPoint() && hasPosition) - { - distanceInMeters = ms::DistanceOnEarth(lat, lon, ll.m_lat, ll.m_lon); - distance = measurement_utils::FormatDistance(distanceInMeters); - } - - bool const popularityHasHigherPriority = PopularityHasHigherPriority(hasPosition, distanceInMeters); - bool const isFeature = result.GetResultType() == Result::Type::Feature; + auto const isFeature = result.GetResultType() == Result::Type::Feature; jni::TScopedLocalRef featureId(env, usermark_helper::CreateFeatureId(env, isFeature ? result.GetFeatureID() : kEmptyFeatureId)); @@ -129,9 +137,12 @@ jobject ToJavaResult(Result const & result, search::ProductInfo const & productI g_popularityConstructor, /// @todo Restore when popularity will be available 0/*static_cast(result.GetRankingInfo().m_popularity)*/)); + jobject ret = + env->NewObject(g_resultClass, g_resultConstructor, name.get(), desc.get(), ll.m_lat, ll.m_lon, + ranges.get(), result.IsHotel(), popularity.get()); + ASSERT(ret, ()); - return env->NewObject(g_resultClass, g_resultConstructor, name.get(), desc.get(), ll.m_lat, ll.m_lon, - ranges.get(), result.IsHotel(), result.GetStarsCount(), popularity.get()); + return ret; } jobjectArray BuildSearchResults(vector const & productInfo, @@ -227,21 +238,21 @@ void OnBookmarksSearchResults(search::BookmarksSearchParams::Results results, extern "C" { JNIEXPORT void JNICALL - Java_app_organicmaps_search_SearchEngine_nativeInit(JNIEnv * env, jobject thiz) + Java_com_mapswithme_maps_search_SearchEngine_nativeInit(JNIEnv * env, jobject thiz) { g_javaListener = env->NewGlobalRef(thiz); // public void onResultsUpdate(@NonNull SearchResult[] results, long timestamp) g_updateResultsId = jni::GetMethodID(env, g_javaListener, "onResultsUpdate", - "([Lapp/organicmaps/search/SearchResult;J)V"); + "([Lcom/mapswithme/maps/search/SearchResult;J)V"); // public void onResultsEnd(long timestamp) g_endResultsId = jni::GetMethodID(env, g_javaListener, "onResultsEnd", "(J)V"); - g_resultClass = jni::GetGlobalClassRef(env, "app/organicmaps/search/SearchResult"); + g_resultClass = jni::GetGlobalClassRef(env, "com/mapswithme/maps/search/SearchResult"); g_resultConstructor = jni::GetConstructorID( env, g_resultClass, - "(Ljava/lang/String;Lapp/organicmaps/search/SearchResult$Description;DD[IZI" - "Lapp/organicmaps/search/Popularity;)V"); + "(Ljava/lang/String;Lcom/mapswithme/maps/search/SearchResult$Description;DD[IZ" + "Lcom/mapswithme/maps/search/Popularity;)V"); g_suggestConstructor = jni::GetConstructorID(env, g_resultClass, "(Ljava/lang/String;Ljava/lang/String;DD[I)V"); - g_descriptionClass = jni::GetGlobalClassRef(env, "app/organicmaps/search/SearchResult$Description"); + g_descriptionClass = jni::GetGlobalClassRef(env, "com/mapswithme/maps/search/SearchResult$Description"); /* Description(FeatureId featureId, String featureType, String region, String distance, String cuisine, String brand, String airportIata, String roadShields, @@ -249,17 +260,17 @@ extern "C" boolean hasPopularityHigherPriority) */ g_descriptionConstructor = jni::GetConstructorID(env, g_descriptionClass, - "(Lapp/organicmaps/bookmarks/data/FeatureId;" + "(Lcom/mapswithme/maps/bookmarks/data/FeatureId;" "Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;" "Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;" "Ljava/lang/String;IIIZ)V"); - g_popularityClass = jni::GetGlobalClassRef(env, "app/organicmaps/search/Popularity"); + g_popularityClass = jni::GetGlobalClassRef(env, "com/mapswithme/maps/search/Popularity"); g_popularityConstructor = jni::GetConstructorID(env, g_popularityClass, "(I)V"); g_mapResultsMethod = jni::GetMethodID(env, g_javaListener, "onMapSearchResults", - "([Lapp/organicmaps/search/NativeMapSearchListener$Result;JZ)V"); - g_mapResultClass = jni::GetGlobalClassRef(env, "app/organicmaps/search/NativeMapSearchListener$Result"); + "([Lcom/mapswithme/maps/search/NativeMapSearchListener$Result;JZ)V"); + g_mapResultClass = jni::GetGlobalClassRef(env, "com/mapswithme/maps/search/NativeMapSearchListener$Result"); g_mapResultCtor = jni::GetConstructorID(env, g_mapResultClass, "(Ljava/lang/String;Ljava/lang/String;)V"); g_updateBookmarksResultsId = @@ -268,7 +279,7 @@ extern "C" jni::GetMethodID(env, g_javaListener, "onBookmarkSearchResultsEnd", "([JJ)V"); } - JNIEXPORT jboolean JNICALL Java_app_organicmaps_search_SearchEngine_nativeRunSearch( + JNIEXPORT jboolean JNICALL Java_com_mapswithme_maps_search_SearchEngine_nativeRunSearch( JNIEnv * env, jclass clazz, jbyteArray bytes, jboolean isCategory, jstring lang, jlong timestamp, jboolean hasPosition, jdouble lat, jdouble lon) { @@ -285,17 +296,15 @@ extern "C" return searchStarted; } - JNIEXPORT void JNICALL Java_app_organicmaps_search_SearchEngine_nativeRunInteractiveSearch( + JNIEXPORT void JNICALL Java_com_mapswithme_maps_search_SearchEngine_nativeRunInteractiveSearch( JNIEnv * env, jclass clazz, jbyteArray bytes, jboolean isCategory, jstring lang, jlong timestamp, jboolean isMapAndTable) { search::ViewportSearchParams vparams{ jni::ToNativeString(env, bytes), jni::ToNativeString(env, lang), - {}, // Default timeout - static_cast(isCategory), - {}, // Empty m_onStarted callback - {}, // Empty m_onCompleted callback + {}, // default timeout + static_cast(isCategory) }; // TODO (@alexzatsepin): set up vparams.m_onCompleted here and use @@ -319,7 +328,7 @@ extern "C" } } - JNIEXPORT void JNICALL Java_app_organicmaps_search_SearchEngine_nativeRunSearchMaps( + JNIEXPORT void JNICALL Java_com_mapswithme_maps_search_SearchEngine_nativeRunSearchMaps( JNIEnv * env, jclass clazz, jbyteArray bytes, jstring lang, jlong timestamp) { storage::DownloaderSearchParams params{ @@ -332,7 +341,7 @@ extern "C" g_queryTimestamp = timestamp; } - JNIEXPORT jboolean JNICALL Java_app_organicmaps_search_SearchEngine_nativeRunSearchInBookmarks( + JNIEXPORT jboolean JNICALL Java_com_mapswithme_maps_search_SearchEngine_nativeRunSearchInBookmarks( JNIEnv * env, jclass clazz, jbyteArray query, jlong catId, jlong timestamp) { search::BookmarksSearchParams params{ @@ -348,25 +357,25 @@ extern "C" } JNIEXPORT void JNICALL - Java_app_organicmaps_search_SearchEngine_nativeShowResult(JNIEnv * env, jclass clazz, jint index) + Java_com_mapswithme_maps_search_SearchEngine_nativeShowResult(JNIEnv * env, jclass clazz, jint index) { g_framework->NativeFramework()->ShowSearchResult(g_results[index]); } JNIEXPORT void JNICALL - Java_app_organicmaps_search_SearchEngine_nativeCancelInteractiveSearch(JNIEnv * env, jclass clazz) + Java_com_mapswithme_maps_search_SearchEngine_nativeCancelInteractiveSearch(JNIEnv * env, jclass clazz) { g_framework->NativeFramework()->GetSearchAPI().CancelSearch(search::Mode::Viewport); } JNIEXPORT void JNICALL - Java_app_organicmaps_search_SearchEngine_nativeCancelEverywhereSearch(JNIEnv * env, jclass clazz) + Java_com_mapswithme_maps_search_SearchEngine_nativeCancelEverywhereSearch(JNIEnv * env, jclass clazz) { g_framework->NativeFramework()->GetSearchAPI().CancelSearch(search::Mode::Everywhere); } JNIEXPORT void JNICALL - Java_app_organicmaps_search_SearchEngine_nativeCancelAllSearches(JNIEnv * env, jclass clazz) + Java_com_mapswithme_maps_search_SearchEngine_nativeCancelAllSearches(JNIEnv * env, jclass clazz) { g_framework->NativeFramework()->GetSearchAPI().CancelAllSearches(); } diff --git a/android/jni/app/organicmaps/SearchRecents.cpp b/android/jni/com/mapswithme/maps/SearchRecents.cpp similarity index 79% rename from android/jni/app/organicmaps/SearchRecents.cpp rename to android/jni/com/mapswithme/maps/SearchRecents.cpp index 4faab693ca..65086c56fc 100644 --- a/android/jni/app/organicmaps/SearchRecents.cpp +++ b/android/jni/com/mapswithme/maps/SearchRecents.cpp @@ -2,14 +2,14 @@ #include "search/result.hpp" -#include "app/organicmaps/core/jni_helper.hpp" +#include "com/mapswithme/core/jni_helper.hpp" using SearchRequest = search::QuerySaver::SearchRequest; extern "C" { JNIEXPORT void JNICALL - Java_app_organicmaps_search_SearchRecents_nativeGetList(JNIEnv * env, jclass thiz, jobject result) + Java_com_mapswithme_maps_search_SearchRecents_nativeGetList(JNIEnv * env, jclass thiz, jobject result) { auto const & items = g_framework->NativeFramework()->GetSearchAPI().GetLastSearchQueries(); if (items.empty()) @@ -31,14 +31,14 @@ extern "C" } JNIEXPORT void JNICALL - Java_app_organicmaps_search_SearchRecents_nativeAdd(JNIEnv * env, jclass thiz, jstring locale, jstring query) + Java_com_mapswithme_maps_search_SearchRecents_nativeAdd(JNIEnv * env, jclass thiz, jstring locale, jstring query) { SearchRequest const sr(jni::ToNativeString(env, locale), jni::ToNativeString(env, query)); g_framework->NativeFramework()->GetSearchAPI().SaveSearchQuery(sr); } JNIEXPORT void JNICALL - Java_app_organicmaps_search_SearchRecents_nativeClear(JNIEnv * env, jclass thiz) + Java_com_mapswithme_maps_search_SearchRecents_nativeClear(JNIEnv * env, jclass thiz) { g_framework->NativeFramework()->GetSearchAPI().ClearSearchHistory(); } diff --git a/android/jni/com/mapswithme/maps/TrackRecorder.cpp b/android/jni/com/mapswithme/maps/TrackRecorder.cpp new file mode 100644 index 0000000000..49a7b47936 --- /dev/null +++ b/android/jni/com/mapswithme/maps/TrackRecorder.cpp @@ -0,0 +1,39 @@ +#include "Framework.hpp" + +#include "map/gps_tracker.hpp" + +#include + +extern "C" +{ + JNIEXPORT void JNICALL + Java_com_mapswithme_maps_location_TrackRecorder_nativeSetEnabled(JNIEnv * env, jclass clazz, jboolean enable) + { + GpsTracker::Instance().SetEnabled(enable); + Framework * const f = frm(); + if (f == nullptr) + return; + if (enable) + f->ConnectToGpsTracker(); + else + f->DisconnectFromGpsTracker(); + } + + JNIEXPORT jboolean JNICALL + Java_com_mapswithme_maps_location_TrackRecorder_nativeIsEnabled(JNIEnv * env, jclass clazz) + { + return GpsTracker::Instance().IsEnabled(); + } + + JNIEXPORT void JNICALL + Java_com_mapswithme_maps_location_TrackRecorder_nativeSetDuration(JNIEnv * env, jclass clazz, jint durationHours) + { + GpsTracker::Instance().SetDuration(std::chrono::hours(durationHours)); + } + + JNIEXPORT jint JNICALL + Java_com_mapswithme_maps_location_TrackRecorder_nativeGetDuration(JNIEnv * env, jclass clazz) + { + return static_cast(GpsTracker::Instance().GetDuration().count()); + } +} diff --git a/android/jni/com/mapswithme/maps/TrafficState.cpp b/android/jni/com/mapswithme/maps/TrafficState.cpp new file mode 100644 index 0000000000..7dbdbb22a5 --- /dev/null +++ b/android/jni/com/mapswithme/maps/TrafficState.cpp @@ -0,0 +1,49 @@ +#include "Framework.hpp" + +#include "com/mapswithme/core/jni_helper.hpp" + +#include "com/mapswithme/platform/Platform.hpp" + +extern "C" +{ +static void TrafficStateChanged(TrafficManager::TrafficState state, std::shared_ptr const & listener) +{ + JNIEnv * env = jni::GetEnv(); + env->CallVoidMethod(*listener, jni::GetMethodID(env, *listener, "onTrafficStateChanged", "(I)V"), static_cast(state)); +} + +JNIEXPORT void JNICALL +Java_com_mapswithme_maps_maplayer_traffic_TrafficState_nativeSetListener(JNIEnv * env, jclass clazz, jobject listener) +{ + CHECK(g_framework, ("Framework isn't created yet!")); + g_framework->SetTrafficStateListener(std::bind(&TrafficStateChanged, std::placeholders::_1, jni::make_global_ref(listener))); +} + +JNIEXPORT void JNICALL +Java_com_mapswithme_maps_maplayer_traffic_TrafficState_nativeRemoveListener(JNIEnv * env, jclass clazz) +{ + CHECK(g_framework, ("Framework isn't created yet!")); + g_framework->SetTrafficStateListener(TrafficManager::TrafficStateChangedFn()); +} + +JNIEXPORT void JNICALL +Java_com_mapswithme_maps_maplayer_traffic_TrafficState_nativeEnable(JNIEnv * env, jclass clazz) +{ + CHECK(g_framework, ("Framework isn't created yet!")); + g_framework->EnableTraffic(); +} + +JNIEXPORT jboolean JNICALL +Java_com_mapswithme_maps_maplayer_traffic_TrafficState_nativeIsEnabled(JNIEnv * env, jclass clazz) +{ + CHECK(g_framework, ("Framework isn't created yet!")); + return static_cast(g_framework->IsTrafficEnabled()); +} + +JNIEXPORT void JNICALL +Java_com_mapswithme_maps_maplayer_traffic_TrafficState_nativeDisable(JNIEnv * env, jclass clazz) +{ + CHECK(g_framework, ("Framework isn't created yet!")); + g_framework->DisableTraffic(); +} +} // extern "C" diff --git a/android/jni/app/organicmaps/UserMarkHelper.cpp b/android/jni/com/mapswithme/maps/UserMarkHelper.cpp similarity index 92% rename from android/jni/app/organicmaps/UserMarkHelper.cpp rename to android/jni/com/mapswithme/maps/UserMarkHelper.cpp index 40936f815c..3852b490cb 100644 --- a/android/jni/app/organicmaps/UserMarkHelper.cpp +++ b/android/jni/com/mapswithme/maps/UserMarkHelper.cpp @@ -28,7 +28,7 @@ void InjectMetadata(JNIEnv * env, jclass const clazz, jobject const mapObject, o jobject CreatePopularity(JNIEnv * env, place_page::Info const & info) { static jclass const popularityClass = - jni::GetGlobalClassRef(env, "app/organicmaps/search/Popularity"); + jni::GetGlobalClassRef(env, "com/mapswithme/maps/search/Popularity"); static jmethodID const popularityConstructor = jni::GetConstructorID(env, popularityClass, "(I)V"); auto const popularityValue = info.GetPopularity(); @@ -47,7 +47,7 @@ jobject CreateMapObject(JNIEnv * env, place_page::Info const & info, int mapObje static jmethodID const ctorId = jni::GetConstructorID( env, g_mapObjectClazz, "(" - "Lapp/organicmaps/bookmarks/data/FeatureId;" // featureId + "Lcom/mapswithme/maps/bookmarks/data/FeatureId;" // featureId "I" // mapObjectType "Ljava/lang/String;" // title "Ljava/lang/String;" // secondaryTitle @@ -55,9 +55,9 @@ jobject CreateMapObject(JNIEnv * env, place_page::Info const & info, int mapObje "Ljava/lang/String;" // address "DD" // lat, lon "Ljava/lang/String;" // appId - "Lapp/organicmaps/routing/RoutePointInfo;" // routePointInfo + "Lcom/mapswithme/maps/routing/RoutePointInfo;" // routePointInfo "I" // openingMode - "Lapp/organicmaps/search/Popularity;" // popularity + "Lcom/mapswithme/maps/search/Popularity;" // popularity "Ljava/lang/String;" // description "I" // roadWarnType "[Ljava/lang/String;" // rawTypes @@ -102,10 +102,10 @@ jobject CreateBookmark(JNIEnv *env, const place_page::Info &info, // @Nullable String[] rawTypes) static jmethodID const ctorId = jni::GetConstructorID(env, g_bookmarkClazz, - "(Lapp/organicmaps/bookmarks/data/FeatureId;JJLjava/lang/String;" + "(Lcom/mapswithme/maps/bookmarks/data/FeatureId;JJLjava/lang/String;" "Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;" - "Lapp/organicmaps/routing/RoutePointInfo;" - "ILapp/organicmaps/search/Popularity;Ljava/lang/String;" + "Lcom/mapswithme/maps/routing/RoutePointInfo;" + "ILcom/mapswithme/maps/search/Popularity;Ljava/lang/String;" "[Ljava/lang/String;)V"); static jmethodID const featureCtorId = jni::GetConstructorID(env, g_featureIdClazz, "(Ljava/lang/String;JI)V"); @@ -135,7 +135,7 @@ jobject CreateBookmark(JNIEnv *env, const place_page::Info &info, jobject CreateElevationPoint(JNIEnv * env, ElevationInfo::Point const & point) { static jclass const pointClass = - jni::GetGlobalClassRef(env, "app/organicmaps/bookmarks/data/ElevationInfo$Point"); + jni::GetGlobalClassRef(env, "com/mapswithme/maps/bookmarks/data/ElevationInfo$Point"); // public Point(double distance, int altitude) static jmethodID const pointCtorId = jni::GetConstructorID(env, pointClass, "(DI)V"); @@ -147,7 +147,7 @@ jobjectArray ToElevationPointArray(JNIEnv * env, ElevationInfo::Points const & p { CHECK(!points.empty(), ("Elevation points must be non empty!")); static jclass const pointClass = - jni::GetGlobalClassRef(env, "app/organicmaps/bookmarks/data/ElevationInfo$Point"); + jni::GetGlobalClassRef(env, "com/mapswithme/maps/bookmarks/data/ElevationInfo$Point"); return jni::ToJavaArray(env, pointClass, points, [](JNIEnv * env, ElevationInfo::Point const & item) { @@ -162,7 +162,7 @@ jobject CreateElevationInfo(JNIEnv * env, ElevationInfo const & info) // long m_duration) static jmethodID const ctorId = jni::GetConstructorID(env, g_elevationInfoClazz, "(JLjava/lang/String;Ljava/lang/String;" - "[Lapp/organicmaps/bookmarks/data/ElevationInfo$Point;" + "[Lcom/mapswithme/maps/bookmarks/data/ElevationInfo$Point;" "IIIIIJ)V"); jni::TScopedLocalRef jName(env, jni::ToJavaString(env, info.GetName())); jni::TScopedLocalObjectArrayRef jPoints(env, ToElevationPointArray(env, info.GetPoints())); @@ -215,7 +215,7 @@ jobject CreateMapObject(JNIEnv * env, place_page::Info const & info) jobject CreateRoutePointInfo(JNIEnv * env, place_page::Info const & info) { - static jclass const clazz = jni::GetGlobalClassRef(env, "app/organicmaps/routing/RoutePointInfo"); + static jclass const clazz = jni::GetGlobalClassRef(env, "com/mapswithme/maps/routing/RoutePointInfo"); static jmethodID const ctorId = jni::GetConstructorID(env, clazz, "(II)V"); int const markType = static_cast(info.GetRouteMarkType()); return env->NewObject(clazz, ctorId, markType, info.GetIntermediateIndex()); diff --git a/android/jni/app/organicmaps/UserMarkHelper.hpp b/android/jni/com/mapswithme/maps/UserMarkHelper.hpp similarity index 94% rename from android/jni/app/organicmaps/UserMarkHelper.hpp rename to android/jni/com/mapswithme/maps/UserMarkHelper.hpp index fed17e0c59..fafa3d8c41 100644 --- a/android/jni/app/organicmaps/UserMarkHelper.hpp +++ b/android/jni/com/mapswithme/maps/UserMarkHelper.hpp @@ -2,8 +2,8 @@ #include -#include "app/organicmaps/core/jni_helper.hpp" -#include "app/organicmaps/Framework.hpp" +#include "com/mapswithme/core/jni_helper.hpp" +#include "com/mapswithme/maps/Framework.hpp" #include diff --git a/android/jni/app/organicmaps/VideoTimer.cpp b/android/jni/com/mapswithme/maps/VideoTimer.cpp similarity index 88% rename from android/jni/app/organicmaps/VideoTimer.cpp rename to android/jni/com/mapswithme/maps/VideoTimer.cpp index 8a0d78107f..08404f322e 100644 --- a/android/jni/app/organicmaps/VideoTimer.cpp +++ b/android/jni/com/mapswithme/maps/VideoTimer.cpp @@ -1,6 +1,6 @@ #include "VideoTimer.hpp" -#include "app/organicmaps/core/jni_helper.hpp" +#include "com/mapswithme/core/jni_helper.hpp" #include "base/assert.hpp" #include "base/logging.hpp" @@ -69,14 +69,14 @@ namespace android extern "C" { JNIEXPORT void JNICALL - Java_app_organicmaps_VideoTimer_nativeRun(JNIEnv * env, jobject thiz) + Java_com_mapswithme_maps_VideoTimer_nativeRun(JNIEnv * env, jobject thiz) { ASSERT ( g_timer, ()); g_timer->perform(); } JNIEXPORT void JNICALL - Java_app_organicmaps_VideoTimer_nativeInit(JNIEnv * env, jobject thiz) + Java_com_mapswithme_maps_VideoTimer_nativeInit(JNIEnv * env, jobject thiz) { ASSERT ( g_timer, ()); g_timer->SetParentObject(thiz); diff --git a/android/jni/app/organicmaps/VideoTimer.hpp b/android/jni/com/mapswithme/maps/VideoTimer.hpp similarity index 100% rename from android/jni/app/organicmaps/VideoTimer.hpp rename to android/jni/com/mapswithme/maps/VideoTimer.hpp diff --git a/android/jni/app/organicmaps/bookmarks/data/BookmarkManager.cpp b/android/jni/com/mapswithme/maps/bookmarks/data/BookmarkManager.cpp similarity index 82% rename from android/jni/app/organicmaps/bookmarks/data/BookmarkManager.cpp rename to android/jni/com/mapswithme/maps/bookmarks/data/BookmarkManager.cpp index 8bdc869e7e..e1b2767012 100644 --- a/android/jni/app/organicmaps/bookmarks/data/BookmarkManager.cpp +++ b/android/jni/com/mapswithme/maps/bookmarks/data/BookmarkManager.cpp @@ -1,6 +1,6 @@ -#include "app/organicmaps/core/jni_helper.hpp" -#include "app/organicmaps/Framework.hpp" -#include "app/organicmaps/UserMarkHelper.hpp" +#include "com/mapswithme/core/jni_helper.hpp" +#include "com/mapswithme/maps/Framework.hpp" +#include "com/mapswithme/maps/UserMarkHelper.hpp" #include "map/bookmark_helpers.hpp" #include "map/place_page_info.hpp" @@ -49,9 +49,9 @@ void PrepareClassRefs(JNIEnv * env) return; g_bookmarkManagerClass = - jni::GetGlobalClassRef(env, "app/organicmaps/bookmarks/data/BookmarkManager"); + jni::GetGlobalClassRef(env, "com/mapswithme/maps/bookmarks/data/BookmarkManager"); g_bookmarkManagerInstanceField = jni::GetStaticFieldID(env, g_bookmarkManagerClass, "INSTANCE", - "Lapp/organicmaps/bookmarks/data/BookmarkManager;"); + "Lcom/mapswithme/maps/bookmarks/data/BookmarkManager;"); jobject bookmarkManagerInstance = env->GetStaticObjectField(g_bookmarkManagerClass, g_bookmarkManagerInstanceField); @@ -66,27 +66,27 @@ void PrepareClassRefs(JNIEnv * env) "(ZLjava/lang/String;Z)V"); g_onPreparedFileForSharingMethod = jni::GetMethodID(env, bookmarkManagerInstance, "onPreparedFileForSharing", - "(Lapp/organicmaps/bookmarks/data/BookmarkSharingResult;)V"); + "(Lcom/mapswithme/maps/bookmarks/data/BookmarkSharingResult;)V"); g_longClass = jni::GetGlobalClassRef(env,"java/lang/Long"); g_longConstructor = jni::GetConstructorID(env, g_longClass, "(J)V"); g_sortedBlockClass = - jni::GetGlobalClassRef(env, "app/organicmaps/bookmarks/data/SortedBlock"); + jni::GetGlobalClassRef(env, "com/mapswithme/maps/bookmarks/data/SortedBlock"); g_sortedBlockConstructor = jni::GetConstructorID(env, g_sortedBlockClass, "(Ljava/lang/String;[Ljava/lang/Long;[Ljava/lang/Long;)V"); g_onBookmarksSortingCompleted = jni::GetMethodID(env, bookmarkManagerInstance, - "onBookmarksSortingCompleted", "([Lapp/organicmaps/bookmarks/data/SortedBlock;J)V"); + "onBookmarksSortingCompleted", "([Lcom/mapswithme/maps/bookmarks/data/SortedBlock;J)V"); g_onBookmarksSortingCancelled = jni::GetMethodID(env, bookmarkManagerInstance, "onBookmarksSortingCancelled", "(J)V"); g_bookmarkInfoClass = - jni::GetGlobalClassRef(env, "app/organicmaps/bookmarks/data/BookmarkInfo"); + jni::GetGlobalClassRef(env, "com/mapswithme/maps/bookmarks/data/BookmarkInfo"); g_bookmarkInfoConstructor = jni::GetConstructorID(env, g_bookmarkInfoClass, "(JJ)V" ); g_bookmarkCategoryClass = - jni::GetGlobalClassRef(env, "app/organicmaps/bookmarks/data/BookmarkCategory"); + jni::GetGlobalClassRef(env, "com/mapswithme/maps/bookmarks/data/BookmarkCategory"); //public BookmarkCategory(long id, // String name, @@ -186,7 +186,7 @@ void OnPreparedFileForSharing(JNIEnv * env, BookmarkManager::SharingResult const g_bookmarkManagerInstanceField); static jclass const classBookmarkSharingResult = jni::GetGlobalClassRef(env, - "app/organicmaps/bookmarks/data/BookmarkSharingResult"); + "com/mapswithme/maps/bookmarks/data/BookmarkSharingResult"); // Java signature : BookmarkSharingResult(long categoryId, @Code int code, // @NonNull String sharingPath, // @NonNull String errorString) @@ -297,21 +297,21 @@ jobjectArray MakeCategories(JNIEnv * env, kml::GroupIdCollection const & ids) extern "C" { JNIEXPORT void JNICALL -Java_app_organicmaps_bookmarks_data_BookmarkManager_nativeShowBookmarkOnMap( +Java_com_mapswithme_maps_bookmarks_data_BookmarkManager_nativeShowBookmarkOnMap( JNIEnv *, jobject, jlong bmkId) { frm()->ShowBookmark(static_cast(bmkId)); } JNIEXPORT void JNICALL -Java_app_organicmaps_bookmarks_data_BookmarkManager_nativeShowBookmarkCategoryOnMap( +Java_com_mapswithme_maps_bookmarks_data_BookmarkManager_nativeShowBookmarkCategoryOnMap( JNIEnv *, jobject, jlong catId) { frm()->ShowBookmarkCategory(static_cast(catId), true /* animated */); } JNIEXPORT void JNICALL -Java_app_organicmaps_bookmarks_data_BookmarkManager_nativeLoadBookmarks(JNIEnv * env, jclass) +Java_com_mapswithme_maps_bookmarks_data_BookmarkManager_nativeLoadBookmarks(JNIEnv * env, jclass) { PrepareClassRefs(env); BookmarkManager::AsyncLoadingCallbacks callbacks; @@ -327,7 +327,7 @@ Java_app_organicmaps_bookmarks_data_BookmarkManager_nativeLoadBookmarks(JNIEnv * } JNIEXPORT jlong JNICALL -Java_app_organicmaps_bookmarks_data_BookmarkManager_nativeCreateCategory( +Java_com_mapswithme_maps_bookmarks_data_BookmarkManager_nativeCreateCategory( JNIEnv * env, jobject, jstring name) { auto const categoryId = frm()->GetBookmarkManager().CreateBookmarkCategory(ToNativeString(env, name)); @@ -336,7 +336,7 @@ Java_app_organicmaps_bookmarks_data_BookmarkManager_nativeCreateCategory( } JNIEXPORT jboolean JNICALL -Java_app_organicmaps_bookmarks_data_BookmarkManager_nativeDeleteCategory( +Java_com_mapswithme_maps_bookmarks_data_BookmarkManager_nativeDeleteCategory( JNIEnv *, jobject, jlong catId) { auto const categoryId = static_cast(catId); @@ -344,20 +344,20 @@ Java_app_organicmaps_bookmarks_data_BookmarkManager_nativeDeleteCategory( } JNIEXPORT void JNICALL -Java_app_organicmaps_bookmarks_data_BookmarkManager_nativeDeleteBookmark(JNIEnv *, jobject, jlong bmkId) +Java_com_mapswithme_maps_bookmarks_data_BookmarkManager_nativeDeleteBookmark(JNIEnv *, jobject, jlong bmkId) { frm()->GetBookmarkManager().GetEditSession().DeleteBookmark(static_cast(bmkId)); } JNIEXPORT void JNICALL -Java_app_organicmaps_bookmarks_data_BookmarkManager_nativeDeleteTrack( +Java_com_mapswithme_maps_bookmarks_data_BookmarkManager_nativeDeleteTrack( JNIEnv *, jobject, jlong trkId) { frm()->GetBookmarkManager().GetEditSession().DeleteTrack(static_cast(trkId)); } JNIEXPORT jobject JNICALL -Java_app_organicmaps_bookmarks_data_BookmarkManager_nativeAddBookmarkToLastEditedCategory( +Java_com_mapswithme_maps_bookmarks_data_BookmarkManager_nativeAddBookmarkToLastEditedCategory( JNIEnv * env, jobject, double lat, double lon) { if (!frm()->HasPlacePageInfo()) @@ -388,48 +388,48 @@ Java_app_organicmaps_bookmarks_data_BookmarkManager_nativeAddBookmarkToLastEdite } JNIEXPORT jlong JNICALL -Java_app_organicmaps_bookmarks_data_BookmarkManager_nativeGetLastEditedCategory( +Java_com_mapswithme_maps_bookmarks_data_BookmarkManager_nativeGetLastEditedCategory( JNIEnv *, jobject) { return static_cast(frm()->LastEditedBMCategory()); } JNIEXPORT jint JNICALL -Java_app_organicmaps_bookmarks_data_BookmarkManager_nativeGetLastEditedColor( +Java_com_mapswithme_maps_bookmarks_data_BookmarkManager_nativeGetLastEditedColor( JNIEnv *, jobject) { return static_cast(frm()->LastEditedBMColor()); } JNIEXPORT void JNICALL -Java_app_organicmaps_bookmarks_data_BookmarkManager_nativeLoadBookmarksFile(JNIEnv * env, jclass, +Java_com_mapswithme_maps_bookmarks_data_BookmarkManager_nativeLoadBookmarksFile(JNIEnv * env, jclass, jstring path, jboolean isTemporaryFile) { frm()->AddBookmarksFile(ToNativeString(env, path), isTemporaryFile); } JNIEXPORT jboolean JNICALL -Java_app_organicmaps_bookmarks_data_BookmarkManager_nativeIsAsyncBookmarksLoadingInProgress(JNIEnv *, jclass) +Java_com_mapswithme_maps_bookmarks_data_BookmarkManager_nativeIsAsyncBookmarksLoadingInProgress(JNIEnv *, jclass) { return static_cast(frm()->GetBookmarkManager().IsAsyncLoadingInProgress()); } JNIEXPORT jboolean JNICALL -Java_app_organicmaps_bookmarks_data_BookmarkManager_nativeIsVisible( +Java_com_mapswithme_maps_bookmarks_data_BookmarkManager_nativeIsVisible( JNIEnv *, jobject, jlong catId) { return static_cast(frm()->GetBookmarkManager().IsVisible(static_cast(catId))); } JNIEXPORT void JNICALL -Java_app_organicmaps_bookmarks_data_BookmarkManager_nativeSetVisibility( +Java_com_mapswithme_maps_bookmarks_data_BookmarkManager_nativeSetVisibility( JNIEnv *, jobject, jlong catId, jboolean isVisible) { frm()->GetBookmarkManager().GetEditSession().SetIsVisible(static_cast(catId), isVisible); } JNIEXPORT void JNICALL -Java_app_organicmaps_bookmarks_data_BookmarkManager_nativeSetCategoryName( +Java_com_mapswithme_maps_bookmarks_data_BookmarkManager_nativeSetCategoryName( JNIEnv * env, jobject, jlong catId, jstring name) { frm()->GetBookmarkManager().GetEditSession().SetCategoryName(static_cast(catId), @@ -437,7 +437,7 @@ Java_app_organicmaps_bookmarks_data_BookmarkManager_nativeSetCategoryName( } JNIEXPORT void JNICALL -Java_app_organicmaps_bookmarks_data_BookmarkManager_nativeSetCategoryDescription(JNIEnv * env, +Java_com_mapswithme_maps_bookmarks_data_BookmarkManager_nativeSetCategoryDescription(JNIEnv * env, jobject, jlong catId, jstring desc) @@ -447,7 +447,7 @@ Java_app_organicmaps_bookmarks_data_BookmarkManager_nativeSetCategoryDescription } JNIEXPORT void JNICALL -Java_app_organicmaps_bookmarks_data_BookmarkManager_nativeSetCategoryTags( +Java_com_mapswithme_maps_bookmarks_data_BookmarkManager_nativeSetCategoryTags( JNIEnv * env, jobject, jlong catId, jobjectArray tagsIds) { auto const size = env->GetArrayLength(tagsIds); @@ -464,7 +464,7 @@ Java_app_organicmaps_bookmarks_data_BookmarkManager_nativeSetCategoryTags( } JNIEXPORT void JNICALL -Java_app_organicmaps_bookmarks_data_BookmarkManager_nativeSetCategoryAccessRules( +Java_com_mapswithme_maps_bookmarks_data_BookmarkManager_nativeSetCategoryAccessRules( JNIEnv *, jobject, jlong catId, jint accessRules) { frm()->GetBookmarkManager().GetEditSession().SetCategoryAccessRules( @@ -472,7 +472,7 @@ Java_app_organicmaps_bookmarks_data_BookmarkManager_nativeSetCategoryAccessRules } JNIEXPORT void JNICALL -Java_app_organicmaps_bookmarks_data_BookmarkManager_nativeSetCategoryCustomProperty( +Java_com_mapswithme_maps_bookmarks_data_BookmarkManager_nativeSetCategoryCustomProperty( JNIEnv * env, jobject, jlong catId, jstring key, jstring value) { frm()->GetBookmarkManager().GetEditSession().SetCategoryCustomProperty( @@ -480,7 +480,7 @@ Java_app_organicmaps_bookmarks_data_BookmarkManager_nativeSetCategoryCustomPrope } JNIEXPORT jobject JNICALL -Java_app_organicmaps_bookmarks_data_BookmarkManager_nativeUpdateBookmarkPlacePage( +Java_com_mapswithme_maps_bookmarks_data_BookmarkManager_nativeUpdateBookmarkPlacePage( JNIEnv * env, jobject, jlong bmkId) { if (!frm()->HasPlacePageInfo()) @@ -495,7 +495,7 @@ Java_app_organicmaps_bookmarks_data_BookmarkManager_nativeUpdateBookmarkPlacePag } JNIEXPORT jobject JNICALL -Java_app_organicmaps_bookmarks_data_BookmarkManager_nativeGetBookmarkInfo( +Java_com_mapswithme_maps_bookmarks_data_BookmarkManager_nativeGetBookmarkInfo( JNIEnv * env, jobject, jlong bmkId) { auto const bookmark = frm()->GetBookmarkManager().GetBookmark(static_cast(bmkId)); @@ -507,7 +507,7 @@ Java_app_organicmaps_bookmarks_data_BookmarkManager_nativeGetBookmarkInfo( } JNIEXPORT jlong JNICALL -Java_app_organicmaps_bookmarks_data_BookmarkManager_nativeGetBookmarkIdByPosition( +Java_com_mapswithme_maps_bookmarks_data_BookmarkManager_nativeGetBookmarkIdByPosition( JNIEnv *, jobject, jlong catId, jint positionInCategory) { auto const & ids = frm()->GetBookmarkManager().GetUserMarkIds(static_cast(catId)); @@ -521,7 +521,7 @@ Java_app_organicmaps_bookmarks_data_BookmarkManager_nativeGetBookmarkIdByPositio static uint32_t shift(uint32_t v, uint8_t bitCount) { return v << bitCount; } JNIEXPORT jobject JNICALL -Java_app_organicmaps_bookmarks_data_BookmarkManager_nativeGetTrack( +Java_com_mapswithme_maps_bookmarks_data_BookmarkManager_nativeGetTrack( JNIEnv * env, jobject, jlong trackId, jclass trackClazz) { // Track(long trackId, long categoryId, String name, String lengthString, int color) @@ -548,7 +548,7 @@ Java_app_organicmaps_bookmarks_data_BookmarkManager_nativeGetTrack( } JNIEXPORT jlong JNICALL -Java_app_organicmaps_bookmarks_data_BookmarkManager_nativeGetTrackIdByPosition( +Java_com_mapswithme_maps_bookmarks_data_BookmarkManager_nativeGetTrackIdByPosition( JNIEnv *, jobject, jlong catId, jint positionInCategory) { auto const & ids = frm()->GetBookmarkManager().GetTrackIds(static_cast(catId)); @@ -560,49 +560,49 @@ Java_app_organicmaps_bookmarks_data_BookmarkManager_nativeGetTrackIdByPosition( } JNIEXPORT jboolean JNICALL -Java_app_organicmaps_bookmarks_data_BookmarkManager_nativeIsUsedCategoryName( +Java_com_mapswithme_maps_bookmarks_data_BookmarkManager_nativeIsUsedCategoryName( JNIEnv * env, jclass, jstring name) { return static_cast(frm()->GetBookmarkManager().IsUsedCategoryName(ToNativeString(env, name))); } JNIEXPORT jboolean JNICALL -Java_app_organicmaps_bookmarks_data_BookmarkManager_nativeIsSearchAllowed( +Java_com_mapswithme_maps_bookmarks_data_BookmarkManager_nativeIsSearchAllowed( JNIEnv *, jclass, jlong catId) { return static_cast(frm()->GetBookmarkManager().IsSearchAllowed(static_cast(catId))); } JNIEXPORT void JNICALL -Java_app_organicmaps_bookmarks_data_BookmarkManager_nativePrepareForSearch( +Java_com_mapswithme_maps_bookmarks_data_BookmarkManager_nativePrepareForSearch( JNIEnv *, jclass, jlong catId) { frm()->GetBookmarkManager().PrepareForSearch(static_cast(catId)); } JNIEXPORT jboolean JNICALL -Java_app_organicmaps_bookmarks_data_BookmarkManager_nativeAreAllCategoriesInvisible( +Java_com_mapswithme_maps_bookmarks_data_BookmarkManager_nativeAreAllCategoriesInvisible( JNIEnv *, jclass) { return static_cast(frm()->GetBookmarkManager().AreAllCategoriesInvisible()); } JNIEXPORT jboolean JNICALL -Java_app_organicmaps_bookmarks_data_BookmarkManager_nativeAreAllCategoriesVisible( +Java_com_mapswithme_maps_bookmarks_data_BookmarkManager_nativeAreAllCategoriesVisible( JNIEnv *, jclass) { return static_cast(frm()->GetBookmarkManager().AreAllCategoriesVisible()); } JNIEXPORT void JNICALL -Java_app_organicmaps_bookmarks_data_BookmarkManager_nativeSetAllCategoriesVisibility( +Java_com_mapswithme_maps_bookmarks_data_BookmarkManager_nativeSetAllCategoriesVisibility( JNIEnv *, jclass, jboolean visible) { frm()->GetBookmarkManager().SetAllCategoriesVisibility(static_cast(visible)); } JNIEXPORT void JNICALL -Java_app_organicmaps_bookmarks_data_BookmarkManager_nativePrepareFileForSharing( +Java_com_mapswithme_maps_bookmarks_data_BookmarkManager_nativePrepareFileForSharing( JNIEnv * env, jclass, jlong catId) { frm()->GetBookmarkManager().PrepareFileForSharing(static_cast(catId), @@ -613,7 +613,7 @@ Java_app_organicmaps_bookmarks_data_BookmarkManager_nativePrepareFileForSharing( } JNIEXPORT jboolean JNICALL -Java_app_organicmaps_bookmarks_data_BookmarkManager_nativeIsCategoryEmpty( +Java_com_mapswithme_maps_bookmarks_data_BookmarkManager_nativeIsCategoryEmpty( JNIEnv *, jclass, jlong catId) { return static_cast(frm()->GetBookmarkManager().IsCategoryEmpty( @@ -621,21 +621,21 @@ Java_app_organicmaps_bookmarks_data_BookmarkManager_nativeIsCategoryEmpty( } JNIEXPORT void JNICALL -Java_app_organicmaps_bookmarks_data_BookmarkManager_nativeSetNotificationsEnabled( +Java_com_mapswithme_maps_bookmarks_data_BookmarkManager_nativeSetNotificationsEnabled( JNIEnv *, jclass, jboolean enabled) { frm()->GetBookmarkManager().SetNotificationsEnabled(static_cast(enabled)); } JNIEXPORT jboolean JNICALL -Java_app_organicmaps_bookmarks_data_BookmarkManager_nativeAreNotificationsEnabled( +Java_com_mapswithme_maps_bookmarks_data_BookmarkManager_nativeAreNotificationsEnabled( JNIEnv *, jclass) { return static_cast(frm()->GetBookmarkManager().AreNotificationsEnabled()); } JNIEXPORT jobject JNICALL -Java_app_organicmaps_bookmarks_data_BookmarkManager_nativeGetBookmarkCategory(JNIEnv *env, +Java_com_mapswithme_maps_bookmarks_data_BookmarkManager_nativeGetBookmarkCategory(JNIEnv *env, jobject, jlong id) { @@ -643,7 +643,7 @@ Java_app_organicmaps_bookmarks_data_BookmarkManager_nativeGetBookmarkCategory(JN } JNIEXPORT jobjectArray JNICALL -Java_app_organicmaps_bookmarks_data_BookmarkManager_nativeGetBookmarkCategories(JNIEnv *env, +Java_com_mapswithme_maps_bookmarks_data_BookmarkManager_nativeGetBookmarkCategories(JNIEnv *env, jobject) { auto const & bm = frm()->GetBookmarkManager(); @@ -653,7 +653,7 @@ Java_app_organicmaps_bookmarks_data_BookmarkManager_nativeGetBookmarkCategories( } JNIEXPORT jobjectArray JNICALL -Java_app_organicmaps_bookmarks_data_BookmarkManager_nativeGetChildrenCategories(JNIEnv *env, +Java_com_mapswithme_maps_bookmarks_data_BookmarkManager_nativeGetChildrenCategories(JNIEnv *env, jobject, jlong parentId) { @@ -664,7 +664,7 @@ Java_app_organicmaps_bookmarks_data_BookmarkManager_nativeGetChildrenCategories( } JNIEXPORT jboolean JNICALL -Java_app_organicmaps_bookmarks_data_BookmarkManager_nativeHasLastSortingType( +Java_com_mapswithme_maps_bookmarks_data_BookmarkManager_nativeHasLastSortingType( JNIEnv *, jobject, jlong catId) { auto const & bm = frm()->GetBookmarkManager(); @@ -673,7 +673,7 @@ Java_app_organicmaps_bookmarks_data_BookmarkManager_nativeHasLastSortingType( } JNIEXPORT jint JNICALL -Java_app_organicmaps_bookmarks_data_BookmarkManager_nativeGetLastSortingType( +Java_com_mapswithme_maps_bookmarks_data_BookmarkManager_nativeGetLastSortingType( JNIEnv *, jobject, jlong catId) { auto const & bm = frm()->GetBookmarkManager(); @@ -685,7 +685,7 @@ Java_app_organicmaps_bookmarks_data_BookmarkManager_nativeGetLastSortingType( } JNIEXPORT void JNICALL -Java_app_organicmaps_bookmarks_data_BookmarkManager_nativeSetLastSortingType( +Java_com_mapswithme_maps_bookmarks_data_BookmarkManager_nativeSetLastSortingType( JNIEnv *, jobject, jlong catId, jint type) { auto & bm = frm()->GetBookmarkManager(); @@ -694,7 +694,7 @@ Java_app_organicmaps_bookmarks_data_BookmarkManager_nativeSetLastSortingType( } JNIEXPORT void JNICALL -Java_app_organicmaps_bookmarks_data_BookmarkManager_nativeResetLastSortingType( +Java_com_mapswithme_maps_bookmarks_data_BookmarkManager_nativeResetLastSortingType( JNIEnv *, jobject, jlong catId) { auto & bm = frm()->GetBookmarkManager(); @@ -702,7 +702,7 @@ Java_app_organicmaps_bookmarks_data_BookmarkManager_nativeResetLastSortingType( } JNIEXPORT jintArray JNICALL -Java_app_organicmaps_bookmarks_data_BookmarkManager_nativeGetAvailableSortingTypes(JNIEnv *env, +Java_com_mapswithme_maps_bookmarks_data_BookmarkManager_nativeGetAvailableSortingTypes(JNIEnv *env, jobject, jlong catId, jboolean hasMyPosition) { auto const & bm = frm()->GetBookmarkManager(); @@ -719,7 +719,7 @@ Java_app_organicmaps_bookmarks_data_BookmarkManager_nativeGetAvailableSortingTyp } JNIEXPORT void JNICALL -Java_app_organicmaps_bookmarks_data_BookmarkManager_nativeGetSortedCategory(JNIEnv *env, +Java_com_mapswithme_maps_bookmarks_data_BookmarkManager_nativeGetSortedCategory(JNIEnv *env, jobject, jlong catId, jint sortingType, jboolean hasMyPosition, jdouble lat, jdouble lon, jlong timestamp) { @@ -736,14 +736,14 @@ Java_app_organicmaps_bookmarks_data_BookmarkManager_nativeGetSortedCategory(JNIE } JNIEXPORT jstring JNICALL -Java_app_organicmaps_bookmarks_data_BookmarkManager_nativeGetBookmarkName( +Java_com_mapswithme_maps_bookmarks_data_BookmarkManager_nativeGetBookmarkName( JNIEnv * env, jclass, jlong bmk) { return jni::ToJavaString(env, getBookmark(bmk)->GetPreferredName()); } JNIEXPORT jstring JNICALL -Java_app_organicmaps_bookmarks_data_BookmarkManager_nativeGetBookmarkFeatureType( +Java_com_mapswithme_maps_bookmarks_data_BookmarkManager_nativeGetBookmarkFeatureType( JNIEnv * env, jclass, jlong bmk) { return jni::ToJavaString(env, @@ -751,14 +751,14 @@ Java_app_organicmaps_bookmarks_data_BookmarkManager_nativeGetBookmarkFeatureType } JNIEXPORT jstring JNICALL -Java_app_organicmaps_bookmarks_data_BookmarkManager_nativeGetBookmarkDescription( +Java_com_mapswithme_maps_bookmarks_data_BookmarkManager_nativeGetBookmarkDescription( JNIEnv * env, jclass, jlong bmk) { return jni::ToJavaString(env, getBookmark(bmk)->GetDescription()); } JNIEXPORT jint JNICALL -Java_app_organicmaps_bookmarks_data_BookmarkManager_nativeGetBookmarkColor( +Java_com_mapswithme_maps_bookmarks_data_BookmarkManager_nativeGetBookmarkColor( JNIEnv *, jclass, jlong bmk) { auto const * mark = getBookmark(bmk); @@ -767,7 +767,7 @@ Java_app_organicmaps_bookmarks_data_BookmarkManager_nativeGetBookmarkColor( } JNIEXPORT jint JNICALL -Java_app_organicmaps_bookmarks_data_BookmarkManager_nativeGetBookmarkIcon( +Java_com_mapswithme_maps_bookmarks_data_BookmarkManager_nativeGetBookmarkIcon( JNIEnv *, jclass, jlong bmk) { auto const * mark = getBookmark(bmk); @@ -776,7 +776,7 @@ Java_app_organicmaps_bookmarks_data_BookmarkManager_nativeGetBookmarkIcon( } JNIEXPORT void JNICALL -Java_app_organicmaps_bookmarks_data_BookmarkManager_nativeSetBookmarkParams( +Java_com_mapswithme_maps_bookmarks_data_BookmarkManager_nativeSetBookmarkParams( JNIEnv * env, jclass, jlong bmk, jstring name, jint color, jstring descr) { @@ -795,7 +795,7 @@ Java_app_organicmaps_bookmarks_data_BookmarkManager_nativeSetBookmarkParams( } JNIEXPORT void JNICALL -Java_app_organicmaps_bookmarks_data_BookmarkManager_nativeChangeBookmarkCategory( +Java_com_mapswithme_maps_bookmarks_data_BookmarkManager_nativeChangeBookmarkCategory( JNIEnv *, jclass, jlong oldCat, jlong newCat, jlong bmk) { g_framework->MoveBookmark(static_cast(bmk), static_cast(oldCat), @@ -803,28 +803,28 @@ Java_app_organicmaps_bookmarks_data_BookmarkManager_nativeChangeBookmarkCategory } JNIEXPORT jobject JNICALL -Java_app_organicmaps_bookmarks_data_BookmarkManager_nativeGetBookmarkXY( +Java_com_mapswithme_maps_bookmarks_data_BookmarkManager_nativeGetBookmarkXY( JNIEnv * env, jclass, jlong bmk) { return jni::GetNewParcelablePointD(env, getBookmark(bmk)->GetPivot()); } JNIEXPORT jdouble JNICALL -Java_app_organicmaps_bookmarks_data_BookmarkManager_nativeGetBookmarkScale( +Java_com_mapswithme_maps_bookmarks_data_BookmarkManager_nativeGetBookmarkScale( JNIEnv *, jclass, jlong bmk) { return getBookmark(bmk)->GetScale(); } JNIEXPORT jstring JNICALL -Java_app_organicmaps_bookmarks_data_BookmarkManager_nativeEncode2Ge0Url( +Java_com_mapswithme_maps_bookmarks_data_BookmarkManager_nativeEncode2Ge0Url( JNIEnv * env, jclass, jlong bmk, jboolean addName) { return jni::ToJavaString(env, frm()->CodeGe0url(getBookmark(bmk), addName)); } JNIEXPORT jstring JNICALL -Java_app_organicmaps_bookmarks_data_BookmarkManager_nativeGetBookmarkAddress( +Java_com_mapswithme_maps_bookmarks_data_BookmarkManager_nativeGetBookmarkAddress( JNIEnv * env, jclass, jlong bmkId) { auto const address = frm()->GetAddressAtPoint(getBookmark(bmkId)->GetPivot()).FormatAddress(); @@ -832,7 +832,7 @@ Java_app_organicmaps_bookmarks_data_BookmarkManager_nativeGetBookmarkAddress( } JNIEXPORT jdouble JNICALL -Java_app_organicmaps_bookmarks_data_BookmarkManager_nativeGetElevationCurPositionDistance( +Java_com_mapswithme_maps_bookmarks_data_BookmarkManager_nativeGetElevationCurPositionDistance( JNIEnv *, jclass, jlong trackId) { auto const & bm = frm()->GetBookmarkManager(); @@ -840,7 +840,7 @@ Java_app_organicmaps_bookmarks_data_BookmarkManager_nativeGetElevationCurPositio } JNIEXPORT void JNICALL -Java_app_organicmaps_bookmarks_data_BookmarkManager_nativeSetElevationCurrentPositionChangedListener( +Java_com_mapswithme_maps_bookmarks_data_BookmarkManager_nativeSetElevationCurrentPositionChangedListener( JNIEnv * env, jclass) { frm()->GetBookmarkManager().SetElevationMyPositionChangedCallback( @@ -848,14 +848,14 @@ Java_app_organicmaps_bookmarks_data_BookmarkManager_nativeSetElevationCurrentPos } JNIEXPORT void JNICALL -Java_app_organicmaps_bookmarks_data_BookmarkManager_nativeRemoveElevationCurrentPositionChangedListener( +Java_com_mapswithme_maps_bookmarks_data_BookmarkManager_nativeRemoveElevationCurrentPositionChangedListener( JNIEnv *, jclass) { frm()->GetBookmarkManager().SetElevationMyPositionChangedCallback(nullptr); } JNIEXPORT void JNICALL -Java_app_organicmaps_bookmarks_data_BookmarkManager_nativeSetElevationActivePoint( +Java_com_mapswithme_maps_bookmarks_data_BookmarkManager_nativeSetElevationActivePoint( JNIEnv *, jclass, jlong trackId, jdouble distanceInMeters) { auto & bm = frm()->GetBookmarkManager(); @@ -864,7 +864,7 @@ Java_app_organicmaps_bookmarks_data_BookmarkManager_nativeSetElevationActivePoin } JNIEXPORT jdouble JNICALL -Java_app_organicmaps_bookmarks_data_BookmarkManager_nativeGetElevationActivePointDistance( +Java_com_mapswithme_maps_bookmarks_data_BookmarkManager_nativeGetElevationActivePointDistance( JNIEnv *, jclass, jlong trackId) { auto & bm = frm()->GetBookmarkManager(); @@ -872,14 +872,14 @@ Java_app_organicmaps_bookmarks_data_BookmarkManager_nativeGetElevationActivePoin } JNIEXPORT void JNICALL -Java_app_organicmaps_bookmarks_data_BookmarkManager_nativeSetElevationActiveChangedListener( +Java_com_mapswithme_maps_bookmarks_data_BookmarkManager_nativeSetElevationActiveChangedListener( JNIEnv *env, jclass) { frm()->GetBookmarkManager().SetElevationActivePointChangedCallback(std::bind(&OnElevationActivePointChanged, env)); } JNIEXPORT void JNICALL -Java_app_organicmaps_bookmarks_data_BookmarkManager_nativeRemoveElevationActiveChangedListener( +Java_com_mapswithme_maps_bookmarks_data_BookmarkManager_nativeRemoveElevationActiveChangedListener( JNIEnv *, jclass) { frm()->GetBookmarkManager().SetElevationActivePointChangedCallback(nullptr); diff --git a/android/jni/com/mapswithme/maps/editor/Editor.cpp b/android/jni/com/mapswithme/maps/editor/Editor.cpp new file mode 100644 index 0000000000..26dd1af967 --- /dev/null +++ b/android/jni/com/mapswithme/maps/editor/Editor.cpp @@ -0,0 +1,525 @@ +#include + +#include "com/mapswithme/core/jni_helper.hpp" +#include "com/mapswithme/maps/Framework.hpp" + +#include "editor/osm_editor.hpp" + +#include "indexer/cuisines.hpp" +#include "indexer/editable_map_object.hpp" +#include "indexer/validate_and_format_contacts.hpp" + +#include "coding/string_utf8_multilang.hpp" + +#include "base/assert.hpp" +#include "base/logging.hpp" +#include "base/string_utils.hpp" + +#include "std/target_os.hpp" + +#include +#include +#include + +namespace +{ +using TCuisine = std::pair; +osm::EditableMapObject g_editableMapObject; + +jclass g_localNameClazz; +jmethodID g_localNameCtor; +jfieldID g_localNameFieldCode; +jfieldID g_localNameFieldName; +jclass g_localStreetClazz; +jmethodID g_localStreetCtor; +jfieldID g_localStreetFieldDef; +jfieldID g_localStreetFieldLoc; +jclass g_namesDataSourceClassID; +jmethodID g_namesDataSourceConstructorID; + +jobject ToJavaName(JNIEnv * env, osm::LocalizedName const & name) +{ + jni::TScopedLocalRef jName(env, jni::ToJavaString(env, name.m_name)); + jni::TScopedLocalRef jLang(env, jni::ToJavaString(env, name.m_lang)); + jni::TScopedLocalRef jLangName(env, jni::ToJavaString(env, name.m_langName)); + return env->NewObject(g_localNameClazz, g_localNameCtor, name.m_code, + jName.get(), jLang.get(), jLangName.get()); +} + +jobject ToJavaStreet(JNIEnv * env, osm::LocalizedStreet const & street) +{ + return env->NewObject(g_localStreetClazz, g_localStreetCtor, + jni::TScopedLocalRef(env, jni::ToJavaString(env, street.m_defaultName)).get(), + jni::TScopedLocalRef(env, jni::ToJavaString(env, street.m_localizedName)).get()); +} + +osm::NewFeatureCategories & GetFeatureCategories() +{ + static osm::NewFeatureCategories categories = g_framework->NativeFramework()->GetEditorCategories(); + return categories; +} +} // namespace + +extern "C" +{ +using osm::Editor; + +JNIEXPORT void JNICALL +Java_com_mapswithme_maps_editor_Editor_nativeInit(JNIEnv * env, jclass) +{ + g_localNameClazz = jni::GetGlobalClassRef(env, "com/mapswithme/maps/editor/data/LocalizedName"); + // LocalizedName(int code, @NonNull String name, @NonNull String lang, @NonNull String langName) + g_localNameCtor = jni::GetConstructorID(env, g_localNameClazz, "(ILjava/lang/String;Ljava/lang/String;Ljava/lang/String;)V"); + g_localNameFieldCode = env->GetFieldID(g_localNameClazz, "code", "I"); + g_localNameFieldName = env->GetFieldID(g_localNameClazz, "name", "Ljava/lang/String;"); + + g_localStreetClazz = jni::GetGlobalClassRef(env, "com/mapswithme/maps/editor/data/LocalizedStreet"); + // LocalizedStreet(@NonNull String defaultName, @NonNull String localizedName) + g_localStreetCtor = jni::GetConstructorID(env, g_localStreetClazz, "(Ljava/lang/String;Ljava/lang/String;)V"); + g_localStreetFieldDef = env->GetFieldID(g_localStreetClazz, "defaultName", "Ljava/lang/String;"); + g_localStreetFieldLoc = env->GetFieldID(g_localStreetClazz, "localizedName", "Ljava/lang/String;"); + + g_namesDataSourceClassID = jni::GetGlobalClassRef(env, "com/mapswithme/maps/editor/data/NamesDataSource"); + g_namesDataSourceConstructorID = jni::GetConstructorID(env, g_namesDataSourceClassID, "([Lcom/mapswithme/maps/editor/data/LocalizedName;I)V"); +} + +JNIEXPORT jstring JNICALL +Java_com_mapswithme_maps_editor_Editor_nativeGetOpeningHours(JNIEnv * env, jclass) +{ + return jni::ToJavaString(env, g_editableMapObject.GetOpeningHours()); +} + +JNIEXPORT void JNICALL +Java_com_mapswithme_maps_editor_Editor_nativeSetOpeningHours(JNIEnv * env, jclass, jstring value) +{ + g_editableMapObject.SetOpeningHours(jni::ToNativeString(env, value)); +} + +JNIEXPORT jstring JNICALL +Java_com_mapswithme_maps_editor_Editor_nativeGetMetadata(JNIEnv * env, jclass, jint id) +{ + auto const metaID = static_cast(id); + ASSERT_LESS(metaID, osm::MapObject::MetadataID::FMD_COUNT, ()); + return jni::ToJavaString(env, g_editableMapObject.GetMetadata(metaID)); +} + +JNIEXPORT jboolean JNICALL +Java_com_mapswithme_maps_editor_Editor_nativeIsMetadataValid(JNIEnv * env, jclass, jint id, jstring value) +{ + auto const metaID = static_cast(id); + ASSERT_LESS(metaID, osm::MapObject::MetadataID::FMD_COUNT, ()); + return osm::EditableMapObject::IsValidMetadata(metaID, jni::ToNativeString(env, value)); +} + +JNIEXPORT void JNICALL +Java_com_mapswithme_maps_editor_Editor_nativeSetMetadata(JNIEnv * env, jclass, jint id, jstring value) +{ + auto const metaID = static_cast(id); + ASSERT_LESS(metaID, osm::MapObject::MetadataID::FMD_COUNT, ()); + g_editableMapObject.SetMetadata(metaID, jni::ToNativeString(env, value)); +} + +JNIEXPORT jint JNICALL +Java_com_mapswithme_maps_editor_Editor_nativeGetStars(JNIEnv * env, jclass) +{ + return g_editableMapObject.GetStars(); +} + +JNIEXPORT jboolean JNICALL +Java_com_mapswithme_maps_editor_Editor_nativeHasWifi(JNIEnv *, jclass) +{ + return g_editableMapObject.GetInternet() == osm::Internet::Wlan; +} + +JNIEXPORT void JNICALL +Java_com_mapswithme_maps_editor_Editor_nativeSetHasWifi(JNIEnv *, jclass, jboolean hasWifi) +{ + g_editableMapObject.SetInternet(hasWifi ? osm::Internet::Wlan : osm::Internet::Unknown); +} + +JNIEXPORT jboolean JNICALL +Java_com_mapswithme_maps_editor_Editor_nativeSaveEditedFeature(JNIEnv *, jclass) +{ + switch (g_framework->NativeFramework()->SaveEditedMapObject(g_editableMapObject)) + { + case osm::Editor::SaveResult::NothingWasChanged: + case osm::Editor::SaveResult::SavedSuccessfully: + return true; + case osm::Editor::SaveResult::NoFreeSpaceError: + case osm::Editor::SaveResult::NoUnderlyingMapError: + case osm::Editor::SaveResult::SavingError: + return false; + } +} + +JNIEXPORT jboolean JNICALL +Java_com_mapswithme_maps_editor_Editor_nativeShouldShowEditPlace(JNIEnv *, jclass) +{ + ::Framework * frm = g_framework->NativeFramework(); + if (!frm->HasPlacePageInfo()) + return static_cast(false); + + return g_framework->GetPlacePageInfo().ShouldShowEditPlace(); +} + +JNIEXPORT jboolean JNICALL +Java_com_mapswithme_maps_editor_Editor_nativeShouldShowAddPlace(JNIEnv *, jclass) +{ + ::Framework * frm = g_framework->NativeFramework(); + if (!frm->HasPlacePageInfo()) + return static_cast(false); + + return g_framework->GetPlacePageInfo().ShouldShowAddPlace(); +} + +JNIEXPORT jboolean JNICALL +Java_com_mapswithme_maps_editor_Editor_nativeShouldShowAddBusiness(JNIEnv *, jclass) +{ + ::Framework * frm = g_framework->NativeFramework(); + if (!frm->HasPlacePageInfo()) + return static_cast(false); + + return g_framework->GetPlacePageInfo().ShouldShowAddBusiness(); +} + +JNIEXPORT jintArray JNICALL +Java_com_mapswithme_maps_editor_Editor_nativeGetEditableProperties(JNIEnv * env, jclass clazz) +{ + auto const & editable = g_editableMapObject.GetEditableProperties(); + size_t const size = editable.size(); + jintArray jEditableFields = env->NewIntArray(static_cast(size)); + jint * arr = env->GetIntArrayElements(jEditableFields, 0); + for (size_t i = 0; i < size; ++i) + arr[i] = base::Underlying(editable[i]); + env->ReleaseIntArrayElements(jEditableFields, arr, 0); + + return jEditableFields; +} + +JNIEXPORT jboolean JNICALL +Java_com_mapswithme_maps_editor_Editor_nativeIsAddressEditable(JNIEnv * env, jclass clazz) +{ + return g_editableMapObject.IsAddressEditable(); +} + +JNIEXPORT jboolean JNICALL +Java_com_mapswithme_maps_editor_Editor_nativeIsNameEditable(JNIEnv * env, jclass clazz) +{ + return g_editableMapObject.IsNameEditable(); +} + +JNIEXPORT jboolean JNICALL +Java_com_mapswithme_maps_editor_Editor_nativeIsPointType(JNIEnv * env, jclass clazz) +{ + return g_editableMapObject.IsPointType(); +} + +JNIEXPORT jboolean JNICALL +Java_com_mapswithme_maps_editor_Editor_nativeIsBuilding(JNIEnv * env, jclass clazz) +{ + return g_editableMapObject.IsBuilding(); +} + +JNIEXPORT jobject JNICALL +Java_com_mapswithme_maps_editor_Editor_nativeGetNamesDataSource(JNIEnv * env, jclass, jboolean needFakes) +{ + auto const namesDataSource = g_editableMapObject.GetNamesDataSource(needFakes); + + jobjectArray names = jni::ToJavaArray(env, g_localNameClazz, namesDataSource.names, ToJavaName); + jsize const mandatoryNamesCount = static_cast(namesDataSource.mandatoryNamesCount); + + return env->NewObject(g_namesDataSourceClassID, g_namesDataSourceConstructorID, names, mandatoryNamesCount); +} + +JNIEXPORT jstring JNICALL +Java_com_mapswithme_maps_editor_Editor_nativeGetDefaultName(JNIEnv * env, jclass) +{ + return jni::ToJavaString(env, g_editableMapObject.GetDefaultName()); +} + +JNIEXPORT void JNICALL +Java_com_mapswithme_maps_editor_Editor_nativeEnableNamesAdvancedMode(JNIEnv *, jclass) +{ + g_editableMapObject.EnableNamesAdvancedMode(); +} + +JNIEXPORT void JNICALL +Java_com_mapswithme_maps_editor_Editor_nativeSetNames(JNIEnv * env, jclass, jobjectArray names) +{ + int const length = env->GetArrayLength(names); + for (int i = 0; i < length; i++) + { + auto jName = env->GetObjectArrayElement(names, i); + g_editableMapObject.SetName(jni::ToNativeString(env, static_cast(env->GetObjectField(jName, g_localNameFieldName))), + env->GetIntField(jName, g_localNameFieldCode)); + } +} + +JNIEXPORT jobject JNICALL +Java_com_mapswithme_maps_editor_Editor_nativeGetStreet(JNIEnv * env, jclass) +{ + return ToJavaStreet(env, g_editableMapObject.GetStreet()); +} + +JNIEXPORT void JNICALL +Java_com_mapswithme_maps_editor_Editor_nativeSetStreet(JNIEnv * env, jclass, jobject street) +{ + g_editableMapObject.SetStreet({jni::ToNativeString(env, (jstring) env->GetObjectField(street, g_localStreetFieldDef)), + jni::ToNativeString(env, (jstring) env->GetObjectField(street, g_localStreetFieldLoc))}); +} +JNIEXPORT jobjectArray JNICALL +Java_com_mapswithme_maps_editor_Editor_nativeGetNearbyStreets(JNIEnv * env, jclass clazz) +{ + return jni::ToJavaArray(env, g_localStreetClazz, g_editableMapObject.GetNearbyStreets(), ToJavaStreet); +} + +JNIEXPORT jobjectArray JNICALL +Java_com_mapswithme_maps_editor_Editor_nativeGetSupportedLanguages(JNIEnv * env, jclass clazz) +{ + using TLang = StringUtf8Multilang::Lang; + //public Language(@NonNull String code, @NonNull String name) + static jclass const langClass = jni::GetGlobalClassRef(env, "com/mapswithme/maps/editor/data/Language"); + static jmethodID const langCtor = jni::GetConstructorID(env, langClass, "(Ljava/lang/String;Ljava/lang/String;)V"); + + return jni::ToJavaArray(env, langClass, StringUtf8Multilang::GetSupportedLanguages(), + [](JNIEnv * env, TLang const & lang) + { + jni::TScopedLocalRef const code(env, jni::ToJavaString(env, lang.m_code)); + jni::TScopedLocalRef const name(env, jni::ToJavaString(env, lang.m_name)); + return env->NewObject(langClass, langCtor, code.get(), name.get()); + }); +} + +JNIEXPORT jstring JNICALL +Java_com_mapswithme_maps_editor_Editor_nativeGetHouseNumber(JNIEnv * env, jclass) +{ + return jni::ToJavaString(env, g_editableMapObject.GetHouseNumber()); +} + +JNIEXPORT void JNICALL +Java_com_mapswithme_maps_editor_Editor_nativeSetHouseNumber(JNIEnv * env, jclass, jstring houseNumber) +{ + g_editableMapObject.SetHouseNumber(jni::ToNativeString(env, houseNumber)); +} + +JNIEXPORT jboolean JNICALL +Java_com_mapswithme_maps_editor_Editor_nativeHasSomethingToUpload(JNIEnv * env, jclass clazz) +{ + return Editor::Instance().HaveMapEditsOrNotesToUpload(); +} + +JNIEXPORT void JNICALL +Java_com_mapswithme_maps_editor_Editor_nativeUploadChanges(JNIEnv * env, jclass clazz, jstring token, jstring secret, + jstring appVersion, jstring appId) +{ + // TODO: Handle upload status in callback + Editor::Instance().UploadChanges(jni::ToNativeString(env, token), jni::ToNativeString(env, secret), + {{"created_by", "Organic Maps " OMIM_OS_NAME " " + jni::ToNativeString(env, appVersion)}, + {"bundle_id", jni::ToNativeString(env, appId)}}, nullptr); +} + +JNIEXPORT jlongArray JNICALL +Java_com_mapswithme_maps_editor_Editor_nativeGetStats(JNIEnv * env, jclass clazz) +{ + auto const stats = Editor::Instance().GetStats(); + jlongArray result = env->NewLongArray(3); + jlong buf[] = {static_cast(stats.m_edits.size()), static_cast(stats.m_uploadedCount), + stats.m_lastUploadTimestamp}; + env->SetLongArrayRegion(result, 0, 3, buf); + return result; +} + +JNIEXPORT void JNICALL +Java_com_mapswithme_maps_editor_Editor_nativeClearLocalEdits(JNIEnv * env, jclass clazz) +{ + Editor::Instance().ClearAllLocalEdits(); +} + +JNIEXPORT void JNICALL +Java_com_mapswithme_maps_editor_Editor_nativeStartEdit(JNIEnv *, jclass) +{ + ::Framework * frm = g_framework->NativeFramework(); + if (!frm->HasPlacePageInfo()) + return; + + place_page::Info const & info = g_framework->GetPlacePageInfo(); + CHECK(frm->GetEditableMapObject(info.GetID(), g_editableMapObject), ("Invalid feature in the place page.")); +} + +JNIEXPORT void JNICALL +Java_com_mapswithme_maps_editor_Editor_nativeCreateMapObject(JNIEnv * env, jclass, + jstring featureType) +{ + ::Framework * frm = g_framework->NativeFramework(); + auto const type = classif().GetTypeByReadableObjectName(jni::ToNativeString(env, featureType)); + CHECK(frm->CreateMapObject(frm->GetViewportCenter(), type, g_editableMapObject), + ("Couldn't create mapobject, wrong coordinates of missing mwm")); +} + +// static void nativeCreateNote(String text); +JNIEXPORT void JNICALL +Java_com_mapswithme_maps_editor_Editor_nativeCreateNote(JNIEnv * env, jclass clazz, jstring text) +{ + g_framework->NativeFramework()->CreateNote( + g_editableMapObject, osm::Editor::NoteProblemType::General, jni::ToNativeString(env, text)); +} + +// static void nativePlaceDoesNotExist(String comment); +JNIEXPORT void JNICALL +Java_com_mapswithme_maps_editor_Editor_nativePlaceDoesNotExist(JNIEnv * env, jclass clazz, jstring comment) +{ + g_framework->NativeFramework()->CreateNote(g_editableMapObject, + osm::Editor::NoteProblemType::PlaceDoesNotExist, + jni::ToNativeString(env, comment)); +} + +JNIEXPORT void JNICALL +Java_com_mapswithme_maps_editor_Editor_nativeRollbackMapObject(JNIEnv * env, jclass clazz) +{ + g_framework->NativeFramework()->RollBackChanges(g_editableMapObject.GetID()); +} + +JNIEXPORT jobjectArray JNICALL +Java_com_mapswithme_maps_editor_Editor_nativeGetAllCreatableFeatureTypes(JNIEnv * env, jclass clazz, + jstring jLang) +{ + std::string const & lang = jni::ToNativeString(env, jLang); + GetFeatureCategories().AddLanguage(lang); + return jni::ToJavaStringArray(env, GetFeatureCategories().GetAllCreatableTypeNames()); +} + +JNIEXPORT jobjectArray JNICALL +Java_com_mapswithme_maps_editor_Editor_nativeSearchCreatableFeatureTypes(JNIEnv * env, jclass clazz, + jstring query, + jstring jLang) +{ + std::string const & lang = jni::ToNativeString(env, jLang); + GetFeatureCategories().AddLanguage(lang); + return jni::ToJavaStringArray(env, + GetFeatureCategories().Search(jni::ToNativeString(env, query))); +} + +JNIEXPORT jobjectArray JNICALL +Java_com_mapswithme_maps_editor_Editor_nativeGetCuisines(JNIEnv * env, jclass clazz) +{ + osm::AllCuisines const & cuisines = osm::Cuisines::Instance().AllSupportedCuisines(); + std::vector keys; + keys.reserve(cuisines.size()); + for (TCuisine const & cuisine : cuisines) + keys.push_back(cuisine.first); + return jni::ToJavaStringArray(env, keys); +} + +JNIEXPORT jobjectArray JNICALL +Java_com_mapswithme_maps_editor_Editor_nativeGetSelectedCuisines(JNIEnv * env, jclass clazz) +{ + return jni::ToJavaStringArray(env, g_editableMapObject.GetCuisines()); +} + +JNIEXPORT jobjectArray JNICALL +Java_com_mapswithme_maps_editor_Editor_nativeFilterCuisinesKeys(JNIEnv * env, jclass thiz, jstring jSubstr) +{ + std::string const substr = jni::ToNativeString(env, jSubstr); + bool const noFilter = substr.length() == 0; + osm::AllCuisines const & cuisines = osm::Cuisines::Instance().AllSupportedCuisines(); + std::vector keys; + keys.reserve(cuisines.size()); + + for (TCuisine const & cuisine : cuisines) + { + std::string const & key = cuisine.first; + std::string const & label = cuisine.second; + if (noFilter || search::ContainsNormalized(key, substr) || search::ContainsNormalized(label, substr)) + keys.push_back(key); + } + + return jni::ToJavaStringArray(env, keys); +} + +JNIEXPORT jobjectArray JNICALL +Java_com_mapswithme_maps_editor_Editor_nativeTranslateCuisines(JNIEnv * env, jclass clazz, jobjectArray jKeys) +{ + int const length = env->GetArrayLength(jKeys); + auto const & cuisines = osm::Cuisines::Instance(); + std::vector translations; + translations.reserve(length); + for (int i = 0; i < length; i++) + { + std::string const key = jni::ToNativeString(env, static_cast(env->GetObjectArrayElement(jKeys, i))); + translations.push_back(cuisines.Translate(key)); + } + return jni::ToJavaStringArray(env, translations); +} + +JNIEXPORT void JNICALL +Java_com_mapswithme_maps_editor_Editor_nativeSetSelectedCuisines(JNIEnv * env, jclass clazz, jobjectArray jKeys) +{ + int const length = env->GetArrayLength(jKeys); + std::vector cuisines; + cuisines.reserve(length); + for (int i = 0; i < length; i++) + cuisines.push_back(jni::ToNativeString(env, static_cast(env->GetObjectArrayElement(jKeys, i)))); + g_editableMapObject.SetCuisines(cuisines); +} + +JNIEXPORT jstring JNICALL +Java_com_mapswithme_maps_editor_Editor_nativeGetFormattedCuisine(JNIEnv * env, jclass clazz) +{ + return jni::ToJavaString(env, g_editableMapObject.FormatCuisines()); +} + +JNIEXPORT jstring JNICALL +Java_com_mapswithme_maps_editor_Editor_nativeGetMwmName(JNIEnv * env, jclass clazz) +{ + return jni::ToJavaString(env, g_editableMapObject.GetID().GetMwmName()); +} + +JNIEXPORT jlong JNICALL +Java_com_mapswithme_maps_editor_Editor_nativeGetMwmVersion(JNIEnv * env, jclass clazz) +{ + return g_editableMapObject.GetID().GetMwmVersion(); +} + +// static boolean nativeIsHouseValid(String houseNumber); +JNIEXPORT jboolean JNICALL +Java_com_mapswithme_maps_editor_Editor_nativeIsHouseValid(JNIEnv * env, jclass clazz, jstring houseNumber) +{ + return osm::EditableMapObject::ValidateHouseNumber(jni::ToNativeString(env, houseNumber)); +} + +JNIEXPORT jboolean JNICALL +Java_com_mapswithme_maps_editor_Editor_nativeIsNameValid(JNIEnv * env, jclass clazz, jstring name) +{ + return osm::EditableMapObject::ValidateName(jni::ToNativeString(env, name)); +} + +JNIEXPORT jstring JNICALL +Java_com_mapswithme_maps_editor_Editor_nativeGetCategory(JNIEnv * env, jclass clazz) +{ + auto types = g_editableMapObject.GetTypes(); + types.SortBySpec(); + return jni::ToJavaString(env, classif().GetReadableObjectName(*types.begin())); +} + +// @FeatureStatus +// static native int nativeGetMapObjectStatus(); +JNIEXPORT jint JNICALL +Java_com_mapswithme_maps_editor_Editor_nativeGetMapObjectStatus(JNIEnv * env, jclass clazz) +{ + return static_cast(osm::Editor::Instance().GetFeatureStatus(g_editableMapObject.GetID())); +} + +JNIEXPORT jboolean JNICALL +Java_com_mapswithme_maps_editor_Editor_nativeIsMapObjectUploaded(JNIEnv * env, jclass clazz) +{ + return osm::Editor::Instance().IsFeatureUploaded(g_editableMapObject.GetID().m_mwmId, g_editableMapObject.GetID().m_index); +} + +// static nativeMakeLocalizedName(String langCode, String name); +JNIEXPORT jobject JNICALL +Java_com_mapswithme_maps_editor_Editor_nativeMakeLocalizedName(JNIEnv * env, jclass clazz, jstring code, jstring name) +{ + osm::LocalizedName localizedName(jni::ToNativeString(env, code), jni::ToNativeString(env, name)); + return ToJavaName(env, localizedName); +} +} // extern "C" diff --git a/android/jni/app/organicmaps/editor/OpeningHours.cpp b/android/jni/com/mapswithme/maps/editor/OpeningHours.cpp similarity index 81% rename from android/jni/app/organicmaps/editor/OpeningHours.cpp rename to android/jni/com/mapswithme/maps/editor/OpeningHours.cpp index 6b82e5b065..c179c969c0 100644 --- a/android/jni/app/organicmaps/editor/OpeningHours.cpp +++ b/android/jni/com/mapswithme/maps/editor/OpeningHours.cpp @@ -1,7 +1,7 @@ #include -#include "app/organicmaps/core/jni_helper.hpp" -#include "app/organicmaps/platform/Platform.hpp" +#include "com/mapswithme/core/jni_helper.hpp" +#include "com/mapswithme/platform/Platform.hpp" #include "editor/opening_hours_ui.hpp" @@ -43,7 +43,7 @@ jfieldID g_fidWeekdays; jobject JavaHoursMinutes(JNIEnv * env, jlong hours, jlong minutes) { static const jclass dateUtilsClass = jni::GetGlobalClassRef(env, - "app/organicmaps/util/DateUtils"); + "com/mapswithme/util/DateUtils"); static jmethodID const is24HourFormatMethod = jni::GetStaticMethodID(env, dateUtilsClass, @@ -182,9 +182,9 @@ TimeTableSet NativeTimetableSet(JNIEnv * env, jobjectArray jTimetables) extern "C" { JNIEXPORT void JNICALL -Java_app_organicmaps_editor_OpeningHours_nativeInit(JNIEnv * env, jclass clazz) +Java_com_mapswithme_maps_editor_OpeningHours_nativeInit(JNIEnv * env, jclass clazz) { - g_clazzHoursMinutes = jni::GetGlobalClassRef(env, "app/organicmaps/editor/data/HoursMinutes"); + g_clazzHoursMinutes = jni::GetGlobalClassRef(env, "com/mapswithme/maps/editor/data/HoursMinutes"); // Java signature : HoursMinutes(@IntRange(from = 0, to = 24) long hours, @IntRange(from = 0, to = 60) long minutes) g_ctorHoursMinutes = env->GetMethodID(g_clazzHoursMinutes, "", "(JJZ)V"); ASSERT(g_ctorHoursMinutes, (jni::DescribeException())); @@ -193,24 +193,24 @@ Java_app_organicmaps_editor_OpeningHours_nativeInit(JNIEnv * env, jclass clazz) g_fidMinutes = env->GetFieldID(g_clazzHoursMinutes, "minutes", "J"); ASSERT(g_fidMinutes, (jni::DescribeException())); - g_clazzTimespan = jni::GetGlobalClassRef(env, "app/organicmaps/editor/data/Timespan"); + g_clazzTimespan = jni::GetGlobalClassRef(env, "com/mapswithme/maps/editor/data/Timespan"); // Java signature : Timespan(HoursMinutes start, HoursMinutes end) g_ctorTimespan = - env->GetMethodID(g_clazzTimespan, "","(Lapp/organicmaps/editor/data/HoursMinutes;Lapp/organicmaps/editor/data/HoursMinutes;)V"); + env->GetMethodID(g_clazzTimespan, "","(Lcom/mapswithme/maps/editor/data/HoursMinutes;Lcom/mapswithme/maps/editor/data/HoursMinutes;)V"); ASSERT(g_ctorTimespan, (jni::DescribeException())); - g_fidStart = env->GetFieldID(g_clazzTimespan, "start", "Lapp/organicmaps/editor/data/HoursMinutes;"); + g_fidStart = env->GetFieldID(g_clazzTimespan, "start", "Lcom/mapswithme/maps/editor/data/HoursMinutes;"); ASSERT(g_fidStart, (jni::DescribeException())); - g_fidEnd = env->GetFieldID(g_clazzTimespan, "end", "Lapp/organicmaps/editor/data/HoursMinutes;"); + g_fidEnd = env->GetFieldID(g_clazzTimespan, "end", "Lcom/mapswithme/maps/editor/data/HoursMinutes;"); ASSERT(g_fidEnd, (jni::DescribeException())); - g_clazzTimetable = jni::GetGlobalClassRef(env, "app/organicmaps/editor/data/Timetable"); + g_clazzTimetable = jni::GetGlobalClassRef(env, "com/mapswithme/maps/editor/data/Timetable"); // Java signature : Timetable(Timespan workingTime, Timespan[] closedHours, boolean isFullday, int weekdays[]) g_ctorTimetable = - env->GetMethodID(g_clazzTimetable, "","(Lapp/organicmaps/editor/data/Timespan;[Lapp/organicmaps/editor/data/Timespan;Z[I)V"); + env->GetMethodID(g_clazzTimetable, "","(Lcom/mapswithme/maps/editor/data/Timespan;[Lcom/mapswithme/maps/editor/data/Timespan;Z[I)V"); ASSERT(g_ctorTimetable, (jni::DescribeException())); - g_fidWorkingTimespan = env->GetFieldID(g_clazzTimetable, "workingTimespan", "Lapp/organicmaps/editor/data/Timespan;"); + g_fidWorkingTimespan = env->GetFieldID(g_clazzTimetable, "workingTimespan", "Lcom/mapswithme/maps/editor/data/Timespan;"); ASSERT(g_fidWorkingTimespan, (jni::DescribeException())); - g_fidClosedTimespans = env->GetFieldID(g_clazzTimetable, "closedTimespans", "[Lapp/organicmaps/editor/data/Timespan;"); + g_fidClosedTimespans = env->GetFieldID(g_clazzTimetable, "closedTimespans", "[Lcom/mapswithme/maps/editor/data/Timespan;"); ASSERT(g_fidClosedTimespans, (jni::DescribeException())); g_fidIsFullday = env->GetFieldID(g_clazzTimetable, "isFullday", "Z"); ASSERT(g_fidIsFullday, (jni::DescribeException())); @@ -219,21 +219,21 @@ Java_app_organicmaps_editor_OpeningHours_nativeInit(JNIEnv * env, jclass clazz) } JNIEXPORT jobjectArray JNICALL -Java_app_organicmaps_editor_OpeningHours_nativeGetDefaultTimetables(JNIEnv * env, jclass clazz) +Java_com_mapswithme_maps_editor_OpeningHours_nativeGetDefaultTimetables(JNIEnv * env, jclass clazz) { TimeTableSet tts; return JavaTimetables(env, tts); } JNIEXPORT jobject JNICALL -Java_app_organicmaps_editor_OpeningHours_nativeGetComplementTimetable(JNIEnv * env, jclass clazz, jobjectArray timetables) +Java_com_mapswithme_maps_editor_OpeningHours_nativeGetComplementTimetable(JNIEnv * env, jclass clazz, jobjectArray timetables) { TimeTableSet const tts = NativeTimetableSet(env, timetables); return JavaTimetable(env, tts.GetComplementTimeTable()); } JNIEXPORT jobject JNICALL -Java_app_organicmaps_editor_OpeningHours_nativeRemoveWorkingDay(JNIEnv * env, jclass clazz, +Java_com_mapswithme_maps_editor_OpeningHours_nativeRemoveWorkingDay(JNIEnv * env, jclass clazz, jobjectArray timetables, jint ttIndex, jint dayIndex) { TimeTableSet tts = NativeTimetableSet(env, timetables); @@ -244,7 +244,7 @@ Java_app_organicmaps_editor_OpeningHours_nativeRemoveWorkingDay(JNIEnv * env, jc } JNIEXPORT jobject JNICALL -Java_app_organicmaps_editor_OpeningHours_nativeAddWorkingDay(JNIEnv * env, jclass clazz, +Java_com_mapswithme_maps_editor_OpeningHours_nativeAddWorkingDay(JNIEnv * env, jclass clazz, jobjectArray timetables, jint ttIndex, jint dayIndex) { TimeTableSet tts = NativeTimetableSet(env, timetables); @@ -255,7 +255,7 @@ Java_app_organicmaps_editor_OpeningHours_nativeAddWorkingDay(JNIEnv * env, jclas } JNIEXPORT jobject JNICALL -Java_app_organicmaps_editor_OpeningHours_nativeSetIsFullday(JNIEnv * env, jclass clazz, +Java_com_mapswithme_maps_editor_OpeningHours_nativeSetIsFullday(JNIEnv * env, jclass clazz, jobject jTimetable, jboolean jIsFullday) { TimeTable tt = NativeTimetable(env, jTimetable); @@ -270,7 +270,7 @@ Java_app_organicmaps_editor_OpeningHours_nativeSetIsFullday(JNIEnv * env, jclass } JNIEXPORT jobject JNICALL -Java_app_organicmaps_editor_OpeningHours_nativeSetOpeningTime(JNIEnv * env, jclass clazz, +Java_com_mapswithme_maps_editor_OpeningHours_nativeSetOpeningTime(JNIEnv * env, jclass clazz, jobject jTimetable, jobject jOpeningTime) { TimeTable tt = NativeTimetable(env, jTimetable); @@ -279,7 +279,7 @@ Java_app_organicmaps_editor_OpeningHours_nativeSetOpeningTime(JNIEnv * env, jcla } JNIEXPORT jobject JNICALL -Java_app_organicmaps_editor_OpeningHours_nativeAddClosedSpan(JNIEnv * env, jclass clazz, +Java_com_mapswithme_maps_editor_OpeningHours_nativeAddClosedSpan(JNIEnv * env, jclass clazz, jobject jTimetable, jobject jClosedSpan) { TimeTable tt = NativeTimetable(env, jTimetable); @@ -288,7 +288,7 @@ Java_app_organicmaps_editor_OpeningHours_nativeAddClosedSpan(JNIEnv * env, jclas } JNIEXPORT jobject JNICALL -Java_app_organicmaps_editor_OpeningHours_nativeRemoveClosedSpan(JNIEnv * env, jclass clazz, +Java_com_mapswithme_maps_editor_OpeningHours_nativeRemoveClosedSpan(JNIEnv * env, jclass clazz, jobject jTimetable, jint jClosedSpanIndex) { TimeTable tt = NativeTimetable(env, jTimetable); @@ -297,7 +297,7 @@ Java_app_organicmaps_editor_OpeningHours_nativeRemoveClosedSpan(JNIEnv * env, jc } JNIEXPORT jobjectArray JNICALL -Java_app_organicmaps_editor_OpeningHours_nativeTimetablesFromString(JNIEnv * env, jclass clazz, jstring jSource) +Java_com_mapswithme_maps_editor_OpeningHours_nativeTimetablesFromString(JNIEnv * env, jclass clazz, jstring jSource) { TimeTableSet tts; std::string const source = jni::ToNativeString(env, jSource); @@ -308,7 +308,7 @@ Java_app_organicmaps_editor_OpeningHours_nativeTimetablesFromString(JNIEnv * env } JNIEXPORT jstring JNICALL -Java_app_organicmaps_editor_OpeningHours_nativeTimetablesToString(JNIEnv * env, jclass clazz, jobjectArray jTts) +Java_com_mapswithme_maps_editor_OpeningHours_nativeTimetablesToString(JNIEnv * env, jclass clazz, jobjectArray jTts) { TimeTableSet tts = NativeTimetableSet(env, jTts); std::stringstream sstr; @@ -317,7 +317,7 @@ Java_app_organicmaps_editor_OpeningHours_nativeTimetablesToString(JNIEnv * env, } JNIEXPORT jboolean JNICALL -Java_app_organicmaps_editor_OpeningHours_nativeIsTimetableStringValid(JNIEnv * env, jclass clazz, jstring jSource) +Java_com_mapswithme_maps_editor_OpeningHours_nativeIsTimetableStringValid(JNIEnv * env, jclass clazz, jstring jSource) { return OpeningHours(jni::ToNativeString(env, jSource)).IsValid(); } diff --git a/android/jni/app/organicmaps/editor/OsmOAuth.cpp b/android/jni/com/mapswithme/maps/editor/OsmOAuth.cpp similarity index 83% rename from android/jni/app/organicmaps/editor/OsmOAuth.cpp rename to android/jni/com/mapswithme/maps/editor/OsmOAuth.cpp index 5b77d7d180..19cd03f52d 100644 --- a/android/jni/app/organicmaps/editor/OsmOAuth.cpp +++ b/android/jni/com/mapswithme/maps/editor/OsmOAuth.cpp @@ -1,7 +1,7 @@ #include -#include "app/organicmaps/core/jni_helper.hpp" -#include "app/organicmaps/Framework.hpp" +#include "com/mapswithme/core/jni_helper.hpp" +#include "com/mapswithme/maps/Framework.hpp" #include "base/logging.hpp" #include "base/string_utils.hpp" @@ -53,7 +53,7 @@ extern "C" { JNIEXPORT jobjectArray JNICALL -Java_app_organicmaps_editor_OsmOAuth_nativeAuthWithPassword(JNIEnv * env, jclass clazz, +Java_com_mapswithme_maps_editor_OsmOAuth_nativeAuthWithPassword(JNIEnv * env, jclass clazz, jstring login, jstring password) { OsmOAuth auth = OsmOAuth::ServerAuth(); @@ -71,7 +71,7 @@ Java_app_organicmaps_editor_OsmOAuth_nativeAuthWithPassword(JNIEnv * env, jclass } JNIEXPORT jobjectArray JNICALL -Java_app_organicmaps_editor_OsmOAuth_nativeAuthWithWebviewToken(JNIEnv * env, jclass clazz, +Java_com_mapswithme_maps_editor_OsmOAuth_nativeAuthWithWebviewToken(JNIEnv * env, jclass clazz, jstring key, jstring secret, jstring verifier) { try @@ -89,7 +89,7 @@ Java_app_organicmaps_editor_OsmOAuth_nativeAuthWithWebviewToken(JNIEnv * env, jc } JNIEXPORT jobjectArray JNICALL -Java_app_organicmaps_editor_OsmOAuth_nativeGetGoogleAuthUrl(JNIEnv * env, jclass clazz) +Java_com_mapswithme_maps_editor_OsmOAuth_nativeGetGoogleAuthUrl(JNIEnv * env, jclass clazz) { try { @@ -104,7 +104,7 @@ Java_app_organicmaps_editor_OsmOAuth_nativeGetGoogleAuthUrl(JNIEnv * env, jclass } JNIEXPORT jstring JNICALL -Java_app_organicmaps_editor_OsmOAuth_nativeGetOsmUsername(JNIEnv * env, jclass, jstring token, jstring secret) +Java_com_mapswithme_maps_editor_OsmOAuth_nativeGetOsmUsername(JNIEnv * env, jclass, jstring token, jstring secret) { const KeySecret keySecret(jni::ToNativeString(env, token), jni::ToNativeString(env, secret)); UserPreferences prefs; @@ -114,7 +114,7 @@ Java_app_organicmaps_editor_OsmOAuth_nativeGetOsmUsername(JNIEnv * env, jclass, } JNIEXPORT jint JNICALL -Java_app_organicmaps_editor_OsmOAuth_nativeGetOsmChangesetsCount(JNIEnv * env, jclass, jstring token, jstring secret) +Java_com_mapswithme_maps_editor_OsmOAuth_nativeGetOsmChangesetsCount(JNIEnv * env, jclass, jstring token, jstring secret) { const KeySecret keySecret(jni::ToNativeString(env, token), jni::ToNativeString(env, secret)); UserPreferences prefs; @@ -124,7 +124,7 @@ Java_app_organicmaps_editor_OsmOAuth_nativeGetOsmChangesetsCount(JNIEnv * env, j } JNIEXPORT jstring JNICALL -Java_app_organicmaps_editor_OsmOAuth_nativeGetHistoryUrl(JNIEnv * env, jclass, jstring user) +Java_com_mapswithme_maps_editor_OsmOAuth_nativeGetHistoryUrl(JNIEnv * env, jclass, jstring user) { return jni::ToJavaString(env, OsmOAuth::ServerAuth().GetHistoryURL(jni::ToNativeString(env, user))); } diff --git a/android/jni/com/mapswithme/maps/isolines/IsolinesManager.cpp b/android/jni/com/mapswithme/maps/isolines/IsolinesManager.cpp new file mode 100644 index 0000000000..40e177bfa3 --- /dev/null +++ b/android/jni/com/mapswithme/maps/isolines/IsolinesManager.cpp @@ -0,0 +1,47 @@ +#include +#include "com/mapswithme/maps/Framework.hpp" +#include "com/mapswithme/core/jni_helper.hpp" +#include "com/mapswithme/platform/Platform.hpp" + +using namespace std::placeholders; + +extern "C" +{ +static void IsolinesStateChanged(IsolinesManager::IsolinesState state, + std::shared_ptr const & listener) +{ + LOG(LINFO, (static_cast(state))); + JNIEnv * env = jni::GetEnv(); + env->CallVoidMethod(*listener, + jni::GetMethodID(env, *listener, "onStateChanged", "(I)V"), + static_cast(state)); +} + + +JNIEXPORT void JNICALL +Java_com_mapswithme_maps_maplayer_isolines_IsolinesManager_nativeAddListener(JNIEnv *env, jclass clazz, jobject listener) +{ + CHECK(g_framework, ("Framework isn't created yet!")); + g_framework->SetIsolinesListener(std::bind(&IsolinesStateChanged, + std::placeholders::_1, + jni::make_global_ref(listener))); +} + +JNIEXPORT void JNICALL +Java_com_mapswithme_maps_maplayer_isolines_IsolinesManager_nativeRemoveListener(JNIEnv * env, jclass clazz) +{ + CHECK(g_framework, ("Framework isn't created yet!")); + g_framework->SetIsolinesListener(nullptr); +} + +JNIEXPORT jboolean JNICALL +Java_com_mapswithme_maps_maplayer_isolines_IsolinesManager_nativeShouldShowNotification(JNIEnv *env, + jclass clazz) +{ + CHECK(g_framework, ("Framework isn't created yet!")); + auto const &manager = g_framework->NativeFramework()->GetIsolinesManager(); + auto const visible = manager.IsVisible(); + auto const enabled = manager.GetState() == IsolinesManager::IsolinesState::Enabled; + return static_cast(!visible && enabled); +} +} diff --git a/android/jni/app/organicmaps/routing/RoutingOptions.cpp b/android/jni/com/mapswithme/maps/routing/RoutingOptions.cpp similarity index 75% rename from android/jni/app/organicmaps/routing/RoutingOptions.cpp rename to android/jni/com/mapswithme/maps/routing/RoutingOptions.cpp index 09fe85c2d2..1cf670a297 100644 --- a/android/jni/app/organicmaps/routing/RoutingOptions.cpp +++ b/android/jni/com/mapswithme/maps/routing/RoutingOptions.cpp @@ -1,6 +1,6 @@ #include -#include -#include +#include +#include #include "routing/routing_options.hpp" routing::RoutingOptions::Road makeValue(jint option) @@ -14,7 +14,7 @@ extern "C" { JNIEXPORT jboolean JNICALL -Java_app_organicmaps_routing_RoutingOptions_nativeHasOption(JNIEnv * env, jclass clazz, jint option) +Java_com_mapswithme_maps_routing_RoutingOptions_nativeHasOption(JNIEnv * env, jclass clazz, jint option) { CHECK(g_framework, ("Framework isn't created yet!")); routing::RoutingOptions routingOptions = routing::RoutingOptions::LoadCarOptionsFromSettings(); @@ -23,7 +23,7 @@ Java_app_organicmaps_routing_RoutingOptions_nativeHasOption(JNIEnv * env, jclass } JNIEXPORT void JNICALL -Java_app_organicmaps_routing_RoutingOptions_nativeAddOption(JNIEnv * env, jclass clazz, jint option) +Java_com_mapswithme_maps_routing_RoutingOptions_nativeAddOption(JNIEnv * env, jclass clazz, jint option) { CHECK(g_framework, ("Framework isn't created yet!")); routing::RoutingOptions routingOptions = routing::RoutingOptions::LoadCarOptionsFromSettings(); @@ -34,7 +34,7 @@ Java_app_organicmaps_routing_RoutingOptions_nativeAddOption(JNIEnv * env, jclass JNIEXPORT void JNICALL -Java_app_organicmaps_routing_RoutingOptions_nativeRemoveOption(JNIEnv * env, jclass clazz, jint option) +Java_com_mapswithme_maps_routing_RoutingOptions_nativeRemoveOption(JNIEnv * env, jclass clazz, jint option) { CHECK(g_framework, ("Framework isn't created yet!")); routing::RoutingOptions routingOptions = routing::RoutingOptions::LoadCarOptionsFromSettings(); diff --git a/android/jni/com/mapswithme/maps/settings/UnitLocale.cpp b/android/jni/com/mapswithme/maps/settings/UnitLocale.cpp new file mode 100644 index 0000000000..5f6df700ae --- /dev/null +++ b/android/jni/com/mapswithme/maps/settings/UnitLocale.cpp @@ -0,0 +1,23 @@ +#include "com/mapswithme/maps/Framework.hpp" + +#include "platform/measurement_utils.hpp" +#include "platform/settings.hpp" + +extern "C" +{ + JNIEXPORT void JNICALL + Java_com_mapswithme_maps_settings_UnitLocale_setCurrentUnits(JNIEnv * env, jobject thiz, jint units) + { + measurement_utils::Units const u = static_cast(units); + settings::Set(settings::kMeasurementUnits, u); + g_framework->SetupMeasurementSystem(); + } + + JNIEXPORT jint JNICALL + Java_com_mapswithme_maps_settings_UnitLocale_getCurrentUnits(JNIEnv * env, jobject thiz) + { + measurement_utils::Units u; + return static_cast( + settings::Get(settings::kMeasurementUnits, u) ? u : measurement_utils::Units::Metric); + } +} diff --git a/android/jni/com/mapswithme/maps/sound/tts.cpp b/android/jni/com/mapswithme/maps/sound/tts.cpp new file mode 100644 index 0000000000..13d3408b66 --- /dev/null +++ b/android/jni/com/mapswithme/maps/sound/tts.cpp @@ -0,0 +1,30 @@ +#include "com/mapswithme/maps/Framework.hpp" + +#include "com/mapswithme/core/jni_helper.hpp" + +extern "C" +{ + JNIEXPORT void JNICALL + Java_com_mapswithme_maps_sound_TtsPlayer_nativeEnableTurnNotifications(JNIEnv *, jclass, jboolean enable) + { + return frm()->GetRoutingManager().EnableTurnNotifications(static_cast(enable)); + } + + JNIEXPORT jboolean JNICALL + Java_com_mapswithme_maps_sound_TtsPlayer_nativeAreTurnNotificationsEnabled(JNIEnv *, jclass) + { + return static_cast(frm()->GetRoutingManager().AreTurnNotificationsEnabled()); + } + + JNIEXPORT void JNICALL + Java_com_mapswithme_maps_sound_TtsPlayer_nativeSetTurnNotificationsLocale(JNIEnv * env, jclass, jstring jLocale) + { + frm()->GetRoutingManager().SetTurnNotificationsLocale(jni::ToNativeString(env, jLocale)); + } + + JNIEXPORT jstring JNICALL + Java_com_mapswithme_maps_sound_TtsPlayer_nativeGetTurnNotificationsLocale(JNIEnv * env, jclass) + { + return jni::ToJavaString(env, frm()->GetRoutingManager().GetTurnNotificationsLocale()); + } +} // extern "C" diff --git a/android/jni/com/mapswithme/maps/subway/SubwayManager.cpp b/android/jni/com/mapswithme/maps/subway/SubwayManager.cpp new file mode 100644 index 0000000000..c276100c35 --- /dev/null +++ b/android/jni/com/mapswithme/maps/subway/SubwayManager.cpp @@ -0,0 +1,32 @@ +#include +#include +#include "com/mapswithme/core/jni_helper.hpp" +#include "com/mapswithme/platform/Platform.hpp" + +extern "C" +{ +static void TransitSchemeStateChanged(TransitReadManager::TransitSchemeState state, + std::shared_ptr const & listener) +{ + JNIEnv * env = jni::GetEnv(); + env->CallVoidMethod(*listener, + jni::GetMethodID(env, *listener, "onTransitStateChanged", "(I)V"), + static_cast(state)); +} + +JNIEXPORT void JNICALL +Java_com_mapswithme_maps_maplayer_subway_SubwayManager_nativeAddListener(JNIEnv *env, jclass clazz, jobject listener) +{ + CHECK(g_framework, ("Framework isn't created yet!")); + g_framework->SetTransitSchemeListener(std::bind(&TransitSchemeStateChanged, + std::placeholders::_1, + jni::make_global_ref(listener))); +} + +JNIEXPORT void JNICALL +Java_com_mapswithme_maps_maplayer_subway_SubwayManager_nativeRemoveListener(JNIEnv * env, jclass clazz) +{ + CHECK(g_framework, ("Framework isn't created yet!")); + g_framework->SetTransitSchemeListener(TransitReadManager::TransitStateChangedFn()); +} +} diff --git a/android/jni/app/organicmaps/opengl/android_gl_utils.cpp b/android/jni/com/mapswithme/opengl/android_gl_utils.cpp similarity index 100% rename from android/jni/app/organicmaps/opengl/android_gl_utils.cpp rename to android/jni/com/mapswithme/opengl/android_gl_utils.cpp diff --git a/android/jni/app/organicmaps/opengl/android_gl_utils.hpp b/android/jni/com/mapswithme/opengl/android_gl_utils.hpp similarity index 100% rename from android/jni/app/organicmaps/opengl/android_gl_utils.hpp rename to android/jni/com/mapswithme/opengl/android_gl_utils.hpp diff --git a/android/jni/app/organicmaps/opengl/androidoglcontext.cpp b/android/jni/com/mapswithme/opengl/androidoglcontext.cpp similarity index 100% rename from android/jni/app/organicmaps/opengl/androidoglcontext.cpp rename to android/jni/com/mapswithme/opengl/androidoglcontext.cpp diff --git a/android/jni/app/organicmaps/opengl/androidoglcontext.hpp b/android/jni/com/mapswithme/opengl/androidoglcontext.hpp similarity index 100% rename from android/jni/app/organicmaps/opengl/androidoglcontext.hpp rename to android/jni/com/mapswithme/opengl/androidoglcontext.hpp diff --git a/android/jni/app/organicmaps/opengl/androidoglcontextfactory.cpp b/android/jni/com/mapswithme/opengl/androidoglcontextfactory.cpp similarity index 99% rename from android/jni/app/organicmaps/opengl/androidoglcontextfactory.cpp rename to android/jni/com/mapswithme/opengl/androidoglcontextfactory.cpp index 9bb15f2606..f71451471b 100644 --- a/android/jni/app/organicmaps/opengl/androidoglcontextfactory.cpp +++ b/android/jni/com/mapswithme/opengl/androidoglcontextfactory.cpp @@ -1,7 +1,7 @@ #include "androidoglcontextfactory.hpp" #include "android_gl_utils.hpp" -#include "app/organicmaps/platform/Platform.hpp" +#include "com/mapswithme/platform/Platform.hpp" #include "base/assert.hpp" #include "base/logging.hpp" diff --git a/android/jni/app/organicmaps/opengl/androidoglcontextfactory.hpp b/android/jni/com/mapswithme/opengl/androidoglcontextfactory.hpp similarity index 97% rename from android/jni/app/organicmaps/opengl/androidoglcontextfactory.hpp rename to android/jni/com/mapswithme/opengl/androidoglcontextfactory.hpp index 8f886a9c4e..2a7ac71c48 100644 --- a/android/jni/app/organicmaps/opengl/androidoglcontextfactory.hpp +++ b/android/jni/com/mapswithme/opengl/androidoglcontextfactory.hpp @@ -1,6 +1,6 @@ #pragma once -#include "app/organicmaps/core/jni_helper.hpp" +#include "com/mapswithme/core/jni_helper.hpp" #include "androidoglcontext.hpp" #include "drape/graphics_context_factory.hpp" diff --git a/android/jni/app/organicmaps/opengl/gl3stub.c b/android/jni/com/mapswithme/opengl/gl3stub.c similarity index 100% rename from android/jni/app/organicmaps/opengl/gl3stub.c rename to android/jni/com/mapswithme/opengl/gl3stub.c diff --git a/android/jni/app/organicmaps/opengl/gl3stub.h b/android/jni/com/mapswithme/opengl/gl3stub.h similarity index 100% rename from android/jni/app/organicmaps/opengl/gl3stub.h rename to android/jni/com/mapswithme/opengl/gl3stub.h diff --git a/android/jni/app/organicmaps/platform/GuiThread.cpp b/android/jni/com/mapswithme/platform/GuiThread.cpp similarity index 91% rename from android/jni/app/organicmaps/platform/GuiThread.cpp rename to android/jni/com/mapswithme/platform/GuiThread.cpp index af87b05bc6..b6e31694a2 100644 --- a/android/jni/app/organicmaps/platform/GuiThread.cpp +++ b/android/jni/com/mapswithme/platform/GuiThread.cpp @@ -1,6 +1,6 @@ -#include "app/organicmaps/platform/GuiThread.hpp" +#include "com/mapswithme/platform/GuiThread.hpp" -#include "app/organicmaps/core/jni_helper.hpp" +#include "com/mapswithme/core/jni_helper.hpp" #include diff --git a/android/jni/app/organicmaps/platform/GuiThread.hpp b/android/jni/com/mapswithme/platform/GuiThread.hpp similarity index 100% rename from android/jni/app/organicmaps/platform/GuiThread.hpp rename to android/jni/com/mapswithme/platform/GuiThread.hpp diff --git a/android/jni/app/organicmaps/platform/HttpThread.cpp b/android/jni/com/mapswithme/platform/HttpThread.cpp similarity index 83% rename from android/jni/app/organicmaps/platform/HttpThread.cpp rename to android/jni/com/mapswithme/platform/HttpThread.cpp index f065ff3f46..f29bca20d7 100644 --- a/android/jni/app/organicmaps/platform/HttpThread.cpp +++ b/android/jni/com/mapswithme/platform/HttpThread.cpp @@ -1,5 +1,5 @@ #include "Platform.hpp" -#include "app/organicmaps/core/jni_helper.hpp" +#include "com/mapswithme/core/jni_helper.hpp" #include "base/logging.hpp" #include "platform/http_thread_callback.hpp" @@ -8,7 +8,6 @@ class HttpThread { private: jobject m_self; - jclass m_klass; public: HttpThread(std::string const & url, @@ -19,8 +18,8 @@ public: std::string const & pb) { JNIEnv * env = jni::GetEnv(); - static jclass const klass = jni::GetGlobalClassRef(env, "app/organicmaps/downloader/ChunkTask"); - m_klass = klass; + + static jclass const klass = jni::GetGlobalClassRef(env, "com/mapswithme/maps/downloader/ChunkTask"); // public ChunkTask(long httpCallbackID, String url, long beg, long end, // long expectedFileSize, byte[] postBody, String userAgent) static jmethodID const initMethodId = jni::GetConstructorID(env, klass, "(JLjava/lang/String;JJJ[B)V"); @@ -52,8 +51,8 @@ public: ~HttpThread() { JNIEnv * env = jni::GetEnv(); - static jmethodID const cancelMethodId = env->GetMethodID(m_klass, "cancel", "(Z)Z"); - env->CallBooleanMethod(m_self, cancelMethodId, false); + jmethodID methodId = jni::GetMethodID(env, m_self, "cancel", "(Z)Z"); + env->CallBooleanMethod(m_self, methodId, false); env->DeleteGlobalRef(m_self); } }; @@ -80,7 +79,7 @@ namespace downloader extern "C" { JNIEXPORT jboolean JNICALL -Java_app_organicmaps_downloader_ChunkTask_nativeOnWrite(JNIEnv * env, jclass clazz, jlong httpCallbackID, jlong beg, jbyteArray data, jlong size) +Java_com_mapswithme_maps_downloader_ChunkTask_nativeOnWrite(JNIEnv * env, jclass clazz, jlong httpCallbackID, jlong beg, jbyteArray data, jlong size) { downloader::IHttpThreadCallback * cb = reinterpret_cast(httpCallbackID); jbyte * buf = env->GetByteArrayElements(data, 0); @@ -101,7 +100,7 @@ Java_app_organicmaps_downloader_ChunkTask_nativeOnWrite(JNIEnv * env, jclass cla } JNIEXPORT void JNICALL -Java_app_organicmaps_downloader_ChunkTask_nativeOnFinish(JNIEnv * env, jclass clazz, jlong httpCallbackID, jlong httpCode, jlong beg, jlong end) +Java_com_mapswithme_maps_downloader_ChunkTask_nativeOnFinish(JNIEnv * env, jclass clazz, jlong httpCallbackID, jlong httpCode, jlong beg, jlong end) { downloader::IHttpThreadCallback * cb = reinterpret_cast(httpCallbackID); cb->OnFinish(static_cast(httpCode), beg, end); diff --git a/android/jni/com/mapswithme/platform/Language.cpp b/android/jni/com/mapswithme/platform/Language.cpp new file mode 100644 index 0000000000..2b5ee1162b --- /dev/null +++ b/android/jni/com/mapswithme/platform/Language.cpp @@ -0,0 +1,57 @@ +#include "android/jni/com/mapswithme/core/jni_helper.hpp" +#include "android/jni/com/mapswithme/core/ScopedLocalRef.hpp" + +#include "platform/locale.hpp" + +#include "base/assert.hpp" +#include "base/logging.hpp" +#include "base/string_utils.hpp" + +#include + +/// This function is called from native c++ code +std::string GetAndroidSystemLanguage() +{ + static char const * DEFAULT_LANG = "en"; + + JNIEnv * env = jni::GetEnv(); + if (!env) + { + LOG(LWARNING, ("Can't get JNIEnv")); + return DEFAULT_LANG; + } + + static jclass const languageClass = jni::GetGlobalClassRef(env, "com/mapswithme/util/Language"); + static jmethodID const getDefaultLocaleId = jni::GetStaticMethodID(env, languageClass, "getDefaultLocale", "()Ljava/lang/String;"); + + jni::TScopedLocalRef localeRef(env, env->CallStaticObjectMethod(languageClass, getDefaultLocaleId)); + + std::string res = jni::ToNativeString(env, (jstring) localeRef.get()); + if (res.empty()) + res = DEFAULT_LANG; + + return res; +} + +namespace platform +{ +Locale GetCurrentLocale() +{ + JNIEnv * env = jni::GetEnv(); + static jmethodID const getLanguageCodeId = jni::GetStaticMethodID(env, g_utilsClazz, "getLanguageCode", + "()Ljava/lang/String;"); + jni::ScopedLocalRef languageCode(env, env->CallStaticObjectMethod(g_utilsClazz, getLanguageCodeId)); + + static jmethodID const getCountryCodeId = jni::GetStaticMethodID(env, g_utilsClazz, "getCountryCode", + "()Ljava/lang/String;"); + jni::ScopedLocalRef countryCode(env, env->CallStaticObjectMethod(g_utilsClazz, getCountryCodeId)); + + static jmethodID const getCurrencyCodeId = jni::GetStaticMethodID(env, g_utilsClazz, "getCurrencyCode", + "()Ljava/lang/String;"); + jni::ScopedLocalRef currencyCode(env, env->CallStaticObjectMethod(g_utilsClazz, getCurrencyCodeId)); + + return {jni::ToNativeString(env, static_cast(languageCode.get())), + jni::ToNativeString(env, static_cast(countryCode.get())), + currencyCode.get() ? jni::ToNativeString(env, static_cast(currencyCode.get())) : ""}; +} +} // namespace platform diff --git a/android/jni/app/organicmaps/platform/Localization.cpp b/android/jni/com/mapswithme/platform/Localization.cpp similarity index 94% rename from android/jni/app/organicmaps/platform/Localization.cpp rename to android/jni/com/mapswithme/platform/Localization.cpp index b0802d28de..a9a991bb59 100644 --- a/android/jni/app/organicmaps/platform/Localization.cpp +++ b/android/jni/com/mapswithme/platform/Localization.cpp @@ -1,8 +1,8 @@ #include -#include "app/organicmaps/core/jni_helper.hpp" -#include "app/organicmaps/core/ScopedLocalRef.hpp" -#include "app/organicmaps/platform/Platform.hpp" +#include "com/mapswithme/core/jni_helper.hpp" +#include "com/mapswithme/core/ScopedLocalRef.hpp" +#include "com/mapswithme/platform/Platform.hpp" #include "platform/localization.hpp" diff --git a/android/jni/app/organicmaps/platform/PThreadImpl.cpp b/android/jni/com/mapswithme/platform/PThreadImpl.cpp similarity index 83% rename from android/jni/app/organicmaps/platform/PThreadImpl.cpp rename to android/jni/com/mapswithme/platform/PThreadImpl.cpp index 9529d29b93..2a8ebf3e26 100644 --- a/android/jni/app/organicmaps/platform/PThreadImpl.cpp +++ b/android/jni/com/mapswithme/platform/PThreadImpl.cpp @@ -1,4 +1,4 @@ -#include "app/organicmaps/core/jni_helper.hpp" +#include "com/mapswithme/core/jni_helper.hpp" /// Implements bodies of base/thread.hpp functions for Android diff --git a/android/jni/app/organicmaps/platform/Platform.cpp b/android/jni/com/mapswithme/platform/Platform.cpp similarity index 93% rename from android/jni/app/organicmaps/platform/Platform.cpp rename to android/jni/com/mapswithme/platform/Platform.cpp index 5c0529ce57..324b5fa1ee 100644 --- a/android/jni/app/organicmaps/platform/Platform.cpp +++ b/android/jni/com/mapswithme/platform/Platform.cpp @@ -1,9 +1,9 @@ -#include "app/organicmaps/platform/Platform.hpp" -#include "app/organicmaps/platform/GuiThread.hpp" +#include "com/mapswithme/platform/Platform.hpp" +#include "com/mapswithme/platform/GuiThread.hpp" -#include "app/organicmaps/core/jni_helper.hpp" +#include "com/mapswithme/core/jni_helper.hpp" -#include "app/organicmaps/util/NetworkPolicy.hpp" +#include "com/mapswithme/util/NetworkPolicy.hpp" #include "platform/network_policy.hpp" #include "platform/settings.hpp" @@ -22,7 +22,7 @@ std::string Platform::GetMemoryInfo() const if (env == nullptr) return std::string(); - static std::shared_ptr classLogsManager = jni::make_global_ref(env->FindClass("app/organicmaps/util/log/LogsManager")); + static std::shared_ptr classLogsManager = jni::make_global_ref(env->FindClass("com/mapswithme/util/log/LogsManager")); ASSERT(classLogsManager, ()); jobject context = android::Platform::Instance().GetContext(); @@ -79,7 +79,7 @@ Platform::EConnectionType Platform::ConnectionStatus() if (env == nullptr) return EConnectionType::CONNECTION_NONE; - static std::shared_ptr clazzConnectionState = jni::make_global_ref(env->FindClass("app/organicmaps/util/ConnectionState")); + static std::shared_ptr clazzConnectionState = jni::make_global_ref(env->FindClass("com/mapswithme/util/ConnectionState")); ASSERT(clazzConnectionState, ()); static jmethodID const getConnectionMethodId = jni::GetStaticMethodID(env, static_cast(*clazzConnectionState), "getConnectionState", "()B"); @@ -93,7 +93,7 @@ Platform::ChargingStatus Platform::GetChargingStatus() return Platform::ChargingStatus::Unknown; static jclass const clazzBatteryState = - jni::GetGlobalClassRef(env, "app/organicmaps/util/BatteryState"); + jni::GetGlobalClassRef(env, "com/mapswithme/util/BatteryState"); ASSERT(clazzBatteryState, ()); static jmethodID const getChargingMethodId = @@ -110,7 +110,7 @@ uint8_t Platform::GetBatteryLevel() return 100; static auto const clazzBatteryState = - jni::GetGlobalClassRef(env, "app/organicmaps/util/BatteryState"); + jni::GetGlobalClassRef(env, "com/mapswithme/util/BatteryState"); ASSERT(clazzBatteryState, ()); static auto const getLevelMethodId = @@ -195,7 +195,7 @@ void Platform::AndroidSecureStorage::Init(JNIEnv * env) if (m_secureStorageClass != nullptr) return; - m_secureStorageClass = jni::GetGlobalClassRef(env, "app/organicmaps/util/SecureStorage"); + m_secureStorageClass = jni::GetGlobalClassRef(env, "com/mapswithme/util/SecureStorage"); ASSERT(m_secureStorageClass, ()); } diff --git a/android/jni/app/organicmaps/platform/Platform.hpp b/android/jni/com/mapswithme/platform/Platform.hpp similarity index 100% rename from android/jni/app/organicmaps/platform/Platform.hpp rename to android/jni/com/mapswithme/platform/Platform.hpp diff --git a/android/jni/app/organicmaps/platform/SecureStorage.cpp b/android/jni/com/mapswithme/platform/SecureStorage.cpp similarity index 100% rename from android/jni/app/organicmaps/platform/SecureStorage.cpp rename to android/jni/com/mapswithme/platform/SecureStorage.cpp diff --git a/android/jni/app/organicmaps/platform/SocketImpl.cpp b/android/jni/com/mapswithme/platform/SocketImpl.cpp similarity index 98% rename from android/jni/app/organicmaps/platform/SocketImpl.cpp rename to android/jni/com/mapswithme/platform/SocketImpl.cpp index 19073209f3..4fd440144b 100644 --- a/android/jni/app/organicmaps/platform/SocketImpl.cpp +++ b/android/jni/com/mapswithme/platform/SocketImpl.cpp @@ -1,4 +1,4 @@ -#include "app/organicmaps/core/jni_helper.hpp" +#include "com/mapswithme/core/jni_helper.hpp" #include "platform/socket.hpp" diff --git a/android/jni/com/mapswithme/util/Config.cpp b/android/jni/com/mapswithme/util/Config.cpp new file mode 100644 index 0000000000..1983893f25 --- /dev/null +++ b/android/jni/com/mapswithme/util/Config.cpp @@ -0,0 +1,114 @@ +#include "com/mapswithme/core/jni_helper.hpp" +#include "com/mapswithme/maps/Framework.hpp" +#include "platform/settings.hpp" + +extern "C" +{ + JNIEXPORT jboolean JNICALL + Java_com_mapswithme_util_Config_nativeGetBoolean(JNIEnv * env, jclass thiz, jstring name, jboolean defaultVal) + { + bool val; + if (settings::Get(jni::ToNativeString(env, name), val)) + return static_cast(val); + + return defaultVal; + } + + JNIEXPORT void JNICALL + Java_com_mapswithme_util_Config_nativeSetBoolean(JNIEnv * env, jclass thiz, jstring name, jboolean val) + { + (void)settings::Set(jni::ToNativeString(env, name), static_cast(val)); + } + + JNIEXPORT jint JNICALL + Java_com_mapswithme_util_Config_nativeGetInt(JNIEnv * env, jclass thiz, jstring name, jint defaultValue) + { + int32_t value; + if (settings::Get(jni::ToNativeString(env, name), value)) + return static_cast(value); + + return defaultValue; + } + + JNIEXPORT void JNICALL + Java_com_mapswithme_util_Config_nativeSetInt(JNIEnv * env, jclass thiz, jstring name, jint value) + { + (void)settings::Set(jni::ToNativeString(env, name), static_cast(value)); + } + + JNIEXPORT jlong JNICALL + Java_com_mapswithme_util_Config_nativeGetLong(JNIEnv * env, jclass thiz, jstring name, jlong defaultValue) + { + int64_t value; + if (settings::Get(jni::ToNativeString(env, name), value)) + return static_cast(value); + + return defaultValue; + } + + JNIEXPORT void JNICALL + Java_com_mapswithme_util_Config_nativeSetLong(JNIEnv * env, jclass thiz, jstring name, jlong value) + { + (void)settings::Set(jni::ToNativeString(env, name), static_cast(value)); + } + + JNIEXPORT jdouble JNICALL + Java_com_mapswithme_util_Config_nativeGetDouble(JNIEnv * env, jclass thiz, jstring name, jdouble defaultValue) + { + double value; + if (settings::Get(jni::ToNativeString(env, name), value)) + return static_cast(value); + + return defaultValue; + } + + JNIEXPORT void JNICALL + Java_com_mapswithme_util_Config_nativeSetDouble(JNIEnv * env, jclass thiz, jstring name, jdouble value) + { + (void)settings::Set(jni::ToNativeString(env, name), static_cast(value)); + } + + JNIEXPORT jstring JNICALL + Java_com_mapswithme_util_Config_nativeGetString(JNIEnv * env, jclass thiz, jstring name, jstring defaultValue) + { + std::string value; + if (settings::Get(jni::ToNativeString(env, name), value)) + return jni::ToJavaString(env, value); + + return defaultValue; + } + + JNIEXPORT void JNICALL + Java_com_mapswithme_util_Config_nativeSetString(JNIEnv * env, jclass thiz, jstring name, jstring value) + { + (void)settings::Set(jni::ToNativeString(env, name), jni::ToNativeString(env, value)); + } + + JNIEXPORT jboolean JNICALL + Java_com_mapswithme_util_Config_nativeGetLargeFontsSize(JNIEnv * env, jclass thiz) + { + return frm()->LoadLargeFontsSize(); + } + + JNIEXPORT void JNICALL + Java_com_mapswithme_util_Config_nativeSetLargeFontsSize(JNIEnv * env, jclass thiz, + jboolean value) + { + frm()->SaveLargeFontsSize(value); + frm()->SetLargeFontsSize(value); + } + + JNIEXPORT jboolean JNICALL + Java_com_mapswithme_util_Config_nativeGetTransliteration(JNIEnv * env, jclass thiz) + { + return frm()->LoadTransliteration(); + } + + JNIEXPORT void JNICALL + Java_com_mapswithme_util_Config_nativeSetTransliteration(JNIEnv * env, jclass thiz, + jboolean value) + { + frm()->SaveTransliteration(value); + frm()->AllowTransliteration(value); + } +} // extern "C" diff --git a/android/jni/app/organicmaps/util/FeatureIdBuilder.hpp b/android/jni/com/mapswithme/util/FeatureIdBuilder.hpp similarity index 87% rename from android/jni/app/organicmaps/util/FeatureIdBuilder.hpp rename to android/jni/com/mapswithme/util/FeatureIdBuilder.hpp index 657f093610..e35b0e3b04 100644 --- a/android/jni/app/organicmaps/util/FeatureIdBuilder.hpp +++ b/android/jni/com/mapswithme/util/FeatureIdBuilder.hpp @@ -1,6 +1,6 @@ #pragma once -#include "app/organicmaps/core/jni_helper.hpp" +#include "com/mapswithme/core/jni_helper.hpp" #include "indexer/feature_decl.hpp" @@ -9,7 +9,7 @@ class FeatureIdBuilder public: FeatureIdBuilder(JNIEnv * env) { - m_class = jni::GetGlobalClassRef(env, "app/organicmaps/bookmarks/data/FeatureId"); + m_class = jni::GetGlobalClassRef(env, "com/mapswithme/maps/bookmarks/data/FeatureId"); m_countryName = env->GetFieldID(m_class, "mMwmName", "Ljava/lang/String;"); m_version = env->GetFieldID(m_class, "mMwmVersion", "J"); m_index = env->GetFieldID(m_class, "mFeatureIndex", "I"); diff --git a/android/jni/app/organicmaps/util/GeoUtils.cpp b/android/jni/com/mapswithme/util/GeoUtils.cpp similarity index 78% rename from android/jni/app/organicmaps/util/GeoUtils.cpp rename to android/jni/com/mapswithme/util/GeoUtils.cpp index 19ae2b3629..e1b36d248d 100644 --- a/android/jni/app/organicmaps/util/GeoUtils.cpp +++ b/android/jni/com/mapswithme/util/GeoUtils.cpp @@ -1,11 +1,11 @@ -#include "android/jni/app/organicmaps/core/jni_helper.hpp" +#include "android/jni/com/mapswithme/core/jni_helper.hpp" #include "geometry/mercator.hpp" extern "C" { JNIEXPORT jobject JNICALL - Java_app_organicmaps_util_GeoUtils_nativeToLatLon( + Java_com_mapswithme_util_GeoUtils_nativeToLatLon( JNIEnv * env, jobject thiz, jdouble mercX, jdouble mercY) { auto const mercPoint = m2::PointD(static_cast(mercX), static_cast(mercY)); diff --git a/android/jni/app/organicmaps/util/HttpBackgroundUploader.cpp b/android/jni/com/mapswithme/util/HttpBackgroundUploader.cpp similarity index 83% rename from android/jni/app/organicmaps/util/HttpBackgroundUploader.cpp rename to android/jni/com/mapswithme/util/HttpBackgroundUploader.cpp index 0aa530f36b..ce9ffcb011 100644 --- a/android/jni/app/organicmaps/util/HttpBackgroundUploader.cpp +++ b/android/jni/com/mapswithme/util/HttpBackgroundUploader.cpp @@ -1,8 +1,8 @@ #include -#include "app/organicmaps/core/ScopedEnv.hpp" -#include "app/organicmaps/core/ScopedLocalRef.hpp" -#include "app/organicmaps/core/jni_helper.hpp" +#include "com/mapswithme/core/ScopedEnv.hpp" +#include "com/mapswithme/core/ScopedLocalRef.hpp" +#include "com/mapswithme/core/jni_helper.hpp" #include "platform/http_uploader.hpp" #include "platform/http_uploader_background.hpp" diff --git a/android/jni/app/organicmaps/util/HttpClient.cpp b/android/jni/com/mapswithme/util/HttpClient.cpp similarity index 96% rename from android/jni/app/organicmaps/util/HttpClient.cpp rename to android/jni/com/mapswithme/util/HttpClient.cpp index db50d92598..bce63ffaed 100644 --- a/android/jni/app/organicmaps/util/HttpClient.cpp +++ b/android/jni/com/mapswithme/util/HttpClient.cpp @@ -23,9 +23,9 @@ SOFTWARE. *******************************************************************************/ #include -#include "app/organicmaps/core/jni_helper.hpp" -#include "app/organicmaps/core/ScopedEnv.hpp" -#include "app/organicmaps/core/ScopedLocalRef.hpp" +#include "com/mapswithme/core/jni_helper.hpp" +#include "com/mapswithme/core/ScopedEnv.hpp" +#include "com/mapswithme/core/ScopedLocalRef.hpp" #include "platform/http_client.hpp" @@ -104,7 +104,7 @@ void SetHeaders(ScopedEnv & env, jobject const params, platform::HttpClient::Hea return; static jmethodID const setHeaders = env->GetMethodID( - g_httpParamsClazz, "setHeaders", "([Lapp/organicmaps/util/KeyValue;)V"); + g_httpParamsClazz, "setHeaders", "([Lcom/mapswithme/util/KeyValue;)V"); RethrowOnJniException(env); @@ -228,7 +228,7 @@ bool HttpClient::RunHttpRequest() static jmethodID const httpClientClassRun = env->GetStaticMethodID(g_httpClientClazz, "run", - "(Lapp/organicmaps/util/HttpClient$Params;)Lapp/organicmaps/util/HttpClient$Params;"); + "(Lcom/mapswithme/util/HttpClient$Params;)Lcom/mapswithme/util/HttpClient$Params;"); jni::ScopedLocalRef const response(env.get(), env->CallStaticObjectMethod(g_httpClientClazz, httpClientClassRun, httpParamsObject.get())); diff --git a/android/jni/app/organicmaps/util/HttpUploader.cpp b/android/jni/com/mapswithme/util/HttpUploader.cpp similarity index 81% rename from android/jni/app/organicmaps/util/HttpUploader.cpp rename to android/jni/com/mapswithme/util/HttpUploader.cpp index 6a3050b422..4712844bda 100644 --- a/android/jni/app/organicmaps/util/HttpUploader.cpp +++ b/android/jni/com/mapswithme/util/HttpUploader.cpp @@ -1,8 +1,8 @@ #include -#include "app/organicmaps/core/ScopedEnv.hpp" -#include "app/organicmaps/core/ScopedLocalRef.hpp" -#include "app/organicmaps/core/jni_helper.hpp" +#include "com/mapswithme/core/ScopedEnv.hpp" +#include "com/mapswithme/core/ScopedLocalRef.hpp" +#include "com/mapswithme/core/jni_helper.hpp" #include "platform/http_uploader.hpp" @@ -48,7 +48,7 @@ HttpUploader::Result HttpUploader::Upload() const jni::ScopedLocalRef const uploaderRef(env, uploader); static jmethodID const uploadId = jni::GetMethodID(env, uploaderRef.get(), "upload", - "()Lapp/organicmaps/util/HttpUploader$Result;"); + "()Lcom/mapswithme/util/HttpUploader$Result;"); jni::ScopedLocalRef const result(env, env->CallObjectMethod(uploaderRef.get(), uploadId)); @@ -68,13 +68,13 @@ HttpUploader::Result HttpUploader::Upload() const extern "C" { JNIEXPORT jstring JNICALL - Java_app_organicmaps_util_HttpUploader_nativeUserBindingCertificate(JNIEnv * env, jclass) + Java_com_mapswithme_util_HttpUploader_nativeUserBindingCertificate(JNIEnv * env, jclass) { return jni::ToJavaString(env, USER_BINDING_PKCS12); } JNIEXPORT jstring JNICALL - Java_app_organicmaps_util_HttpUploader_nativeUserBindingPassword(JNIEnv * env, jclass) + Java_com_mapswithme_util_HttpUploader_nativeUserBindingPassword(JNIEnv * env, jclass) { return jni::ToJavaString(env, USER_BINDING_PKCS12_PASSWORD); } diff --git a/android/jni/app/organicmaps/util/HttpUploaderUtils.cpp b/android/jni/com/mapswithme/util/HttpUploaderUtils.cpp similarity index 81% rename from android/jni/app/organicmaps/util/HttpUploaderUtils.cpp rename to android/jni/com/mapswithme/util/HttpUploaderUtils.cpp index 55dad5affc..355912a266 100644 --- a/android/jni/app/organicmaps/util/HttpUploaderUtils.cpp +++ b/android/jni/com/mapswithme/util/HttpUploaderUtils.cpp @@ -1,8 +1,8 @@ #include -#include "app/organicmaps/core/ScopedEnv.hpp" -#include "app/organicmaps/core/ScopedLocalRef.hpp" -#include "app/organicmaps/core/jni_helper.hpp" +#include "com/mapswithme/core/ScopedEnv.hpp" +#include "com/mapswithme/core/ScopedLocalRef.hpp" +#include "com/mapswithme/core/jni_helper.hpp" #include "platform/http_uploader.hpp" @@ -13,8 +13,8 @@ jobject ToJavaHttpPayload(JNIEnv *env, const platform::HttpPayload payload) static jmethodID const constructor = jni::GetConstructorID(env, g_httpPayloadClazz, "(Ljava/lang/String;Ljava/lang/String;" - "[Lapp/organicmaps/util/KeyValue;" - "[Lapp/organicmaps/util/KeyValue;" + "[Lcom/mapswithme/util/KeyValue;" + "[Lcom/mapswithme/util/KeyValue;" "Ljava/lang/String;Ljava/lang/String;Z)V"); jni::ScopedLocalRef const method(env, jni::ToJavaString(env, payload.m_method)); @@ -33,7 +33,7 @@ jobject ToJavaHttpPayload(JNIEnv *env, const platform::HttpPayload payload) jobject MakeHttpUploader(JNIEnv * env, const platform::HttpPayload payload, jclass uploaderClass) { static jmethodID const httpUploaderConstructor = - jni::GetConstructorID(env, uploaderClass, "(Lapp/organicmaps/util/HttpPayload;)V"); + jni::GetConstructorID(env, uploaderClass, "(Lcom/mapswithme/util/HttpPayload;)V"); jni::TScopedLocalRef javaPayloadRef(env, ToJavaHttpPayload(env, payload)); diff --git a/android/jni/app/organicmaps/util/HttpUploaderUtils.hpp b/android/jni/com/mapswithme/util/HttpUploaderUtils.hpp similarity index 100% rename from android/jni/app/organicmaps/util/HttpUploaderUtils.hpp rename to android/jni/com/mapswithme/util/HttpUploaderUtils.hpp diff --git a/android/jni/com/mapswithme/util/Language.cpp b/android/jni/com/mapswithme/util/Language.cpp new file mode 100644 index 0000000000..64972101e4 --- /dev/null +++ b/android/jni/com/mapswithme/util/Language.cpp @@ -0,0 +1,12 @@ +#include "android/jni/com/mapswithme/core/jni_helper.hpp" +#include "platform/preferred_languages.hpp" + +extern "C" +{ +JNIEXPORT jstring JNICALL +Java_com_mapswithme_util_Language_nativeNormalize(JNIEnv *env, jclass type, jstring lang) +{ + std::string locale = languages::Normalize(jni::ToNativeString(env, lang)); + return jni::ToJavaString(env, locale); +} +} diff --git a/android/jni/com/mapswithme/util/LogsManager.cpp b/android/jni/com/mapswithme/util/LogsManager.cpp new file mode 100644 index 0000000000..79efa1224a --- /dev/null +++ b/android/jni/com/mapswithme/util/LogsManager.cpp @@ -0,0 +1,11 @@ +#include +#include "com/mapswithme/core/logging.hpp" + +extern "C" { +JNIEXPORT void JNICALL +Java_com_mapswithme_util_log_LogsManager_nativeToggleCoreDebugLogs( + JNIEnv * /*env*/, jclass /*clazz*/, jboolean enabled) +{ + jni::ToggleDebugLogs(enabled); +} +} // extern "C" diff --git a/android/jni/app/organicmaps/util/NetworkPolicy.cpp b/android/jni/com/mapswithme/util/NetworkPolicy.cpp similarity index 92% rename from android/jni/app/organicmaps/util/NetworkPolicy.cpp rename to android/jni/com/mapswithme/util/NetworkPolicy.cpp index 405b2d3a8b..b52fe8ccf1 100644 --- a/android/jni/app/organicmaps/util/NetworkPolicy.cpp +++ b/android/jni/com/mapswithme/util/NetworkPolicy.cpp @@ -1,4 +1,4 @@ -#include "app/organicmaps/core/jni_helper.hpp" +#include "com/mapswithme/core/jni_helper.hpp" namespace network_policy { diff --git a/android/jni/app/organicmaps/util/NetworkPolicy.hpp b/android/jni/com/mapswithme/util/NetworkPolicy.hpp similarity index 100% rename from android/jni/app/organicmaps/util/NetworkPolicy.hpp rename to android/jni/com/mapswithme/util/NetworkPolicy.hpp diff --git a/android/jni/com/mapswithme/util/StringUtils.cpp b/android/jni/com/mapswithme/util/StringUtils.cpp new file mode 100644 index 0000000000..0e225ecba4 --- /dev/null +++ b/android/jni/com/mapswithme/util/StringUtils.cpp @@ -0,0 +1,103 @@ +#include "com/mapswithme/core/jni_helper.hpp" + +#include "indexer/search_string_utils.hpp" + +#include "platform/localization.hpp" +#include "platform/measurement_utils.hpp" +#include "platform/settings.hpp" + +#include + +namespace +{ +jobject MakeJavaPair(JNIEnv * env, std::string const & first, std::string const & second) +{ + static jclass const pairClass = jni::GetGlobalClassRef(env, "android/util/Pair"); + static jmethodID const pairCtor = + jni::GetConstructorID(env, pairClass, "(Ljava/lang/Object;Ljava/lang/Object;)V"); + return env->NewObject(pairClass, pairCtor, jni::ToJavaString(env, first), + jni::ToJavaString(env, second)); +} +} // namespace + +extern "C" +{ +JNIEXPORT jboolean JNICALL +Java_com_mapswithme_util_StringUtils_nativeIsHtml(JNIEnv * env, jclass thiz, jstring text) +{ + return strings::IsHTML(jni::ToNativeString(env, text)); +} + +JNIEXPORT jboolean JNICALL +Java_com_mapswithme_util_StringUtils_nativeContainsNormalized(JNIEnv * env, jclass thiz, jstring str, jstring substr) +{ + return search::ContainsNormalized(jni::ToNativeString(env, str), jni::ToNativeString(env, substr)); +} + +JNIEXPORT jobjectArray JNICALL +Java_com_mapswithme_util_StringUtils_nativeFilterContainsNormalized(JNIEnv * env, jclass thiz, jobjectArray src, jstring jSubstr) +{ + std::string const substr = jni::ToNativeString(env, jSubstr); + int const length = env->GetArrayLength(src); + std::vector filtered; + filtered.reserve(length); + for (int i = 0; i < length; i++) + { + std::string const str = jni::ToNativeString(env, static_cast(env->GetObjectArrayElement(src, i))); + if (search::ContainsNormalized(str, substr)) + filtered.push_back(str); + } + + return jni::ToJavaStringArray(env, filtered); +} + +JNIEXPORT jobject JNICALL Java_com_mapswithme_util_StringUtils_nativeFormatSpeedAndUnits( + JNIEnv * env, jclass thiz, jdouble metersPerSecond) +{ + auto units = measurement_utils::Units::Metric; + settings::Get(settings::kMeasurementUnits, units); + return MakeJavaPair(env, measurement_utils::FormatSpeedNumeric(metersPerSecond, units), + measurement_utils::FormatSpeedUnits(units)); +} + +JNIEXPORT jstring JNICALL +Java_com_mapswithme_util_StringUtils_nativeFormatDistance(JNIEnv * env, jclass thiz, + jdouble distanceInMeters) +{ + auto const localizedUnits = platform::GetLocalizedDistanceUnits(); + return jni::ToJavaString(env, measurement_utils::FormatDistanceWithLocalization(distanceInMeters, + localizedUnits.m_high, + localizedUnits.m_low)); +} + +JNIEXPORT jstring JNICALL +Java_com_mapswithme_util_StringUtils_nativeFormatDistanceWithLocalization(JNIEnv * env, jclass, + jdouble distanceInMeters, + jstring high, + jstring low) +{ + auto const distance = measurement_utils::FormatDistanceWithLocalization( + distanceInMeters, jni::ToNativeString(env, high), jni::ToNativeString(env, low)); + return jni::ToJavaString(env, distance); +} + +JNIEXPORT jobject JNICALL +Java_com_mapswithme_util_StringUtils_nativeGetLocalizedDistanceUnits(JNIEnv * env, jclass) +{ + auto const localizedUnits = platform::GetLocalizedDistanceUnits(); + return MakeJavaPair(env, localizedUnits.m_high, localizedUnits.m_low); +} + +JNIEXPORT jobject JNICALL +Java_com_mapswithme_util_StringUtils_nativeGetLocalizedAltitudeUnits(JNIEnv * env, jclass) +{ + auto const localizedUnits = platform::GetLocalizedAltitudeUnits(); + return MakeJavaPair(env, localizedUnits.m_high, localizedUnits.m_low); +} + +JNIEXPORT jstring JNICALL +Java_com_mapswithme_util_StringUtils_nativeGetLocalizedSpeedUnits(JNIEnv * env, jclass) +{ + return jni::ToJavaString(env, platform::GetLocalizedSpeedUnits()); +} +} // extern "C" diff --git a/android/jni/app/organicmaps/vulkan/android_vulkan_context_factory.cpp b/android/jni/com/mapswithme/vulkan/android_vulkan_context_factory.cpp similarity index 99% rename from android/jni/app/organicmaps/vulkan/android_vulkan_context_factory.cpp rename to android/jni/com/mapswithme/vulkan/android_vulkan_context_factory.cpp index 4c49071cab..0f058c93a9 100644 --- a/android/jni/app/organicmaps/vulkan/android_vulkan_context_factory.cpp +++ b/android/jni/com/mapswithme/vulkan/android_vulkan_context_factory.cpp @@ -1,6 +1,6 @@ #include "android_vulkan_context_factory.hpp" -#include "app/organicmaps/platform/Platform.hpp" +#include "com/mapswithme/platform/Platform.hpp" #include "drape/drape_diagnostics.hpp" #include "drape/support_manager.hpp" diff --git a/android/jni/app/organicmaps/vulkan/android_vulkan_context_factory.hpp b/android/jni/com/mapswithme/vulkan/android_vulkan_context_factory.hpp similarity index 97% rename from android/jni/app/organicmaps/vulkan/android_vulkan_context_factory.hpp rename to android/jni/com/mapswithme/vulkan/android_vulkan_context_factory.hpp index dc6798614a..e57bb2916e 100644 --- a/android/jni/app/organicmaps/vulkan/android_vulkan_context_factory.hpp +++ b/android/jni/com/mapswithme/vulkan/android_vulkan_context_factory.hpp @@ -1,6 +1,6 @@ #pragma once -#include "app/organicmaps/core/jni_helper.hpp" +#include "com/mapswithme/core/jni_helper.hpp" #include "drape/graphics_context_factory.hpp" #include "drape/vulkan/vulkan_base_context.hpp" diff --git a/android/multidex-config.txt b/android/multidex-config.txt index 0cdbed832d..669246ab7e 100644 --- a/android/multidex-config.txt +++ b/android/multidex-config.txt @@ -1,20 +1,20 @@ -app/organicmaps/maps/api/ParsingResult.class -app/organicmaps/maps/bookmarks/data/Bookmark.class -app/organicmaps/maps/bookmarks/data/ElevationInfo.class -app/organicmaps/maps/bookmarks/data/FeatureId.class -app/organicmaps/maps/bookmarks/data/MapObject.class -app/organicmaps/maps/location/PlatformSocket.class -app/organicmaps/maps/search/PopularityProvider.class -app/organicmaps/maps/widget/placepage/PlacePageData.class -app/organicmaps/util/HttpClient$Params.class -app/organicmaps/util/HttpClient.class -app/organicmaps/util/HttpPayload.class -app/organicmaps/util/HttpUploader$Result.class -app/organicmaps/util/HttpUploader.class -app/organicmaps/util/KeyValue.class -app/organicmaps/util/SharedPropertiesUtils.class -app/organicmaps/util/log/Logger.class -app/organicmaps/util/log/LogsManager.class -app/organicmaps/util/NetworkPolicy.class -app/organicmaps/util/sharing/ShareableInfoProvider.class -app/organicmaps/util/Utils.class +com/mapswithme/maps/api/ParsingResult.class +com/mapswithme/maps/bookmarks/data/Bookmark.class +com/mapswithme/maps/bookmarks/data/ElevationInfo.class +com/mapswithme/maps/bookmarks/data/FeatureId.class +com/mapswithme/maps/bookmarks/data/MapObject.class +com/mapswithme/maps/location/PlatformSocket.class +com/mapswithme/maps/search/PopularityProvider.class +com/mapswithme/maps/widget/placepage/PlacePageData.class +com/mapswithme/util/HttpClient$Params.class +com/mapswithme/util/HttpClient.class +com/mapswithme/util/HttpPayload.class +com/mapswithme/util/HttpUploader$Result.class +com/mapswithme/util/HttpUploader.class +com/mapswithme/util/KeyValue.class +com/mapswithme/util/SharedPropertiesUtils.class +com/mapswithme/util/log/Logger.class +com/mapswithme/util/log/LogsManager.class +com/mapswithme/util/NetworkPolicy.class +com/mapswithme/util/sharing/ShareableInfoProvider.class +com/mapswithme/util/Utils.class diff --git a/android/proguard-mwm.txt b/android/proguard-mwm.txt index be80b77d4c..9562c5bb3b 100644 --- a/android/proguard-mwm.txt +++ b/android/proguard-mwm.txt @@ -7,10 +7,10 @@ -keep class !android.support.v7.internal.view.menu.**,** {*;} # Gson support --keep class app.organicmaps.util.Gsonable --keep class * implements app.organicmaps.util.Gsonable +-keep class com.mapswithme.util.Gsonable +-keep class * implements com.mapswithme.util.Gsonable --keepclassmembernames class * implements app.organicmaps.util.Gsonable { +-keepclassmembernames class * implements com.mapswithme.util.Gsonable { !transient ; } @@ -18,15 +18,15 @@ # Execution failed for task ':minifyFdroidReleaseWithR8'. # > com.android.tools.r8.CompilationFailedException: Compilation failed to complete # Optimizing leads to crashes like -# No pending exception expected: java.lang.ClassNotFoundException: Didn't find class "app.organicmaps.util.HttpClient" +# No pending exception expected: java.lang.ClassNotFoundException: Didn't find class "com.mapswithme.util.HttpClient" # It requires to manually mark all methods and classes called from NDK. -dontoptimize --keepnames class * implements app.organicmaps.util.Gsonable { +-keepnames class * implements com.mapswithme.util.Gsonable { !transient ; } --keepclassmembers class * implements app.organicmaps.util.Gsonable { +-keepclassmembers class * implements com.mapswithme.util.Gsonable { (...); } @@ -36,5 +36,3 @@ -dontwarn androidx.** -keep class androidx.** { *; } -keep interface androidx.** { *; } - --dontwarn javax.lang.model.element.Modifier diff --git a/android/res/color/button.xml b/android/res/color-v21/button.xml similarity index 100% rename from android/res/color/button.xml rename to android/res/color-v21/button.xml diff --git a/android/res/color/button_accent.xml b/android/res/color-v21/button_accent.xml similarity index 100% rename from android/res/color/button_accent.xml rename to android/res/color-v21/button_accent.xml diff --git a/android/res/color/button_accent_night.xml b/android/res/color-v21/button_accent_night.xml similarity index 100% rename from android/res/color/button_accent_night.xml rename to android/res/color-v21/button_accent_night.xml diff --git a/android/res/color/button_night.xml b/android/res/color-v21/button_night.xml similarity index 100% rename from android/res/color/button_night.xml rename to android/res/color-v21/button_night.xml diff --git a/android/res/color-v21/button_text_ghost_night.xml b/android/res/color-v21/button_text_ghost_night.xml new file mode 100644 index 0000000000..7be887c7d4 --- /dev/null +++ b/android/res/color-v21/button_text_ghost_night.xml @@ -0,0 +1,6 @@ + + + + + diff --git a/android/res/color/button_text_ghost.xml b/android/res/color/button_text_ghost.xml new file mode 100644 index 0000000000..3a913171da --- /dev/null +++ b/android/res/color/button_text_ghost.xml @@ -0,0 +1,6 @@ + + + + + diff --git a/android/res/color/filter_date_property_color.xml b/android/res/color/filter_date_property_color.xml new file mode 100644 index 0000000000..e8b90a1a51 --- /dev/null +++ b/android/res/color/filter_date_property_color.xml @@ -0,0 +1,5 @@ + + + + + diff --git a/android/res/color/filter_date_property_color_night.xml b/android/res/color/filter_date_property_color_night.xml new file mode 100644 index 0000000000..afbecca758 --- /dev/null +++ b/android/res/color/filter_date_property_color_night.xml @@ -0,0 +1,5 @@ + + + + + diff --git a/android/res/color/icon_tint_selector.xml b/android/res/color/icon_tint_selector.xml new file mode 100644 index 0000000000..1608f0fb9c --- /dev/null +++ b/android/res/color/icon_tint_selector.xml @@ -0,0 +1,5 @@ + + + + + diff --git a/android/res/drawable-hdpi/bg_place_page_head_closed.9.png b/android/res/drawable-hdpi/bg_place_page_head_closed.9.png new file mode 100644 index 0000000000..d2a960d292 Binary files /dev/null and b/android/res/drawable-hdpi/bg_place_page_head_closed.9.png differ diff --git a/android/res/drawable-hdpi/bg_place_page_head_closed_night.9.png b/android/res/drawable-hdpi/bg_place_page_head_closed_night.9.png new file mode 100644 index 0000000000..dc0bfd898e Binary files /dev/null and b/android/res/drawable-hdpi/bg_place_page_head_closed_night.9.png differ diff --git a/android/res/drawable-hdpi/bg_place_page_head_open.9.png b/android/res/drawable-hdpi/bg_place_page_head_open.9.png new file mode 100644 index 0000000000..7938785da2 Binary files /dev/null and b/android/res/drawable-hdpi/bg_place_page_head_open.9.png differ diff --git a/android/res/drawable-hdpi/bg_place_page_head_open_night.9.png b/android/res/drawable-hdpi/bg_place_page_head_open_night.9.png new file mode 100644 index 0000000000..245b221a4b Binary files /dev/null and b/android/res/drawable-hdpi/bg_place_page_head_open_night.9.png differ diff --git a/android/res/drawable-hdpi/card_frame.9.png b/android/res/drawable-hdpi/card_frame.9.png new file mode 100644 index 0000000000..f63d633db7 Binary files /dev/null and b/android/res/drawable-hdpi/card_frame.9.png differ diff --git a/android/res/drawable-hdpi/card_frame_night.9.png b/android/res/drawable-hdpi/card_frame_night.9.png new file mode 100644 index 0000000000..95e7f8c5c4 Binary files /dev/null and b/android/res/drawable-hdpi/card_frame_night.9.png differ diff --git a/android/res/drawable-hdpi/ic_24px_clear.webp b/android/res/drawable-hdpi/ic_24px_clear.webp new file mode 100644 index 0000000000..adcbf894c3 Binary files /dev/null and b/android/res/drawable-hdpi/ic_24px_clear.webp differ diff --git a/android/res/drawable-hdpi/ic_24px_rating_bad.webp b/android/res/drawable-hdpi/ic_24px_rating_bad.webp new file mode 100644 index 0000000000..be07227e37 Binary files /dev/null and b/android/res/drawable-hdpi/ic_24px_rating_bad.webp differ diff --git a/android/res/drawable-hdpi/ic_24px_rating_coming_soon.webp b/android/res/drawable-hdpi/ic_24px_rating_coming_soon.webp new file mode 100644 index 0000000000..eafcff43f0 Binary files /dev/null and b/android/res/drawable-hdpi/ic_24px_rating_coming_soon.webp differ diff --git a/android/res/drawable-hdpi/ic_24px_rating_excellent.webp b/android/res/drawable-hdpi/ic_24px_rating_excellent.webp new file mode 100644 index 0000000000..86c7eb6360 Binary files /dev/null and b/android/res/drawable-hdpi/ic_24px_rating_excellent.webp differ diff --git a/android/res/drawable-hdpi/ic_24px_rating_good.webp b/android/res/drawable-hdpi/ic_24px_rating_good.webp new file mode 100644 index 0000000000..d2bd77b6ea Binary files /dev/null and b/android/res/drawable-hdpi/ic_24px_rating_good.webp differ diff --git a/android/res/drawable-hdpi/ic_24px_rating_horrible.webp b/android/res/drawable-hdpi/ic_24px_rating_horrible.webp new file mode 100644 index 0000000000..9dc508de95 Binary files /dev/null and b/android/res/drawable-hdpi/ic_24px_rating_horrible.webp differ diff --git a/android/res/drawable-hdpi/ic_24px_rating_normal.webp b/android/res/drawable-hdpi/ic_24px_rating_normal.webp new file mode 100644 index 0000000000..8879df9a8f Binary files /dev/null and b/android/res/drawable-hdpi/ic_24px_rating_normal.webp differ diff --git a/android/res/drawable-hdpi/ic_24px_route_point_a.webp b/android/res/drawable-hdpi/ic_24px_route_point_a.webp new file mode 100644 index 0000000000..3ac6a7b298 Binary files /dev/null and b/android/res/drawable-hdpi/ic_24px_route_point_a.webp differ diff --git a/android/res/drawable-hdpi/ic_24px_route_point_b.webp b/android/res/drawable-hdpi/ic_24px_route_point_b.webp new file mode 100644 index 0000000000..23e842bc0f Binary files /dev/null and b/android/res/drawable-hdpi/ic_24px_route_point_b.webp differ diff --git a/android/res/drawable-hdpi/ic_24px_route_point_c.webp b/android/res/drawable-hdpi/ic_24px_route_point_c.webp new file mode 100644 index 0000000000..c99d840b9f Binary files /dev/null and b/android/res/drawable-hdpi/ic_24px_route_point_c.webp differ diff --git a/android/res/drawable-hdpi/ic_ab_left.webp b/android/res/drawable-hdpi/ic_ab_left.webp new file mode 100644 index 0000000000..37d16c0324 Binary files /dev/null and b/android/res/drawable-hdpi/ic_ab_left.webp differ diff --git a/android/res/drawable-hdpi/ic_ab_right.webp b/android/res/drawable-hdpi/ic_ab_right.webp new file mode 100644 index 0000000000..4b23695c1f Binary files /dev/null and b/android/res/drawable-hdpi/ic_ab_right.webp differ diff --git a/android/res/drawable-hdpi/ic_ad_dark.webp b/android/res/drawable-hdpi/ic_ad_dark.webp new file mode 100644 index 0000000000..f91f4957e1 Binary files /dev/null and b/android/res/drawable-hdpi/ic_ad_dark.webp differ diff --git a/android/res/drawable-hdpi/ic_ad_light.webp b/android/res/drawable-hdpi/ic_ad_light.webp new file mode 100644 index 0000000000..f91f4957e1 Binary files /dev/null and b/android/res/drawable-hdpi/ic_ad_light.webp differ diff --git a/android/res/drawable-hdpi/ic_booking.webp b/android/res/drawable-hdpi/ic_booking.webp new file mode 100644 index 0000000000..daf9252145 Binary files /dev/null and b/android/res/drawable-hdpi/ic_booking.webp differ diff --git a/android/res/drawable-hdpi/ic_chevron_right_white.webp b/android/res/drawable-hdpi/ic_chevron_right_white.webp new file mode 100644 index 0000000000..b2d1ff5b39 Binary files /dev/null and b/android/res/drawable-hdpi/ic_chevron_right_white.webp differ diff --git a/android/res/drawable-hdpi/ic_clear.webp b/android/res/drawable-hdpi/ic_clear.webp new file mode 100644 index 0000000000..d69517e0e9 Binary files /dev/null and b/android/res/drawable-hdpi/ic_clear.webp differ diff --git a/android/res/drawable-hdpi/ic_deal_dark.webp b/android/res/drawable-hdpi/ic_deal_dark.webp new file mode 100644 index 0000000000..8fb191f39d Binary files /dev/null and b/android/res/drawable-hdpi/ic_deal_dark.webp differ diff --git a/android/res/drawable-hdpi/ic_deal_light.webp b/android/res/drawable-hdpi/ic_deal_light.webp new file mode 100644 index 0000000000..60f078fe2d Binary files /dev/null and b/android/res/drawable-hdpi/ic_deal_light.webp differ diff --git a/android/res/drawable-hdpi/ic_discovery_error.webp b/android/res/drawable-hdpi/ic_discovery_error.webp new file mode 100644 index 0000000000..6dc05ca7a8 Binary files /dev/null and b/android/res/drawable-hdpi/ic_discovery_error.webp differ diff --git a/android/res/drawable-hdpi/ic_dog_bg.webp b/android/res/drawable-hdpi/ic_dog_bg.webp new file mode 100644 index 0000000000..3d7ce6ef64 Binary files /dev/null and b/android/res/drawable-hdpi/ic_dog_bg.webp differ diff --git a/android/res/drawable-hdpi/ic_dog_bg_night.webp b/android/res/drawable-hdpi/ic_dog_bg_night.webp new file mode 100644 index 0000000000..9e0790cb95 Binary files /dev/null and b/android/res/drawable-hdpi/ic_dog_bg_night.webp differ diff --git a/android/res/drawable-hdpi/ic_drop_down.webp b/android/res/drawable-hdpi/ic_drop_down.webp new file mode 100644 index 0000000000..e5c6888514 Binary files /dev/null and b/android/res/drawable-hdpi/ic_drop_down.webp differ diff --git a/android/res/drawable-hdpi/ic_error_36px.webp b/android/res/drawable-hdpi/ic_error_36px.webp new file mode 100644 index 0000000000..8b21b797c4 Binary files /dev/null and b/android/res/drawable-hdpi/ic_error_36px.webp differ diff --git a/android/res/drawable-hdpi/ic_error_red.webp b/android/res/drawable-hdpi/ic_error_red.webp new file mode 100644 index 0000000000..d2c0151973 Binary files /dev/null and b/android/res/drawable-hdpi/ic_error_red.webp differ diff --git a/android/res/drawable-hdpi/ic_filter_list.webp b/android/res/drawable-hdpi/ic_filter_list.webp new file mode 100644 index 0000000000..6300b76745 Binary files /dev/null and b/android/res/drawable-hdpi/ic_filter_list.webp differ diff --git a/android/res/drawable-hdpi/ic_globe.webp b/android/res/drawable-hdpi/ic_globe.webp new file mode 100644 index 0000000000..47976243b6 Binary files /dev/null and b/android/res/drawable-hdpi/ic_globe.webp differ diff --git a/android/res/drawable-hdpi/ic_leaderboard.webp b/android/res/drawable-hdpi/ic_leaderboard.webp new file mode 100644 index 0000000000..b72066be27 Binary files /dev/null and b/android/res/drawable-hdpi/ic_leaderboard.webp differ diff --git a/android/res/drawable-hdpi/ic_link.webp b/android/res/drawable-hdpi/ic_link.webp new file mode 100644 index 0000000000..b5e0525328 Binary files /dev/null and b/android/res/drawable-hdpi/ic_link.webp differ diff --git a/android/res/drawable-hdpi/ic_local_expert_default.webp b/android/res/drawable-hdpi/ic_local_expert_default.webp new file mode 100644 index 0000000000..667dae3f56 Binary files /dev/null and b/android/res/drawable-hdpi/ic_local_expert_default.webp differ diff --git a/android/res/drawable-hdpi/ic_logo_uber.webp b/android/res/drawable-hdpi/ic_logo_uber.webp new file mode 100644 index 0000000000..bf3df3795c Binary files /dev/null and b/android/res/drawable-hdpi/ic_logo_uber.webp differ diff --git a/android/res/drawable-hdpi/ic_logo_yandex_taxi.webp b/android/res/drawable-hdpi/ic_logo_yandex_taxi.webp new file mode 100644 index 0000000000..bf3df3795c Binary files /dev/null and b/android/res/drawable-hdpi/ic_logo_yandex_taxi.webp differ diff --git a/android/res/drawable-hdpi/ic_minus_red.webp b/android/res/drawable-hdpi/ic_minus_red.webp new file mode 100644 index 0000000000..8240fcbc25 Binary files /dev/null and b/android/res/drawable-hdpi/ic_minus_red.webp differ diff --git a/android/res/drawable-hdpi/ic_navigation_light.webp b/android/res/drawable-hdpi/ic_navigation_light.webp new file mode 100644 index 0000000000..f6aa8fd7d5 Binary files /dev/null and b/android/res/drawable-hdpi/ic_navigation_light.webp differ diff --git a/android/res/drawable-hdpi/ic_opentable.webp b/android/res/drawable-hdpi/ic_opentable.webp new file mode 100644 index 0000000000..87cb197ce7 Binary files /dev/null and b/android/res/drawable-hdpi/ic_opentable.webp differ diff --git a/android/res/drawable-hdpi/ic_planning_route_isomaps_dark_on.webp b/android/res/drawable-hdpi/ic_planning_route_isomaps_dark_on.webp new file mode 100644 index 0000000000..caaac92da3 Binary files /dev/null and b/android/res/drawable-hdpi/ic_planning_route_isomaps_dark_on.webp differ diff --git a/android/res/drawable-hdpi/ic_plus_green.webp b/android/res/drawable-hdpi/ic_plus_green.webp new file mode 100644 index 0000000000..8bb042a3bd Binary files /dev/null and b/android/res/drawable-hdpi/ic_plus_green.webp differ diff --git a/android/res/drawable-hdpi/ic_rate_empty.webp b/android/res/drawable-hdpi/ic_rate_empty.webp new file mode 100644 index 0000000000..8556bdf724 Binary files /dev/null and b/android/res/drawable-hdpi/ic_rate_empty.webp differ diff --git a/android/res/drawable-hdpi/ic_rate_full.webp b/android/res/drawable-hdpi/ic_rate_full.webp new file mode 100644 index 0000000000..9f1d27363a Binary files /dev/null and b/android/res/drawable-hdpi/ic_rate_full.webp differ diff --git a/android/res/drawable-hdpi/ic_review_active_12.webp b/android/res/drawable-hdpi/ic_review_active_12.webp new file mode 100644 index 0000000000..58cdf9aabd Binary files /dev/null and b/android/res/drawable-hdpi/ic_review_active_12.webp differ diff --git a/android/res/drawable-hdpi/ic_review_active_24.webp b/android/res/drawable-hdpi/ic_review_active_24.webp new file mode 100644 index 0000000000..11de231f06 Binary files /dev/null and b/android/res/drawable-hdpi/ic_review_active_24.webp differ diff --git a/android/res/drawable-hdpi/ic_review_disable_dark_12.webp b/android/res/drawable-hdpi/ic_review_disable_dark_12.webp new file mode 100644 index 0000000000..58cdf9aabd Binary files /dev/null and b/android/res/drawable-hdpi/ic_review_disable_dark_12.webp differ diff --git a/android/res/drawable-hdpi/ic_review_disable_dark_24.webp b/android/res/drawable-hdpi/ic_review_disable_dark_24.webp new file mode 100644 index 0000000000..11de231f06 Binary files /dev/null and b/android/res/drawable-hdpi/ic_review_disable_dark_24.webp differ diff --git a/android/res/drawable-hdpi/ic_review_disable_light_12.webp b/android/res/drawable-hdpi/ic_review_disable_light_12.webp new file mode 100644 index 0000000000..58cdf9aabd Binary files /dev/null and b/android/res/drawable-hdpi/ic_review_disable_light_12.webp differ diff --git a/android/res/drawable-hdpi/ic_review_disable_light_24.webp b/android/res/drawable-hdpi/ic_review_disable_light_24.webp new file mode 100644 index 0000000000..d668ebf7bf Binary files /dev/null and b/android/res/drawable-hdpi/ic_review_disable_light_24.webp differ diff --git a/android/res/drawable-hdpi/ic_routing_search_on.webp b/android/res/drawable-hdpi/ic_routing_search_on.webp new file mode 100644 index 0000000000..66e0f4cc67 Binary files /dev/null and b/android/res/drawable-hdpi/ic_routing_search_on.webp differ diff --git a/android/res/drawable-hdpi/ic_search.webp b/android/res/drawable-hdpi/ic_search.webp new file mode 100644 index 0000000000..958909f98f Binary files /dev/null and b/android/res/drawable-hdpi/ic_search.webp differ diff --git a/android/res/drawable-hdpi/ic_setting_traffic_off.webp b/android/res/drawable-hdpi/ic_setting_traffic_off.webp new file mode 100644 index 0000000000..3f9f7396b0 Binary files /dev/null and b/android/res/drawable-hdpi/ic_setting_traffic_off.webp differ diff --git a/android/res/drawable-hdpi/ic_setting_traffic_on.webp b/android/res/drawable-hdpi/ic_setting_traffic_on.webp new file mode 100644 index 0000000000..78ac9400e6 Binary files /dev/null and b/android/res/drawable-hdpi/ic_setting_traffic_on.webp differ diff --git a/android/res/drawable-hdpi/ic_sightseeing_checkox.webp b/android/res/drawable-hdpi/ic_sightseeing_checkox.webp new file mode 100644 index 0000000000..4f9cece2fe Binary files /dev/null and b/android/res/drawable-hdpi/ic_sightseeing_checkox.webp differ diff --git a/android/res/drawable-hdpi/ic_star_small.webp b/android/res/drawable-hdpi/ic_star_small.webp new file mode 100644 index 0000000000..2db1eac79c Binary files /dev/null and b/android/res/drawable-hdpi/ic_star_small.webp differ diff --git a/android/res/drawable-hdpi/ic_star_small_full.webp b/android/res/drawable-hdpi/ic_star_small_full.webp new file mode 100644 index 0000000000..89aafb5537 Binary files /dev/null and b/android/res/drawable-hdpi/ic_star_small_full.webp differ diff --git a/android/res/drawable-hdpi/ic_taxi_logo_maksim.webp b/android/res/drawable-hdpi/ic_taxi_logo_maksim.webp new file mode 100644 index 0000000000..bf3df3795c Binary files /dev/null and b/android/res/drawable-hdpi/ic_taxi_logo_maksim.webp differ diff --git a/android/res/drawable-hdpi/ic_taxi_logo_vezet.webp b/android/res/drawable-hdpi/ic_taxi_logo_vezet.webp new file mode 100644 index 0000000000..bf3df3795c Binary files /dev/null and b/android/res/drawable-hdpi/ic_taxi_logo_vezet.webp differ diff --git a/android/res/drawable-hdpi/ic_undo.webp b/android/res/drawable-hdpi/ic_undo.webp new file mode 100644 index 0000000000..f917ef697c Binary files /dev/null and b/android/res/drawable-hdpi/ic_undo.webp differ diff --git a/android/res/drawable-hdpi/ic_wikicommons.webp b/android/res/drawable-hdpi/ic_wikicommons.webp new file mode 100644 index 0000000000..14510bf6c7 Binary files /dev/null and b/android/res/drawable-hdpi/ic_wikicommons.webp differ diff --git a/android/res/drawable-hdpi/img_auth.webp b/android/res/drawable-hdpi/img_auth.webp new file mode 100644 index 0000000000..05b0f8b1d6 Binary files /dev/null and b/android/res/drawable-hdpi/img_auth.webp differ diff --git a/android/res/drawable-hdpi/img_editor_medal.webp b/android/res/drawable-hdpi/img_editor_medal.webp new file mode 100644 index 0000000000..cda77f51e9 Binary files /dev/null and b/android/res/drawable-hdpi/img_editor_medal.webp differ diff --git a/android/res/drawable-hdpi/img_sightseeing_footer.webp b/android/res/drawable-hdpi/img_sightseeing_footer.webp new file mode 100644 index 0000000000..703308679a Binary files /dev/null and b/android/res/drawable-hdpi/img_sightseeing_footer.webp differ diff --git a/android/res/drawable-hdpi/logo_luggagehero_dark.webp b/android/res/drawable-hdpi/logo_luggagehero_dark.webp new file mode 100644 index 0000000000..f3589df3b9 Binary files /dev/null and b/android/res/drawable-hdpi/logo_luggagehero_dark.webp differ diff --git a/android/res/drawable-hdpi/logo_luggagehero_light.webp b/android/res/drawable-hdpi/logo_luggagehero_light.webp new file mode 100644 index 0000000000..f3589df3b9 Binary files /dev/null and b/android/res/drawable-hdpi/logo_luggagehero_light.webp differ diff --git a/android/res/drawable-hdpi/wn_autoupdate.webp b/android/res/drawable-hdpi/wn_autoupdate.webp new file mode 100644 index 0000000000..4c7543b47a Binary files /dev/null and b/android/res/drawable-hdpi/wn_autoupdate.webp differ diff --git a/android/res/drawable-mdpi/bg_place_page_head_closed.9.png b/android/res/drawable-mdpi/bg_place_page_head_closed.9.png new file mode 100644 index 0000000000..01b77d1025 Binary files /dev/null and b/android/res/drawable-mdpi/bg_place_page_head_closed.9.png differ diff --git a/android/res/drawable-mdpi/bg_place_page_head_closed_night.9.png b/android/res/drawable-mdpi/bg_place_page_head_closed_night.9.png new file mode 100644 index 0000000000..1ab0e2178c Binary files /dev/null and b/android/res/drawable-mdpi/bg_place_page_head_closed_night.9.png differ diff --git a/android/res/drawable-mdpi/bg_place_page_head_open.9.png b/android/res/drawable-mdpi/bg_place_page_head_open.9.png new file mode 100644 index 0000000000..f7aa91eac8 Binary files /dev/null and b/android/res/drawable-mdpi/bg_place_page_head_open.9.png differ diff --git a/android/res/drawable-mdpi/bg_place_page_head_open_night.9.png b/android/res/drawable-mdpi/bg_place_page_head_open_night.9.png new file mode 100644 index 0000000000..9dc6f8e6aa Binary files /dev/null and b/android/res/drawable-mdpi/bg_place_page_head_open_night.9.png differ diff --git a/android/res/drawable-mdpi/card_frame.9.png b/android/res/drawable-mdpi/card_frame.9.png new file mode 100644 index 0000000000..911db6f4e4 Binary files /dev/null and b/android/res/drawable-mdpi/card_frame.9.png differ diff --git a/android/res/drawable-mdpi/card_frame_night.9.png b/android/res/drawable-mdpi/card_frame_night.9.png new file mode 100644 index 0000000000..81ef1e77d9 Binary files /dev/null and b/android/res/drawable-mdpi/card_frame_night.9.png differ diff --git a/android/res/drawable-mdpi/ic_24px_clear.webp b/android/res/drawable-mdpi/ic_24px_clear.webp new file mode 100644 index 0000000000..158c44fe70 Binary files /dev/null and b/android/res/drawable-mdpi/ic_24px_clear.webp differ diff --git a/android/res/drawable-mdpi/ic_24px_rating_bad.webp b/android/res/drawable-mdpi/ic_24px_rating_bad.webp new file mode 100644 index 0000000000..2e9df50628 Binary files /dev/null and b/android/res/drawable-mdpi/ic_24px_rating_bad.webp differ diff --git a/android/res/drawable-mdpi/ic_24px_rating_coming_soon.webp b/android/res/drawable-mdpi/ic_24px_rating_coming_soon.webp new file mode 100644 index 0000000000..9b87dd7725 Binary files /dev/null and b/android/res/drawable-mdpi/ic_24px_rating_coming_soon.webp differ diff --git a/android/res/drawable-mdpi/ic_24px_rating_excellent.webp b/android/res/drawable-mdpi/ic_24px_rating_excellent.webp new file mode 100644 index 0000000000..7def4bce35 Binary files /dev/null and b/android/res/drawable-mdpi/ic_24px_rating_excellent.webp differ diff --git a/android/res/drawable-mdpi/ic_24px_rating_good.webp b/android/res/drawable-mdpi/ic_24px_rating_good.webp new file mode 100644 index 0000000000..42b3274505 Binary files /dev/null and b/android/res/drawable-mdpi/ic_24px_rating_good.webp differ diff --git a/android/res/drawable-mdpi/ic_24px_rating_horrible.webp b/android/res/drawable-mdpi/ic_24px_rating_horrible.webp new file mode 100644 index 0000000000..b81a7e60bd Binary files /dev/null and b/android/res/drawable-mdpi/ic_24px_rating_horrible.webp differ diff --git a/android/res/drawable-mdpi/ic_24px_rating_normal.webp b/android/res/drawable-mdpi/ic_24px_rating_normal.webp new file mode 100644 index 0000000000..112144a57f Binary files /dev/null and b/android/res/drawable-mdpi/ic_24px_rating_normal.webp differ diff --git a/android/res/drawable-mdpi/ic_24px_route_point_a.webp b/android/res/drawable-mdpi/ic_24px_route_point_a.webp new file mode 100644 index 0000000000..e35e36085d Binary files /dev/null and b/android/res/drawable-mdpi/ic_24px_route_point_a.webp differ diff --git a/android/res/drawable-mdpi/ic_24px_route_point_b.webp b/android/res/drawable-mdpi/ic_24px_route_point_b.webp new file mode 100644 index 0000000000..4b1ad3388c Binary files /dev/null and b/android/res/drawable-mdpi/ic_24px_route_point_b.webp differ diff --git a/android/res/drawable-mdpi/ic_24px_route_point_c.webp b/android/res/drawable-mdpi/ic_24px_route_point_c.webp new file mode 100644 index 0000000000..9b02507ba2 Binary files /dev/null and b/android/res/drawable-mdpi/ic_24px_route_point_c.webp differ diff --git a/android/res/drawable-mdpi/ic_ab_left.webp b/android/res/drawable-mdpi/ic_ab_left.webp new file mode 100644 index 0000000000..2b77d9b126 Binary files /dev/null and b/android/res/drawable-mdpi/ic_ab_left.webp differ diff --git a/android/res/drawable-mdpi/ic_ab_right.webp b/android/res/drawable-mdpi/ic_ab_right.webp new file mode 100644 index 0000000000..abe3c98338 Binary files /dev/null and b/android/res/drawable-mdpi/ic_ab_right.webp differ diff --git a/android/res/drawable-mdpi/ic_ad_dark.webp b/android/res/drawable-mdpi/ic_ad_dark.webp new file mode 100644 index 0000000000..9077519bc8 Binary files /dev/null and b/android/res/drawable-mdpi/ic_ad_dark.webp differ diff --git a/android/res/drawable-mdpi/ic_ad_light.webp b/android/res/drawable-mdpi/ic_ad_light.webp new file mode 100644 index 0000000000..9077519bc8 Binary files /dev/null and b/android/res/drawable-mdpi/ic_ad_light.webp differ diff --git a/android/res/drawable-mdpi/ic_booking.webp b/android/res/drawable-mdpi/ic_booking.webp new file mode 100644 index 0000000000..8ba1a8a2e3 Binary files /dev/null and b/android/res/drawable-mdpi/ic_booking.webp differ diff --git a/android/res/drawable-mdpi/ic_chevron_right_white.webp b/android/res/drawable-mdpi/ic_chevron_right_white.webp new file mode 100644 index 0000000000..a5ef99308e Binary files /dev/null and b/android/res/drawable-mdpi/ic_chevron_right_white.webp differ diff --git a/android/res/drawable-mdpi/ic_clear.webp b/android/res/drawable-mdpi/ic_clear.webp new file mode 100644 index 0000000000..6c7ee9b777 Binary files /dev/null and b/android/res/drawable-mdpi/ic_clear.webp differ diff --git a/android/res/drawable-mdpi/ic_deal_dark.webp b/android/res/drawable-mdpi/ic_deal_dark.webp new file mode 100644 index 0000000000..59e0a07f19 Binary files /dev/null and b/android/res/drawable-mdpi/ic_deal_dark.webp differ diff --git a/android/res/drawable-mdpi/ic_deal_light.webp b/android/res/drawable-mdpi/ic_deal_light.webp new file mode 100644 index 0000000000..312893b16a Binary files /dev/null and b/android/res/drawable-mdpi/ic_deal_light.webp differ diff --git a/android/res/drawable-mdpi/ic_discovery_error.webp b/android/res/drawable-mdpi/ic_discovery_error.webp new file mode 100644 index 0000000000..f4f8789808 Binary files /dev/null and b/android/res/drawable-mdpi/ic_discovery_error.webp differ diff --git a/android/res/drawable-mdpi/ic_dog_bg.webp b/android/res/drawable-mdpi/ic_dog_bg.webp new file mode 100644 index 0000000000..2b6b4d6b65 Binary files /dev/null and b/android/res/drawable-mdpi/ic_dog_bg.webp differ diff --git a/android/res/drawable-mdpi/ic_dog_bg_night.webp b/android/res/drawable-mdpi/ic_dog_bg_night.webp new file mode 100644 index 0000000000..64fbbb7900 Binary files /dev/null and b/android/res/drawable-mdpi/ic_dog_bg_night.webp differ diff --git a/android/res/drawable-mdpi/ic_drop_down.webp b/android/res/drawable-mdpi/ic_drop_down.webp new file mode 100644 index 0000000000..44e5145aea Binary files /dev/null and b/android/res/drawable-mdpi/ic_drop_down.webp differ diff --git a/android/res/drawable-mdpi/ic_error_36px.webp b/android/res/drawable-mdpi/ic_error_36px.webp new file mode 100644 index 0000000000..a364b24729 Binary files /dev/null and b/android/res/drawable-mdpi/ic_error_36px.webp differ diff --git a/android/res/drawable-mdpi/ic_error_red.webp b/android/res/drawable-mdpi/ic_error_red.webp new file mode 100644 index 0000000000..362664d161 Binary files /dev/null and b/android/res/drawable-mdpi/ic_error_red.webp differ diff --git a/android/res/drawable-mdpi/ic_filter_list.webp b/android/res/drawable-mdpi/ic_filter_list.webp new file mode 100644 index 0000000000..a143b47da2 Binary files /dev/null and b/android/res/drawable-mdpi/ic_filter_list.webp differ diff --git a/android/res/drawable-mdpi/ic_globe.webp b/android/res/drawable-mdpi/ic_globe.webp new file mode 100644 index 0000000000..2155f9b5f6 Binary files /dev/null and b/android/res/drawable-mdpi/ic_globe.webp differ diff --git a/android/res/drawable-mdpi/ic_leaderboard.webp b/android/res/drawable-mdpi/ic_leaderboard.webp new file mode 100644 index 0000000000..259d740540 Binary files /dev/null and b/android/res/drawable-mdpi/ic_leaderboard.webp differ diff --git a/android/res/drawable-mdpi/ic_link.webp b/android/res/drawable-mdpi/ic_link.webp new file mode 100644 index 0000000000..6545f327df Binary files /dev/null and b/android/res/drawable-mdpi/ic_link.webp differ diff --git a/android/res/drawable-mdpi/ic_local_expert_default.webp b/android/res/drawable-mdpi/ic_local_expert_default.webp new file mode 100644 index 0000000000..2fde5aad4b Binary files /dev/null and b/android/res/drawable-mdpi/ic_local_expert_default.webp differ diff --git a/android/res/drawable-mdpi/ic_logo_uber.webp b/android/res/drawable-mdpi/ic_logo_uber.webp new file mode 100644 index 0000000000..a5d0bf24e0 Binary files /dev/null and b/android/res/drawable-mdpi/ic_logo_uber.webp differ diff --git a/android/res/drawable-mdpi/ic_logo_yandex_taxi.webp b/android/res/drawable-mdpi/ic_logo_yandex_taxi.webp new file mode 100644 index 0000000000..a5d0bf24e0 Binary files /dev/null and b/android/res/drawable-mdpi/ic_logo_yandex_taxi.webp differ diff --git a/android/res/drawable-mdpi/ic_minus_red.webp b/android/res/drawable-mdpi/ic_minus_red.webp new file mode 100644 index 0000000000..6a1856cfed Binary files /dev/null and b/android/res/drawable-mdpi/ic_minus_red.webp differ diff --git a/android/res/drawable-mdpi/ic_navigation_light.webp b/android/res/drawable-mdpi/ic_navigation_light.webp new file mode 100644 index 0000000000..aa9a47745c Binary files /dev/null and b/android/res/drawable-mdpi/ic_navigation_light.webp differ diff --git a/android/res/drawable-mdpi/ic_opentable.webp b/android/res/drawable-mdpi/ic_opentable.webp new file mode 100644 index 0000000000..b0529881c0 Binary files /dev/null and b/android/res/drawable-mdpi/ic_opentable.webp differ diff --git a/android/res/drawable-mdpi/ic_planning_route_isomaps_dark_on.webp b/android/res/drawable-mdpi/ic_planning_route_isomaps_dark_on.webp new file mode 100644 index 0000000000..ec198d3b6f Binary files /dev/null and b/android/res/drawable-mdpi/ic_planning_route_isomaps_dark_on.webp differ diff --git a/android/res/drawable-mdpi/ic_plus_green.webp b/android/res/drawable-mdpi/ic_plus_green.webp new file mode 100644 index 0000000000..91c14e7f9f Binary files /dev/null and b/android/res/drawable-mdpi/ic_plus_green.webp differ diff --git a/android/res/drawable-mdpi/ic_rate_empty.webp b/android/res/drawable-mdpi/ic_rate_empty.webp new file mode 100644 index 0000000000..497938bcd7 Binary files /dev/null and b/android/res/drawable-mdpi/ic_rate_empty.webp differ diff --git a/android/res/drawable-mdpi/ic_rate_full.webp b/android/res/drawable-mdpi/ic_rate_full.webp new file mode 100644 index 0000000000..7b69dfc8c4 Binary files /dev/null and b/android/res/drawable-mdpi/ic_rate_full.webp differ diff --git a/android/res/drawable-mdpi/ic_review_active_12.webp b/android/res/drawable-mdpi/ic_review_active_12.webp new file mode 100644 index 0000000000..d8c3ae50fe Binary files /dev/null and b/android/res/drawable-mdpi/ic_review_active_12.webp differ diff --git a/android/res/drawable-mdpi/ic_review_active_24.webp b/android/res/drawable-mdpi/ic_review_active_24.webp new file mode 100644 index 0000000000..8ca50cf3f1 Binary files /dev/null and b/android/res/drawable-mdpi/ic_review_active_24.webp differ diff --git a/android/res/drawable-mdpi/ic_review_disable_dark_12.webp b/android/res/drawable-mdpi/ic_review_disable_dark_12.webp new file mode 100644 index 0000000000..d8c3ae50fe Binary files /dev/null and b/android/res/drawable-mdpi/ic_review_disable_dark_12.webp differ diff --git a/android/res/drawable-mdpi/ic_review_disable_dark_24.webp b/android/res/drawable-mdpi/ic_review_disable_dark_24.webp new file mode 100644 index 0000000000..8ca50cf3f1 Binary files /dev/null and b/android/res/drawable-mdpi/ic_review_disable_dark_24.webp differ diff --git a/android/res/drawable-mdpi/ic_review_disable_light_12.webp b/android/res/drawable-mdpi/ic_review_disable_light_12.webp new file mode 100644 index 0000000000..d8c3ae50fe Binary files /dev/null and b/android/res/drawable-mdpi/ic_review_disable_light_12.webp differ diff --git a/android/res/drawable-mdpi/ic_review_disable_light_24.webp b/android/res/drawable-mdpi/ic_review_disable_light_24.webp new file mode 100644 index 0000000000..8ca50cf3f1 Binary files /dev/null and b/android/res/drawable-mdpi/ic_review_disable_light_24.webp differ diff --git a/android/res/drawable-mdpi/ic_routing_search_on.webp b/android/res/drawable-mdpi/ic_routing_search_on.webp new file mode 100644 index 0000000000..2ee204bcb0 Binary files /dev/null and b/android/res/drawable-mdpi/ic_routing_search_on.webp differ diff --git a/android/res/drawable-mdpi/ic_search.webp b/android/res/drawable-mdpi/ic_search.webp new file mode 100644 index 0000000000..562325ffe9 Binary files /dev/null and b/android/res/drawable-mdpi/ic_search.webp differ diff --git a/android/res/drawable-mdpi/ic_setting_traffic_off.webp b/android/res/drawable-mdpi/ic_setting_traffic_off.webp new file mode 100644 index 0000000000..478f8c5670 Binary files /dev/null and b/android/res/drawable-mdpi/ic_setting_traffic_off.webp differ diff --git a/android/res/drawable-mdpi/ic_setting_traffic_on.webp b/android/res/drawable-mdpi/ic_setting_traffic_on.webp new file mode 100644 index 0000000000..9338a0012e Binary files /dev/null and b/android/res/drawable-mdpi/ic_setting_traffic_on.webp differ diff --git a/android/res/drawable-mdpi/ic_sightseeing_checkox.webp b/android/res/drawable-mdpi/ic_sightseeing_checkox.webp new file mode 100644 index 0000000000..92131db6bc Binary files /dev/null and b/android/res/drawable-mdpi/ic_sightseeing_checkox.webp differ diff --git a/android/res/drawable-mdpi/ic_star_small.webp b/android/res/drawable-mdpi/ic_star_small.webp new file mode 100644 index 0000000000..7e5aedb3e4 Binary files /dev/null and b/android/res/drawable-mdpi/ic_star_small.webp differ diff --git a/android/res/drawable-mdpi/ic_star_small_full.webp b/android/res/drawable-mdpi/ic_star_small_full.webp new file mode 100644 index 0000000000..c746006f81 Binary files /dev/null and b/android/res/drawable-mdpi/ic_star_small_full.webp differ diff --git a/android/res/drawable-mdpi/ic_taxi_logo_maksim.webp b/android/res/drawable-mdpi/ic_taxi_logo_maksim.webp new file mode 100644 index 0000000000..a5d0bf24e0 Binary files /dev/null and b/android/res/drawable-mdpi/ic_taxi_logo_maksim.webp differ diff --git a/android/res/drawable-mdpi/ic_taxi_logo_vezet.webp b/android/res/drawable-mdpi/ic_taxi_logo_vezet.webp new file mode 100644 index 0000000000..a5d0bf24e0 Binary files /dev/null and b/android/res/drawable-mdpi/ic_taxi_logo_vezet.webp differ diff --git a/android/res/drawable-mdpi/ic_undo.webp b/android/res/drawable-mdpi/ic_undo.webp new file mode 100644 index 0000000000..764c99f20f Binary files /dev/null and b/android/res/drawable-mdpi/ic_undo.webp differ diff --git a/android/res/drawable-mdpi/img_auth.webp b/android/res/drawable-mdpi/img_auth.webp new file mode 100644 index 0000000000..667dae3f56 Binary files /dev/null and b/android/res/drawable-mdpi/img_auth.webp differ diff --git a/android/res/drawable-mdpi/img_editor_medal.webp b/android/res/drawable-mdpi/img_editor_medal.webp new file mode 100644 index 0000000000..c2420082fe Binary files /dev/null and b/android/res/drawable-mdpi/img_editor_medal.webp differ diff --git a/android/res/drawable-mdpi/img_sightseeing_footer.webp b/android/res/drawable-mdpi/img_sightseeing_footer.webp new file mode 100644 index 0000000000..280747cf75 Binary files /dev/null and b/android/res/drawable-mdpi/img_sightseeing_footer.webp differ diff --git a/android/res/drawable-mdpi/logo_luggagehero_dark.webp b/android/res/drawable-mdpi/logo_luggagehero_dark.webp new file mode 100644 index 0000000000..414dcab6e9 Binary files /dev/null and b/android/res/drawable-mdpi/logo_luggagehero_dark.webp differ diff --git a/android/res/drawable-mdpi/logo_luggagehero_light.webp b/android/res/drawable-mdpi/logo_luggagehero_light.webp new file mode 100644 index 0000000000..414dcab6e9 Binary files /dev/null and b/android/res/drawable-mdpi/logo_luggagehero_light.webp differ diff --git a/android/res/drawable-mdpi/wn_autoupdate.webp b/android/res/drawable-mdpi/wn_autoupdate.webp new file mode 100644 index 0000000000..cda77f51e9 Binary files /dev/null and b/android/res/drawable-mdpi/wn_autoupdate.webp differ diff --git a/android/res/drawable-v21/bg_active_icon.xml b/android/res/drawable-v21/bg_active_icon.xml new file mode 100644 index 0000000000..f9d51f4a6d --- /dev/null +++ b/android/res/drawable-v21/bg_active_icon.xml @@ -0,0 +1,15 @@ + + + + + + + + + diff --git a/android/res/drawable-v21/bg_active_icon_night.xml b/android/res/drawable-v21/bg_active_icon_night.xml new file mode 100644 index 0000000000..4213c398ca --- /dev/null +++ b/android/res/drawable-v21/bg_active_icon_night.xml @@ -0,0 +1,15 @@ + + + + + + + + + diff --git a/android/res/drawable-v21/bg_steady_icon.xml b/android/res/drawable-v21/bg_steady_icon.xml new file mode 100644 index 0000000000..a47cc39d35 --- /dev/null +++ b/android/res/drawable-v21/bg_steady_icon.xml @@ -0,0 +1,15 @@ + + + + + + + + + diff --git a/android/res/drawable-v21/bg_steady_icon_night.xml b/android/res/drawable-v21/bg_steady_icon_night.xml new file mode 100644 index 0000000000..0dc5b43b03 --- /dev/null +++ b/android/res/drawable-v21/bg_steady_icon_night.xml @@ -0,0 +1,15 @@ + + + + + + + + + diff --git a/android/res/drawable-v21/button.xml b/android/res/drawable-v21/button.xml new file mode 100644 index 0000000000..e5c2d39a13 --- /dev/null +++ b/android/res/drawable-v21/button.xml @@ -0,0 +1,10 @@ + + + + + + + + + diff --git a/android/res/drawable-v21/button_accent.xml b/android/res/drawable-v21/button_accent.xml new file mode 100644 index 0000000000..102a72b2a8 --- /dev/null +++ b/android/res/drawable-v21/button_accent.xml @@ -0,0 +1,7 @@ + + + + + diff --git a/android/res/drawable-v21/button_accent_night.xml b/android/res/drawable-v21/button_accent_night.xml new file mode 100644 index 0000000000..192a6af3ec --- /dev/null +++ b/android/res/drawable-v21/button_accent_night.xml @@ -0,0 +1,7 @@ + + + + + diff --git a/android/res/drawable-v21/button_accent_round_normal.xml b/android/res/drawable-v21/button_accent_round_normal.xml new file mode 100644 index 0000000000..41a68cc12f --- /dev/null +++ b/android/res/drawable-v21/button_accent_round_normal.xml @@ -0,0 +1,11 @@ + + + + + + + + + + diff --git a/android/res/drawable-v21/button_accent_round_normal_night.xml b/android/res/drawable-v21/button_accent_round_normal_night.xml new file mode 100644 index 0000000000..bc38fc84ab --- /dev/null +++ b/android/res/drawable-v21/button_accent_round_normal_night.xml @@ -0,0 +1,11 @@ + + + + + + + + + + diff --git a/android/res/drawable-v21/button_booking.xml b/android/res/drawable-v21/button_booking.xml new file mode 100644 index 0000000000..aa8cf6949c --- /dev/null +++ b/android/res/drawable-v21/button_booking.xml @@ -0,0 +1,9 @@ + + + + + + + + \ No newline at end of file diff --git a/android/res/drawable-v21/button_editor_light.xml b/android/res/drawable-v21/button_editor_light.xml new file mode 100644 index 0000000000..3cea8a1a18 --- /dev/null +++ b/android/res/drawable-v21/button_editor_light.xml @@ -0,0 +1,11 @@ + + + + + + + + + \ No newline at end of file diff --git a/android/res/drawable-v21/button_leave_review.xml b/android/res/drawable-v21/button_leave_review.xml new file mode 100644 index 0000000000..48006ddad6 --- /dev/null +++ b/android/res/drawable-v21/button_leave_review.xml @@ -0,0 +1,29 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/android/res/drawable-v21/button_leave_review_night.xml b/android/res/drawable-v21/button_leave_review_night.xml new file mode 100644 index 0000000000..c7b70b6cba --- /dev/null +++ b/android/res/drawable-v21/button_leave_review_night.xml @@ -0,0 +1,29 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/android/res/drawable-v21/button_night.xml b/android/res/drawable-v21/button_night.xml new file mode 100644 index 0000000000..a4f3d16e0f --- /dev/null +++ b/android/res/drawable-v21/button_night.xml @@ -0,0 +1,10 @@ + + + + + + + + + \ No newline at end of file diff --git a/android/res/drawable-v21/button_opentable.xml b/android/res/drawable-v21/button_opentable.xml new file mode 100644 index 0000000000..e1b31e63e2 --- /dev/null +++ b/android/res/drawable-v21/button_opentable.xml @@ -0,0 +1,9 @@ + + + + + + + + diff --git a/android/res/drawable-v21/button_red.xml b/android/res/drawable-v21/button_red.xml new file mode 100644 index 0000000000..f8132991f8 --- /dev/null +++ b/android/res/drawable-v21/button_red.xml @@ -0,0 +1,10 @@ + + + + + + + + + \ No newline at end of file diff --git a/android/res/drawable-v21/button_secondary_transparent.xml b/android/res/drawable-v21/button_secondary_transparent.xml new file mode 100644 index 0000000000..1cf1af4479 --- /dev/null +++ b/android/res/drawable-v21/button_secondary_transparent.xml @@ -0,0 +1,6 @@ + + + + diff --git a/android/res/drawable-v21/button_with_border.xml b/android/res/drawable-v21/button_with_border.xml new file mode 100644 index 0000000000..05899789f9 --- /dev/null +++ b/android/res/drawable-v21/button_with_border.xml @@ -0,0 +1,6 @@ + + + + diff --git a/android/res/drawable-v21/button_with_border_night.xml b/android/res/drawable-v21/button_with_border_night.xml new file mode 100644 index 0000000000..cd61a5291c --- /dev/null +++ b/android/res/drawable-v21/button_with_border_night.xml @@ -0,0 +1,6 @@ + + + + diff --git a/android/res/drawable-v21/menu_button.xml b/android/res/drawable-v21/menu_button.xml new file mode 100644 index 0000000000..5c985872ae --- /dev/null +++ b/android/res/drawable-v21/menu_button.xml @@ -0,0 +1,9 @@ + + + + + + \ No newline at end of file diff --git a/android/res/drawable-v21/menu_button_circle.xml b/android/res/drawable-v21/menu_button_circle.xml new file mode 100644 index 0000000000..b27e49cb91 --- /dev/null +++ b/android/res/drawable-v21/menu_button_circle.xml @@ -0,0 +1,8 @@ + + + + + + \ No newline at end of file diff --git a/android/res/drawable/ripple_mask.xml b/android/res/drawable-v21/ripple_mask.xml similarity index 100% rename from android/res/drawable/ripple_mask.xml rename to android/res/drawable-v21/ripple_mask.xml diff --git a/android/res/drawable-v21/routing_toolbar_button.xml b/android/res/drawable-v21/routing_toolbar_button.xml new file mode 100644 index 0000000000..d007dff933 --- /dev/null +++ b/android/res/drawable-v21/routing_toolbar_button.xml @@ -0,0 +1,13 @@ + + + + + + + + + diff --git a/android/res/drawable-v21/routing_toolbar_button_night.xml b/android/res/drawable-v21/routing_toolbar_button_night.xml new file mode 100644 index 0000000000..0be952a4b4 --- /dev/null +++ b/android/res/drawable-v21/routing_toolbar_button_night.xml @@ -0,0 +1,13 @@ + + + + + + + + + diff --git a/android/res/drawable-xhdpi/bg_place_page_head_closed.9.png b/android/res/drawable-xhdpi/bg_place_page_head_closed.9.png new file mode 100644 index 0000000000..2f3c0edf62 Binary files /dev/null and b/android/res/drawable-xhdpi/bg_place_page_head_closed.9.png differ diff --git a/android/res/drawable-xhdpi/bg_place_page_head_closed_night.9.png b/android/res/drawable-xhdpi/bg_place_page_head_closed_night.9.png new file mode 100644 index 0000000000..f1ecc44364 Binary files /dev/null and b/android/res/drawable-xhdpi/bg_place_page_head_closed_night.9.png differ diff --git a/android/res/drawable-xhdpi/bg_place_page_head_open.9.png b/android/res/drawable-xhdpi/bg_place_page_head_open.9.png new file mode 100644 index 0000000000..4b7d38c9f8 Binary files /dev/null and b/android/res/drawable-xhdpi/bg_place_page_head_open.9.png differ diff --git a/android/res/drawable-xhdpi/bg_place_page_head_open_night.9.png b/android/res/drawable-xhdpi/bg_place_page_head_open_night.9.png new file mode 100644 index 0000000000..94b7b4ca82 Binary files /dev/null and b/android/res/drawable-xhdpi/bg_place_page_head_open_night.9.png differ diff --git a/android/res/drawable-xhdpi/card_frame.9.png b/android/res/drawable-xhdpi/card_frame.9.png new file mode 100644 index 0000000000..8da4678639 Binary files /dev/null and b/android/res/drawable-xhdpi/card_frame.9.png differ diff --git a/android/res/drawable-xhdpi/card_frame_night.9.png b/android/res/drawable-xhdpi/card_frame_night.9.png new file mode 100644 index 0000000000..72133cc86e Binary files /dev/null and b/android/res/drawable-xhdpi/card_frame_night.9.png differ diff --git a/android/res/drawable-xhdpi/ic_24px_clear.webp b/android/res/drawable-xhdpi/ic_24px_clear.webp new file mode 100644 index 0000000000..7c6db7b82e Binary files /dev/null and b/android/res/drawable-xhdpi/ic_24px_clear.webp differ diff --git a/android/res/drawable-xhdpi/ic_24px_rating_bad.webp b/android/res/drawable-xhdpi/ic_24px_rating_bad.webp new file mode 100644 index 0000000000..c65f8914b5 Binary files /dev/null and b/android/res/drawable-xhdpi/ic_24px_rating_bad.webp differ diff --git a/android/res/drawable-xhdpi/ic_24px_rating_coming_soon.webp b/android/res/drawable-xhdpi/ic_24px_rating_coming_soon.webp new file mode 100644 index 0000000000..08a9970a05 Binary files /dev/null and b/android/res/drawable-xhdpi/ic_24px_rating_coming_soon.webp differ diff --git a/android/res/drawable-xhdpi/ic_24px_rating_excellent.webp b/android/res/drawable-xhdpi/ic_24px_rating_excellent.webp new file mode 100644 index 0000000000..0234c2f439 Binary files /dev/null and b/android/res/drawable-xhdpi/ic_24px_rating_excellent.webp differ diff --git a/android/res/drawable-xhdpi/ic_24px_rating_good.webp b/android/res/drawable-xhdpi/ic_24px_rating_good.webp new file mode 100644 index 0000000000..77001aa1b2 Binary files /dev/null and b/android/res/drawable-xhdpi/ic_24px_rating_good.webp differ diff --git a/android/res/drawable-xhdpi/ic_24px_rating_horrible.webp b/android/res/drawable-xhdpi/ic_24px_rating_horrible.webp new file mode 100644 index 0000000000..3ee5cc7109 Binary files /dev/null and b/android/res/drawable-xhdpi/ic_24px_rating_horrible.webp differ diff --git a/android/res/drawable-xhdpi/ic_24px_rating_normal.webp b/android/res/drawable-xhdpi/ic_24px_rating_normal.webp new file mode 100644 index 0000000000..cafcc062dc Binary files /dev/null and b/android/res/drawable-xhdpi/ic_24px_rating_normal.webp differ diff --git a/android/res/drawable-xhdpi/ic_24px_route_point_a.webp b/android/res/drawable-xhdpi/ic_24px_route_point_a.webp new file mode 100644 index 0000000000..428ac781cd Binary files /dev/null and b/android/res/drawable-xhdpi/ic_24px_route_point_a.webp differ diff --git a/android/res/drawable-xhdpi/ic_24px_route_point_b.webp b/android/res/drawable-xhdpi/ic_24px_route_point_b.webp new file mode 100644 index 0000000000..91f2170248 Binary files /dev/null and b/android/res/drawable-xhdpi/ic_24px_route_point_b.webp differ diff --git a/android/res/drawable-xhdpi/ic_24px_route_point_c.webp b/android/res/drawable-xhdpi/ic_24px_route_point_c.webp new file mode 100644 index 0000000000..43bbade930 Binary files /dev/null and b/android/res/drawable-xhdpi/ic_24px_route_point_c.webp differ diff --git a/android/res/drawable-xhdpi/ic_ab_left.webp b/android/res/drawable-xhdpi/ic_ab_left.webp new file mode 100644 index 0000000000..2425bb3e0c Binary files /dev/null and b/android/res/drawable-xhdpi/ic_ab_left.webp differ diff --git a/android/res/drawable-xhdpi/ic_ab_right.webp b/android/res/drawable-xhdpi/ic_ab_right.webp new file mode 100644 index 0000000000..8cc1ad16f2 Binary files /dev/null and b/android/res/drawable-xhdpi/ic_ab_right.webp differ diff --git a/android/res/drawable-xhdpi/ic_ad_dark.webp b/android/res/drawable-xhdpi/ic_ad_dark.webp new file mode 100644 index 0000000000..0c2e6589e1 Binary files /dev/null and b/android/res/drawable-xhdpi/ic_ad_dark.webp differ diff --git a/android/res/drawable-xhdpi/ic_ad_light.webp b/android/res/drawable-xhdpi/ic_ad_light.webp new file mode 100644 index 0000000000..0c2e6589e1 Binary files /dev/null and b/android/res/drawable-xhdpi/ic_ad_light.webp differ diff --git a/android/res/drawable-xhdpi/ic_booking.webp b/android/res/drawable-xhdpi/ic_booking.webp new file mode 100644 index 0000000000..db3840fd5f Binary files /dev/null and b/android/res/drawable-xhdpi/ic_booking.webp differ diff --git a/android/res/drawable-xhdpi/ic_chevron_right_white.webp b/android/res/drawable-xhdpi/ic_chevron_right_white.webp new file mode 100644 index 0000000000..44c0e5b306 Binary files /dev/null and b/android/res/drawable-xhdpi/ic_chevron_right_white.webp differ diff --git a/android/res/drawable-xhdpi/ic_clear.webp b/android/res/drawable-xhdpi/ic_clear.webp new file mode 100644 index 0000000000..fb0670c406 Binary files /dev/null and b/android/res/drawable-xhdpi/ic_clear.webp differ diff --git a/android/res/drawable-xhdpi/ic_deal_dark.webp b/android/res/drawable-xhdpi/ic_deal_dark.webp new file mode 100644 index 0000000000..c6614cfc6c Binary files /dev/null and b/android/res/drawable-xhdpi/ic_deal_dark.webp differ diff --git a/android/res/drawable-xhdpi/ic_deal_light.webp b/android/res/drawable-xhdpi/ic_deal_light.webp new file mode 100644 index 0000000000..20a83cc0ff Binary files /dev/null and b/android/res/drawable-xhdpi/ic_deal_light.webp differ diff --git a/android/res/drawable-xhdpi/ic_discovery_error.webp b/android/res/drawable-xhdpi/ic_discovery_error.webp new file mode 100644 index 0000000000..2c59b8ac56 Binary files /dev/null and b/android/res/drawable-xhdpi/ic_discovery_error.webp differ diff --git a/android/res/drawable-xhdpi/ic_dog_bg.webp b/android/res/drawable-xhdpi/ic_dog_bg.webp new file mode 100644 index 0000000000..ae0fb37586 Binary files /dev/null and b/android/res/drawable-xhdpi/ic_dog_bg.webp differ diff --git a/android/res/drawable-xhdpi/ic_dog_bg_night.webp b/android/res/drawable-xhdpi/ic_dog_bg_night.webp new file mode 100644 index 0000000000..ca02b20758 Binary files /dev/null and b/android/res/drawable-xhdpi/ic_dog_bg_night.webp differ diff --git a/android/res/drawable-xhdpi/ic_drop_down.webp b/android/res/drawable-xhdpi/ic_drop_down.webp new file mode 100644 index 0000000000..258383ede9 Binary files /dev/null and b/android/res/drawable-xhdpi/ic_drop_down.webp differ diff --git a/android/res/drawable-xhdpi/ic_error_36px.webp b/android/res/drawable-xhdpi/ic_error_36px.webp new file mode 100644 index 0000000000..97f3b9a40f Binary files /dev/null and b/android/res/drawable-xhdpi/ic_error_36px.webp differ diff --git a/android/res/drawable-xhdpi/ic_error_red.webp b/android/res/drawable-xhdpi/ic_error_red.webp new file mode 100644 index 0000000000..22277aaf54 Binary files /dev/null and b/android/res/drawable-xhdpi/ic_error_red.webp differ diff --git a/android/res/drawable-xhdpi/ic_filter_list.webp b/android/res/drawable-xhdpi/ic_filter_list.webp new file mode 100644 index 0000000000..b10da81708 Binary files /dev/null and b/android/res/drawable-xhdpi/ic_filter_list.webp differ diff --git a/android/res/drawable-xhdpi/ic_globe.webp b/android/res/drawable-xhdpi/ic_globe.webp new file mode 100644 index 0000000000..d44b1870f1 Binary files /dev/null and b/android/res/drawable-xhdpi/ic_globe.webp differ diff --git a/android/res/drawable-xhdpi/ic_leaderboard.webp b/android/res/drawable-xhdpi/ic_leaderboard.webp new file mode 100644 index 0000000000..7070654b74 Binary files /dev/null and b/android/res/drawable-xhdpi/ic_leaderboard.webp differ diff --git a/android/res/drawable-xhdpi/ic_link.webp b/android/res/drawable-xhdpi/ic_link.webp new file mode 100644 index 0000000000..447e2a9627 Binary files /dev/null and b/android/res/drawable-xhdpi/ic_link.webp differ diff --git a/android/res/drawable-xhdpi/ic_local_expert_default.webp b/android/res/drawable-xhdpi/ic_local_expert_default.webp new file mode 100644 index 0000000000..c2420082fe Binary files /dev/null and b/android/res/drawable-xhdpi/ic_local_expert_default.webp differ diff --git a/android/res/drawable-xhdpi/ic_logo_uber.webp b/android/res/drawable-xhdpi/ic_logo_uber.webp new file mode 100644 index 0000000000..c496836aab Binary files /dev/null and b/android/res/drawable-xhdpi/ic_logo_uber.webp differ diff --git a/android/res/drawable-xhdpi/ic_logo_yandex_taxi.webp b/android/res/drawable-xhdpi/ic_logo_yandex_taxi.webp new file mode 100644 index 0000000000..c496836aab Binary files /dev/null and b/android/res/drawable-xhdpi/ic_logo_yandex_taxi.webp differ diff --git a/android/res/drawable-xhdpi/ic_minus_red.webp b/android/res/drawable-xhdpi/ic_minus_red.webp new file mode 100644 index 0000000000..05afc318a4 Binary files /dev/null and b/android/res/drawable-xhdpi/ic_minus_red.webp differ diff --git a/android/res/drawable-xhdpi/ic_navigation_light.webp b/android/res/drawable-xhdpi/ic_navigation_light.webp new file mode 100644 index 0000000000..334f9e3787 Binary files /dev/null and b/android/res/drawable-xhdpi/ic_navigation_light.webp differ diff --git a/android/res/drawable-xhdpi/ic_opentable.webp b/android/res/drawable-xhdpi/ic_opentable.webp new file mode 100644 index 0000000000..42be380a91 Binary files /dev/null and b/android/res/drawable-xhdpi/ic_opentable.webp differ diff --git a/android/res/drawable-xhdpi/ic_planning_route_isomaps_dark_on.webp b/android/res/drawable-xhdpi/ic_planning_route_isomaps_dark_on.webp new file mode 100644 index 0000000000..c7d177d40f Binary files /dev/null and b/android/res/drawable-xhdpi/ic_planning_route_isomaps_dark_on.webp differ diff --git a/android/res/drawable-xhdpi/ic_plus_green.webp b/android/res/drawable-xhdpi/ic_plus_green.webp new file mode 100644 index 0000000000..2a1ebd0424 Binary files /dev/null and b/android/res/drawable-xhdpi/ic_plus_green.webp differ diff --git a/android/res/drawable-xhdpi/ic_rate_empty.webp b/android/res/drawable-xhdpi/ic_rate_empty.webp new file mode 100644 index 0000000000..7e64a9ae6c Binary files /dev/null and b/android/res/drawable-xhdpi/ic_rate_empty.webp differ diff --git a/android/res/drawable-xhdpi/ic_rate_full.webp b/android/res/drawable-xhdpi/ic_rate_full.webp new file mode 100644 index 0000000000..c137bf5136 Binary files /dev/null and b/android/res/drawable-xhdpi/ic_rate_full.webp differ diff --git a/android/res/drawable-xhdpi/ic_review_active_12.webp b/android/res/drawable-xhdpi/ic_review_active_12.webp new file mode 100644 index 0000000000..8ca50cf3f1 Binary files /dev/null and b/android/res/drawable-xhdpi/ic_review_active_12.webp differ diff --git a/android/res/drawable-xhdpi/ic_review_active_24.webp b/android/res/drawable-xhdpi/ic_review_active_24.webp new file mode 100644 index 0000000000..90fa79bf85 Binary files /dev/null and b/android/res/drawable-xhdpi/ic_review_active_24.webp differ diff --git a/android/res/drawable-xhdpi/ic_review_disable_dark_12.webp b/android/res/drawable-xhdpi/ic_review_disable_dark_12.webp new file mode 100644 index 0000000000..8ca50cf3f1 Binary files /dev/null and b/android/res/drawable-xhdpi/ic_review_disable_dark_12.webp differ diff --git a/android/res/drawable-xhdpi/ic_review_disable_dark_24.webp b/android/res/drawable-xhdpi/ic_review_disable_dark_24.webp new file mode 100644 index 0000000000..90fa79bf85 Binary files /dev/null and b/android/res/drawable-xhdpi/ic_review_disable_dark_24.webp differ diff --git a/android/res/drawable-xhdpi/ic_review_disable_light_12.webp b/android/res/drawable-xhdpi/ic_review_disable_light_12.webp new file mode 100644 index 0000000000..8ca50cf3f1 Binary files /dev/null and b/android/res/drawable-xhdpi/ic_review_disable_light_12.webp differ diff --git a/android/res/drawable-xhdpi/ic_review_disable_light_24.webp b/android/res/drawable-xhdpi/ic_review_disable_light_24.webp new file mode 100644 index 0000000000..90fa79bf85 Binary files /dev/null and b/android/res/drawable-xhdpi/ic_review_disable_light_24.webp differ diff --git a/android/res/drawable-xhdpi/ic_routing_search_on.webp b/android/res/drawable-xhdpi/ic_routing_search_on.webp new file mode 100644 index 0000000000..13e7126f5d Binary files /dev/null and b/android/res/drawable-xhdpi/ic_routing_search_on.webp differ diff --git a/android/res/drawable-xhdpi/ic_search.webp b/android/res/drawable-xhdpi/ic_search.webp new file mode 100644 index 0000000000..31e25ec20c Binary files /dev/null and b/android/res/drawable-xhdpi/ic_search.webp differ diff --git a/android/res/drawable-xhdpi/ic_setting_traffic_off.webp b/android/res/drawable-xhdpi/ic_setting_traffic_off.webp new file mode 100644 index 0000000000..ad2cb9fac1 Binary files /dev/null and b/android/res/drawable-xhdpi/ic_setting_traffic_off.webp differ diff --git a/android/res/drawable-xhdpi/ic_setting_traffic_on.webp b/android/res/drawable-xhdpi/ic_setting_traffic_on.webp new file mode 100644 index 0000000000..da16ff5313 Binary files /dev/null and b/android/res/drawable-xhdpi/ic_setting_traffic_on.webp differ diff --git a/android/res/drawable-xhdpi/ic_sightseeing_checkox.webp b/android/res/drawable-xhdpi/ic_sightseeing_checkox.webp new file mode 100644 index 0000000000..40beb1c9fb Binary files /dev/null and b/android/res/drawable-xhdpi/ic_sightseeing_checkox.webp differ diff --git a/android/res/drawable-xhdpi/ic_star_small.webp b/android/res/drawable-xhdpi/ic_star_small.webp new file mode 100644 index 0000000000..96877b5731 Binary files /dev/null and b/android/res/drawable-xhdpi/ic_star_small.webp differ diff --git a/android/res/drawable-xhdpi/ic_star_small_full.webp b/android/res/drawable-xhdpi/ic_star_small_full.webp new file mode 100644 index 0000000000..dc69475d65 Binary files /dev/null and b/android/res/drawable-xhdpi/ic_star_small_full.webp differ diff --git a/android/res/drawable-xhdpi/ic_taxi_logo_maksim.webp b/android/res/drawable-xhdpi/ic_taxi_logo_maksim.webp new file mode 100644 index 0000000000..c496836aab Binary files /dev/null and b/android/res/drawable-xhdpi/ic_taxi_logo_maksim.webp differ diff --git a/android/res/drawable-xhdpi/ic_taxi_logo_vezet.webp b/android/res/drawable-xhdpi/ic_taxi_logo_vezet.webp new file mode 100644 index 0000000000..c496836aab Binary files /dev/null and b/android/res/drawable-xhdpi/ic_taxi_logo_vezet.webp differ diff --git a/android/res/drawable-xhdpi/ic_undo.webp b/android/res/drawable-xhdpi/ic_undo.webp new file mode 100644 index 0000000000..9ee0ce6253 Binary files /dev/null and b/android/res/drawable-xhdpi/ic_undo.webp differ diff --git a/android/res/drawable-xhdpi/img_auth.webp b/android/res/drawable-xhdpi/img_auth.webp new file mode 100644 index 0000000000..cda77f51e9 Binary files /dev/null and b/android/res/drawable-xhdpi/img_auth.webp differ diff --git a/android/res/drawable-xhdpi/img_editor_medal.webp b/android/res/drawable-xhdpi/img_editor_medal.webp new file mode 100644 index 0000000000..4c8b178cbb Binary files /dev/null and b/android/res/drawable-xhdpi/img_editor_medal.webp differ diff --git a/android/res/drawable-xhdpi/img_sightseeing_footer.webp b/android/res/drawable-xhdpi/img_sightseeing_footer.webp new file mode 100644 index 0000000000..012ddeadbd Binary files /dev/null and b/android/res/drawable-xhdpi/img_sightseeing_footer.webp differ diff --git a/android/res/drawable-xhdpi/logo_luggagehero_dark.webp b/android/res/drawable-xhdpi/logo_luggagehero_dark.webp new file mode 100644 index 0000000000..71cf8dce60 Binary files /dev/null and b/android/res/drawable-xhdpi/logo_luggagehero_dark.webp differ diff --git a/android/res/drawable-xhdpi/logo_luggagehero_light.webp b/android/res/drawable-xhdpi/logo_luggagehero_light.webp new file mode 100644 index 0000000000..71cf8dce60 Binary files /dev/null and b/android/res/drawable-xhdpi/logo_luggagehero_light.webp differ diff --git a/android/res/drawable-xhdpi/wn_autoupdate.webp b/android/res/drawable-xhdpi/wn_autoupdate.webp new file mode 100644 index 0000000000..2cd633fee7 Binary files /dev/null and b/android/res/drawable-xhdpi/wn_autoupdate.webp differ diff --git a/android/res/drawable-xxhdpi/bg_place_page_head_closed.9.png b/android/res/drawable-xxhdpi/bg_place_page_head_closed.9.png new file mode 100644 index 0000000000..c8b8a9c443 Binary files /dev/null and b/android/res/drawable-xxhdpi/bg_place_page_head_closed.9.png differ diff --git a/android/res/drawable-xxhdpi/bg_place_page_head_closed_night.9.png b/android/res/drawable-xxhdpi/bg_place_page_head_closed_night.9.png new file mode 100644 index 0000000000..e8eaffd723 Binary files /dev/null and b/android/res/drawable-xxhdpi/bg_place_page_head_closed_night.9.png differ diff --git a/android/res/drawable-xxhdpi/bg_place_page_head_open.9.png b/android/res/drawable-xxhdpi/bg_place_page_head_open.9.png new file mode 100644 index 0000000000..eb3495b912 Binary files /dev/null and b/android/res/drawable-xxhdpi/bg_place_page_head_open.9.png differ diff --git a/android/res/drawable-xxhdpi/bg_place_page_head_open_night.9.png b/android/res/drawable-xxhdpi/bg_place_page_head_open_night.9.png new file mode 100644 index 0000000000..a450de6b80 Binary files /dev/null and b/android/res/drawable-xxhdpi/bg_place_page_head_open_night.9.png differ diff --git a/android/res/drawable-xxhdpi/card_frame.9.png b/android/res/drawable-xxhdpi/card_frame.9.png new file mode 100644 index 0000000000..18b2e68ccf Binary files /dev/null and b/android/res/drawable-xxhdpi/card_frame.9.png differ diff --git a/android/res/drawable-xxhdpi/card_frame_night.9.png b/android/res/drawable-xxhdpi/card_frame_night.9.png new file mode 100644 index 0000000000..5afa2362f9 Binary files /dev/null and b/android/res/drawable-xxhdpi/card_frame_night.9.png differ diff --git a/android/res/drawable-xxhdpi/ic_24px_clear.webp b/android/res/drawable-xxhdpi/ic_24px_clear.webp new file mode 100644 index 0000000000..9c103eef55 Binary files /dev/null and b/android/res/drawable-xxhdpi/ic_24px_clear.webp differ diff --git a/android/res/drawable-xxhdpi/ic_24px_rating_bad.webp b/android/res/drawable-xxhdpi/ic_24px_rating_bad.webp new file mode 100644 index 0000000000..5e40e07cfe Binary files /dev/null and b/android/res/drawable-xxhdpi/ic_24px_rating_bad.webp differ diff --git a/android/res/drawable-xxhdpi/ic_24px_rating_coming_soon.webp b/android/res/drawable-xxhdpi/ic_24px_rating_coming_soon.webp new file mode 100644 index 0000000000..796d36426f Binary files /dev/null and b/android/res/drawable-xxhdpi/ic_24px_rating_coming_soon.webp differ diff --git a/android/res/drawable-xxhdpi/ic_24px_rating_excellent.webp b/android/res/drawable-xxhdpi/ic_24px_rating_excellent.webp new file mode 100644 index 0000000000..faf003c3d8 Binary files /dev/null and b/android/res/drawable-xxhdpi/ic_24px_rating_excellent.webp differ diff --git a/android/res/drawable-xxhdpi/ic_24px_rating_good.webp b/android/res/drawable-xxhdpi/ic_24px_rating_good.webp new file mode 100644 index 0000000000..5b6ceb6e04 Binary files /dev/null and b/android/res/drawable-xxhdpi/ic_24px_rating_good.webp differ diff --git a/android/res/drawable-xxhdpi/ic_24px_rating_horrible.webp b/android/res/drawable-xxhdpi/ic_24px_rating_horrible.webp new file mode 100644 index 0000000000..a6dbbb8eaa Binary files /dev/null and b/android/res/drawable-xxhdpi/ic_24px_rating_horrible.webp differ diff --git a/android/res/drawable-xxhdpi/ic_24px_rating_normal.webp b/android/res/drawable-xxhdpi/ic_24px_rating_normal.webp new file mode 100644 index 0000000000..42b41a5a4a Binary files /dev/null and b/android/res/drawable-xxhdpi/ic_24px_rating_normal.webp differ diff --git a/android/res/drawable-xxhdpi/ic_24px_route_point_a.webp b/android/res/drawable-xxhdpi/ic_24px_route_point_a.webp new file mode 100644 index 0000000000..d13e73fe22 Binary files /dev/null and b/android/res/drawable-xxhdpi/ic_24px_route_point_a.webp differ diff --git a/android/res/drawable-xxhdpi/ic_24px_route_point_b.webp b/android/res/drawable-xxhdpi/ic_24px_route_point_b.webp new file mode 100644 index 0000000000..5bbf20c147 Binary files /dev/null and b/android/res/drawable-xxhdpi/ic_24px_route_point_b.webp differ diff --git a/android/res/drawable-xxhdpi/ic_24px_route_point_c.webp b/android/res/drawable-xxhdpi/ic_24px_route_point_c.webp new file mode 100644 index 0000000000..ce69825493 Binary files /dev/null and b/android/res/drawable-xxhdpi/ic_24px_route_point_c.webp differ diff --git a/android/res/drawable-xxhdpi/ic_ab_left.webp b/android/res/drawable-xxhdpi/ic_ab_left.webp new file mode 100644 index 0000000000..800c7828ce Binary files /dev/null and b/android/res/drawable-xxhdpi/ic_ab_left.webp differ diff --git a/android/res/drawable-xxhdpi/ic_ab_right.webp b/android/res/drawable-xxhdpi/ic_ab_right.webp new file mode 100644 index 0000000000..6006e66e97 Binary files /dev/null and b/android/res/drawable-xxhdpi/ic_ab_right.webp differ diff --git a/android/res/drawable-xxhdpi/ic_ad_dark.webp b/android/res/drawable-xxhdpi/ic_ad_dark.webp new file mode 100644 index 0000000000..4503e3a46c Binary files /dev/null and b/android/res/drawable-xxhdpi/ic_ad_dark.webp differ diff --git a/android/res/drawable-xxhdpi/ic_ad_light.webp b/android/res/drawable-xxhdpi/ic_ad_light.webp new file mode 100644 index 0000000000..4503e3a46c Binary files /dev/null and b/android/res/drawable-xxhdpi/ic_ad_light.webp differ diff --git a/android/res/drawable-xxhdpi/ic_booking.webp b/android/res/drawable-xxhdpi/ic_booking.webp new file mode 100644 index 0000000000..d98bcbdc04 Binary files /dev/null and b/android/res/drawable-xxhdpi/ic_booking.webp differ diff --git a/android/res/drawable-xxhdpi/ic_chevron_right_white.webp b/android/res/drawable-xxhdpi/ic_chevron_right_white.webp new file mode 100644 index 0000000000..66549d82f8 Binary files /dev/null and b/android/res/drawable-xxhdpi/ic_chevron_right_white.webp differ diff --git a/android/res/drawable-xxhdpi/ic_clear.webp b/android/res/drawable-xxhdpi/ic_clear.webp new file mode 100644 index 0000000000..9e6db0133d Binary files /dev/null and b/android/res/drawable-xxhdpi/ic_clear.webp differ diff --git a/android/res/drawable-xxhdpi/ic_deal_dark.webp b/android/res/drawable-xxhdpi/ic_deal_dark.webp new file mode 100644 index 0000000000..8fe3366d6d Binary files /dev/null and b/android/res/drawable-xxhdpi/ic_deal_dark.webp differ diff --git a/android/res/drawable-xxhdpi/ic_deal_light.webp b/android/res/drawable-xxhdpi/ic_deal_light.webp new file mode 100644 index 0000000000..a1aa36ca6d Binary files /dev/null and b/android/res/drawable-xxhdpi/ic_deal_light.webp differ diff --git a/android/res/drawable-xxhdpi/ic_discovery_error.webp b/android/res/drawable-xxhdpi/ic_discovery_error.webp new file mode 100644 index 0000000000..717e3b841e Binary files /dev/null and b/android/res/drawable-xxhdpi/ic_discovery_error.webp differ diff --git a/android/res/drawable-xxhdpi/ic_dog_bg.webp b/android/res/drawable-xxhdpi/ic_dog_bg.webp new file mode 100644 index 0000000000..73d4d7f382 Binary files /dev/null and b/android/res/drawable-xxhdpi/ic_dog_bg.webp differ diff --git a/android/res/drawable-xxhdpi/ic_dog_bg_night.webp b/android/res/drawable-xxhdpi/ic_dog_bg_night.webp new file mode 100644 index 0000000000..d739466ca7 Binary files /dev/null and b/android/res/drawable-xxhdpi/ic_dog_bg_night.webp differ diff --git a/android/res/drawable-xxhdpi/ic_drop_down.webp b/android/res/drawable-xxhdpi/ic_drop_down.webp new file mode 100644 index 0000000000..9f31732a89 Binary files /dev/null and b/android/res/drawable-xxhdpi/ic_drop_down.webp differ diff --git a/android/res/drawable-xxhdpi/ic_error_36px.webp b/android/res/drawable-xxhdpi/ic_error_36px.webp new file mode 100644 index 0000000000..0a45f0cd04 Binary files /dev/null and b/android/res/drawable-xxhdpi/ic_error_36px.webp differ diff --git a/android/res/drawable-xxhdpi/ic_error_red.webp b/android/res/drawable-xxhdpi/ic_error_red.webp new file mode 100644 index 0000000000..8f8c6694e9 Binary files /dev/null and b/android/res/drawable-xxhdpi/ic_error_red.webp differ diff --git a/android/res/drawable-xxhdpi/ic_filter_list.webp b/android/res/drawable-xxhdpi/ic_filter_list.webp new file mode 100644 index 0000000000..202e20dfd8 Binary files /dev/null and b/android/res/drawable-xxhdpi/ic_filter_list.webp differ diff --git a/android/res/drawable-xxhdpi/ic_globe.webp b/android/res/drawable-xxhdpi/ic_globe.webp new file mode 100644 index 0000000000..e6ecbb31aa Binary files /dev/null and b/android/res/drawable-xxhdpi/ic_globe.webp differ diff --git a/android/res/drawable-xxhdpi/ic_leaderboard.webp b/android/res/drawable-xxhdpi/ic_leaderboard.webp new file mode 100644 index 0000000000..e9bce8f239 Binary files /dev/null and b/android/res/drawable-xxhdpi/ic_leaderboard.webp differ diff --git a/android/res/drawable-xxhdpi/ic_link.webp b/android/res/drawable-xxhdpi/ic_link.webp new file mode 100644 index 0000000000..d821508be3 Binary files /dev/null and b/android/res/drawable-xxhdpi/ic_link.webp differ diff --git a/android/res/drawable-xxhdpi/ic_local_expert_default.webp b/android/res/drawable-xxhdpi/ic_local_expert_default.webp new file mode 100644 index 0000000000..cda77f51e9 Binary files /dev/null and b/android/res/drawable-xxhdpi/ic_local_expert_default.webp differ diff --git a/android/res/drawable-xxhdpi/ic_logo_uber.webp b/android/res/drawable-xxhdpi/ic_logo_uber.webp new file mode 100644 index 0000000000..9388c7be69 Binary files /dev/null and b/android/res/drawable-xxhdpi/ic_logo_uber.webp differ diff --git a/android/res/drawable-xxhdpi/ic_logo_yandex_taxi.webp b/android/res/drawable-xxhdpi/ic_logo_yandex_taxi.webp new file mode 100644 index 0000000000..9388c7be69 Binary files /dev/null and b/android/res/drawable-xxhdpi/ic_logo_yandex_taxi.webp differ diff --git a/android/res/drawable-xxhdpi/ic_minus_red.webp b/android/res/drawable-xxhdpi/ic_minus_red.webp new file mode 100644 index 0000000000..5b4b7702b4 Binary files /dev/null and b/android/res/drawable-xxhdpi/ic_minus_red.webp differ diff --git a/android/res/drawable-xxhdpi/ic_navigation_light.webp b/android/res/drawable-xxhdpi/ic_navigation_light.webp new file mode 100644 index 0000000000..988090aa19 Binary files /dev/null and b/android/res/drawable-xxhdpi/ic_navigation_light.webp differ diff --git a/android/res/drawable-xxhdpi/ic_opentable.webp b/android/res/drawable-xxhdpi/ic_opentable.webp new file mode 100644 index 0000000000..7e9bf62688 Binary files /dev/null and b/android/res/drawable-xxhdpi/ic_opentable.webp differ diff --git a/android/res/drawable-xxhdpi/ic_planning_route_isomaps_dark_on.webp b/android/res/drawable-xxhdpi/ic_planning_route_isomaps_dark_on.webp new file mode 100644 index 0000000000..d8825d813a Binary files /dev/null and b/android/res/drawable-xxhdpi/ic_planning_route_isomaps_dark_on.webp differ diff --git a/android/res/drawable-xxhdpi/ic_plus_green.webp b/android/res/drawable-xxhdpi/ic_plus_green.webp new file mode 100644 index 0000000000..2aeef76629 Binary files /dev/null and b/android/res/drawable-xxhdpi/ic_plus_green.webp differ diff --git a/android/res/drawable-xxhdpi/ic_rate_empty.webp b/android/res/drawable-xxhdpi/ic_rate_empty.webp new file mode 100644 index 0000000000..01a0ff963e Binary files /dev/null and b/android/res/drawable-xxhdpi/ic_rate_empty.webp differ diff --git a/android/res/drawable-xxhdpi/ic_rate_full.webp b/android/res/drawable-xxhdpi/ic_rate_full.webp new file mode 100644 index 0000000000..e02865f151 Binary files /dev/null and b/android/res/drawable-xxhdpi/ic_rate_full.webp differ diff --git a/android/res/drawable-xxhdpi/ic_review_active_12.webp b/android/res/drawable-xxhdpi/ic_review_active_12.webp new file mode 100644 index 0000000000..11de231f06 Binary files /dev/null and b/android/res/drawable-xxhdpi/ic_review_active_12.webp differ diff --git a/android/res/drawable-xxhdpi/ic_review_active_24.webp b/android/res/drawable-xxhdpi/ic_review_active_24.webp new file mode 100644 index 0000000000..df4e0f434c Binary files /dev/null and b/android/res/drawable-xxhdpi/ic_review_active_24.webp differ diff --git a/android/res/drawable-xxhdpi/ic_review_disable_dark_12.webp b/android/res/drawable-xxhdpi/ic_review_disable_dark_12.webp new file mode 100644 index 0000000000..11de231f06 Binary files /dev/null and b/android/res/drawable-xxhdpi/ic_review_disable_dark_12.webp differ diff --git a/android/res/drawable-xxhdpi/ic_review_disable_dark_24.webp b/android/res/drawable-xxhdpi/ic_review_disable_dark_24.webp new file mode 100644 index 0000000000..df4e0f434c Binary files /dev/null and b/android/res/drawable-xxhdpi/ic_review_disable_dark_24.webp differ diff --git a/android/res/drawable-xxhdpi/ic_review_disable_light_12.webp b/android/res/drawable-xxhdpi/ic_review_disable_light_12.webp new file mode 100644 index 0000000000..11de231f06 Binary files /dev/null and b/android/res/drawable-xxhdpi/ic_review_disable_light_12.webp differ diff --git a/android/res/drawable-xxhdpi/ic_review_disable_light_24.webp b/android/res/drawable-xxhdpi/ic_review_disable_light_24.webp new file mode 100644 index 0000000000..df4e0f434c Binary files /dev/null and b/android/res/drawable-xxhdpi/ic_review_disable_light_24.webp differ diff --git a/android/res/drawable-xxhdpi/ic_routing_search_on.webp b/android/res/drawable-xxhdpi/ic_routing_search_on.webp new file mode 100644 index 0000000000..dab56f7c1d Binary files /dev/null and b/android/res/drawable-xxhdpi/ic_routing_search_on.webp differ diff --git a/android/res/drawable-xxhdpi/ic_search.webp b/android/res/drawable-xxhdpi/ic_search.webp new file mode 100644 index 0000000000..a640a2d8a3 Binary files /dev/null and b/android/res/drawable-xxhdpi/ic_search.webp differ diff --git a/android/res/drawable-xxhdpi/ic_setting_traffic_off.webp b/android/res/drawable-xxhdpi/ic_setting_traffic_off.webp new file mode 100644 index 0000000000..3f21349dbf Binary files /dev/null and b/android/res/drawable-xxhdpi/ic_setting_traffic_off.webp differ diff --git a/android/res/drawable-xxhdpi/ic_setting_traffic_on.webp b/android/res/drawable-xxhdpi/ic_setting_traffic_on.webp new file mode 100644 index 0000000000..4753633b7f Binary files /dev/null and b/android/res/drawable-xxhdpi/ic_setting_traffic_on.webp differ diff --git a/android/res/drawable-xxhdpi/ic_sightseeing_checkox.webp b/android/res/drawable-xxhdpi/ic_sightseeing_checkox.webp new file mode 100644 index 0000000000..d2ef5b652c Binary files /dev/null and b/android/res/drawable-xxhdpi/ic_sightseeing_checkox.webp differ diff --git a/android/res/drawable-xxhdpi/ic_star_small.webp b/android/res/drawable-xxhdpi/ic_star_small.webp new file mode 100644 index 0000000000..a6009f5fc5 Binary files /dev/null and b/android/res/drawable-xxhdpi/ic_star_small.webp differ diff --git a/android/res/drawable-xxhdpi/ic_star_small_full.webp b/android/res/drawable-xxhdpi/ic_star_small_full.webp new file mode 100644 index 0000000000..22f7af9489 Binary files /dev/null and b/android/res/drawable-xxhdpi/ic_star_small_full.webp differ diff --git a/android/res/drawable-xxhdpi/ic_taxi.webp b/android/res/drawable-xxhdpi/ic_taxi.webp new file mode 100644 index 0000000000..c77ef09389 Binary files /dev/null and b/android/res/drawable-xxhdpi/ic_taxi.webp differ diff --git a/android/res/drawable-xxhdpi/ic_taxi_logo_maksim.webp b/android/res/drawable-xxhdpi/ic_taxi_logo_maksim.webp new file mode 100644 index 0000000000..9388c7be69 Binary files /dev/null and b/android/res/drawable-xxhdpi/ic_taxi_logo_maksim.webp differ diff --git a/android/res/drawable-xxhdpi/ic_taxi_logo_vezet.webp b/android/res/drawable-xxhdpi/ic_taxi_logo_vezet.webp new file mode 100644 index 0000000000..9388c7be69 Binary files /dev/null and b/android/res/drawable-xxhdpi/ic_taxi_logo_vezet.webp differ diff --git a/android/res/drawable-xxhdpi/ic_undo.webp b/android/res/drawable-xxhdpi/ic_undo.webp new file mode 100644 index 0000000000..075f2c0a71 Binary files /dev/null and b/android/res/drawable-xxhdpi/ic_undo.webp differ diff --git a/android/res/drawable-xxhdpi/img_auth.webp b/android/res/drawable-xxhdpi/img_auth.webp new file mode 100644 index 0000000000..4c7543b47a Binary files /dev/null and b/android/res/drawable-xxhdpi/img_auth.webp differ diff --git a/android/res/drawable-xxhdpi/img_editor_medal.webp b/android/res/drawable-xxhdpi/img_editor_medal.webp new file mode 100644 index 0000000000..2cd633fee7 Binary files /dev/null and b/android/res/drawable-xxhdpi/img_editor_medal.webp differ diff --git a/android/res/drawable-xxhdpi/img_sightseeing_footer.webp b/android/res/drawable-xxhdpi/img_sightseeing_footer.webp new file mode 100644 index 0000000000..291a7275c1 Binary files /dev/null and b/android/res/drawable-xxhdpi/img_sightseeing_footer.webp differ diff --git a/android/res/drawable-xxhdpi/logo_luggagehero_dark.webp b/android/res/drawable-xxhdpi/logo_luggagehero_dark.webp new file mode 100644 index 0000000000..22ad917fed Binary files /dev/null and b/android/res/drawable-xxhdpi/logo_luggagehero_dark.webp differ diff --git a/android/res/drawable-xxhdpi/logo_luggagehero_light.webp b/android/res/drawable-xxhdpi/logo_luggagehero_light.webp new file mode 100644 index 0000000000..22ad917fed Binary files /dev/null and b/android/res/drawable-xxhdpi/logo_luggagehero_light.webp differ diff --git a/android/res/drawable-xxhdpi/wn_autoupdate.webp b/android/res/drawable-xxhdpi/wn_autoupdate.webp new file mode 100644 index 0000000000..91df98208f Binary files /dev/null and b/android/res/drawable-xxhdpi/wn_autoupdate.webp differ diff --git a/android/res/drawable-xxxhdpi/bg_place_page_head_closed.9.png b/android/res/drawable-xxxhdpi/bg_place_page_head_closed.9.png new file mode 100644 index 0000000000..c8c1f040cd Binary files /dev/null and b/android/res/drawable-xxxhdpi/bg_place_page_head_closed.9.png differ diff --git a/android/res/drawable-xxxhdpi/bg_place_page_head_closed_night.9.png b/android/res/drawable-xxxhdpi/bg_place_page_head_closed_night.9.png new file mode 100644 index 0000000000..6431ed879f Binary files /dev/null and b/android/res/drawable-xxxhdpi/bg_place_page_head_closed_night.9.png differ diff --git a/android/res/drawable-xxxhdpi/bg_place_page_head_open.9.png b/android/res/drawable-xxxhdpi/bg_place_page_head_open.9.png new file mode 100644 index 0000000000..0009e69b78 Binary files /dev/null and b/android/res/drawable-xxxhdpi/bg_place_page_head_open.9.png differ diff --git a/android/res/drawable-xxxhdpi/bg_place_page_head_open_night.9.png b/android/res/drawable-xxxhdpi/bg_place_page_head_open_night.9.png new file mode 100644 index 0000000000..2637447088 Binary files /dev/null and b/android/res/drawable-xxxhdpi/bg_place_page_head_open_night.9.png differ diff --git a/android/res/drawable-xxxhdpi/card_frame.9.png b/android/res/drawable-xxxhdpi/card_frame.9.png new file mode 100644 index 0000000000..c7bd91de28 Binary files /dev/null and b/android/res/drawable-xxxhdpi/card_frame.9.png differ diff --git a/android/res/drawable-xxxhdpi/card_frame_night.9.png b/android/res/drawable-xxxhdpi/card_frame_night.9.png new file mode 100644 index 0000000000..b629aa6157 Binary files /dev/null and b/android/res/drawable-xxxhdpi/card_frame_night.9.png differ diff --git a/android/res/drawable-xxxhdpi/ic_24px_clear.webp b/android/res/drawable-xxxhdpi/ic_24px_clear.webp new file mode 100644 index 0000000000..8afb37ffc7 Binary files /dev/null and b/android/res/drawable-xxxhdpi/ic_24px_clear.webp differ diff --git a/android/res/drawable-xxxhdpi/ic_24px_rating_bad.webp b/android/res/drawable-xxxhdpi/ic_24px_rating_bad.webp new file mode 100644 index 0000000000..b77548ed50 Binary files /dev/null and b/android/res/drawable-xxxhdpi/ic_24px_rating_bad.webp differ diff --git a/android/res/drawable-xxxhdpi/ic_24px_rating_coming_soon.webp b/android/res/drawable-xxxhdpi/ic_24px_rating_coming_soon.webp new file mode 100644 index 0000000000..ef68e0a5d1 Binary files /dev/null and b/android/res/drawable-xxxhdpi/ic_24px_rating_coming_soon.webp differ diff --git a/android/res/drawable-xxxhdpi/ic_24px_rating_excellent.webp b/android/res/drawable-xxxhdpi/ic_24px_rating_excellent.webp new file mode 100644 index 0000000000..7982534d9d Binary files /dev/null and b/android/res/drawable-xxxhdpi/ic_24px_rating_excellent.webp differ diff --git a/android/res/drawable-xxxhdpi/ic_24px_rating_good.webp b/android/res/drawable-xxxhdpi/ic_24px_rating_good.webp new file mode 100644 index 0000000000..cf29209109 Binary files /dev/null and b/android/res/drawable-xxxhdpi/ic_24px_rating_good.webp differ diff --git a/android/res/drawable-xxxhdpi/ic_24px_rating_horrible.webp b/android/res/drawable-xxxhdpi/ic_24px_rating_horrible.webp new file mode 100644 index 0000000000..d031e650f4 Binary files /dev/null and b/android/res/drawable-xxxhdpi/ic_24px_rating_horrible.webp differ diff --git a/android/res/drawable-xxxhdpi/ic_24px_rating_normal.webp b/android/res/drawable-xxxhdpi/ic_24px_rating_normal.webp new file mode 100644 index 0000000000..0f074b64d1 Binary files /dev/null and b/android/res/drawable-xxxhdpi/ic_24px_rating_normal.webp differ diff --git a/android/res/drawable-xxxhdpi/ic_24px_route_point_a.webp b/android/res/drawable-xxxhdpi/ic_24px_route_point_a.webp new file mode 100644 index 0000000000..af59d45fa5 Binary files /dev/null and b/android/res/drawable-xxxhdpi/ic_24px_route_point_a.webp differ diff --git a/android/res/drawable-xxxhdpi/ic_24px_route_point_b.webp b/android/res/drawable-xxxhdpi/ic_24px_route_point_b.webp new file mode 100644 index 0000000000..fe8320b2b8 Binary files /dev/null and b/android/res/drawable-xxxhdpi/ic_24px_route_point_b.webp differ diff --git a/android/res/drawable-xxxhdpi/ic_24px_route_point_c.webp b/android/res/drawable-xxxhdpi/ic_24px_route_point_c.webp new file mode 100644 index 0000000000..7a8b1ac67d Binary files /dev/null and b/android/res/drawable-xxxhdpi/ic_24px_route_point_c.webp differ diff --git a/android/res/drawable-xxxhdpi/ic_ab_left.webp b/android/res/drawable-xxxhdpi/ic_ab_left.webp new file mode 100644 index 0000000000..66ca3415c2 Binary files /dev/null and b/android/res/drawable-xxxhdpi/ic_ab_left.webp differ diff --git a/android/res/drawable-xxxhdpi/ic_ab_right.webp b/android/res/drawable-xxxhdpi/ic_ab_right.webp new file mode 100644 index 0000000000..3b365d806e Binary files /dev/null and b/android/res/drawable-xxxhdpi/ic_ab_right.webp differ diff --git a/android/res/drawable-xxxhdpi/ic_ad_dark.webp b/android/res/drawable-xxxhdpi/ic_ad_dark.webp new file mode 100644 index 0000000000..0fdbab3d03 Binary files /dev/null and b/android/res/drawable-xxxhdpi/ic_ad_dark.webp differ diff --git a/android/res/drawable-xxxhdpi/ic_ad_light.webp b/android/res/drawable-xxxhdpi/ic_ad_light.webp new file mode 100644 index 0000000000..0fdbab3d03 Binary files /dev/null and b/android/res/drawable-xxxhdpi/ic_ad_light.webp differ diff --git a/android/res/drawable-xxxhdpi/ic_booking.webp b/android/res/drawable-xxxhdpi/ic_booking.webp new file mode 100644 index 0000000000..304679c6a7 Binary files /dev/null and b/android/res/drawable-xxxhdpi/ic_booking.webp differ diff --git a/android/res/drawable-xxxhdpi/ic_chevron_right_white.webp b/android/res/drawable-xxxhdpi/ic_chevron_right_white.webp new file mode 100644 index 0000000000..68b3f8e262 Binary files /dev/null and b/android/res/drawable-xxxhdpi/ic_chevron_right_white.webp differ diff --git a/android/res/drawable-xxxhdpi/ic_clear.webp b/android/res/drawable-xxxhdpi/ic_clear.webp new file mode 100644 index 0000000000..7e883fba13 Binary files /dev/null and b/android/res/drawable-xxxhdpi/ic_clear.webp differ diff --git a/android/res/drawable-xxxhdpi/ic_deal_dark.webp b/android/res/drawable-xxxhdpi/ic_deal_dark.webp new file mode 100644 index 0000000000..fe946cd07e Binary files /dev/null and b/android/res/drawable-xxxhdpi/ic_deal_dark.webp differ diff --git a/android/res/drawable-xxxhdpi/ic_deal_light.webp b/android/res/drawable-xxxhdpi/ic_deal_light.webp new file mode 100644 index 0000000000..bcb1c1ea8a Binary files /dev/null and b/android/res/drawable-xxxhdpi/ic_deal_light.webp differ diff --git a/android/res/drawable-xxxhdpi/ic_discovery_error.webp b/android/res/drawable-xxxhdpi/ic_discovery_error.webp new file mode 100644 index 0000000000..057eecfab2 Binary files /dev/null and b/android/res/drawable-xxxhdpi/ic_discovery_error.webp differ diff --git a/android/res/drawable-xxxhdpi/ic_dog_bg.webp b/android/res/drawable-xxxhdpi/ic_dog_bg.webp new file mode 100644 index 0000000000..53b7ec6e25 Binary files /dev/null and b/android/res/drawable-xxxhdpi/ic_dog_bg.webp differ diff --git a/android/res/drawable-xxxhdpi/ic_dog_bg_night.webp b/android/res/drawable-xxxhdpi/ic_dog_bg_night.webp new file mode 100644 index 0000000000..5f0526372d Binary files /dev/null and b/android/res/drawable-xxxhdpi/ic_dog_bg_night.webp differ diff --git a/android/res/drawable-xxxhdpi/ic_drop_down.webp b/android/res/drawable-xxxhdpi/ic_drop_down.webp new file mode 100644 index 0000000000..8a45c13e80 Binary files /dev/null and b/android/res/drawable-xxxhdpi/ic_drop_down.webp differ diff --git a/android/res/drawable-xxxhdpi/ic_error_36px.webp b/android/res/drawable-xxxhdpi/ic_error_36px.webp new file mode 100644 index 0000000000..8f31065033 Binary files /dev/null and b/android/res/drawable-xxxhdpi/ic_error_36px.webp differ diff --git a/android/res/drawable-xxxhdpi/ic_error_red.webp b/android/res/drawable-xxxhdpi/ic_error_red.webp new file mode 100644 index 0000000000..69c075ea5a Binary files /dev/null and b/android/res/drawable-xxxhdpi/ic_error_red.webp differ diff --git a/android/res/drawable-xxxhdpi/ic_filter_list.webp b/android/res/drawable-xxxhdpi/ic_filter_list.webp new file mode 100644 index 0000000000..f190764ed8 Binary files /dev/null and b/android/res/drawable-xxxhdpi/ic_filter_list.webp differ diff --git a/android/res/drawable-xxxhdpi/ic_globe.webp b/android/res/drawable-xxxhdpi/ic_globe.webp new file mode 100644 index 0000000000..f7430f91ed Binary files /dev/null and b/android/res/drawable-xxxhdpi/ic_globe.webp differ diff --git a/android/res/drawable-xxxhdpi/ic_link.webp b/android/res/drawable-xxxhdpi/ic_link.webp new file mode 100644 index 0000000000..2f47ce4cc5 Binary files /dev/null and b/android/res/drawable-xxxhdpi/ic_link.webp differ diff --git a/android/res/drawable-xxxhdpi/ic_local_expert_default.webp b/android/res/drawable-xxxhdpi/ic_local_expert_default.webp new file mode 100644 index 0000000000..4c8b178cbb Binary files /dev/null and b/android/res/drawable-xxxhdpi/ic_local_expert_default.webp differ diff --git a/android/res/drawable-xxxhdpi/ic_logo_uber.webp b/android/res/drawable-xxxhdpi/ic_logo_uber.webp new file mode 100644 index 0000000000..d4dedb9ac3 Binary files /dev/null and b/android/res/drawable-xxxhdpi/ic_logo_uber.webp differ diff --git a/android/res/drawable-xxxhdpi/ic_logo_yandex_taxi.webp b/android/res/drawable-xxxhdpi/ic_logo_yandex_taxi.webp new file mode 100644 index 0000000000..d4dedb9ac3 Binary files /dev/null and b/android/res/drawable-xxxhdpi/ic_logo_yandex_taxi.webp differ diff --git a/android/res/drawable-xxxhdpi/ic_minus_red.webp b/android/res/drawable-xxxhdpi/ic_minus_red.webp new file mode 100644 index 0000000000..5aa76f93e9 Binary files /dev/null and b/android/res/drawable-xxxhdpi/ic_minus_red.webp differ diff --git a/android/res/drawable-xxxhdpi/ic_navigation_light.webp b/android/res/drawable-xxxhdpi/ic_navigation_light.webp new file mode 100644 index 0000000000..52f73590d5 Binary files /dev/null and b/android/res/drawable-xxxhdpi/ic_navigation_light.webp differ diff --git a/android/res/drawable-xxxhdpi/ic_opentable.webp b/android/res/drawable-xxxhdpi/ic_opentable.webp new file mode 100644 index 0000000000..160461b8b1 Binary files /dev/null and b/android/res/drawable-xxxhdpi/ic_opentable.webp differ diff --git a/android/res/drawable-xxxhdpi/ic_planning_route_isomaps_dark_on.webp b/android/res/drawable-xxxhdpi/ic_planning_route_isomaps_dark_on.webp new file mode 100644 index 0000000000..5770e1e18b Binary files /dev/null and b/android/res/drawable-xxxhdpi/ic_planning_route_isomaps_dark_on.webp differ diff --git a/android/res/drawable-xxxhdpi/ic_plus_green.webp b/android/res/drawable-xxxhdpi/ic_plus_green.webp new file mode 100644 index 0000000000..3caa7b35b3 Binary files /dev/null and b/android/res/drawable-xxxhdpi/ic_plus_green.webp differ diff --git a/android/res/drawable-xxxhdpi/ic_review_active_12.webp b/android/res/drawable-xxxhdpi/ic_review_active_12.webp new file mode 100644 index 0000000000..90fa79bf85 Binary files /dev/null and b/android/res/drawable-xxxhdpi/ic_review_active_12.webp differ diff --git a/android/res/drawable-xxxhdpi/ic_review_active_24.webp b/android/res/drawable-xxxhdpi/ic_review_active_24.webp new file mode 100644 index 0000000000..bbf78cfee9 Binary files /dev/null and b/android/res/drawable-xxxhdpi/ic_review_active_24.webp differ diff --git a/android/res/drawable-xxxhdpi/ic_review_disable_dark_12.webp b/android/res/drawable-xxxhdpi/ic_review_disable_dark_12.webp new file mode 100644 index 0000000000..90fa79bf85 Binary files /dev/null and b/android/res/drawable-xxxhdpi/ic_review_disable_dark_12.webp differ diff --git a/android/res/drawable-xxxhdpi/ic_review_disable_dark_24.webp b/android/res/drawable-xxxhdpi/ic_review_disable_dark_24.webp new file mode 100644 index 0000000000..bbf78cfee9 Binary files /dev/null and b/android/res/drawable-xxxhdpi/ic_review_disable_dark_24.webp differ diff --git a/android/res/drawable-xxxhdpi/ic_review_disable_light_12.webp b/android/res/drawable-xxxhdpi/ic_review_disable_light_12.webp new file mode 100644 index 0000000000..90fa79bf85 Binary files /dev/null and b/android/res/drawable-xxxhdpi/ic_review_disable_light_12.webp differ diff --git a/android/res/drawable-xxxhdpi/ic_review_disable_light_24.webp b/android/res/drawable-xxxhdpi/ic_review_disable_light_24.webp new file mode 100644 index 0000000000..bbf78cfee9 Binary files /dev/null and b/android/res/drawable-xxxhdpi/ic_review_disable_light_24.webp differ diff --git a/android/res/drawable-xxxhdpi/ic_routing_search_on.webp b/android/res/drawable-xxxhdpi/ic_routing_search_on.webp new file mode 100644 index 0000000000..a35b955ebf Binary files /dev/null and b/android/res/drawable-xxxhdpi/ic_routing_search_on.webp differ diff --git a/android/res/drawable-xxxhdpi/ic_search.webp b/android/res/drawable-xxxhdpi/ic_search.webp new file mode 100644 index 0000000000..f52138606d Binary files /dev/null and b/android/res/drawable-xxxhdpi/ic_search.webp differ diff --git a/android/res/drawable-xxxhdpi/ic_setting_traffic_off.webp b/android/res/drawable-xxxhdpi/ic_setting_traffic_off.webp new file mode 100644 index 0000000000..a58712ed5d Binary files /dev/null and b/android/res/drawable-xxxhdpi/ic_setting_traffic_off.webp differ diff --git a/android/res/drawable-xxxhdpi/ic_setting_traffic_on.webp b/android/res/drawable-xxxhdpi/ic_setting_traffic_on.webp new file mode 100644 index 0000000000..193e3619a4 Binary files /dev/null and b/android/res/drawable-xxxhdpi/ic_setting_traffic_on.webp differ diff --git a/android/res/drawable-xxxhdpi/ic_sightseeing_checkox.webp b/android/res/drawable-xxxhdpi/ic_sightseeing_checkox.webp new file mode 100644 index 0000000000..09a2e8cc11 Binary files /dev/null and b/android/res/drawable-xxxhdpi/ic_sightseeing_checkox.webp differ diff --git a/android/res/drawable-xxxhdpi/ic_star_small.webp b/android/res/drawable-xxxhdpi/ic_star_small.webp new file mode 100644 index 0000000000..09eec95d19 Binary files /dev/null and b/android/res/drawable-xxxhdpi/ic_star_small.webp differ diff --git a/android/res/drawable-xxxhdpi/ic_star_small_full.webp b/android/res/drawable-xxxhdpi/ic_star_small_full.webp new file mode 100644 index 0000000000..78c9f70be6 Binary files /dev/null and b/android/res/drawable-xxxhdpi/ic_star_small_full.webp differ diff --git a/android/res/drawable-xxxhdpi/ic_taxi_logo_maksim.webp b/android/res/drawable-xxxhdpi/ic_taxi_logo_maksim.webp new file mode 100644 index 0000000000..d4dedb9ac3 Binary files /dev/null and b/android/res/drawable-xxxhdpi/ic_taxi_logo_maksim.webp differ diff --git a/android/res/drawable-xxxhdpi/ic_taxi_logo_vezet.webp b/android/res/drawable-xxxhdpi/ic_taxi_logo_vezet.webp new file mode 100644 index 0000000000..d4dedb9ac3 Binary files /dev/null and b/android/res/drawable-xxxhdpi/ic_taxi_logo_vezet.webp differ diff --git a/android/res/drawable-xxxhdpi/ic_undo.webp b/android/res/drawable-xxxhdpi/ic_undo.webp new file mode 100644 index 0000000000..8f4210cc44 Binary files /dev/null and b/android/res/drawable-xxxhdpi/ic_undo.webp differ diff --git a/android/res/drawable-xxxhdpi/img_auth.webp b/android/res/drawable-xxxhdpi/img_auth.webp new file mode 100644 index 0000000000..2cd633fee7 Binary files /dev/null and b/android/res/drawable-xxxhdpi/img_auth.webp differ diff --git a/android/res/drawable-xxxhdpi/img_editor_medal.webp b/android/res/drawable-xxxhdpi/img_editor_medal.webp new file mode 100644 index 0000000000..8300e9103b Binary files /dev/null and b/android/res/drawable-xxxhdpi/img_editor_medal.webp differ diff --git a/android/res/drawable-xxxhdpi/img_sightseeing_footer.webp b/android/res/drawable-xxxhdpi/img_sightseeing_footer.webp new file mode 100644 index 0000000000..0c29a058e0 Binary files /dev/null and b/android/res/drawable-xxxhdpi/img_sightseeing_footer.webp differ diff --git a/android/res/drawable-xxxhdpi/logo_luggagehero_dark.webp b/android/res/drawable-xxxhdpi/logo_luggagehero_dark.webp new file mode 100644 index 0000000000..5e02406820 Binary files /dev/null and b/android/res/drawable-xxxhdpi/logo_luggagehero_dark.webp differ diff --git a/android/res/drawable-xxxhdpi/logo_luggagehero_light.webp b/android/res/drawable-xxxhdpi/logo_luggagehero_light.webp new file mode 100644 index 0000000000..5e02406820 Binary files /dev/null and b/android/res/drawable-xxxhdpi/logo_luggagehero_light.webp differ diff --git a/android/res/drawable-xxxhdpi/wn_autoupdate.webp b/android/res/drawable-xxxhdpi/wn_autoupdate.webp new file mode 100644 index 0000000000..c73bb290d3 Binary files /dev/null and b/android/res/drawable-xxxhdpi/wn_autoupdate.webp differ diff --git a/android/res/drawable/bg_active_icon.xml b/android/res/drawable/bg_active_icon.xml new file mode 100644 index 0000000000..bfdeed2693 --- /dev/null +++ b/android/res/drawable/bg_active_icon.xml @@ -0,0 +1,7 @@ + + + + diff --git a/android/res/drawable/bg_active_icon_night.xml b/android/res/drawable/bg_active_icon_night.xml new file mode 100644 index 0000000000..fa73f0e6c4 --- /dev/null +++ b/android/res/drawable/bg_active_icon_night.xml @@ -0,0 +1,7 @@ + + + + \ No newline at end of file diff --git a/android/res/drawable/bg_circle_green.xml b/android/res/drawable/bg_circle_green.xml new file mode 100644 index 0000000000..24f254e751 --- /dev/null +++ b/android/res/drawable/bg_circle_green.xml @@ -0,0 +1,8 @@ + + + + + diff --git a/android/res/drawable/bg_circle_green_night.xml b/android/res/drawable/bg_circle_green_night.xml new file mode 100644 index 0000000000..59127c39ac --- /dev/null +++ b/android/res/drawable/bg_circle_green_night.xml @@ -0,0 +1,8 @@ + + + + + diff --git a/android/res/drawable/bg_circle_red.xml b/android/res/drawable/bg_circle_red.xml new file mode 100644 index 0000000000..c5a44a59a0 --- /dev/null +++ b/android/res/drawable/bg_circle_red.xml @@ -0,0 +1,8 @@ + + + + + diff --git a/android/res/drawable/bg_circle_red_night.xml b/android/res/drawable/bg_circle_red_night.xml new file mode 100644 index 0000000000..61cb40cf65 --- /dev/null +++ b/android/res/drawable/bg_circle_red_night.xml @@ -0,0 +1,8 @@ + + + + + diff --git a/android/res/drawable/bg_grey.xml b/android/res/drawable/bg_grey.xml new file mode 100644 index 0000000000..075fd03268 --- /dev/null +++ b/android/res/drawable/bg_grey.xml @@ -0,0 +1,5 @@ + + + + + diff --git a/android/res/drawable/bg_grey_dark.xml b/android/res/drawable/bg_grey_dark.xml new file mode 100644 index 0000000000..596039b132 --- /dev/null +++ b/android/res/drawable/bg_grey_dark.xml @@ -0,0 +1,5 @@ + + + + + diff --git a/android/res/drawable/bg_rating_button.xml b/android/res/drawable/bg_rating_button.xml new file mode 100644 index 0000000000..3e06cbba51 --- /dev/null +++ b/android/res/drawable/bg_rating_button.xml @@ -0,0 +1,6 @@ + + + + diff --git a/android/res/drawable/bg_rating_button_night.xml b/android/res/drawable/bg_rating_button_night.xml new file mode 100644 index 0000000000..9d13d278b0 --- /dev/null +++ b/android/res/drawable/bg_rating_button_night.xml @@ -0,0 +1,6 @@ + + + + diff --git a/android/res/drawable/bg_rounded_card.xml b/android/res/drawable/bg_rounded_card.xml new file mode 100644 index 0000000000..f551fe1b38 --- /dev/null +++ b/android/res/drawable/bg_rounded_card.xml @@ -0,0 +1,7 @@ + + + + + diff --git a/android/res/drawable/bg_rounded_card_night.xml b/android/res/drawable/bg_rounded_card_night.xml new file mode 100644 index 0000000000..abbca14c6f --- /dev/null +++ b/android/res/drawable/bg_rounded_card_night.xml @@ -0,0 +1,7 @@ + + + + + diff --git a/android/res/drawable/bg_steady_icon.xml b/android/res/drawable/bg_steady_icon.xml new file mode 100644 index 0000000000..907426b69b --- /dev/null +++ b/android/res/drawable/bg_steady_icon.xml @@ -0,0 +1,7 @@ + + + + diff --git a/android/res/drawable/bg_steady_icon_night.xml b/android/res/drawable/bg_steady_icon_night.xml new file mode 100644 index 0000000000..ec05ef536f --- /dev/null +++ b/android/res/drawable/bg_steady_icon_night.xml @@ -0,0 +1,7 @@ + + + + \ No newline at end of file diff --git a/android/res/drawable/button.xml b/android/res/drawable/button.xml index e5c2d39a13..3249c892ad 100644 --- a/android/res/drawable/button.xml +++ b/android/res/drawable/button.xml @@ -1,10 +1,10 @@ - - - - - - - - + + + + + + + \ No newline at end of file diff --git a/android/res/drawable/button_accent.xml b/android/res/drawable/button_accent.xml index 102a72b2a8..72ffa49022 100644 --- a/android/res/drawable/button_accent.xml +++ b/android/res/drawable/button_accent.xml @@ -1,7 +1,5 @@ - - + - + diff --git a/android/res/drawable/button_accent_night.xml b/android/res/drawable/button_accent_night.xml index 192a6af3ec..c2b770f0d5 100644 --- a/android/res/drawable/button_accent_night.xml +++ b/android/res/drawable/button_accent_night.xml @@ -1,7 +1,5 @@ - - + - + diff --git a/android/res/drawable/button_accent_round.xml b/android/res/drawable/button_accent_round.xml new file mode 100644 index 0000000000..3a1913237f --- /dev/null +++ b/android/res/drawable/button_accent_round.xml @@ -0,0 +1,10 @@ + + + + + + + + diff --git a/android/res/drawable/button_accent_round_disabled.xml b/android/res/drawable/button_accent_round_disabled.xml new file mode 100644 index 0000000000..2bb7fd67cf --- /dev/null +++ b/android/res/drawable/button_accent_round_disabled.xml @@ -0,0 +1,7 @@ + + + + + + diff --git a/android/res/drawable/button_accent_round_disabled_night.xml b/android/res/drawable/button_accent_round_disabled_night.xml new file mode 100644 index 0000000000..4812137a29 --- /dev/null +++ b/android/res/drawable/button_accent_round_disabled_night.xml @@ -0,0 +1,7 @@ + + + + + + diff --git a/android/res/drawable/button_accent_round_night.xml b/android/res/drawable/button_accent_round_night.xml new file mode 100644 index 0000000000..231320010b --- /dev/null +++ b/android/res/drawable/button_accent_round_night.xml @@ -0,0 +1,10 @@ + + + + + + + + diff --git a/android/res/drawable/button_accent_round_normal.xml b/android/res/drawable/button_accent_round_normal.xml new file mode 100644 index 0000000000..26a305f8f4 --- /dev/null +++ b/android/res/drawable/button_accent_round_normal.xml @@ -0,0 +1,7 @@ + + + + + + diff --git a/android/res/drawable/button_accent_round_normal_night.xml b/android/res/drawable/button_accent_round_normal_night.xml new file mode 100644 index 0000000000..6b3ec343c8 --- /dev/null +++ b/android/res/drawable/button_accent_round_normal_night.xml @@ -0,0 +1,7 @@ + + + + + + diff --git a/android/res/drawable/button_accent_round_pressed.xml b/android/res/drawable/button_accent_round_pressed.xml new file mode 100644 index 0000000000..16cd98fa83 --- /dev/null +++ b/android/res/drawable/button_accent_round_pressed.xml @@ -0,0 +1,7 @@ + + + + + + diff --git a/android/res/drawable/button_accent_round_pressed_night.xml b/android/res/drawable/button_accent_round_pressed_night.xml new file mode 100644 index 0000000000..4c764c850c --- /dev/null +++ b/android/res/drawable/button_accent_round_pressed_night.xml @@ -0,0 +1,7 @@ + + + + + + diff --git a/android/res/drawable/button_booking.xml b/android/res/drawable/button_booking.xml new file mode 100644 index 0000000000..5821efb2dc --- /dev/null +++ b/android/res/drawable/button_booking.xml @@ -0,0 +1,7 @@ + + + + + + \ No newline at end of file diff --git a/android/res/drawable/button_editor_light.xml b/android/res/drawable/button_editor_light.xml index 3cea8a1a18..3e104c6f8d 100644 --- a/android/res/drawable/button_editor_light.xml +++ b/android/res/drawable/button_editor_light.xml @@ -1,11 +1,18 @@ - - + + + + + + + + + + - \ No newline at end of file + \ No newline at end of file diff --git a/android/res/drawable/button_ghost.xml b/android/res/drawable/button_ghost.xml new file mode 100644 index 0000000000..c031483506 --- /dev/null +++ b/android/res/drawable/button_ghost.xml @@ -0,0 +1,6 @@ + + + + + diff --git a/android/res/drawable/button_ghost_background.xml b/android/res/drawable/button_ghost_background.xml new file mode 100644 index 0000000000..df056581fa --- /dev/null +++ b/android/res/drawable/button_ghost_background.xml @@ -0,0 +1,9 @@ + + + + + + diff --git a/android/res/drawable/button_ghost_background_disabled.xml b/android/res/drawable/button_ghost_background_disabled.xml new file mode 100644 index 0000000000..853565b77e --- /dev/null +++ b/android/res/drawable/button_ghost_background_disabled.xml @@ -0,0 +1,9 @@ + + + + + + diff --git a/android/res/drawable/button_ghost_background_disabled_night.xml b/android/res/drawable/button_ghost_background_disabled_night.xml new file mode 100644 index 0000000000..985c0c086d --- /dev/null +++ b/android/res/drawable/button_ghost_background_disabled_night.xml @@ -0,0 +1,9 @@ + + + + + + diff --git a/android/res/drawable/button_ghost_night.xml b/android/res/drawable/button_ghost_night.xml new file mode 100644 index 0000000000..94e5d588b3 --- /dev/null +++ b/android/res/drawable/button_ghost_night.xml @@ -0,0 +1,6 @@ + + + + + diff --git a/android/res/drawable/button_leave_review.xml b/android/res/drawable/button_leave_review.xml new file mode 100644 index 0000000000..9048deab19 --- /dev/null +++ b/android/res/drawable/button_leave_review.xml @@ -0,0 +1,23 @@ + + + + + + + + + + + + + + + + + + + + + + + diff --git a/android/res/drawable/button_leave_review_night.xml b/android/res/drawable/button_leave_review_night.xml new file mode 100644 index 0000000000..4ac6ba6953 --- /dev/null +++ b/android/res/drawable/button_leave_review_night.xml @@ -0,0 +1,23 @@ + + + + + + + + + + + + + + + + + + + + + + + diff --git a/android/res/drawable/button_night.xml b/android/res/drawable/button_night.xml index a4f3d16e0f..0d04298f79 100644 --- a/android/res/drawable/button_night.xml +++ b/android/res/drawable/button_night.xml @@ -1,10 +1,10 @@ - - - - - - - - \ No newline at end of file + + + + + + + \ No newline at end of file diff --git a/android/res/drawable/button_opentable.xml b/android/res/drawable/button_opentable.xml new file mode 100644 index 0000000000..fcbddd3705 --- /dev/null +++ b/android/res/drawable/button_opentable.xml @@ -0,0 +1,7 @@ + + + + + + diff --git a/android/res/drawable/button_red.xml b/android/res/drawable/button_red.xml index f8132991f8..9b81d5bc3d 100644 --- a/android/res/drawable/button_red.xml +++ b/android/res/drawable/button_red.xml @@ -1,10 +1,10 @@ - - - - - - - - \ No newline at end of file + + + + + + + \ No newline at end of file diff --git a/android/res/drawable/button_secondary_transparent.xml b/android/res/drawable/button_secondary_transparent.xml new file mode 100644 index 0000000000..a4759e4a7b --- /dev/null +++ b/android/res/drawable/button_secondary_transparent.xml @@ -0,0 +1,5 @@ + + + + diff --git a/android/res/drawable/button_secondary_transparent_internal.xml b/android/res/drawable/button_secondary_transparent_internal.xml new file mode 100644 index 0000000000..0a3b8d70b7 --- /dev/null +++ b/android/res/drawable/button_secondary_transparent_internal.xml @@ -0,0 +1,5 @@ + + + + + diff --git a/android/res/drawable/button_secondary_transparent_normal.xml b/android/res/drawable/button_secondary_transparent_normal.xml new file mode 100644 index 0000000000..3ce015d8ce --- /dev/null +++ b/android/res/drawable/button_secondary_transparent_normal.xml @@ -0,0 +1,8 @@ + + + + + + diff --git a/android/res/drawable/button_secondary_transparent_pressed.xml b/android/res/drawable/button_secondary_transparent_pressed.xml new file mode 100644 index 0000000000..3d14be80d8 --- /dev/null +++ b/android/res/drawable/button_secondary_transparent_pressed.xml @@ -0,0 +1,7 @@ + + + + + diff --git a/android/res/drawable/button_with_border.xml b/android/res/drawable/button_with_border.xml new file mode 100644 index 0000000000..004ab13d6f --- /dev/null +++ b/android/res/drawable/button_with_border.xml @@ -0,0 +1,4 @@ + + + + diff --git a/android/res/drawable/button_with_border_default.xml b/android/res/drawable/button_with_border_default.xml new file mode 100644 index 0000000000..eaa8a3d5a9 --- /dev/null +++ b/android/res/drawable/button_with_border_default.xml @@ -0,0 +1,8 @@ + + + + + diff --git a/android/res/drawable/button_with_border_disabled.xml b/android/res/drawable/button_with_border_disabled.xml new file mode 100644 index 0000000000..0ebe5e60f6 --- /dev/null +++ b/android/res/drawable/button_with_border_disabled.xml @@ -0,0 +1,9 @@ + + + + + + diff --git a/android/res/drawable/button_with_border_internal.xml b/android/res/drawable/button_with_border_internal.xml new file mode 100644 index 0000000000..602fe812c1 --- /dev/null +++ b/android/res/drawable/button_with_border_internal.xml @@ -0,0 +1,5 @@ + + + + + diff --git a/android/res/drawable/button_with_border_night.xml b/android/res/drawable/button_with_border_night.xml new file mode 100644 index 0000000000..189bd465b6 --- /dev/null +++ b/android/res/drawable/button_with_border_night.xml @@ -0,0 +1,4 @@ + + + + diff --git a/android/res/drawable/button_with_border_night_default.xml b/android/res/drawable/button_with_border_night_default.xml new file mode 100644 index 0000000000..a0c9042e9c --- /dev/null +++ b/android/res/drawable/button_with_border_night_default.xml @@ -0,0 +1,8 @@ + + + + + diff --git a/android/res/drawable/button_with_border_night_disabled.xml b/android/res/drawable/button_with_border_night_disabled.xml new file mode 100644 index 0000000000..d93c2e101a --- /dev/null +++ b/android/res/drawable/button_with_border_night_disabled.xml @@ -0,0 +1,8 @@ + + + + + diff --git a/android/res/drawable/button_with_border_night_internal.xml b/android/res/drawable/button_with_border_night_internal.xml new file mode 100644 index 0000000000..8cb8c4ffa4 --- /dev/null +++ b/android/res/drawable/button_with_border_night_internal.xml @@ -0,0 +1,5 @@ + + + + + diff --git a/android/res/drawable/circle_accent.xml b/android/res/drawable/circle_accent.xml new file mode 100644 index 0000000000..88585f6882 --- /dev/null +++ b/android/res/drawable/circle_accent.xml @@ -0,0 +1,6 @@ + + + + \ No newline at end of file diff --git a/android/res/drawable/circle_accent_night.xml b/android/res/drawable/circle_accent_night.xml new file mode 100644 index 0000000000..eec2d0e8f6 --- /dev/null +++ b/android/res/drawable/circle_accent_night.xml @@ -0,0 +1,6 @@ + + + + \ No newline at end of file diff --git a/android/res/drawable/dist.xml b/android/res/drawable/dist.xml new file mode 100644 index 0000000000..2e43df418d --- /dev/null +++ b/android/res/drawable/dist.xml @@ -0,0 +1,13 @@ + + + + + \ No newline at end of file diff --git a/android/res/drawable/dist_dark.xml b/android/res/drawable/dist_dark.xml new file mode 100644 index 0000000000..2f14ea6989 --- /dev/null +++ b/android/res/drawable/dist_dark.xml @@ -0,0 +1,13 @@ + + + + + \ No newline at end of file diff --git a/android/res/drawable/dot.xml b/android/res/drawable/dot.xml new file mode 100644 index 0000000000..d516cfd4b9 --- /dev/null +++ b/android/res/drawable/dot.xml @@ -0,0 +1,7 @@ + + + + + diff --git a/android/res/drawable/dot_night.xml b/android/res/drawable/dot_night.xml new file mode 100644 index 0000000000..c00a42ec22 --- /dev/null +++ b/android/res/drawable/dot_night.xml @@ -0,0 +1,7 @@ + + + + + diff --git a/android/res/drawable/ic_child.xml b/android/res/drawable/ic_child.xml new file mode 100644 index 0000000000..883df5b606 --- /dev/null +++ b/android/res/drawable/ic_child.xml @@ -0,0 +1,10 @@ + + + diff --git a/android/res/drawable/ic_christmas_tree.xml b/android/res/drawable/ic_christmas_tree.xml deleted file mode 100644 index bdcb7c5abc..0000000000 --- a/android/res/drawable/ic_christmas_tree.xml +++ /dev/null @@ -1,16 +0,0 @@ - - - - - - - - - - - - - - - diff --git a/android/res/drawable/ic_claim.xml b/android/res/drawable/ic_claim.xml new file mode 100644 index 0000000000..b438eebb6d --- /dev/null +++ b/android/res/drawable/ic_claim.xml @@ -0,0 +1,13 @@ + + + + diff --git a/android/res/drawable/ic_claim_city.xml b/android/res/drawable/ic_claim_city.xml new file mode 100644 index 0000000000..f28907f232 --- /dev/null +++ b/android/res/drawable/ic_claim_city.xml @@ -0,0 +1,13 @@ + + + + diff --git a/android/res/drawable/ic_claim_city_night.xml b/android/res/drawable/ic_claim_city_night.xml new file mode 100644 index 0000000000..cd49b8d290 --- /dev/null +++ b/android/res/drawable/ic_claim_city_night.xml @@ -0,0 +1,13 @@ + + + + diff --git a/android/res/drawable/ic_claim_night.xml b/android/res/drawable/ic_claim_night.xml new file mode 100644 index 0000000000..fb6ec5962f --- /dev/null +++ b/android/res/drawable/ic_claim_night.xml @@ -0,0 +1,13 @@ + + + + diff --git a/android/res/drawable/ic_counter_minus.xml b/android/res/drawable/ic_counter_minus.xml new file mode 100644 index 0000000000..3cfcef2906 --- /dev/null +++ b/android/res/drawable/ic_counter_minus.xml @@ -0,0 +1,9 @@ + + + diff --git a/android/res/drawable/ic_counter_plus.xml b/android/res/drawable/ic_counter_plus.xml new file mode 100644 index 0000000000..d53b77d460 --- /dev/null +++ b/android/res/drawable/ic_counter_plus.xml @@ -0,0 +1,9 @@ + + + diff --git a/android/res/drawable/ic_dropdown.xml b/android/res/drawable/ic_dropdown.xml new file mode 100644 index 0000000000..49125747cc --- /dev/null +++ b/android/res/drawable/ic_dropdown.xml @@ -0,0 +1,10 @@ + + + diff --git a/android/res/drawable/ic_follow.xml b/android/res/drawable/ic_follow.xml index 8f455f91df..e14a53b610 100644 --- a/android/res/drawable/ic_follow.xml +++ b/android/res/drawable/ic_follow.xml @@ -1,5 +1,5 @@ - + diff --git a/android/res/drawable/ic_follow_and_rotate.xml b/android/res/drawable/ic_follow_and_rotate.xml index b53c6f1be9..d9510afe89 100644 --- a/android/res/drawable/ic_follow_and_rotate.xml +++ b/android/res/drawable/ic_follow_and_rotate.xml @@ -1,22 +1,5 @@ - - - - + + diff --git a/android/res/drawable/ic_location_off.xml b/android/res/drawable/ic_location_off.xml deleted file mode 100644 index bfea6c4255..0000000000 --- a/android/res/drawable/ic_location_off.xml +++ /dev/null @@ -1,10 +0,0 @@ - - - diff --git a/android/res/drawable/ic_logo_citymobil.xml b/android/res/drawable/ic_logo_citymobil.xml new file mode 100644 index 0000000000..9c2e40b679 --- /dev/null +++ b/android/res/drawable/ic_logo_citymobil.xml @@ -0,0 +1,6 @@ + + diff --git a/android/res/drawable/ic_logo_freenow.xml b/android/res/drawable/ic_logo_freenow.xml new file mode 100644 index 0000000000..786f835590 --- /dev/null +++ b/android/res/drawable/ic_logo_freenow.xml @@ -0,0 +1,3 @@ + + diff --git a/android/res/drawable/ic_logo_yango.xml b/android/res/drawable/ic_logo_yango.xml new file mode 100644 index 0000000000..0538b87cb7 --- /dev/null +++ b/android/res/drawable/ic_logo_yango.xml @@ -0,0 +1,7 @@ + + diff --git a/android/res/drawable/ic_lp_logo.xml b/android/res/drawable/ic_lp_logo.xml new file mode 100644 index 0000000000..7458308099 --- /dev/null +++ b/android/res/drawable/ic_lp_logo.xml @@ -0,0 +1,6 @@ + + diff --git a/android/res/drawable/ic_mastodon.xml b/android/res/drawable/ic_mastodon.xml deleted file mode 100644 index ad988c9949..0000000000 --- a/android/res/drawable/ic_mastodon.xml +++ /dev/null @@ -1,26 +0,0 @@ - - - - - - - - - - - diff --git a/android/res/drawable/ic_menu_open.xml b/android/res/drawable/ic_menu_open.xml index 470db52083..a97455fbdb 100644 --- a/android/res/drawable/ic_menu_open.xml +++ b/android/res/drawable/ic_menu_open.xml @@ -1,5 +1,15 @@ - - + + + + diff --git a/android/res/drawable/ic_menu_point_to_point.xml b/android/res/drawable/ic_menu_point_to_point.xml new file mode 100644 index 0000000000..82d4293eb1 --- /dev/null +++ b/android/res/drawable/ic_menu_point_to_point.xml @@ -0,0 +1,16 @@ + + + + + diff --git a/android/res/drawable/ic_negative_review.xml b/android/res/drawable/ic_negative_review.xml new file mode 100644 index 0000000000..a28a8a5646 --- /dev/null +++ b/android/res/drawable/ic_negative_review.xml @@ -0,0 +1,15 @@ + + + + + diff --git a/android/res/drawable/ic_negative_review_night.xml b/android/res/drawable/ic_negative_review_night.xml new file mode 100644 index 0000000000..475fd403dc --- /dev/null +++ b/android/res/drawable/ic_negative_review_night.xml @@ -0,0 +1,15 @@ + + + + + diff --git a/android/res/drawable/ic_people.xml b/android/res/drawable/ic_people.xml new file mode 100644 index 0000000000..4202e091f6 --- /dev/null +++ b/android/res/drawable/ic_people.xml @@ -0,0 +1,10 @@ + + + diff --git a/android/res/drawable/ic_peoplepicker.xml b/android/res/drawable/ic_peoplepicker.xml new file mode 100644 index 0000000000..49e2ea9fdb --- /dev/null +++ b/android/res/drawable/ic_peoplepicker.xml @@ -0,0 +1,10 @@ + + + diff --git a/android/res/drawable/ic_positive_review.xml b/android/res/drawable/ic_positive_review.xml new file mode 100644 index 0000000000..e3fc607c73 --- /dev/null +++ b/android/res/drawable/ic_positive_review.xml @@ -0,0 +1,15 @@ + + + + + diff --git a/android/res/drawable/ic_positive_review_night.xml b/android/res/drawable/ic_positive_review_night.xml new file mode 100644 index 0000000000..317ce7719c --- /dev/null +++ b/android/res/drawable/ic_positive_review_night.xml @@ -0,0 +1,15 @@ + + + + + diff --git a/android/res/drawable/ic_room.xml b/android/res/drawable/ic_room.xml new file mode 100644 index 0000000000..d1ab439c73 --- /dev/null +++ b/android/res/drawable/ic_room.xml @@ -0,0 +1,10 @@ + + + diff --git a/android/res/drawable/ic_wikimedia_commons_white.xml b/android/res/drawable/ic_wikimedia_commons_white.xml deleted file mode 100644 index 588e43d650..0000000000 --- a/android/res/drawable/ic_wikimedia_commons_white.xml +++ /dev/null @@ -1,63 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - diff --git a/android/res/drawable/menu_button.xml b/android/res/drawable/menu_button.xml new file mode 100644 index 0000000000..e740440b51 --- /dev/null +++ b/android/res/drawable/menu_button.xml @@ -0,0 +1,4 @@ + + + + diff --git a/android/res/drawable/news_marker.xml b/android/res/drawable/news_marker.xml new file mode 100644 index 0000000000..e37e1f4bb7 --- /dev/null +++ b/android/res/drawable/news_marker.xml @@ -0,0 +1,10 @@ + + + + + \ No newline at end of file diff --git a/android/res/drawable/news_marker_active.xml b/android/res/drawable/news_marker_active.xml new file mode 100644 index 0000000000..96de8eef06 --- /dev/null +++ b/android/res/drawable/news_marker_active.xml @@ -0,0 +1,8 @@ + + + + + + \ No newline at end of file diff --git a/android/res/drawable/news_marker_active_night.xml b/android/res/drawable/news_marker_active_night.xml new file mode 100644 index 0000000000..7cf4f144de --- /dev/null +++ b/android/res/drawable/news_marker_active_night.xml @@ -0,0 +1,8 @@ + + + + + + \ No newline at end of file diff --git a/android/res/drawable/news_marker_inactive.xml b/android/res/drawable/news_marker_inactive.xml new file mode 100644 index 0000000000..a4de0248de --- /dev/null +++ b/android/res/drawable/news_marker_inactive.xml @@ -0,0 +1,8 @@ + + + + + + \ No newline at end of file diff --git a/android/res/drawable/news_marker_inactive_night.xml b/android/res/drawable/news_marker_inactive_night.xml new file mode 100644 index 0000000000..710a8d3008 --- /dev/null +++ b/android/res/drawable/news_marker_inactive_night.xml @@ -0,0 +1,8 @@ + + + + + + \ No newline at end of file diff --git a/android/res/drawable/news_marker_night.xml b/android/res/drawable/news_marker_night.xml new file mode 100644 index 0000000000..fbd57163b9 --- /dev/null +++ b/android/res/drawable/news_marker_night.xml @@ -0,0 +1,10 @@ + + + + + \ No newline at end of file diff --git a/android/res/drawable/onmap_downloader_background.xml b/android/res/drawable/onmap_downloader_background.xml deleted file mode 100644 index ecfe233aa6..0000000000 --- a/android/res/drawable/onmap_downloader_background.xml +++ /dev/null @@ -1,6 +0,0 @@ - - - - - - diff --git a/android/res/drawable/place_holder.xml b/android/res/drawable/place_holder.xml new file mode 100644 index 0000000000..7fabcbeae4 --- /dev/null +++ b/android/res/drawable/place_holder.xml @@ -0,0 +1,20 @@ + + + + + + + + \ No newline at end of file diff --git a/android/res/drawable/place_holder_dark.xml b/android/res/drawable/place_holder_dark.xml new file mode 100644 index 0000000000..e607dffaa2 --- /dev/null +++ b/android/res/drawable/place_holder_dark.xml @@ -0,0 +1,20 @@ + + + + + + + + \ No newline at end of file diff --git a/android/res/drawable/rating_bar.xml b/android/res/drawable/rating_bar.xml new file mode 100644 index 0000000000..52bbbc195c --- /dev/null +++ b/android/res/drawable/rating_bar.xml @@ -0,0 +1,9 @@ + + + + + + diff --git a/android/res/drawable/rating_bar_small.xml b/android/res/drawable/rating_bar_small.xml new file mode 100644 index 0000000000..1bc225b97b --- /dev/null +++ b/android/res/drawable/rating_bar_small.xml @@ -0,0 +1,9 @@ + + + + + + \ No newline at end of file diff --git a/android/res/drawable/routing_toolbar_button.xml b/android/res/drawable/routing_toolbar_button.xml index d007dff933..fcc598f54c 100644 --- a/android/res/drawable/routing_toolbar_button.xml +++ b/android/res/drawable/routing_toolbar_button.xml @@ -1,13 +1,9 @@ - - - - - - - - + + + + diff --git a/android/res/drawable/routing_toolbar_button_night.xml b/android/res/drawable/routing_toolbar_button_night.xml index 0be952a4b4..9a25142f67 100644 --- a/android/res/drawable/routing_toolbar_button_night.xml +++ b/android/res/drawable/routing_toolbar_button_night.xml @@ -1,13 +1,9 @@ - - - - - - - - + + + + diff --git a/android/res/drawable/routing_toolbar_button_normal.xml b/android/res/drawable/routing_toolbar_button_normal.xml index ebfa6cbb6a..e7300577fc 100644 --- a/android/res/drawable/routing_toolbar_button_normal.xml +++ b/android/res/drawable/routing_toolbar_button_normal.xml @@ -3,5 +3,5 @@ android:shape="oval" android:height="40dp" android:width="40dp"> - + diff --git a/android/res/drawable/routing_toolbar_button_normal_night.xml b/android/res/drawable/routing_toolbar_button_normal_night.xml index 47906aacb4..93cb90ce2c 100644 --- a/android/res/drawable/routing_toolbar_button_normal_night.xml +++ b/android/res/drawable/routing_toolbar_button_normal_night.xml @@ -3,5 +3,5 @@ android:shape="oval" android:height="40dp" android:width="40dp"> - + diff --git a/android/res/drawable/sale_view_bg.xml b/android/res/drawable/sale_view_bg.xml new file mode 100644 index 0000000000..81c84f6ec5 --- /dev/null +++ b/android/res/drawable/sale_view_bg.xml @@ -0,0 +1,5 @@ + + + + + diff --git a/android/res/drawable/search_closed_marker.xml b/android/res/drawable/search_closed_marker.xml new file mode 100644 index 0000000000..5a5a657909 --- /dev/null +++ b/android/res/drawable/search_closed_marker.xml @@ -0,0 +1,6 @@ + + + + + diff --git a/android/res/drawable/search_closed_marker_night.xml b/android/res/drawable/search_closed_marker_night.xml new file mode 100644 index 0000000000..37553b06ac --- /dev/null +++ b/android/res/drawable/search_closed_marker_night.xml @@ -0,0 +1,6 @@ + + + + + diff --git a/android/res/drawable/sights.xml b/android/res/drawable/sights.xml new file mode 100644 index 0000000000..6c7c7a07bc --- /dev/null +++ b/android/res/drawable/sights.xml @@ -0,0 +1,12 @@ + + + + + \ No newline at end of file diff --git a/android/res/drawable/sights_dark.xml b/android/res/drawable/sights_dark.xml new file mode 100644 index 0000000000..2bc0ba5f4f --- /dev/null +++ b/android/res/drawable/sights_dark.xml @@ -0,0 +1,12 @@ + + + + + \ No newline at end of file diff --git a/android/res/drawable/time.xml b/android/res/drawable/time.xml new file mode 100644 index 0000000000..6d0b78d125 --- /dev/null +++ b/android/res/drawable/time.xml @@ -0,0 +1,13 @@ + + + + + \ No newline at end of file diff --git a/android/res/drawable/time_dark.xml b/android/res/drawable/time_dark.xml new file mode 100644 index 0000000000..2a72feb0f0 --- /dev/null +++ b/android/res/drawable/time_dark.xml @@ -0,0 +1,13 @@ + + + + + \ No newline at end of file diff --git a/android/res/layout-h400dp/map_buttons_layout_regular.xml b/android/res/layout-h400dp/map_buttons_layout_regular.xml index 3b42e5683f..58add5ad9c 100644 --- a/android/res/layout-h400dp/map_buttons_layout_regular.xml +++ b/android/res/layout-h400dp/map_buttons_layout_regular.xml @@ -13,6 +13,7 @@ android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_alignParentTop="true" + android:layout_marginTop="@dimen/margin_double" android:clipChildren="false" android:clipToPadding="false" android:layoutDirection="ltr" @@ -51,10 +52,46 @@ app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintEnd_toEndOf="parent" /> - + android:clipChildren="false" + android:clipToPadding="false" + android:layoutDirection="ltr" + android:padding="@dimen/nav_frame_padding"> + + + + + \ No newline at end of file diff --git a/android/res/layout-land/fragment_direction.xml b/android/res/layout-land/fragment_direction.xml index 87466d2703..1d6660d56d 100644 --- a/android/res/layout-land/fragment_direction.xml +++ b/android/res/layout-land/fragment_direction.xml @@ -12,7 +12,7 @@ android:layout_height="wrap_content" android:layout_gravity="center"> - - - - + - + - diff --git a/android/res/layout-land/map_buttons_bottom.xml b/android/res/layout-land/map_buttons_bottom.xml deleted file mode 100644 index 50d58607c2..0000000000 --- a/android/res/layout-land/map_buttons_bottom.xml +++ /dev/null @@ -1,40 +0,0 @@ - - - - - - - \ No newline at end of file diff --git a/android/res/layout-land/onmap_downloader.xml b/android/res/layout-land/onmap_downloader.xml index 022971104d..c443bc13e5 100644 --- a/android/res/layout-land/onmap_downloader.xml +++ b/android/res/layout-land/onmap_downloader.xml @@ -11,8 +11,7 @@ android:layout_width="wrap_content" android:layout_height="wrap_content" android:orientation="horizontal" - android:backgroundTint="?menuBackground" - android:background="@drawable/onmap_downloader_background" + android:background="?cardFrame" android:padding="@dimen/margin_base" android:clipToPadding="false" android:clipChildren="false" @@ -20,62 +19,86 @@ android:gravity="center" tools:ignore="UselessParent"> - + - - - -