diff --git a/.github/actions/setup-ccache/action.yml b/.github/actions/setup-ccache/action.yml new file mode 100644 index 0000000..01ee12b --- /dev/null +++ b/.github/actions/setup-ccache/action.yml @@ -0,0 +1,56 @@ +name: Setup ccache +description: "Install ccache, configure it, and restore/save the cache" +inputs: + key: + description: "Cache key for actions/cache" + required: true + restore-keys: + description: "Restore-key prefix for actions/cache" + required: true + maxsize: + description: "CCACHE_MAXSIZE" + required: false + default: "400M" + sloppiness: + description: "CCACHE_SLOPPINESS" + required: false + default: "pch_defines,time_macros" +runs: + using: "composite" + steps: + - name: Configure ccache + shell: bash + env: + CCACHE_MAXSIZE: ${{ inputs.maxsize }} + CCACHE_SLOPPINESS: ${{ inputs.sloppiness }} + run: | + { + echo "CCACHE_BASEDIR=$GITHUB_WORKSPACE" + echo "CCACHE_DIR=$GITHUB_WORKSPACE/.ccache" + echo "CCACHE_COMPRESS=true" + echo "CCACHE_COMPRESSLEVEL=6" + echo "CCACHE_MAXSIZE=$CCACHE_MAXSIZE" + echo "CCACHE_SLOPPINESS=$CCACHE_SLOPPINESS" + } >> "$GITHUB_ENV" + + - name: Install ccache + shell: bash + run: | + # Only used as a compiler launcher on GNU/Clang; ccache's MSVC launcher + # hangs compiler detection on Windows, so skip it there. + if [ "$RUNNER_OS" = "Linux" ]; then + sudo apt-get install -y ccache + elif [ "$RUNNER_OS" = "macOS" ]; then + brew install ccache + fi + + - name: Restore/save ccache + uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # v4.3.0 + with: + path: ${{ github.workspace }}/.ccache + key: ${{ inputs.key }} + restore-keys: ${{ inputs.restore-keys }} + + - name: Zero ccache stats + shell: bash + run: ccache --zero-stats diff --git a/.github/actions/setup-mongo-c-driver/action.yml b/.github/actions/setup-mongo-c-driver/action.yml new file mode 100644 index 0000000..7fc548e --- /dev/null +++ b/.github/actions/setup-mongo-c-driver/action.yml @@ -0,0 +1,32 @@ +name: Setup mongo-c-driver +description: "Cache and fetch the mongo-c-driver release pinned in meson.build" +runs: + using: "composite" + steps: + - name: Exclude the workspace from Windows Defender + if: runner.os == 'Windows' + shell: powershell + run: | + # Real-time MSVC compilation on GitHub-hosted Windows is throttled by + # Defender; excluding the workspace is the standard, big win. + Add-MpPreference -ExclusionPath "$env:GITHUB_WORKSPACE" -ErrorAction SilentlyContinue + Add-MpPreference -ExclusionPath "$env:GITHUB_WORKSPACE\build" -ErrorAction SilentlyContinue + + - name: Read the pinned mongo-c-driver version + id: pinned + shell: bash + run: | + set -euo pipefail + VERSION=$(python -c "import re,pathlib; print(re.search(r\"mcd_version\s*=\s*'([0-9.]+)'\", pathlib.Path('meson.build').read_text()).group(1))") + echo "version=$VERSION" >> "$GITHUB_OUTPUT" + + - name: Restore/save mongo-c-driver tarball + uses: actions/cache@0057852bfaa89a56745cba8c7296529d2fc39830 # v4.3.0 + with: + path: ${{ github.workspace }}/.mongo-c-driver + key: mcd-${{ steps.pinned.outputs.version }}-${{ runner.os }}-${{ github.sha }} + restore-keys: mcd-${{ steps.pinned.outputs.version }}-${{ runner.os }}- + + - name: Fetch and extract mongo-c-driver + shell: bash + run: python scripts/fetch_mongo_c_driver.py diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml new file mode 100644 index 0000000..f5b8ab7 --- /dev/null +++ b/.github/workflows/codeql.yml @@ -0,0 +1,54 @@ +name: "CodeQL" + +on: + push: + branches: ["master"] + pull_request: + schedule: + - cron: '17 10 * * 2' + +concurrency: + group: codeql-${{ github.ref }} + cancel-in-progress: true + +jobs: + analyze: + name: Analyze (${{ matrix.language }}) + runs-on: ubuntu-latest + permissions: + security-events: write + contents: read + actions: read + + strategy: + fail-fast: false + matrix: + include: + - language: c-cpp + build-mode: manual + # Configure with Meson so libbson's config.h/version.h are generated + # and the extension's compile flags are computed in one place, then + # compile bsonjs.c with the exact command recorded in + # compile_commands.json so the flags cannot drift from meson.build. + # CodeQL's tracer only extracts files the compiler is actually + # invoked on, so filtering to bsonjs.c keeps libbson out of scope. + manual-build-command: | + pip install "meson>=1.3" ninja + python3 scripts/fetch_mongo_c_driver.py + meson setup /tmp/codeql-build + cmd=$(jq -r '.[] | select(.file | endswith("bsonjs.c")) | .command' /tmp/codeql-build/compile_commands.json) + o=$(printf '%s' "$cmd" | grep -o '\-o [^ ]*' | cut -d' ' -f2) + (cd /tmp/codeql-build && mkdir -p "$(dirname "$o")" && bash -c "$cmd") + - language: python + build-mode: none + - language: actions + build-mode: none + steps: + - uses: mongodb-labs/drivers-github-tools/codeql@f137fdd28483af14ebf466ebc5aa789fbf867218 # v3 + with: + language: ${{ matrix.language }} + build-mode: ${{ matrix.build-mode }} + manual-build-command: ${{ matrix.manual-build-command }} + config: | + paths-ignore: + - 'test/**' diff --git a/.github/workflows/dist.yml b/.github/workflows/dist.yml index 83da385..386fa84 100644 --- a/.github/workflows/dist.yml +++ b/.github/workflows/dist.yml @@ -23,19 +23,61 @@ defaults: run: shell: bash -eux {0} +permissions: + contents: read + jobs: build_wheels: runs-on: ${{ matrix.os }} strategy: + fail-fast: false matrix: - os: [macos-latest, windows-latest, ubuntu-24.04-arm, ubuntu-latest] + os: [macos-latest, windows-2022, ubuntu-24.04-arm, ubuntu-latest] name: Build CPython-${{ matrix.os }} steps: - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 with: persist-credentials: false - - uses: pypa/cibuildwheel@4726cd35bb13f7bde50cf2761f2499ac7b3aa32c # v4.1.1 - - uses: actions/upload-artifact@v7 + - name: Set up ccache + if: runner.os != 'Windows' + uses: ./.github/actions/setup-ccache + with: + key: ccache-${{ runner.os }}-${{ github.sha }} + restore-keys: ccache-${{ runner.os }}- + - name: Set up mongo-c-driver + uses: ./.github/actions/setup-mongo-c-driver + - name: Build wheels (macOS/Linux) + if: runner.os != 'Windows' + uses: pypa/cibuildwheel@4726cd35bb13f7bde50cf2761f2499ac7b3aa32c # v4.1.1 + - name: Build wheels (Windows AMD64) + if: runner.os == 'Windows' + uses: pypa/cibuildwheel@4726cd35bb13f7bde50cf2761f2499ac7b3aa32c # v4.1.1 + env: + CIBW_ARCHS: AMD64 + # Meson's --vsenv activates only the x64 toolset, and its Python + # dependency check rejects a 32-bit Python against an x64 compiler + # ("Need python for x86_64, but found x86"). Exporting the x86 toolset + # environment here makes Meson skip its own activation (VSINSTALLDIR is + # set) and detect the x86 compiler instead, so the host machine reads + # as x86 and matches the 32-bit Python. + - name: Export the x86 MSVC environment + if: runner.os == 'Windows' + shell: powershell + run: | + $vswhere = "${env:ProgramFiles(x86)}\Microsoft Visual Studio\Installer\vswhere.exe" + $vcvarsall = & $vswhere -latest -products * -requires Microsoft.VisualStudio.Component.VC.Tools.x86.x64 -find "VC\Auxiliary\Build\vcvarsall.bat" | Select-Object -First 1 + if (-not $vcvarsall) { throw "vcvarsall.bat not found" } + cmd /s /c "`"$vcvarsall`" x86 && set" | ForEach-Object { + if ($_ -match '^([^=]+)=(.*)$') { + Add-Content -Path $env:GITHUB_ENV -Value "$($Matches[1])=$($Matches[2])" + } + } + - name: Build wheels (Windows x86) + if: runner.os == 'Windows' + uses: pypa/cibuildwheel@4726cd35bb13f7bde50cf2761f2499ac7b3aa32c # v4.1.1 + env: + CIBW_ARCHS: x86 + - uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 with: name: ${{ matrix.os }}-wheel path: ./wheelhouse/*.whl @@ -50,12 +92,12 @@ jobs: - name: Setup Python uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97 # v7.0.0 with: - python-version: 3.9 + python-version: 3.11 - name: Build SDist run: | python -m pip install build python -m build --sdist - - uses: actions/upload-artifact@v7 + - uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 with: name: "sdist" path: dist/*.tar.gz @@ -65,13 +107,13 @@ jobs: name: Download Wheels steps: - name: Download all workflow run artifacts - uses: actions/download-artifact@v8 + uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1 - name: Flatten directory working-directory: . run: | find . -mindepth 2 -type f -exec mv {} . \; find . -type d -empty -delete - - uses: actions/upload-artifact@v7 + - uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 with: name: all-dist-${{ github.run_id }} path: "./*" \ No newline at end of file diff --git a/.github/workflows/release-python.yml b/.github/workflows/release-python.yml index 6c674f1..59a0714 100644 --- a/.github/workflows/release-python.yml +++ b/.github/workflows/release-python.yml @@ -29,6 +29,9 @@ defaults: run: shell: bash -eux {0} +permissions: + contents: read + jobs: pre-publish: environment: release @@ -73,7 +76,7 @@ jobs: id-token: write steps: - name: Download all the dists - uses: actions/download-artifact@v8 + uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1 with: name: all-dist-${{ github.run_id }} path: dist/ diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 16440cb..58f8640 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -6,29 +6,184 @@ on: pull_request: workflow_dispatch: +permissions: + contents: read + concurrency: group: test-${{ github.ref }} cancel-in-progress: true +defaults: + run: + shell: bash + jobs: - build: + # Build the cp311-abi3 wheel once per platform, as separate jobs so each + # OS's tests only wait on its own build (not on the others). + build-macos: + runs-on: macos-latest + steps: + - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + with: + persist-credentials: false + - name: Set up Python + uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97 # v7.0.0 + with: + python-version: "3.11" + - name: Set up ccache + uses: ./.github/actions/setup-ccache + with: + key: ccache-${{ runner.os }}-wheel-${{ github.sha }} + restore-keys: ccache-${{ runner.os }}-wheel- + - name: Set up mongo-c-driver + uses: ./.github/actions/setup-mongo-c-driver + - name: Install build dependencies + run: python -m pip install "meson-python>=0.17" "meson>=1.3" ninja + - name: Build wheel + run: python -m pip wheel --no-build-isolation --no-deps -w dist . + - name: Show ccache stats + if: runner.os != 'Windows' + run: ccache -s + - uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 + with: + name: wheel-macos + path: ./dist/*.whl + + build-ubuntu: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + with: + persist-credentials: false + - name: Set up Python + uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97 # v7.0.0 + with: + python-version: "3.11" + - name: Set up ccache + uses: ./.github/actions/setup-ccache + with: + key: ccache-${{ runner.os }}-wheel-${{ github.sha }} + restore-keys: ccache-${{ runner.os }}-wheel- + - name: Set up mongo-c-driver + uses: ./.github/actions/setup-mongo-c-driver + - name: Install build dependencies + run: python -m pip install "meson-python>=0.17" "meson>=1.3" ninja + - name: Build wheel + run: python -m pip wheel --no-build-isolation --no-deps -w dist . + - name: Show ccache stats + if: runner.os != 'Windows' + run: ccache -s + - uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 + with: + name: wheel-ubuntu + path: ./dist/*.whl + + build-windows: + runs-on: windows-2022 + steps: + - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + with: + persist-credentials: false + - name: Set up Python + uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97 # v7.0.0 + with: + python-version: "3.11" + - name: Set up ccache + if: runner.os != 'Windows' + uses: ./.github/actions/setup-ccache + with: + key: ccache-${{ runner.os }}-wheel-${{ github.sha }} + restore-keys: ccache-${{ runner.os }}-wheel- + - name: Set up mongo-c-driver + uses: ./.github/actions/setup-mongo-c-driver + - name: Install build dependencies + run: python -m pip install "meson-python>=0.17" "meson>=1.3" ninja + - name: Build wheel + run: python -m pip wheel --no-build-isolation -Csetup-args=--vsenv --no-deps -w dist . + - name: Show ccache stats + if: runner.os != 'Windows' + run: ccache -s + - uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 + with: + name: wheel-windows + path: ./dist/*.whl + + # Install the prebuilt wheel and run the tests on every supported Python + # version. Each platform's tests depend only on that platform's build. + test-macos: + needs: build-macos + runs-on: macos-latest + strategy: + fail-fast: false + matrix: + python-version: ["3.11", "3.12", "3.13", "3.14"] + steps: + - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + with: + persist-credentials: false + - name: Download wheel + uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1 + with: + name: wheel-macos + path: dist + - name: Set up Python ${{ matrix.python-version }} + uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97 # v7.0.0 + with: + python-version: ${{ matrix.python-version }} + allow-prereleases: true + - name: Test against wheel + run: | + python -m pip install "pymongo>=4" pytest dist/*.whl + pytest - runs-on: ${{ matrix.os }} + test-ubuntu: + needs: build-ubuntu + runs-on: ubuntu-latest strategy: + fail-fast: false matrix: - os: [macos-latest, ubuntu-latest, windows-latest] - python-version: ["3.9", "3.10", "3.11", "3.12", "3.13", "3.14"] + python-version: ["3.11", "3.12", "3.13", "3.14"] + steps: + - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + with: + persist-credentials: false + - name: Download wheel + uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1 + with: + name: wheel-ubuntu + path: dist + - name: Set up Python ${{ matrix.python-version }} + uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97 # v7.0.0 + with: + python-version: ${{ matrix.python-version }} + allow-prereleases: true + - name: Test against wheel + run: | + python -m pip install "pymongo>=4" pytest dist/*.whl + pytest + test-windows: + needs: build-windows + runs-on: windows-2022 + strategy: + fail-fast: false + matrix: + python-version: ["3.11", "3.12", "3.13", "3.14"] steps: - uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 with: persist-credentials: false + - name: Download wheel + uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1 + with: + name: wheel-windows + path: dist - name: Set up Python ${{ matrix.python-version }} uses: actions/setup-python@5fda3b95a4ea91299a34e894583c3862153e4b97 # v7.0.0 with: python-version: ${{ matrix.python-version }} allow-prereleases: true - - name: Test with python + - name: Test against wheel run: | - python -m pip install -v -e ".[test]" + python -m pip install "pymongo>=4" pytest dist/*.whl pytest diff --git a/.gitignore b/.gitignore index b2c9eb3..b450389 100644 --- a/.gitignore +++ b/.gitignore @@ -132,4 +132,7 @@ ENV/ .idea/** # Local checkout of mongo-c-driver -mongo-c-driver/ \ No newline at end of file +mongo-c-driver/ + +# CI cache of the mongo-c-driver release tarball +.mongo-c-driver/ diff --git a/CHANGELOG.rst b/CHANGELOG.rst index fa098c0..bad264f 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -1,6 +1,17 @@ Changelog ========= +0.8.0 +````` +Version 0.8.0 updates the bundled libbson to 2.5.3 and compiles it from the +pinned mongo-c-driver release instead of vendoring C sources. The build now +uses Meson and requires Python 3.11+ (up from 3.9), so the extension is +built against the CPython 3.11 Limited API. Building from source downloads +the mongo-c-driver release tarball on first build. +For a detailed breakdown of what changed in each version of libbson see its changelog: +https://github.com/mongodb/mongo-c-driver/blob/2.5.3/NEWS +http://mongoc.org/libbson/2.5.3/ + 0.7.0 ````` - Add support for Python 3.14. diff --git a/MANIFEST.in b/MANIFEST.in deleted file mode 100644 index 5531919..0000000 --- a/MANIFEST.in +++ /dev/null @@ -1,10 +0,0 @@ -include README.rst -include CHANGELOG.rst -include LICENSE -recursive-include bsonjs LICENSE -recursive-include bsonjs *.h -recursive-include bsonjs *.py -exclude benchmark.py -exclude build-wheels.sh -exclude docker-build.sh -exclude vendor.sh diff --git a/README.rst b/README.rst index 6feb7e2..933488e 100644 --- a/README.rst +++ b/README.rst @@ -9,7 +9,7 @@ About ===== A fast BSON to MongoDB Extended JSON converter for Python that uses -`libbson `_. +`libbson `_. Installation ============ @@ -55,22 +55,22 @@ Using bsonjs with pymongo to insert a RawBSONDocument. Speed ===== -bsonjs is roughly 3-4x faster than PyMongo's json_util at decoding BSON to -JSON and encoding JSON to BSON. See `benchmark.py`:: +bsonjs is roughly 3-9x faster than PyMongo 4.18.1's +json_util at decoding BSON to JSON and encoding JSON to BSON. Benchmarked +against libbson 2.5.3. See `scripts/benchmark.py`:: - $ python benchmark.py + $ python scripts/benchmark.py Timing: bsonjs.dumps(b) - 10000 loops, best of 3: 0.04682216700166464 + 10000 loops, best of 3: 0.024979124995297752 Timing: json_util.dumps(bson.decode(b)) - 10000 loops, best of 3: 0.17319270805455744 - bsonjs is 3.70x faster than json_util + 10000 loops, best of 3: 0.22723987500648946 + bsonjs is 9.10x faster than json_util Timing: bsonjs.loads(j) - 10000 loops, best of 3: 0.053156834095716476 + 10000 loops, best of 3: 0.06294979200174566 Timing: bson.encode(json_util.loads(j)) - 10000 loops, best of 3: 0.15982166700996459 - bsonjs is 3.01x faster than json_util - + 10000 loops, best of 3: 0.2087057090102462 + bsonjs is 3.32x faster than json_util Limitations =========== @@ -107,7 +107,12 @@ like so Installing From Source ====================== -python-bsonjs supports CPython 3.9+. +python-bsonjs supports CPython 3.11+ and builds with Meson through +meson-python. The build compiles libbson from the mongo-c-driver release +pinned in ``meson.build``. It downloads that release on first build, so +the first build needs an internet connection. To build offline, extract +the release under ``.mongo-c-driver/`` or pass +``-Dmongo-c-driver-dir=/path/to/mongo-c-driver-`` to meson. Compiler ```````` @@ -116,7 +121,7 @@ You must build python-bsonjs separately for each version of Python. On Windows this means you must use the same C compiler your Python version was built with. -- Windows build requires Microsoft Visual Studio 2015 +- Windows build requires Microsoft Visual Studio 2019 or newer Source `````` @@ -138,3 +143,18 @@ Test To run the test suite:: $ python -m pytest + +Updating libbson +```````````````` + +The package pulls libbson from the mongo-c-driver release pinned in +`meson.build`. To bump the version, rebuild, and refresh the benchmark +numbers in the Speed section, run:: + + $ bash scripts/bump-libbson.sh + +With no argument the script uses the latest mongo-c-driver release and +exits without making changes when the pinned version is already current. +Pass a version to target a specific release:: + + $ bash scripts/bump-libbson.sh 2.5.3 diff --git a/bson/meson.build b/bson/meson.build new file mode 100644 index 0000000..56e528e --- /dev/null +++ b/bson/meson.build @@ -0,0 +1,16 @@ +# Generated libbson headers (config.h, version.h). +# +# libbson's sources do `#include ` and ``, so +# these must land in /bson/ (the root adds to the include +# path). output cannot contain a path segment, so this lives in a `bson/` +# subdir whose build dir is /bson/. +configure_file( + input: mcd_src / 'src' / 'libbson' / 'src' / 'bson' / 'config.h.in', + output: 'config.h', + configuration: conf, +) +configure_file( + input: mcd_src / 'src' / 'libbson' / 'src' / 'bson' / 'version.h.in', + output: 'version.h', + configuration: version_conf, +) diff --git a/bsonjs/bson/bcon.c b/bsonjs/bson/bcon.c deleted file mode 100644 index 0779d89..0000000 --- a/bsonjs/bson/bcon.c +++ /dev/null @@ -1,995 +0,0 @@ -/* - * @file bcon.c - * @brief BCON (BSON C Object Notation) Implementation - */ - -/* Copyright 2009-2013 MongoDB, Inc. - * - * 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. - */ - - -#include - -#include "bcon.h" -#include - -/* These stack manipulation macros are used to manage append recursion in - * bcon_append_ctx_va(). They take care of some awkward dereference rules (the - * real bson object isn't in the stack, but accessed by pointer) and add in run - * time asserts to make sure we don't blow the stack in either direction */ - -#define STACK_ELE(_delta, _name) (ctx->stack[(_delta) + ctx->n]._name) - -#define STACK_BSON(_delta) (((_delta) + ctx->n) == 0 ? bson : &STACK_ELE (_delta, bson)) - -#define STACK_ITER(_delta) (((_delta) + ctx->n) == 0 ? &root_iter : &STACK_ELE (_delta, iter)) - -#define STACK_BSON_PARENT STACK_BSON (-1) -#define STACK_BSON_CHILD STACK_BSON (0) - -#define STACK_ITER_PARENT STACK_ITER (-1) -#define STACK_ITER_CHILD STACK_ITER (0) - -#define STACK_I STACK_ELE (0, i) -#define STACK_IS_ARRAY STACK_ELE (0, is_array) - -#define STACK_PUSH_ARRAY(statement) \ - do { \ - BSON_ASSERT (ctx->n < (BCON_STACK_MAX - 1)); \ - ctx->n++; \ - STACK_I = 0; \ - STACK_IS_ARRAY = 1; \ - statement; \ - } while (0) - -#define STACK_PUSH_DOC(statement) \ - do { \ - BSON_ASSERT (ctx->n < (BCON_STACK_MAX - 1)); \ - ctx->n++; \ - STACK_IS_ARRAY = 0; \ - statement; \ - } while (0) - -#define STACK_POP_ARRAY(statement) \ - do { \ - BSON_ASSERT (STACK_IS_ARRAY); \ - BSON_ASSERT (ctx->n != 0); \ - statement; \ - ctx->n--; \ - } while (0) - -#define STACK_POP_DOC(statement) \ - do { \ - BSON_ASSERT (!STACK_IS_ARRAY); \ - BSON_ASSERT (ctx->n != 0); \ - statement; \ - ctx->n--; \ - } while (0) - -/* This is a landing pad union for all of the types we can process with bcon. - * We need actual storage for this to capture the return value of va_arg, which - * takes multiple calls to get everything we need for some complex types */ -typedef union bcon_append { - char *UTF8; - double DOUBLE; - bson_t *DOCUMENT; - bson_t *ARRAY; - bson_t *BCON; - - struct { - bson_subtype_t subtype; - uint8_t *binary; - uint32_t length; - } BIN; - - bson_oid_t *OID; - bool BOOL; - int64_t DATE_TIME; - - struct { - char *regex; - char *flags; - } REGEX; - - struct { - char *collection; - bson_oid_t *oid; - } DBPOINTER; - - const char *CODE; - - char *SYMBOL; - - struct { - const char *js; - bson_t *scope; - } CODEWSCOPE; - - int32_t INT32; - - struct { - uint32_t timestamp; - uint32_t increment; - } TIMESTAMP; - - int64_t INT64; - bson_decimal128_t *DECIMAL128; - const bson_iter_t *ITER; -} bcon_append_t; - -/* same as bcon_append_t. Some extra symbols and varying types that handle the - * differences between bson_append and bson_iter */ -typedef union bcon_extract { - bson_type_t TYPE; - bson_iter_t *ITER; - const char *key; - const char **UTF8; - double *DOUBLE; - bson_t *DOCUMENT; - bson_t *ARRAY; - - struct { - bson_subtype_t *subtype; - const uint8_t **binary; - uint32_t *length; - } BIN; - - const bson_oid_t **OID; - bool *BOOL; - int64_t *DATE_TIME; - - struct { - const char **regex; - const char **flags; - } REGEX; - - struct { - const char **collection; - const bson_oid_t **oid; - } DBPOINTER; - - const char **CODE; - - const char **SYMBOL; - - struct { - const char **js; - bson_t *scope; - } CODEWSCOPE; - - int32_t *INT32; - - struct { - uint32_t *timestamp; - uint32_t *increment; - } TIMESTAMP; - - int64_t *INT64; - bson_decimal128_t *DECIMAL128; -} bcon_extract_t; - -static const char *gBconMagic = "BCON_MAGIC"; -static const char *gBconeMagic = "BCONE_MAGIC"; - -const char * -bson_bcon_magic (void) -{ - return gBconMagic; -} - - -const char * -bson_bcone_magic (void) -{ - return gBconeMagic; -} - -static void -_noop (void) -{ -} - -/* appends val to the passed bson object. Meant to be a super simple dispatch - * table */ -static void -_bcon_append_single (bson_t *bson, bcon_type_t type, const char *key, bcon_append_t *val) -{ - switch ((int) type) { - case BCON_TYPE_UTF8: - BSON_ASSERT (bson_append_utf8 (bson, key, -1, val->UTF8, -1)); - break; - case BCON_TYPE_DOUBLE: - BSON_ASSERT (bson_append_double (bson, key, -1, val->DOUBLE)); - break; - case BCON_TYPE_BIN: { - BSON_ASSERT (bson_append_binary (bson, key, -1, val->BIN.subtype, val->BIN.binary, val->BIN.length)); - break; - } - case BCON_TYPE_UNDEFINED: - BSON_ASSERT (bson_append_undefined (bson, key, -1)); - break; - case BCON_TYPE_OID: - BSON_ASSERT (bson_append_oid (bson, key, -1, val->OID)); - break; - case BCON_TYPE_BOOL: - BSON_ASSERT (bson_append_bool (bson, key, -1, (bool) val->BOOL)); - break; - case BCON_TYPE_DATE_TIME: - BSON_ASSERT (bson_append_date_time (bson, key, -1, val->DATE_TIME)); - break; - case BCON_TYPE_NULL: - BSON_ASSERT (bson_append_null (bson, key, -1)); - break; - case BCON_TYPE_REGEX: { - BSON_ASSERT (bson_append_regex (bson, key, -1, val->REGEX.regex, val->REGEX.flags)); - break; - } - case BCON_TYPE_DBPOINTER: { - BSON_ASSERT (bson_append_dbpointer (bson, key, -1, val->DBPOINTER.collection, val->DBPOINTER.oid)); - break; - } - case BCON_TYPE_CODE: - BSON_ASSERT (bson_append_code (bson, key, -1, val->CODE)); - break; - case BCON_TYPE_SYMBOL: - BSON_ASSERT (bson_append_symbol (bson, key, -1, val->SYMBOL, -1)); - break; - case BCON_TYPE_CODEWSCOPE: - BSON_ASSERT (bson_append_code_with_scope (bson, key, -1, val->CODEWSCOPE.js, val->CODEWSCOPE.scope)); - break; - case BCON_TYPE_INT32: - BSON_ASSERT (bson_append_int32 (bson, key, -1, val->INT32)); - break; - case BCON_TYPE_TIMESTAMP: { - BSON_ASSERT (bson_append_timestamp (bson, key, -1, val->TIMESTAMP.timestamp, val->TIMESTAMP.increment)); - break; - } - case BCON_TYPE_INT64: - BSON_ASSERT (bson_append_int64 (bson, key, -1, val->INT64)); - break; - case BCON_TYPE_DECIMAL128: - BSON_ASSERT (bson_append_decimal128 (bson, key, -1, val->DECIMAL128)); - break; - case BCON_TYPE_MAXKEY: - BSON_ASSERT (bson_append_maxkey (bson, key, -1)); - break; - case BCON_TYPE_MINKEY: - BSON_ASSERT (bson_append_minkey (bson, key, -1)); - break; - case BCON_TYPE_ARRAY: { - BSON_ASSERT (bson_append_array (bson, key, -1, val->ARRAY)); - break; - } - case BCON_TYPE_DOCUMENT: { - BSON_ASSERT (bson_append_document (bson, key, -1, val->DOCUMENT)); - break; - } - case BCON_TYPE_ITER: - BSON_ASSERT (bson_append_iter (bson, key, -1, val->ITER)); - break; - default: - BSON_ASSERT (0); - break; - } -} - -#define CHECK_TYPE(_type) \ - do { \ - if (bson_iter_type (iter) != (_type)) { \ - return false; \ - } \ - } while (0) - -/* extracts the value under the iterator and writes it to val. returns false - * if the iterator type doesn't match the token type. - * - * There are two magic tokens: - * - * BCONE_SKIP - - * Let's us verify that a key has a type, without caring about its value. - * This allows for wider declarative BSON verification - * - * BCONE_ITER - - * Returns the underlying iterator. This could allow for more complicated, - * procedural verification (if a parameter could have multiple types). - * */ -static bool -_bcon_extract_single (const bson_iter_t *iter, bcon_type_t type, bcon_extract_t *val) -{ - switch ((int) type) { - case BCON_TYPE_UTF8: - CHECK_TYPE (BSON_TYPE_UTF8); - *val->UTF8 = bson_iter_utf8 (iter, NULL); - break; - case BCON_TYPE_DOUBLE: - CHECK_TYPE (BSON_TYPE_DOUBLE); - *val->DOUBLE = bson_iter_double (iter); - break; - case BCON_TYPE_BIN: - CHECK_TYPE (BSON_TYPE_BINARY); - bson_iter_binary (iter, val->BIN.subtype, val->BIN.length, val->BIN.binary); - break; - case BCON_TYPE_UNDEFINED: - CHECK_TYPE (BSON_TYPE_UNDEFINED); - break; - case BCON_TYPE_OID: - CHECK_TYPE (BSON_TYPE_OID); - *val->OID = bson_iter_oid (iter); - break; - case BCON_TYPE_BOOL: - CHECK_TYPE (BSON_TYPE_BOOL); - *val->BOOL = bson_iter_bool (iter); - break; - case BCON_TYPE_DATE_TIME: - CHECK_TYPE (BSON_TYPE_DATE_TIME); - *val->DATE_TIME = bson_iter_date_time (iter); - break; - case BCON_TYPE_NULL: - CHECK_TYPE (BSON_TYPE_NULL); - break; - case BCON_TYPE_REGEX: - CHECK_TYPE (BSON_TYPE_REGEX); - *val->REGEX.regex = bson_iter_regex (iter, val->REGEX.flags); - - break; - case BCON_TYPE_DBPOINTER: - CHECK_TYPE (BSON_TYPE_DBPOINTER); - bson_iter_dbpointer (iter, NULL, val->DBPOINTER.collection, val->DBPOINTER.oid); - break; - case BCON_TYPE_CODE: - CHECK_TYPE (BSON_TYPE_CODE); - *val->CODE = bson_iter_code (iter, NULL); - break; - case BCON_TYPE_SYMBOL: - CHECK_TYPE (BSON_TYPE_SYMBOL); - *val->SYMBOL = bson_iter_symbol (iter, NULL); - break; - case BCON_TYPE_CODEWSCOPE: { - const uint8_t *buf; - uint32_t len; - - CHECK_TYPE (BSON_TYPE_CODEWSCOPE); - - *val->CODEWSCOPE.js = bson_iter_codewscope (iter, NULL, &len, &buf); - - BSON_ASSERT (bson_init_static (val->CODEWSCOPE.scope, buf, len)); - break; - } - case BCON_TYPE_INT32: - CHECK_TYPE (BSON_TYPE_INT32); - *val->INT32 = bson_iter_int32 (iter); - break; - case BCON_TYPE_TIMESTAMP: - CHECK_TYPE (BSON_TYPE_TIMESTAMP); - bson_iter_timestamp (iter, val->TIMESTAMP.timestamp, val->TIMESTAMP.increment); - break; - case BCON_TYPE_INT64: - CHECK_TYPE (BSON_TYPE_INT64); - *val->INT64 = bson_iter_int64 (iter); - break; - case BCON_TYPE_DECIMAL128: - CHECK_TYPE (BSON_TYPE_DECIMAL128); - BSON_ASSERT (bson_iter_decimal128 (iter, val->DECIMAL128)); - break; - case BCON_TYPE_MAXKEY: - CHECK_TYPE (BSON_TYPE_MAXKEY); - break; - case BCON_TYPE_MINKEY: - CHECK_TYPE (BSON_TYPE_MINKEY); - break; - case BCON_TYPE_ARRAY: { - const uint8_t *buf; - uint32_t len; - - CHECK_TYPE (BSON_TYPE_ARRAY); - - bson_iter_array (iter, &len, &buf); - - BSON_ASSERT (bson_init_static (val->ARRAY, buf, len)); - break; - } - case BCON_TYPE_DOCUMENT: { - const uint8_t *buf; - uint32_t len; - - CHECK_TYPE (BSON_TYPE_DOCUMENT); - - bson_iter_document (iter, &len, &buf); - - BSON_ASSERT (bson_init_static (val->DOCUMENT, buf, len)); - break; - } - case BCON_TYPE_SKIP: - CHECK_TYPE (val->TYPE); - break; - case BCON_TYPE_ITER: - memcpy (val->ITER, iter, sizeof *iter); - break; - default: - BSON_ASSERT (0); - break; - } - - return true; -} - -/* Consumes ap, storing output values into u and returning the type of the - * captured token. - * - * The basic workflow goes like this: - * - * 1. Look at the current arg. It will be a char * - * a. If it's a NULL, we're done processing. - * b. If it's BCON_MAGIC (a symbol with storage in this module) - * I. The next token is the type - * II. The type specifies how many args to eat and their types - * c. Otherwise it's either recursion related or a raw string - * I. If the first byte is '{', '}', '[', or ']' pass back an - * appropriate recursion token - * II. If not, just call it a UTF8 token and pass that back - */ -static bcon_type_t -_bcon_append_tokenize (va_list *ap, bcon_append_t *u) -{ - char *mark; - bcon_type_t type; - - mark = va_arg (*ap, char *); - - BSON_ASSERT (mark != BCONE_MAGIC); - - if (mark == NULL) { - type = BCON_TYPE_END; - } else if (mark == BCON_MAGIC) { - type = va_arg (*ap, bcon_type_t); - - switch ((int) type) { - case BCON_TYPE_UTF8: - u->UTF8 = va_arg (*ap, char *); - break; - case BCON_TYPE_DOUBLE: - u->DOUBLE = va_arg (*ap, double); - break; - case BCON_TYPE_DOCUMENT: - u->DOCUMENT = va_arg (*ap, bson_t *); - break; - case BCON_TYPE_ARRAY: - u->ARRAY = va_arg (*ap, bson_t *); - break; - case BCON_TYPE_BIN: - u->BIN.subtype = va_arg (*ap, bson_subtype_t); - u->BIN.binary = va_arg (*ap, uint8_t *); - u->BIN.length = va_arg (*ap, uint32_t); - break; - case BCON_TYPE_UNDEFINED: - break; - case BCON_TYPE_OID: - u->OID = va_arg (*ap, bson_oid_t *); - break; - case BCON_TYPE_BOOL: - u->BOOL = va_arg (*ap, int); - break; - case BCON_TYPE_DATE_TIME: - u->DATE_TIME = va_arg (*ap, int64_t); - break; - case BCON_TYPE_NULL: - break; - case BCON_TYPE_REGEX: - u->REGEX.regex = va_arg (*ap, char *); - u->REGEX.flags = va_arg (*ap, char *); - break; - case BCON_TYPE_DBPOINTER: - u->DBPOINTER.collection = va_arg (*ap, char *); - u->DBPOINTER.oid = va_arg (*ap, bson_oid_t *); - break; - case BCON_TYPE_CODE: - u->CODE = va_arg (*ap, char *); - break; - case BCON_TYPE_SYMBOL: - u->SYMBOL = va_arg (*ap, char *); - break; - case BCON_TYPE_CODEWSCOPE: - u->CODEWSCOPE.js = va_arg (*ap, char *); - u->CODEWSCOPE.scope = va_arg (*ap, bson_t *); - break; - case BCON_TYPE_INT32: - u->INT32 = va_arg (*ap, int32_t); - break; - case BCON_TYPE_TIMESTAMP: - u->TIMESTAMP.timestamp = va_arg (*ap, uint32_t); - u->TIMESTAMP.increment = va_arg (*ap, uint32_t); - break; - case BCON_TYPE_INT64: - u->INT64 = va_arg (*ap, int64_t); - break; - case BCON_TYPE_DECIMAL128: - u->DECIMAL128 = va_arg (*ap, bson_decimal128_t *); - break; - case BCON_TYPE_MAXKEY: - break; - case BCON_TYPE_MINKEY: - break; - case BCON_TYPE_BCON: - u->BCON = va_arg (*ap, bson_t *); - break; - case BCON_TYPE_ITER: - u->ITER = va_arg (*ap, const bson_iter_t *); - break; - default: - BSON_ASSERT (0); - break; - } - } else { - switch (mark[0]) { - case '{': - type = BCON_TYPE_DOC_START; - break; - case '}': - type = BCON_TYPE_DOC_END; - break; - case '[': - type = BCON_TYPE_ARRAY_START; - break; - case ']': - type = BCON_TYPE_ARRAY_END; - break; - - default: - type = BCON_TYPE_UTF8; - u->UTF8 = mark; - break; - } - } - - return type; -} - - -/* Consumes ap, storing output values into u and returning the type of the - * captured token. - * - * The basic workflow goes like this: - * - * 1. Look at the current arg. It will be a char * - * a. If it's a NULL, we're done processing. - * b. If it's BCONE_MAGIC (a symbol with storage in this module) - * I. The next token is the type - * II. The type specifies how many args to eat and their types - * c. Otherwise it's either recursion related or a raw string - * I. If the first byte is '{', '}', '[', or ']' pass back an - * appropriate recursion token - * II. If not, just call it a UTF8 token and pass that back - */ -static bcon_type_t -_bcon_extract_tokenize (va_list *ap, bcon_extract_t *u) -{ - char *mark; - bcon_type_t type; - - mark = va_arg (*ap, char *); - - BSON_ASSERT (mark != BCON_MAGIC); - - if (mark == NULL) { - type = BCON_TYPE_END; - } else if (mark == BCONE_MAGIC) { - type = va_arg (*ap, bcon_type_t); - - switch ((int) type) { - case BCON_TYPE_UTF8: - u->UTF8 = va_arg (*ap, const char **); - break; - case BCON_TYPE_DOUBLE: - u->DOUBLE = va_arg (*ap, double *); - break; - case BCON_TYPE_DOCUMENT: - u->DOCUMENT = va_arg (*ap, bson_t *); - break; - case BCON_TYPE_ARRAY: - u->ARRAY = va_arg (*ap, bson_t *); - break; - case BCON_TYPE_BIN: - u->BIN.subtype = va_arg (*ap, bson_subtype_t *); - u->BIN.binary = va_arg (*ap, const uint8_t **); - u->BIN.length = va_arg (*ap, uint32_t *); - break; - case BCON_TYPE_UNDEFINED: - break; - case BCON_TYPE_OID: - u->OID = va_arg (*ap, const bson_oid_t **); - break; - case BCON_TYPE_BOOL: - u->BOOL = va_arg (*ap, bool *); - break; - case BCON_TYPE_DATE_TIME: - u->DATE_TIME = va_arg (*ap, int64_t *); - break; - case BCON_TYPE_NULL: - break; - case BCON_TYPE_REGEX: - u->REGEX.regex = va_arg (*ap, const char **); - u->REGEX.flags = va_arg (*ap, const char **); - break; - case BCON_TYPE_DBPOINTER: - u->DBPOINTER.collection = va_arg (*ap, const char **); - u->DBPOINTER.oid = va_arg (*ap, const bson_oid_t **); - break; - case BCON_TYPE_CODE: - u->CODE = va_arg (*ap, const char **); - break; - case BCON_TYPE_SYMBOL: - u->SYMBOL = va_arg (*ap, const char **); - break; - case BCON_TYPE_CODEWSCOPE: - u->CODEWSCOPE.js = va_arg (*ap, const char **); - u->CODEWSCOPE.scope = va_arg (*ap, bson_t *); - break; - case BCON_TYPE_INT32: - u->INT32 = va_arg (*ap, int32_t *); - break; - case BCON_TYPE_TIMESTAMP: - u->TIMESTAMP.timestamp = va_arg (*ap, uint32_t *); - u->TIMESTAMP.increment = va_arg (*ap, uint32_t *); - break; - case BCON_TYPE_INT64: - u->INT64 = va_arg (*ap, int64_t *); - break; - case BCON_TYPE_DECIMAL128: - u->DECIMAL128 = va_arg (*ap, bson_decimal128_t *); - break; - case BCON_TYPE_MAXKEY: - break; - case BCON_TYPE_MINKEY: - break; - case BCON_TYPE_SKIP: - u->TYPE = va_arg (*ap, bson_type_t); - break; - case BCON_TYPE_ITER: - u->ITER = va_arg (*ap, bson_iter_t *); - break; - default: - BSON_ASSERT (0); - break; - } - } else { - switch (mark[0]) { - case '{': - type = BCON_TYPE_DOC_START; - break; - case '}': - type = BCON_TYPE_DOC_END; - break; - case '[': - type = BCON_TYPE_ARRAY_START; - break; - case ']': - type = BCON_TYPE_ARRAY_END; - break; - - default: - type = BCON_TYPE_RAW; - u->key = mark; - break; - } - } - - return type; -} - - -/* This trivial utility function is useful for concatenating a bson object onto - * the end of another, ignoring the keys from the source bson object and - * continuing to use and increment the keys from the source. It's only useful - * when called from bcon_append_ctx_va */ -static void -_bson_concat_array (bson_t *dest, const bson_t *src, bcon_append_ctx_t *ctx) -{ - bson_iter_t iter; - const char *key; - char i_str[16]; - bool r; - - r = bson_iter_init (&iter, src); - - if (!r) { - fprintf (stderr, "Invalid BSON document, possible memory coruption.\n"); - return; - } - - STACK_I--; - - while (bson_iter_next (&iter)) { - bson_uint32_to_string (STACK_I, &key, i_str, sizeof i_str); - STACK_I++; - - BSON_ASSERT (bson_append_iter (dest, key, -1, &iter)); - } -} - - -/* Append_ctx_va consumes the va_list until NULL is found, appending into bson - * as tokens are found. It can receive or return an in-progress bson object - * via the ctx param. It can also operate on the middle of a va_list, and so - * can be wrapped inside of another varargs function. - * - * Note that passing in a va_list that isn't perferectly formatted for BCON - * ingestion will almost certainly result in undefined behavior - * - * The workflow relies on the passed ctx object, which holds a stack of bson - * objects, along with metadata (if the emedded layer is an array, and which - * element it is on if so). We iterate, generating tokens from the va_list, - * until we reach an END token. If any errors occur, we just blow up (the - * var_args stuff is already incredibly fragile to mistakes, and we have no way - * of introspecting, so just don't screw it up). - * - * There are also a few STACK_* macros in here which manipulate ctx that are - * defined up top. - * */ -void -bcon_append_ctx_va (bson_t *bson, bcon_append_ctx_t *ctx, va_list *ap) -{ - bcon_type_t type; - const char *key; - char i_str[16]; - - bcon_append_t u = {0}; - - while (1) { - if (STACK_IS_ARRAY) { - bson_uint32_to_string (STACK_I, &key, i_str, sizeof i_str); - STACK_I++; - } else { - type = _bcon_append_tokenize (ap, &u); - - if (type == BCON_TYPE_END) { - return; - } - - if (type == BCON_TYPE_DOC_END) { - STACK_POP_DOC (bson_append_document_end (STACK_BSON_PARENT, STACK_BSON_CHILD)); - continue; - } - - if (type == BCON_TYPE_BCON) { - bson_concat (STACK_BSON_CHILD, u.BCON); - continue; - } - - BSON_ASSERT (type == BCON_TYPE_UTF8); - - key = u.UTF8; - } - - type = _bcon_append_tokenize (ap, &u); - BSON_ASSERT (type != BCON_TYPE_END); - - switch ((int) type) { - case BCON_TYPE_BCON: - BSON_ASSERT (STACK_IS_ARRAY); - _bson_concat_array (STACK_BSON_CHILD, u.BCON, ctx); - - break; - case BCON_TYPE_DOC_START: - STACK_PUSH_DOC (bson_append_document_begin (STACK_BSON_PARENT, key, -1, STACK_BSON_CHILD)); - break; - case BCON_TYPE_DOC_END: - STACK_POP_DOC (bson_append_document_end (STACK_BSON_PARENT, STACK_BSON_CHILD)); - break; - case BCON_TYPE_ARRAY_START: - STACK_PUSH_ARRAY (bson_append_array_begin (STACK_BSON_PARENT, key, -1, STACK_BSON_CHILD)); - break; - case BCON_TYPE_ARRAY_END: - STACK_POP_ARRAY (bson_append_array_end (STACK_BSON_PARENT, STACK_BSON_CHILD)); - break; - default: - _bcon_append_single (STACK_BSON_CHILD, type, key, &u); - - break; - } - } -} - - -/* extract_ctx_va consumes the va_list until NULL is found, extracting values - * as tokens are found. It can receive or return an in-progress bson object - * via the ctx param. It can also operate on the middle of a va_list, and so - * can be wrapped inside of another varargs function. - * - * Note that passing in a va_list that isn't perferectly formatted for BCON - * ingestion will almost certainly result in undefined behavior - * - * The workflow relies on the passed ctx object, which holds a stack of iterator - * objects, along with metadata (if the emedded layer is an array, and which - * element it is on if so). We iterate, generating tokens from the va_list, - * until we reach an END token. If any errors occur, we just blow up (the - * var_args stuff is already incredibly fragile to mistakes, and we have no way - * of introspecting, so just don't screw it up). - * - * There are also a few STACK_* macros in here which manipulate ctx that are - * defined up top. - * - * The function returns true if all tokens could be successfully matched, false - * otherwise. - * */ -bool -bcon_extract_ctx_va (bson_t *bson, bcon_extract_ctx_t *ctx, va_list *ap) -{ - bcon_type_t type; - const char *key; - bson_iter_t root_iter; - bson_iter_t current_iter; - char i_str[16]; - - bcon_extract_t u = {0}; - - BSON_ASSERT (bson_iter_init (&root_iter, bson)); - - while (1) { - if (STACK_IS_ARRAY) { - bson_uint32_to_string (STACK_I, &key, i_str, sizeof i_str); - STACK_I++; - } else { - type = _bcon_extract_tokenize (ap, &u); - - if (type == BCON_TYPE_END) { - return true; - } - - if (type == BCON_TYPE_DOC_END) { - STACK_POP_DOC (_noop ()); - continue; - } - - BSON_ASSERT (type == BCON_TYPE_RAW); - - key = u.key; - } - - type = _bcon_extract_tokenize (ap, &u); - BSON_ASSERT (type != BCON_TYPE_END); - - if (type == BCON_TYPE_DOC_END) { - STACK_POP_DOC (_noop ()); - } else if (type == BCON_TYPE_ARRAY_END) { - STACK_POP_ARRAY (_noop ()); - } else { - memcpy (¤t_iter, STACK_ITER_CHILD, sizeof current_iter); - - if (!bson_iter_find (¤t_iter, key)) { - return false; - } - - switch ((int) type) { - case BCON_TYPE_DOC_START: - - if (bson_iter_type (¤t_iter) != BSON_TYPE_DOCUMENT) { - return false; - } - - STACK_PUSH_DOC (bson_iter_recurse (¤t_iter, STACK_ITER_CHILD)); - break; - case BCON_TYPE_ARRAY_START: - - if (bson_iter_type (¤t_iter) != BSON_TYPE_ARRAY) { - return false; - } - - STACK_PUSH_ARRAY (bson_iter_recurse (¤t_iter, STACK_ITER_CHILD)); - break; - default: - - if (!_bcon_extract_single (¤t_iter, type, &u)) { - return false; - } - - break; - } - } - } -} - -void -bcon_extract_ctx_init (bcon_extract_ctx_t *ctx) -{ - ctx->n = 0; - ctx->stack[0].is_array = false; -} - -bool -bcon_extract (bson_t *bson, ...) -{ - va_list ap; - bcon_extract_ctx_t ctx; - bool r; - - bcon_extract_ctx_init (&ctx); - - va_start (ap, bson); - - r = bcon_extract_ctx_va (bson, &ctx, &ap); - - va_end (ap); - - return r; -} - - -void -bcon_append (bson_t *bson, ...) -{ - va_list ap; - bcon_append_ctx_t ctx; - - bcon_append_ctx_init (&ctx); - - va_start (ap, bson); - - bcon_append_ctx_va (bson, &ctx, &ap); - - va_end (ap); -} - - -void -bcon_append_ctx (bson_t *bson, bcon_append_ctx_t *ctx, ...) -{ - va_list ap; - - va_start (ap, ctx); - - bcon_append_ctx_va (bson, ctx, &ap); - - va_end (ap); -} - - -void -bcon_extract_ctx (bson_t *bson, bcon_extract_ctx_t *ctx, ...) -{ - va_list ap; - - va_start (ap, ctx); - - bcon_extract_ctx_va (bson, ctx, &ap); - - va_end (ap); -} - -void -bcon_append_ctx_init (bcon_append_ctx_t *ctx) -{ - ctx->n = 0; - ctx->stack[0].is_array = 0; -} - - -bson_t * -bcon_new (void *unused, ...) -{ - va_list ap; - bcon_append_ctx_t ctx; - bson_t *bson; - - bcon_append_ctx_init (&ctx); - - bson = bson_new (); - - va_start (ap, unused); - - bcon_append_ctx_va (bson, &ctx, &ap); - - va_end (ap); - - return bson; -} diff --git a/bsonjs/bson/bcon.h b/bsonjs/bson/bcon.h deleted file mode 100644 index d35365e..0000000 --- a/bsonjs/bson/bcon.h +++ /dev/null @@ -1,245 +0,0 @@ -/* - * @file bcon.h - * @brief BCON (BSON C Object Notation) Declarations - */ - -#include - -/* Copyright 2009-2013 MongoDB, Inc. - * - * 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. - */ - -#ifndef BCON_H_ -#define BCON_H_ - -#include "bson.h" - - -BSON_BEGIN_DECLS - - -#define BCON_STACK_MAX 100 - -#define BCON_ENSURE_DECLARE(fun, type) \ - static BSON_INLINE type bcon_ensure_##fun (type _t) \ - { \ - return _t; \ - } - -#define BCON_ENSURE(fun, val) bcon_ensure_##fun (val) - -#define BCON_ENSURE_STORAGE(fun, val) bcon_ensure_##fun (&(val)) - -BCON_ENSURE_DECLARE (const_char_ptr, const char *) -BCON_ENSURE_DECLARE (const_char_ptr_ptr, const char **) -BCON_ENSURE_DECLARE (double, double) -BCON_ENSURE_DECLARE (double_ptr, double *) -BCON_ENSURE_DECLARE (const_bson_ptr, const bson_t *) -BCON_ENSURE_DECLARE (bson_ptr, bson_t *) -BCON_ENSURE_DECLARE (subtype, bson_subtype_t) -BCON_ENSURE_DECLARE (subtype_ptr, bson_subtype_t *) -BCON_ENSURE_DECLARE (const_uint8_ptr, const uint8_t *) -BCON_ENSURE_DECLARE (const_uint8_ptr_ptr, const uint8_t **) -BCON_ENSURE_DECLARE (uint32, uint32_t) -BCON_ENSURE_DECLARE (uint32_ptr, uint32_t *) -BCON_ENSURE_DECLARE (const_oid_ptr, const bson_oid_t *) -BCON_ENSURE_DECLARE (const_oid_ptr_ptr, const bson_oid_t **) -BCON_ENSURE_DECLARE (int32, int32_t) -BCON_ENSURE_DECLARE (int32_ptr, int32_t *) -BCON_ENSURE_DECLARE (int64, int64_t) -BCON_ENSURE_DECLARE (int64_ptr, int64_t *) -BCON_ENSURE_DECLARE (const_decimal128_ptr, const bson_decimal128_t *) -BCON_ENSURE_DECLARE (bool, bool) -BCON_ENSURE_DECLARE (bool_ptr, bool *) -BCON_ENSURE_DECLARE (bson_type, bson_type_t) -BCON_ENSURE_DECLARE (bson_iter_ptr, bson_iter_t *) -BCON_ENSURE_DECLARE (const_bson_iter_ptr, const bson_iter_t *) - -#define BCON_UTF8(_val) BCON_MAGIC, BCON_TYPE_UTF8, BCON_ENSURE (const_char_ptr, (_val)) -#define BCON_DOUBLE(_val) BCON_MAGIC, BCON_TYPE_DOUBLE, BCON_ENSURE (double, (_val)) -#define BCON_DOCUMENT(_val) BCON_MAGIC, BCON_TYPE_DOCUMENT, BCON_ENSURE (const_bson_ptr, (_val)) -#define BCON_ARRAY(_val) BCON_MAGIC, BCON_TYPE_ARRAY, BCON_ENSURE (const_bson_ptr, (_val)) -#define BCON_BIN(_subtype, _binary, _length) \ - BCON_MAGIC, BCON_TYPE_BIN, BCON_ENSURE (subtype, (_subtype)), BCON_ENSURE (const_uint8_ptr, (_binary)), \ - BCON_ENSURE (uint32, (_length)) -#define BCON_UNDEFINED BCON_MAGIC, BCON_TYPE_UNDEFINED -#define BCON_OID(_val) BCON_MAGIC, BCON_TYPE_OID, BCON_ENSURE (const_oid_ptr, (_val)) -#define BCON_BOOL(_val) BCON_MAGIC, BCON_TYPE_BOOL, BCON_ENSURE (bool, (_val)) -#define BCON_DATE_TIME(_val) BCON_MAGIC, BCON_TYPE_DATE_TIME, BCON_ENSURE (int64, (_val)) -#define BCON_NULL BCON_MAGIC, BCON_TYPE_NULL -#define BCON_REGEX(_regex, _flags) \ - BCON_MAGIC, BCON_TYPE_REGEX, BCON_ENSURE (const_char_ptr, (_regex)), BCON_ENSURE (const_char_ptr, (_flags)) -#define BCON_DBPOINTER(_collection, _oid) \ - BCON_MAGIC, BCON_TYPE_DBPOINTER, BCON_ENSURE (const_char_ptr, (_collection)), BCON_ENSURE (const_oid_ptr, (_oid)) -#define BCON_CODE(_val) BCON_MAGIC, BCON_TYPE_CODE, BCON_ENSURE (const_char_ptr, (_val)) -#define BCON_SYMBOL(_val) BCON_MAGIC, BCON_TYPE_SYMBOL, BCON_ENSURE (const_char_ptr, (_val)) -#define BCON_CODEWSCOPE(_js, _scope) \ - BCON_MAGIC, BCON_TYPE_CODEWSCOPE, BCON_ENSURE (const_char_ptr, (_js)), BCON_ENSURE (const_bson_ptr, (_scope)) -#define BCON_INT32(_val) BCON_MAGIC, BCON_TYPE_INT32, BCON_ENSURE (int32, (_val)) -#define BCON_TIMESTAMP(_timestamp, _increment) \ - BCON_MAGIC, BCON_TYPE_TIMESTAMP, BCON_ENSURE (int32, (_timestamp)), BCON_ENSURE (int32, (_increment)) -#define BCON_INT64(_val) BCON_MAGIC, BCON_TYPE_INT64, BCON_ENSURE (int64, (_val)) -#define BCON_DECIMAL128(_val) BCON_MAGIC, BCON_TYPE_DECIMAL128, BCON_ENSURE (const_decimal128_ptr, (_val)) -#define BCON_MAXKEY BCON_MAGIC, BCON_TYPE_MAXKEY -#define BCON_MINKEY BCON_MAGIC, BCON_TYPE_MINKEY -#define BCON(_val) BCON_MAGIC, BCON_TYPE_BCON, BCON_ENSURE (const_bson_ptr, (_val)) -#define BCON_ITER(_val) BCON_MAGIC, BCON_TYPE_ITER, BCON_ENSURE (const_bson_iter_ptr, (_val)) - -#define BCONE_UTF8(_val) BCONE_MAGIC, BCON_TYPE_UTF8, BCON_ENSURE_STORAGE (const_char_ptr_ptr, (_val)) -#define BCONE_DOUBLE(_val) BCONE_MAGIC, BCON_TYPE_DOUBLE, BCON_ENSURE_STORAGE (double_ptr, (_val)) -#define BCONE_DOCUMENT(_val) BCONE_MAGIC, BCON_TYPE_DOCUMENT, BCON_ENSURE_STORAGE (bson_ptr, (_val)) -#define BCONE_ARRAY(_val) BCONE_MAGIC, BCON_TYPE_ARRAY, BCON_ENSURE_STORAGE (bson_ptr, (_val)) -#define BCONE_BIN(subtype, binary, length) \ - BCONE_MAGIC, BCON_TYPE_BIN, BCON_ENSURE_STORAGE (subtype_ptr, (subtype)), \ - BCON_ENSURE_STORAGE (const_uint8_ptr_ptr, (binary)), BCON_ENSURE_STORAGE (uint32_ptr, (length)) -#define BCONE_UNDEFINED BCONE_MAGIC, BCON_TYPE_UNDEFINED -#define BCONE_OID(_val) BCONE_MAGIC, BCON_TYPE_OID, BCON_ENSURE_STORAGE (const_oid_ptr_ptr, (_val)) -#define BCONE_BOOL(_val) BCONE_MAGIC, BCON_TYPE_BOOL, BCON_ENSURE_STORAGE (bool_ptr, (_val)) -#define BCONE_DATE_TIME(_val) BCONE_MAGIC, BCON_TYPE_DATE_TIME, BCON_ENSURE_STORAGE (int64_ptr, (_val)) -#define BCONE_NULL BCONE_MAGIC, BCON_TYPE_NULL -#define BCONE_REGEX(_regex, _flags) \ - BCONE_MAGIC, BCON_TYPE_REGEX, BCON_ENSURE_STORAGE (const_char_ptr_ptr, (_regex)), \ - BCON_ENSURE_STORAGE (const_char_ptr_ptr, (_flags)) -#define BCONE_DBPOINTER(_collection, _oid) \ - BCONE_MAGIC, BCON_TYPE_DBPOINTER, BCON_ENSURE_STORAGE (const_char_ptr_ptr, (_collection)), \ - BCON_ENSURE_STORAGE (const_oid_ptr_ptr, (_oid)) -#define BCONE_CODE(_val) BCONE_MAGIC, BCON_TYPE_CODE, BCON_ENSURE_STORAGE (const_char_ptr_ptr, (_val)) -#define BCONE_SYMBOL(_val) BCONE_MAGIC, BCON_TYPE_SYMBOL, BCON_ENSURE_STORAGE (const_char_ptr_ptr, (_val)) -#define BCONE_CODEWSCOPE(_js, _scope) \ - BCONE_MAGIC, BCON_TYPE_CODEWSCOPE, BCON_ENSURE_STORAGE (const_char_ptr_ptr, (_js)), \ - BCON_ENSURE_STORAGE (bson_ptr, (_scope)) -#define BCONE_INT32(_val) BCONE_MAGIC, BCON_TYPE_INT32, BCON_ENSURE_STORAGE (int32_ptr, (_val)) -#define BCONE_TIMESTAMP(_timestamp, _increment) \ - BCONE_MAGIC, BCON_TYPE_TIMESTAMP, BCON_ENSURE_STORAGE (int32_ptr, (_timestamp)), \ - BCON_ENSURE_STORAGE (int32_ptr, (_increment)) -#define BCONE_INT64(_val) BCONE_MAGIC, BCON_TYPE_INT64, BCON_ENSURE_STORAGE (int64_ptr, (_val)) -#define BCONE_DECIMAL128(_val) BCONE_MAGIC, BCON_TYPE_DECIMAL128, BCON_ENSURE_STORAGE (const_decimal128_ptr, (_val)) -#define BCONE_MAXKEY BCONE_MAGIC, BCON_TYPE_MAXKEY -#define BCONE_MINKEY BCONE_MAGIC, BCON_TYPE_MINKEY -#define BCONE_SKIP(_val) BCONE_MAGIC, BCON_TYPE_SKIP, BCON_ENSURE (bson_type, (_val)) -#define BCONE_ITER(_val) BCONE_MAGIC, BCON_TYPE_ITER, BCON_ENSURE_STORAGE (bson_iter_ptr, (_val)) - -#define BCON_MAGIC bson_bcon_magic () -#define BCONE_MAGIC bson_bcone_magic () - -typedef enum { - BCON_TYPE_UTF8, - BCON_TYPE_DOUBLE, - BCON_TYPE_DOCUMENT, - BCON_TYPE_ARRAY, - BCON_TYPE_BIN, - BCON_TYPE_UNDEFINED, - BCON_TYPE_OID, - BCON_TYPE_BOOL, - BCON_TYPE_DATE_TIME, - BCON_TYPE_NULL, - BCON_TYPE_REGEX, - BCON_TYPE_DBPOINTER, - BCON_TYPE_CODE, - BCON_TYPE_SYMBOL, - BCON_TYPE_CODEWSCOPE, - BCON_TYPE_INT32, - BCON_TYPE_TIMESTAMP, - BCON_TYPE_INT64, - BCON_TYPE_DECIMAL128, - BCON_TYPE_MAXKEY, - BCON_TYPE_MINKEY, - BCON_TYPE_BCON, - BCON_TYPE_ARRAY_START, - BCON_TYPE_ARRAY_END, - BCON_TYPE_DOC_START, - BCON_TYPE_DOC_END, - BCON_TYPE_END, - BCON_TYPE_RAW, - BCON_TYPE_SKIP, - BCON_TYPE_ITER, - BCON_TYPE_ERROR, -} bcon_type_t; - -typedef struct bcon_append_ctx_frame { - int i; - bool is_array; - bson_t bson; -} bcon_append_ctx_frame_t; - -typedef struct bcon_extract_ctx_frame { - int i; - bool is_array; - bson_iter_t iter; -} bcon_extract_ctx_frame_t; - -typedef struct _bcon_append_ctx_t { - bcon_append_ctx_frame_t stack[BCON_STACK_MAX]; - int n; -} bcon_append_ctx_t; - -typedef struct _bcon_extract_ctx_t { - bcon_extract_ctx_frame_t stack[BCON_STACK_MAX]; - int n; -} bcon_extract_ctx_t; - -BSON_EXPORT (void) -bcon_append (bson_t *bson, ...) BSON_GNUC_NULL_TERMINATED; -BSON_EXPORT (void) -bcon_append_ctx (bson_t *bson, bcon_append_ctx_t *ctx, ...) BSON_GNUC_NULL_TERMINATED; -BSON_EXPORT (void) -bcon_append_ctx_va (bson_t *bson, bcon_append_ctx_t *ctx, va_list *va); -BSON_EXPORT (void) -bcon_append_ctx_init (bcon_append_ctx_t *ctx); - -BSON_EXPORT (void) -bcon_extract_ctx_init (bcon_extract_ctx_t *ctx); - -BSON_EXPORT (void) -bcon_extract_ctx (bson_t *bson, bcon_extract_ctx_t *ctx, ...) BSON_GNUC_NULL_TERMINATED; - -BSON_EXPORT (bool) -bcon_extract_ctx_va (bson_t *bson, bcon_extract_ctx_t *ctx, va_list *ap); - -BSON_EXPORT (bool) -bcon_extract (bson_t *bson, ...) BSON_GNUC_NULL_TERMINATED; - -BSON_EXPORT (bool) -bcon_extract_va (bson_t *bson, bcon_extract_ctx_t *ctx, ...) BSON_GNUC_NULL_TERMINATED; - -BSON_EXPORT (bson_t *) -bcon_new (void *unused, ...) BSON_GNUC_NULL_TERMINATED; - -/** - * The bcon_..() functions are all declared with __attribute__((sentinel)). - * - * From GCC manual for "sentinel": "A valid NULL in this context is defined as - * zero with any pointer type. If your system defines the NULL macro with an - * integer type then you need to add an explicit cast." - * Case in point: GCC on Solaris (at least) - */ -#define BCON_APPEND(_bson, ...) bcon_append ((_bson), __VA_ARGS__, (void *) NULL) -#define BCON_APPEND_CTX(_bson, _ctx, ...) bcon_append_ctx ((_bson), (_ctx), __VA_ARGS__, (void *) NULL) - -#define BCON_EXTRACT(_bson, ...) bcon_extract ((_bson), __VA_ARGS__, (void *) NULL) - -#define BCON_EXTRACT_CTX(_bson, _ctx, ...) bcon_extract ((_bson), (_ctx), __VA_ARGS__, (void *) NULL) - -#define BCON_NEW(...) bcon_new (NULL, __VA_ARGS__, (void *) NULL) - -BSON_EXPORT (const char *) -bson_bcon_magic (void) BSON_GNUC_PURE; -BSON_EXPORT (const char *) -bson_bcone_magic (void) BSON_GNUC_PURE; - - -BSON_END_DECLS - - -#endif diff --git a/bsonjs/bson/bson-atomic.c b/bsonjs/bson/bson-atomic.c deleted file mode 100644 index 18dd4ed..0000000 --- a/bsonjs/bson/bson-atomic.c +++ /dev/null @@ -1,269 +0,0 @@ -/* - * Copyright 2014 MongoDB, Inc. - * - * 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. - */ - - -#include - -#ifdef BSON_OS_UNIX -/* For sched_yield() */ -#include -#endif - -int32_t -bson_atomic_int_add (volatile int32_t *p, int32_t n) -{ - return n + bson_atomic_int32_fetch_add ((DECL_ATOMIC_INTEGRAL_INT32 *) p, n, bson_memory_order_seq_cst); -} - -int64_t -bson_atomic_int64_add (volatile int64_t *p, int64_t n) -{ - return n + bson_atomic_int64_fetch_add (p, n, bson_memory_order_seq_cst); -} - -void -bson_thrd_yield (void) -{ - BSON_IF_WINDOWS (SwitchToThread ();) - BSON_IF_POSIX (sched_yield ();) -} - -void -bson_memory_barrier (void) -{ - bson_atomic_thread_fence (); -} - -/** - * Some platforms do not support compiler intrinsics for atomic operations. - * We emulate that here using a spin lock and regular arithmetic operations - */ -static int8_t gEmulAtomicLock = 0; - -static void -_lock_emul_atomic (void) -{ - int i; - if (bson_atomic_int8_compare_exchange_weak (&gEmulAtomicLock, 0, 1, bson_memory_order_acquire) == 0) { - /* Successfully took the spinlock */ - return; - } - /* Failed. Try taking ten more times, then begin sleeping. */ - for (i = 0; i < 10; ++i) { - if (bson_atomic_int8_compare_exchange_weak (&gEmulAtomicLock, 0, 1, bson_memory_order_acquire) == 0) { - /* Succeeded in taking the lock */ - return; - } - } - /* Still don't have the lock. Spin and yield */ - while (bson_atomic_int8_compare_exchange_weak (&gEmulAtomicLock, 0, 1, bson_memory_order_acquire) != 0) { - bson_thrd_yield (); - } -} - -static void -_unlock_emul_atomic (void) -{ - int64_t rv = bson_atomic_int8_exchange (&gEmulAtomicLock, 0, bson_memory_order_release); - BSON_ASSERT (rv == 1 && "Released atomic lock while not holding it"); -} - -int64_t -_bson_emul_atomic_int64_fetch_add (volatile int64_t *p, int64_t n, enum bson_memory_order _unused) -{ - int64_t ret; - - BSON_UNUSED (_unused); - - _lock_emul_atomic (); - ret = *p; - *p += n; - _unlock_emul_atomic (); - return ret; -} - -int64_t -_bson_emul_atomic_int64_exchange (volatile int64_t *p, int64_t n, enum bson_memory_order _unused) -{ - int64_t ret; - - BSON_UNUSED (_unused); - - _lock_emul_atomic (); - ret = *p; - *p = n; - _unlock_emul_atomic (); - return ret; -} - -int64_t -_bson_emul_atomic_int64_compare_exchange_strong (volatile int64_t *p, - int64_t expect_value, - int64_t new_value, - enum bson_memory_order _unused) -{ - int64_t ret; - - BSON_UNUSED (_unused); - - _lock_emul_atomic (); - ret = *p; - if (ret == expect_value) { - *p = new_value; - } - _unlock_emul_atomic (); - return ret; -} - -int64_t -_bson_emul_atomic_int64_compare_exchange_weak (volatile int64_t *p, - int64_t expect_value, - int64_t new_value, - enum bson_memory_order order) -{ - /* We're emulating. We can't do a weak version. */ - return _bson_emul_atomic_int64_compare_exchange_strong (p, expect_value, new_value, order); -} - - -int32_t -_bson_emul_atomic_int32_fetch_add (volatile int32_t *p, int32_t n, enum bson_memory_order _unused) -{ - int32_t ret; - - BSON_UNUSED (_unused); - - _lock_emul_atomic (); - ret = *p; - *p += n; - _unlock_emul_atomic (); - return ret; -} - -int32_t -_bson_emul_atomic_int32_exchange (volatile int32_t *p, int32_t n, enum bson_memory_order _unused) -{ - int32_t ret; - - BSON_UNUSED (_unused); - - _lock_emul_atomic (); - ret = *p; - *p = n; - _unlock_emul_atomic (); - return ret; -} - -int32_t -_bson_emul_atomic_int32_compare_exchange_strong (volatile int32_t *p, - int32_t expect_value, - int32_t new_value, - enum bson_memory_order _unused) -{ - int32_t ret; - - BSON_UNUSED (_unused); - - _lock_emul_atomic (); - ret = *p; - if (ret == expect_value) { - *p = new_value; - } - _unlock_emul_atomic (); - return ret; -} - -int32_t -_bson_emul_atomic_int32_compare_exchange_weak (volatile int32_t *p, - int32_t expect_value, - int32_t new_value, - enum bson_memory_order order) -{ - /* We're emulating. We can't do a weak version. */ - return _bson_emul_atomic_int32_compare_exchange_strong (p, expect_value, new_value, order); -} - - -int -_bson_emul_atomic_int_fetch_add (volatile int *p, int n, enum bson_memory_order _unused) -{ - int ret; - - BSON_UNUSED (_unused); - - _lock_emul_atomic (); - ret = *p; - *p += n; - _unlock_emul_atomic (); - return ret; -} - -int -_bson_emul_atomic_int_exchange (volatile int *p, int n, enum bson_memory_order _unused) -{ - int ret; - - BSON_UNUSED (_unused); - - _lock_emul_atomic (); - ret = *p; - *p = n; - _unlock_emul_atomic (); - return ret; -} - -int -_bson_emul_atomic_int_compare_exchange_strong (volatile int *p, - int expect_value, - int new_value, - enum bson_memory_order _unused) -{ - int ret; - - BSON_UNUSED (_unused); - - _lock_emul_atomic (); - ret = *p; - if (ret == expect_value) { - *p = new_value; - } - _unlock_emul_atomic (); - return ret; -} - -int -_bson_emul_atomic_int_compare_exchange_weak (volatile int *p, - int expect_value, - int new_value, - enum bson_memory_order order) -{ - /* We're emulating. We can't do a weak version. */ - return _bson_emul_atomic_int_compare_exchange_strong (p, expect_value, new_value, order); -} - -void * -_bson_emul_atomic_ptr_exchange (void *volatile *p, void *n, enum bson_memory_order _unused) -{ - void *ret; - - BSON_UNUSED (_unused); - - _lock_emul_atomic (); - ret = *p; - *p = n; - _unlock_emul_atomic (); - return ret; -} diff --git a/bsonjs/bson/bson-atomic.h b/bsonjs/bson/bson-atomic.h deleted file mode 100644 index 60ab74c..0000000 --- a/bsonjs/bson/bson-atomic.h +++ /dev/null @@ -1,611 +0,0 @@ -/* - * Copyright 2013-2014 MongoDB, Inc. - * - * 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. - */ - -#include - - -#ifndef BSON_ATOMIC_H -#define BSON_ATOMIC_H - - -#include -#include -#include - -#ifdef _MSC_VER -#include -#endif - - -BSON_BEGIN_DECLS - -enum bson_memory_order { - bson_memory_order_seq_cst, - bson_memory_order_acquire, - bson_memory_order_release, - bson_memory_order_relaxed, - bson_memory_order_acq_rel, - bson_memory_order_consume, -}; - -#if defined(_M_ARM) /* MSVC memorder atomics are only avail on ARM */ -#define MSVC_MEMORDER_SUFFIX(X) X -#else -#define MSVC_MEMORDER_SUFFIX(X) -#endif - -#if defined(USE_LEGACY_GCC_ATOMICS) || (!defined(__clang__) && __GNUC__ == 4) || defined(__xlC__) -#define BSON_USE_LEGACY_GCC_ATOMICS -#else -#undef BSON_USE_LEGACY_GCC_ATOMICS -#endif - -/* Not all GCC-like compilers support the current __atomic built-ins. Older - * GCC (pre-5) used different built-ins named with the __sync prefix. When - * compiling with such older GCC versions, it is necessary to use the applicable - * functions, which requires redefining BSON_IF_GNU_LIKE and defining the - * additional BSON_IF_GNU_LEGACY_ATOMICS macro here. */ -#ifdef BSON_USE_LEGACY_GCC_ATOMICS -#undef BSON_IF_GNU_LIKE -#define BSON_IF_GNU_LIKE(...) -#define BSON_IF_MSVC(...) -#define BSON_IF_GNU_LEGACY_ATOMICS(...) __VA_ARGS__ -#else -#define BSON_IF_GNU_LEGACY_ATOMICS(...) -#endif - -/* CDRIVER-4229 zSeries with gcc 4.8.4 produces illegal instructions for int and - * int32 atomic intrinsics. */ -#if defined(__s390__) || defined(__s390x__) || defined(__zarch__) -#define BSON_EMULATE_INT32 -#define BSON_EMULATE_INT -#endif - -/* CDRIVER-4264 Contrary to documentation, VS 2013 targeting x86 does not - * correctly/consistently provide _InterlockedPointerExchange. */ -#if defined(_MSC_VER) && _MSC_VER < 1900 && defined(_M_IX86) -#define BSON_EMULATE_PTR -#endif - -#define DEF_ATOMIC_OP(MSVC_Intrinsic, GNU_Intrinsic, GNU_Legacy_Intrinsic, Order, ...) \ - do { \ - switch (Order) { \ - case bson_memory_order_acq_rel: \ - BSON_IF_MSVC (return MSVC_Intrinsic (__VA_ARGS__);) \ - BSON_IF_GNU_LIKE (return GNU_Intrinsic (__VA_ARGS__, __ATOMIC_ACQ_REL);) \ - BSON_IF_GNU_LEGACY_ATOMICS (return GNU_Legacy_Intrinsic (__VA_ARGS__);) \ - case bson_memory_order_seq_cst: \ - BSON_IF_MSVC (return MSVC_Intrinsic (__VA_ARGS__);) \ - BSON_IF_GNU_LIKE (return GNU_Intrinsic (__VA_ARGS__, __ATOMIC_SEQ_CST);) \ - BSON_IF_GNU_LEGACY_ATOMICS (return GNU_Legacy_Intrinsic (__VA_ARGS__);) \ - case bson_memory_order_acquire: \ - BSON_IF_MSVC (return BSON_CONCAT (MSVC_Intrinsic, MSVC_MEMORDER_SUFFIX (_acq)) (__VA_ARGS__);) \ - BSON_IF_GNU_LIKE (return GNU_Intrinsic (__VA_ARGS__, __ATOMIC_ACQUIRE);) \ - BSON_IF_GNU_LEGACY_ATOMICS (return GNU_Legacy_Intrinsic (__VA_ARGS__);) \ - case bson_memory_order_consume: \ - BSON_IF_MSVC (return BSON_CONCAT (MSVC_Intrinsic, MSVC_MEMORDER_SUFFIX (_acq)) (__VA_ARGS__);) \ - BSON_IF_GNU_LIKE (return GNU_Intrinsic (__VA_ARGS__, __ATOMIC_CONSUME);) \ - BSON_IF_GNU_LEGACY_ATOMICS (return GNU_Legacy_Intrinsic (__VA_ARGS__);) \ - case bson_memory_order_release: \ - BSON_IF_MSVC (return BSON_CONCAT (MSVC_Intrinsic, MSVC_MEMORDER_SUFFIX (_rel)) (__VA_ARGS__);) \ - BSON_IF_GNU_LIKE (return GNU_Intrinsic (__VA_ARGS__, __ATOMIC_RELEASE);) \ - BSON_IF_GNU_LEGACY_ATOMICS (return GNU_Legacy_Intrinsic (__VA_ARGS__);) \ - case bson_memory_order_relaxed: \ - BSON_IF_MSVC (return BSON_CONCAT (MSVC_Intrinsic, MSVC_MEMORDER_SUFFIX (_nf)) (__VA_ARGS__);) \ - BSON_IF_GNU_LIKE (return GNU_Intrinsic (__VA_ARGS__, __ATOMIC_RELAXED);) \ - BSON_IF_GNU_LEGACY_ATOMICS (return GNU_Legacy_Intrinsic (__VA_ARGS__);) \ - default: \ - BSON_UNREACHABLE ("Invalid bson_memory_order value"); \ - } \ - } while (0) - - -#define DEF_ATOMIC_CMPEXCH_STRONG(VCSuffix1, VCSuffix2, GNU_MemOrder, Ptr, ExpectActualVar, NewValue) \ - do { \ - BSON_IF_MSVC (ExpectActualVar = BSON_CONCAT3 (_InterlockedCompareExchange, VCSuffix1, VCSuffix2) ( \ - Ptr, NewValue, ExpectActualVar);) \ - BSON_IF_GNU_LIKE ((void) __atomic_compare_exchange_n (Ptr, \ - &ExpectActualVar, \ - NewValue, \ - false, /* Not weak */ \ - GNU_MemOrder, \ - GNU_MemOrder);) \ - BSON_IF_GNU_LEGACY_ATOMICS (__typeof__ (ExpectActualVar) _val; \ - _val = __sync_val_compare_and_swap (Ptr, ExpectActualVar, NewValue); \ - ExpectActualVar = _val;) \ - } while (0) - - -#define DEF_ATOMIC_CMPEXCH_WEAK(VCSuffix1, VCSuffix2, GNU_MemOrder, Ptr, ExpectActualVar, NewValue) \ - do { \ - BSON_IF_MSVC (ExpectActualVar = BSON_CONCAT3 (_InterlockedCompareExchange, VCSuffix1, VCSuffix2) ( \ - Ptr, NewValue, ExpectActualVar);) \ - BSON_IF_GNU_LIKE ((void) __atomic_compare_exchange_n (Ptr, \ - &ExpectActualVar, \ - NewValue, \ - true, /* Yes weak */ \ - GNU_MemOrder, \ - GNU_MemOrder);) \ - BSON_IF_GNU_LEGACY_ATOMICS (__typeof__ (ExpectActualVar) _val; \ - _val = __sync_val_compare_and_swap (Ptr, ExpectActualVar, NewValue); \ - ExpectActualVar = _val;) \ - } while (0) - - -#define DECL_ATOMIC_INTEGRAL(NamePart, Type, VCIntrinSuffix) \ - static BSON_INLINE Type bson_atomic_##NamePart##_fetch_add ( \ - Type volatile *a, Type addend, enum bson_memory_order ord) \ - { \ - DEF_ATOMIC_OP (BSON_CONCAT (_InterlockedExchangeAdd, VCIntrinSuffix), \ - __atomic_fetch_add, \ - __sync_fetch_and_add, \ - ord, \ - a, \ - addend); \ - } \ - \ - static BSON_INLINE Type bson_atomic_##NamePart##_fetch_sub ( \ - Type volatile *a, Type subtrahend, enum bson_memory_order ord) \ - { \ - /* MSVC doesn't have a subtract intrinsic, so just reuse addition */ \ - BSON_IF_MSVC (return bson_atomic_##NamePart##_fetch_add (a, -subtrahend, ord);) \ - BSON_IF_GNU_LIKE (DEF_ATOMIC_OP (~, __atomic_fetch_sub, ~, ord, a, subtrahend);) \ - BSON_IF_GNU_LEGACY_ATOMICS (DEF_ATOMIC_OP (~, ~, __sync_fetch_and_sub, ord, a, subtrahend);) \ - } \ - \ - static BSON_INLINE Type bson_atomic_##NamePart##_fetch (Type volatile const *a, enum bson_memory_order order) \ - { \ - /* MSVC doesn't have a load intrinsic, so just add zero */ \ - BSON_IF_MSVC (return bson_atomic_##NamePart##_fetch_add ((Type volatile *) a, 0, order);) \ - /* GNU doesn't want RELEASE order for the fetch operation, so we can't \ - * just use DEF_ATOMIC_OP. */ \ - BSON_IF_GNU_LIKE (switch (order) { \ - case bson_memory_order_release: /* Fall back to seqcst */ \ - case bson_memory_order_acq_rel: /* Fall back to seqcst */ \ - case bson_memory_order_seq_cst: \ - return __atomic_load_n (a, __ATOMIC_SEQ_CST); \ - case bson_memory_order_acquire: \ - return __atomic_load_n (a, __ATOMIC_ACQUIRE); \ - case bson_memory_order_consume: \ - return __atomic_load_n (a, __ATOMIC_CONSUME); \ - case bson_memory_order_relaxed: \ - return __atomic_load_n (a, __ATOMIC_RELAXED); \ - default: \ - BSON_UNREACHABLE ("Invalid bson_memory_order value"); \ - }) \ - BSON_IF_GNU_LEGACY_ATOMICS ({ \ - __sync_synchronize (); \ - return *a; \ - }) \ - } \ - \ - static BSON_INLINE Type bson_atomic_##NamePart##_exchange ( \ - Type volatile *a, Type value, enum bson_memory_order ord) \ - { \ - BSON_IF_MSVC (DEF_ATOMIC_OP (BSON_CONCAT (_InterlockedExchange, VCIntrinSuffix), ~, ~, ord, a, value);) \ - /* GNU doesn't want CONSUME order for the exchange operation, so we \ - * cannot use DEF_ATOMIC_OP. */ \ - BSON_IF_GNU_LIKE (switch (ord) { \ - case bson_memory_order_acq_rel: \ - return __atomic_exchange_n (a, value, __ATOMIC_ACQ_REL); \ - case bson_memory_order_release: \ - return __atomic_exchange_n (a, value, __ATOMIC_RELEASE); \ - case bson_memory_order_seq_cst: \ - return __atomic_exchange_n (a, value, __ATOMIC_SEQ_CST); \ - case bson_memory_order_consume: /* Fall back to acquire */ \ - case bson_memory_order_acquire: \ - return __atomic_exchange_n (a, value, __ATOMIC_ACQUIRE); \ - case bson_memory_order_relaxed: \ - return __atomic_exchange_n (a, value, __ATOMIC_RELAXED); \ - default: \ - BSON_UNREACHABLE ("Invalid bson_memory_order value"); \ - }) \ - BSON_IF_GNU_LEGACY_ATOMICS (return __sync_val_compare_and_swap (a, *a, value);) \ - } \ - \ - static BSON_INLINE Type bson_atomic_##NamePart##_compare_exchange_strong ( \ - Type volatile *a, Type expect, Type new_value, enum bson_memory_order ord) \ - { \ - Type actual = expect; \ - switch (ord) { \ - case bson_memory_order_release: \ - case bson_memory_order_acq_rel: \ - case bson_memory_order_seq_cst: \ - DEF_ATOMIC_CMPEXCH_STRONG (VCIntrinSuffix, , __ATOMIC_SEQ_CST, a, actual, new_value); \ - break; \ - case bson_memory_order_acquire: \ - DEF_ATOMIC_CMPEXCH_STRONG ( \ - VCIntrinSuffix, MSVC_MEMORDER_SUFFIX (_acq), __ATOMIC_ACQUIRE, a, actual, new_value); \ - break; \ - case bson_memory_order_consume: \ - DEF_ATOMIC_CMPEXCH_STRONG ( \ - VCIntrinSuffix, MSVC_MEMORDER_SUFFIX (_acq), __ATOMIC_CONSUME, a, actual, new_value); \ - break; \ - case bson_memory_order_relaxed: \ - DEF_ATOMIC_CMPEXCH_STRONG ( \ - VCIntrinSuffix, MSVC_MEMORDER_SUFFIX (_nf), __ATOMIC_RELAXED, a, actual, new_value); \ - break; \ - default: \ - BSON_UNREACHABLE ("Invalid bson_memory_order value"); \ - } \ - return actual; \ - } \ - \ - static BSON_INLINE Type bson_atomic_##NamePart##_compare_exchange_weak ( \ - Type volatile *a, Type expect, Type new_value, enum bson_memory_order ord) \ - { \ - Type actual = expect; \ - switch (ord) { \ - case bson_memory_order_release: \ - case bson_memory_order_acq_rel: \ - case bson_memory_order_seq_cst: \ - DEF_ATOMIC_CMPEXCH_WEAK (VCIntrinSuffix, , __ATOMIC_SEQ_CST, a, actual, new_value); \ - break; \ - case bson_memory_order_acquire: \ - DEF_ATOMIC_CMPEXCH_WEAK ( \ - VCIntrinSuffix, MSVC_MEMORDER_SUFFIX (_acq), __ATOMIC_ACQUIRE, a, actual, new_value); \ - break; \ - case bson_memory_order_consume: \ - DEF_ATOMIC_CMPEXCH_WEAK ( \ - VCIntrinSuffix, MSVC_MEMORDER_SUFFIX (_acq), __ATOMIC_CONSUME, a, actual, new_value); \ - break; \ - case bson_memory_order_relaxed: \ - DEF_ATOMIC_CMPEXCH_WEAK (VCIntrinSuffix, MSVC_MEMORDER_SUFFIX (_nf), __ATOMIC_RELAXED, a, actual, new_value); \ - break; \ - default: \ - BSON_UNREACHABLE ("Invalid bson_memory_order value"); \ - } \ - return actual; \ - } - -#define DECL_ATOMIC_STDINT(Name, VCSuffix) DECL_ATOMIC_INTEGRAL (Name, Name##_t, VCSuffix) - -#if defined(_MSC_VER) || defined(BSON_USE_LEGACY_GCC_ATOMICS) -/* MSVC and GCC require built-in types (not typedefs) for their atomic - * intrinsics. */ -#if defined(_MSC_VER) -#define DECL_ATOMIC_INTEGRAL_INT8 char -#define DECL_ATOMIC_INTEGRAL_INT32 long -#define DECL_ATOMIC_INTEGRAL_INT long -#else -#define DECL_ATOMIC_INTEGRAL_INT8 signed char -#define DECL_ATOMIC_INTEGRAL_INT32 int -#define DECL_ATOMIC_INTEGRAL_INT int -#endif -DECL_ATOMIC_INTEGRAL (int8, DECL_ATOMIC_INTEGRAL_INT8, 8) -DECL_ATOMIC_INTEGRAL (int16, short, 16) -#if !defined(BSON_EMULATE_INT32) -DECL_ATOMIC_INTEGRAL (int32, DECL_ATOMIC_INTEGRAL_INT32, ) -#endif -#if !defined(BSON_EMULATE_INT) -DECL_ATOMIC_INTEGRAL (int, DECL_ATOMIC_INTEGRAL_INT, ) -#endif -#else -/* Other compilers that we support provide generic intrinsics */ -DECL_ATOMIC_STDINT (int8, 8) -DECL_ATOMIC_STDINT (int16, 16) -#if !defined(BSON_EMULATE_INT32) -DECL_ATOMIC_STDINT (int32, ) -#endif -#if !defined(BSON_EMULATE_INT) -DECL_ATOMIC_INTEGRAL (int, int, ) -#endif -#endif - -#ifndef DECL_ATOMIC_INTEGRAL_INT32 -#define DECL_ATOMIC_INTEGRAL_INT32 int32_t -#endif - -BSON_EXPORT (int64_t) -_bson_emul_atomic_int64_fetch_add (int64_t volatile *val, int64_t v, enum bson_memory_order); -BSON_EXPORT (int64_t) -_bson_emul_atomic_int64_exchange (int64_t volatile *val, int64_t v, enum bson_memory_order); -BSON_EXPORT (int64_t) -_bson_emul_atomic_int64_compare_exchange_strong (int64_t volatile *val, - int64_t expect_value, - int64_t new_value, - enum bson_memory_order); - -BSON_EXPORT (int64_t) -_bson_emul_atomic_int64_compare_exchange_weak (int64_t volatile *val, - int64_t expect_value, - int64_t new_value, - enum bson_memory_order); - -BSON_EXPORT (int32_t) -_bson_emul_atomic_int32_fetch_add (int32_t volatile *val, int32_t v, enum bson_memory_order); -BSON_EXPORT (int32_t) -_bson_emul_atomic_int32_exchange (int32_t volatile *val, int32_t v, enum bson_memory_order); -BSON_EXPORT (int32_t) -_bson_emul_atomic_int32_compare_exchange_strong (int32_t volatile *val, - int32_t expect_value, - int32_t new_value, - enum bson_memory_order); - -BSON_EXPORT (int32_t) -_bson_emul_atomic_int32_compare_exchange_weak (int32_t volatile *val, - int32_t expect_value, - int32_t new_value, - enum bson_memory_order); - -BSON_EXPORT (int) -_bson_emul_atomic_int_fetch_add (int volatile *val, int v, enum bson_memory_order); -BSON_EXPORT (int) -_bson_emul_atomic_int_exchange (int volatile *val, int v, enum bson_memory_order); -BSON_EXPORT (int) -_bson_emul_atomic_int_compare_exchange_strong (int volatile *val, - int expect_value, - int new_value, - enum bson_memory_order); - -BSON_EXPORT (int) -_bson_emul_atomic_int_compare_exchange_weak (int volatile *val, - int expect_value, - int new_value, - enum bson_memory_order); - -BSON_EXPORT (void *) -_bson_emul_atomic_ptr_exchange (void *volatile *val, void *v, enum bson_memory_order); - -BSON_EXPORT (void) -bson_thrd_yield (void); - -#if (defined(_MSC_VER) && !defined(_M_IX86)) || (defined(__LP64__) && __LP64__) -/* (64-bit intrinsics are only available in x64) */ -#ifdef _MSC_VER -DECL_ATOMIC_INTEGRAL (int64, __int64, 64) -#else -DECL_ATOMIC_STDINT (int64, 64) -#endif -#else -static BSON_INLINE int64_t -bson_atomic_int64_fetch (const int64_t volatile *val, enum bson_memory_order order) -{ - return _bson_emul_atomic_int64_fetch_add ((int64_t volatile *) val, 0, order); -} - -static BSON_INLINE int64_t -bson_atomic_int64_fetch_add (int64_t volatile *val, int64_t v, enum bson_memory_order order) -{ - return _bson_emul_atomic_int64_fetch_add (val, v, order); -} - -static BSON_INLINE int64_t -bson_atomic_int64_fetch_sub (int64_t volatile *val, int64_t v, enum bson_memory_order order) -{ - return _bson_emul_atomic_int64_fetch_add (val, -v, order); -} - -static BSON_INLINE int64_t -bson_atomic_int64_exchange (int64_t volatile *val, int64_t v, enum bson_memory_order order) -{ - return _bson_emul_atomic_int64_exchange (val, v, order); -} - -static BSON_INLINE int64_t -bson_atomic_int64_compare_exchange_strong (int64_t volatile *val, - int64_t expect_value, - int64_t new_value, - enum bson_memory_order order) -{ - return _bson_emul_atomic_int64_compare_exchange_strong (val, expect_value, new_value, order); -} - -static BSON_INLINE int64_t -bson_atomic_int64_compare_exchange_weak (int64_t volatile *val, - int64_t expect_value, - int64_t new_value, - enum bson_memory_order order) -{ - return _bson_emul_atomic_int64_compare_exchange_weak (val, expect_value, new_value, order); -} -#endif - -#if defined(BSON_EMULATE_INT32) -static BSON_INLINE int32_t -bson_atomic_int32_fetch (const int32_t volatile *val, enum bson_memory_order order) -{ - return _bson_emul_atomic_int32_fetch_add ((int32_t volatile *) val, 0, order); -} - -static BSON_INLINE int32_t -bson_atomic_int32_fetch_add (int32_t volatile *val, int32_t v, enum bson_memory_order order) -{ - return _bson_emul_atomic_int32_fetch_add (val, v, order); -} - -static BSON_INLINE int32_t -bson_atomic_int32_fetch_sub (int32_t volatile *val, int32_t v, enum bson_memory_order order) -{ - return _bson_emul_atomic_int32_fetch_add (val, -v, order); -} - -static BSON_INLINE int32_t -bson_atomic_int32_exchange (int32_t volatile *val, int32_t v, enum bson_memory_order order) -{ - return _bson_emul_atomic_int32_exchange (val, v, order); -} - -static BSON_INLINE int32_t -bson_atomic_int32_compare_exchange_strong (int32_t volatile *val, - int32_t expect_value, - int32_t new_value, - enum bson_memory_order order) -{ - return _bson_emul_atomic_int32_compare_exchange_strong (val, expect_value, new_value, order); -} - -static BSON_INLINE int32_t -bson_atomic_int32_compare_exchange_weak (int32_t volatile *val, - int32_t expect_value, - int32_t new_value, - enum bson_memory_order order) -{ - return _bson_emul_atomic_int32_compare_exchange_weak (val, expect_value, new_value, order); -} -#endif /* BSON_EMULATE_INT32 */ - -#if defined(BSON_EMULATE_INT) -static BSON_INLINE int -bson_atomic_int_fetch (const int volatile *val, enum bson_memory_order order) -{ - return _bson_emul_atomic_int_fetch_add ((int volatile *) val, 0, order); -} - -static BSON_INLINE int -bson_atomic_int_fetch_add (int volatile *val, int v, enum bson_memory_order order) -{ - return _bson_emul_atomic_int_fetch_add (val, v, order); -} - -static BSON_INLINE int -bson_atomic_int_fetch_sub (int volatile *val, int v, enum bson_memory_order order) -{ - return _bson_emul_atomic_int_fetch_add (val, -v, order); -} - -static BSON_INLINE int -bson_atomic_int_exchange (int volatile *val, int v, enum bson_memory_order order) -{ - return _bson_emul_atomic_int_exchange (val, v, order); -} - -static BSON_INLINE int -bson_atomic_int_compare_exchange_strong (int volatile *val, - int expect_value, - int new_value, - enum bson_memory_order order) -{ - return _bson_emul_atomic_int_compare_exchange_strong (val, expect_value, new_value, order); -} - -static BSON_INLINE int -bson_atomic_int_compare_exchange_weak (int volatile *val, int expect_value, int new_value, enum bson_memory_order order) -{ - return _bson_emul_atomic_int_compare_exchange_weak (val, expect_value, new_value, order); -} -#endif /* BSON_EMULATE_INT */ - -static BSON_INLINE void * -bson_atomic_ptr_exchange (void *volatile *ptr, void *new_value, enum bson_memory_order ord) -{ -#if defined(BSON_EMULATE_PTR) - return _bson_emul_atomic_ptr_exchange (ptr, new_value, ord); -#elif defined(BSON_USE_LEGACY_GCC_ATOMICS) - /* The older __sync_val_compare_and_swap also takes oldval */ - DEF_ATOMIC_OP (_InterlockedExchangePointer, , __sync_val_compare_and_swap, ord, ptr, *ptr, new_value); -#else - DEF_ATOMIC_OP (_InterlockedExchangePointer, __atomic_exchange_n, , ord, ptr, new_value); -#endif -} - -static BSON_INLINE void * -bson_atomic_ptr_compare_exchange_strong (void *volatile *ptr, void *expect, void *new_value, enum bson_memory_order ord) -{ - switch (ord) { - case bson_memory_order_release: - case bson_memory_order_acq_rel: - case bson_memory_order_seq_cst: - DEF_ATOMIC_CMPEXCH_STRONG (Pointer, , __ATOMIC_SEQ_CST, ptr, expect, new_value); - return expect; - case bson_memory_order_relaxed: - DEF_ATOMIC_CMPEXCH_STRONG (Pointer, MSVC_MEMORDER_SUFFIX (_nf), __ATOMIC_RELAXED, ptr, expect, new_value); - return expect; - case bson_memory_order_consume: - DEF_ATOMIC_CMPEXCH_STRONG (Pointer, MSVC_MEMORDER_SUFFIX (_acq), __ATOMIC_CONSUME, ptr, expect, new_value); - return expect; - case bson_memory_order_acquire: - DEF_ATOMIC_CMPEXCH_STRONG (Pointer, MSVC_MEMORDER_SUFFIX (_acq), __ATOMIC_ACQUIRE, ptr, expect, new_value); - return expect; - default: - BSON_UNREACHABLE ("Invalid bson_memory_order value"); - } -} - - -static BSON_INLINE void * -bson_atomic_ptr_compare_exchange_weak (void *volatile *ptr, void *expect, void *new_value, enum bson_memory_order ord) -{ - switch (ord) { - case bson_memory_order_release: - case bson_memory_order_acq_rel: - case bson_memory_order_seq_cst: - DEF_ATOMIC_CMPEXCH_WEAK (Pointer, , __ATOMIC_SEQ_CST, ptr, expect, new_value); - return expect; - case bson_memory_order_relaxed: - DEF_ATOMIC_CMPEXCH_WEAK (Pointer, MSVC_MEMORDER_SUFFIX (_nf), __ATOMIC_RELAXED, ptr, expect, new_value); - return expect; - case bson_memory_order_consume: - DEF_ATOMIC_CMPEXCH_WEAK (Pointer, MSVC_MEMORDER_SUFFIX (_acq), __ATOMIC_CONSUME, ptr, expect, new_value); - return expect; - case bson_memory_order_acquire: - DEF_ATOMIC_CMPEXCH_WEAK (Pointer, MSVC_MEMORDER_SUFFIX (_acq), __ATOMIC_ACQUIRE, ptr, expect, new_value); - return expect; - default: - BSON_UNREACHABLE ("Invalid bson_memory_order value"); - } -} - - -static BSON_INLINE void * -bson_atomic_ptr_fetch (void *volatile const *ptr, enum bson_memory_order ord) -{ - return bson_atomic_ptr_compare_exchange_strong ((void *volatile *) ptr, NULL, NULL, ord); -} - -#undef DECL_ATOMIC_STDINT -#undef DECL_ATOMIC_INTEGRAL -#undef DEF_ATOMIC_OP -#undef DEF_ATOMIC_CMPEXCH_STRONG -#undef DEF_ATOMIC_CMPEXCH_WEAK -#undef MSVC_MEMORDER_SUFFIX - -/** - * @brief Generate a full-fence memory barrier at the call site. - */ -static BSON_INLINE void -bson_atomic_thread_fence (void) -{ - BSON_IF_MSVC (MemoryBarrier ();) - BSON_IF_GNU_LIKE (__sync_synchronize ();) - BSON_IF_GNU_LEGACY_ATOMICS (__sync_synchronize ();) -} - -#ifdef BSON_USE_LEGACY_GCC_ATOMICS -#undef BSON_IF_GNU_LIKE -#define BSON_IF_GNU_LIKE(...) __VA_ARGS__ -#endif -#undef BSON_IF_GNU_LEGACY_ATOMICS -#undef BSON_USE_LEGACY_GCC_ATOMICS - -BSON_GNUC_DEPRECATED_FOR ("bson_atomic_thread_fence") -BSON_EXPORT (void) bson_memory_barrier (void); - -BSON_GNUC_DEPRECATED_FOR ("bson_atomic_int_fetch_add") -BSON_EXPORT (int32_t) bson_atomic_int_add (volatile int32_t *p, int32_t n); - -BSON_GNUC_DEPRECATED_FOR ("bson_atomic_int64_fetch_add") -BSON_EXPORT (int64_t) bson_atomic_int64_add (volatile int64_t *p, int64_t n); - - -#undef BSON_EMULATE_PTR -#undef BSON_EMULATE_INT32 -#undef BSON_EMULATE_INT - -BSON_END_DECLS - - -#endif /* BSON_ATOMIC_H */ diff --git a/bsonjs/bson/bson-clock.c b/bsonjs/bson/bson-clock.c deleted file mode 100644 index a9510c2..0000000 --- a/bsonjs/bson/bson-clock.c +++ /dev/null @@ -1,132 +0,0 @@ -/* - * Copyright 2013 MongoDB, Inc. - * - * 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. - */ - -#include -#include - - -#if defined(BSON_HAVE_CLOCK_GETTIME) -#include -#include -#endif - -#include - -/* - *-------------------------------------------------------------------------- - * - * bson_gettimeofday -- - * - * A wrapper around gettimeofday() with fallback support for Windows. - * - * Returns: - * 0 if successful. - * - * Side effects: - * @tv is set. - * - *-------------------------------------------------------------------------- - */ - -int -bson_gettimeofday (struct timeval *tv) /* OUT */ -{ -#if defined(_WIN32) -#if defined(_MSC_VER) -#define DELTA_EPOCH_IN_MICROSEC 11644473600000000Ui64 -#else -#define DELTA_EPOCH_IN_MICROSEC 11644473600000000ULL -#endif - FILETIME ft; - uint64_t tmp = 0; - - /* - * The const value is shamelessly stolen from - * http://www.boost.org/doc/libs/1_55_0/boost/chrono/detail/inlined/win/chrono.hpp - * - * File times are the number of 100 nanosecond intervals elapsed since - * 12:00 am Jan 1, 1601 UTC. I haven't check the math particularly hard - * - * ... good luck - */ - - if (tv) { - GetSystemTimeAsFileTime (&ft); - - /* pull out of the filetime into a 64 bit uint */ - tmp |= ft.dwHighDateTime; - tmp <<= 32; - tmp |= ft.dwLowDateTime; - - /* convert from 100's of nanosecs to microsecs */ - tmp /= 10; - - /* adjust to unix epoch */ - tmp -= DELTA_EPOCH_IN_MICROSEC; - - tv->tv_sec = (long) (tmp / 1000000UL); - tv->tv_usec = (long) (tmp % 1000000UL); - } - - return 0; -#else - return gettimeofday (tv, NULL); -#endif -} - - -/* - *-------------------------------------------------------------------------- - * - * bson_get_monotonic_time -- - * - * Returns the monotonic system time, if available. A best effort is - * made to use the monotonic clock. However, some systems may not - * support such a feature. - * - * Returns: - * The monotonic clock in microseconds. - * - * Side effects: - * None. - * - *-------------------------------------------------------------------------- - */ - -int64_t -bson_get_monotonic_time (void) -{ -#if defined(BSON_HAVE_CLOCK_GETTIME) && defined(CLOCK_MONOTONIC) - struct timespec ts; - /* ts.tv_sec may be a four-byte integer on 32 bit machines, so cast to - * int64_t to avoid truncation. */ - clock_gettime (CLOCK_MONOTONIC, &ts); - return (((int64_t) ts.tv_sec * 1000000) + (ts.tv_nsec / 1000)); -#elif defined(_WIN32) - /* Despite it's name, this is in milliseconds! */ - int64_t ticks = GetTickCount64 (); - return (ticks * 1000); -#elif defined(__hpux__) - int64_t nanosec = gethrtime (); - return (nanosec / 1000UL); -#else -#pragma message "Monotonic clock is not yet supported on your platform." - struct timeval tv; - - bson_gettimeofday (&tv); - return ((int64_t) tv.tv_sec * 1000000) + tv.tv_usec; -#endif -} diff --git a/bsonjs/bson/bson-clock.h b/bsonjs/bson/bson-clock.h deleted file mode 100644 index a4845b7..0000000 --- a/bsonjs/bson/bson-clock.h +++ /dev/null @@ -1,41 +0,0 @@ -/* - * Copyright 2014 MongoDB, Inc. - * - * 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. - */ - -#include - - -#ifndef BSON_CLOCK_H -#define BSON_CLOCK_H - - -#include -#include -#include - - -BSON_BEGIN_DECLS - - -BSON_EXPORT (int64_t) -bson_get_monotonic_time (void); -BSON_EXPORT (int) -bson_gettimeofday (struct timeval *tv); - - -BSON_END_DECLS - - -#endif /* BSON_CLOCK_H */ diff --git a/bsonjs/bson/bson-cmp.h b/bsonjs/bson/bson-cmp.h deleted file mode 100644 index 5a90d0f..0000000 --- a/bsonjs/bson/bson-cmp.h +++ /dev/null @@ -1,173 +0,0 @@ -/* - * Copyright 2022 MongoDB, Inc. - * - * 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. - */ - -#include - - -#ifndef BSON_CMP_H -#define BSON_CMP_H - - -#include /* ssize_t */ -#include /* BSON_CONCAT */ - -#include -#include -#include - - -BSON_BEGIN_DECLS - - -/* Based on the "Safe Integral Comparisons" proposal merged in C++20: - * http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2020/p0586r2.html - * - * Due to lack of type deduction in C, relational comparison functions (e.g. - * `cmp_less`) are defined in sets of four "functions" according to the - * signedness of each value argument, e.g.: - * - bson_cmp_less_ss (signed-value, signed-value) - * - bson_cmp_less_uu (unsigned-value, unsigned-value) - * - bson_cmp_less_su (signed-value, unsigned-value) - * - bson_cmp_less_us (unsigned-value, signed-value) - * - * Similarly, the `in_range` function is defined as a set of two "functions" - * according to the signedness of the value argument: - * - bson_in_range_signed (Type, signed-value) - * - bson_in_range_unsigned (Type, unsigned-value) - * - * The user must take care to use the correct signedness for the provided - * argument(s). Enabling compiler warnings for implicit sign conversions is - * recommended. - */ - - -#define BSON_CMP_SET(op, ss, uu, su, us) \ - static BSON_INLINE bool BSON_CONCAT3 (bson_cmp_, op, _ss) (int64_t t, int64_t u) \ - { \ - return (ss); \ - } \ - \ - static BSON_INLINE bool BSON_CONCAT3 (bson_cmp_, op, _uu) (uint64_t t, uint64_t u) \ - { \ - return (uu); \ - } \ - \ - static BSON_INLINE bool BSON_CONCAT3 (bson_cmp_, op, _su) (int64_t t, uint64_t u) \ - { \ - return (su); \ - } \ - \ - static BSON_INLINE bool BSON_CONCAT3 (bson_cmp_, op, _us) (uint64_t t, int64_t u) \ - { \ - return (us); \ - } - -BSON_CMP_SET (equal, t == u, t == u, t < 0 ? false : (uint64_t) (t) == u, u < 0 ? false : t == (uint64_t) (u)) - -BSON_CMP_SET (not_equal, - !bson_cmp_equal_ss (t, u), - !bson_cmp_equal_uu (t, u), - !bson_cmp_equal_su (t, u), - !bson_cmp_equal_us (t, u)) - -BSON_CMP_SET (less, t < u, t < u, t < 0 ? true : (uint64_t) (t) < u, u < 0 ? false : t < (uint64_t) (u)) - -BSON_CMP_SET ( - greater, bson_cmp_less_ss (u, t), bson_cmp_less_uu (u, t), bson_cmp_less_us (u, t), bson_cmp_less_su (u, t)) - -BSON_CMP_SET (less_equal, - !bson_cmp_greater_ss (t, u), - !bson_cmp_greater_uu (t, u), - !bson_cmp_greater_su (t, u), - !bson_cmp_greater_us (t, u)) - -BSON_CMP_SET (greater_equal, - !bson_cmp_less_ss (t, u), - !bson_cmp_less_uu (t, u), - !bson_cmp_less_su (t, u), - !bson_cmp_less_us (t, u)) - -#undef BSON_CMP_SET - - -/* Return true if the given value is within the range of the corresponding - * signed type. The suffix must match the signedness of the given value. */ -#define BSON_IN_RANGE_SET_SIGNED(Type, min, max) \ - static BSON_INLINE bool BSON_CONCAT3 (bson_in_range, _##Type, _signed) (int64_t value) \ - { \ - return bson_cmp_greater_equal_ss (value, min) && bson_cmp_less_equal_ss (value, max); \ - } \ - \ - static BSON_INLINE bool BSON_CONCAT3 (bson_in_range, _##Type, _unsigned) (uint64_t value) \ - { \ - return bson_cmp_greater_equal_us (value, min) && bson_cmp_less_equal_us (value, max); \ - } - -/* Return true if the given value is within the range of the corresponding - * unsigned type. The suffix must match the signedness of the given value. */ -#define BSON_IN_RANGE_SET_UNSIGNED(Type, max) \ - static BSON_INLINE bool BSON_CONCAT3 (bson_in_range, _##Type, _signed) (int64_t value) \ - { \ - return bson_cmp_greater_equal_su (value, 0u) && bson_cmp_less_equal_su (value, max); \ - } \ - \ - static BSON_INLINE bool BSON_CONCAT3 (bson_in_range, _##Type, _unsigned) (uint64_t value) \ - { \ - return bson_cmp_less_equal_uu (value, max); \ - } - -BSON_IN_RANGE_SET_SIGNED (signed_char, SCHAR_MIN, SCHAR_MAX) -BSON_IN_RANGE_SET_SIGNED (short, SHRT_MIN, SHRT_MAX) -BSON_IN_RANGE_SET_SIGNED (int, INT_MIN, INT_MAX) -BSON_IN_RANGE_SET_SIGNED (long, LONG_MIN, LONG_MAX) -BSON_IN_RANGE_SET_SIGNED (long_long, LLONG_MIN, LLONG_MAX) - -BSON_IN_RANGE_SET_UNSIGNED (unsigned_char, UCHAR_MAX) -BSON_IN_RANGE_SET_UNSIGNED (unsigned_short, USHRT_MAX) -BSON_IN_RANGE_SET_UNSIGNED (unsigned_int, UINT_MAX) -BSON_IN_RANGE_SET_UNSIGNED (unsigned_long, ULONG_MAX) -BSON_IN_RANGE_SET_UNSIGNED (unsigned_long_long, ULLONG_MAX) - -BSON_IN_RANGE_SET_SIGNED (int8_t, INT8_MIN, INT8_MAX) -BSON_IN_RANGE_SET_SIGNED (int16_t, INT16_MIN, INT16_MAX) -BSON_IN_RANGE_SET_SIGNED (int32_t, INT32_MIN, INT32_MAX) -BSON_IN_RANGE_SET_SIGNED (int64_t, INT64_MIN, INT64_MAX) - -BSON_IN_RANGE_SET_UNSIGNED (uint8_t, UINT8_MAX) -BSON_IN_RANGE_SET_UNSIGNED (uint16_t, UINT16_MAX) -BSON_IN_RANGE_SET_UNSIGNED (uint32_t, UINT32_MAX) -BSON_IN_RANGE_SET_UNSIGNED (uint64_t, UINT64_MAX) - -BSON_IN_RANGE_SET_SIGNED (ssize_t, SSIZE_MIN, SSIZE_MAX) -BSON_IN_RANGE_SET_UNSIGNED (size_t, SIZE_MAX) - -#undef BSON_IN_RANGE_SET_SIGNED -#undef BSON_IN_RANGE_SET_UNSIGNED - - -/* Return true if the value with *signed* type is in the representable range of - * Type and false otherwise. */ -#define bson_in_range_signed(Type, value) BSON_CONCAT3 (bson_in_range, _##Type, _signed) (value) - -/* Return true if the value with *unsigned* type is in the representable range - * of Type and false otherwise. */ -#define bson_in_range_unsigned(Type, value) BSON_CONCAT3 (bson_in_range, _##Type, _unsigned) (value) - - -BSON_END_DECLS - - -#endif /* BSON_CMP_H */ diff --git a/bsonjs/bson/bson-compat.h b/bsonjs/bson/bson-compat.h deleted file mode 100644 index f403fb4..0000000 --- a/bsonjs/bson/bson-compat.h +++ /dev/null @@ -1,223 +0,0 @@ -/* - * Copyright 2013 MongoDB, Inc. - * - * 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. - */ - -#include - - -#ifndef BSON_COMPAT_H -#define BSON_COMPAT_H - - -#if defined(__MINGW32__) -#if defined(__USE_MINGW_ANSI_STDIO) -#if __USE_MINGW_ANSI_STDIO < 1 -#error "__USE_MINGW_ANSI_STDIO > 0 is required for correct PRI* macros" -#endif -#else -#define __USE_MINGW_ANSI_STDIO 1 -#endif -#endif - -#include -#include - - -#ifdef BSON_OS_WIN32 -#if defined(_WIN32_WINNT) && (_WIN32_WINNT < 0x0600) -#undef _WIN32_WINNT -#endif -#ifndef _WIN32_WINNT -#define _WIN32_WINNT 0x0600 -#endif -#ifndef NOMINMAX -#define NOMINMAX -#endif -#include -#ifndef WIN32_LEAN_AND_MEAN -#define WIN32_LEAN_AND_MEAN -#include -#undef WIN32_LEAN_AND_MEAN -#else -#include -#endif -#include -#include -#endif - - -#ifdef BSON_OS_UNIX -#include -#include -#endif - - -#include - - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - - -BSON_BEGIN_DECLS - -#if !defined(_MSC_VER) || (_MSC_VER >= 1800) -#include -#endif -#ifdef _MSC_VER -#ifndef __cplusplus -/* benign redefinition of type */ -#pragma warning(disable : 4142) -#ifndef _SSIZE_T_DEFINED -#define _SSIZE_T_DEFINED -typedef SSIZE_T ssize_t; -#endif -#ifndef _SIZE_T_DEFINED -#define _SIZE_T_DEFINED -typedef SIZE_T size_t; -#endif -#pragma warning(default : 4142) -#else -/* - * MSVC++ does not include ssize_t, just size_t. - * So we need to synthesize that as well. - */ -#pragma warning(disable : 4142) -#ifndef _SSIZE_T_DEFINED -#define _SSIZE_T_DEFINED -typedef SSIZE_T ssize_t; -#endif -#pragma warning(default : 4142) -#endif -#ifndef PRIi32 -#define PRIi32 "d" -#endif -#ifndef PRId32 -#define PRId32 "d" -#endif -#ifndef PRIu32 -#define PRIu32 "u" -#endif -#ifndef PRIi64 -#define PRIi64 "I64i" -#endif -#ifndef PRId64 -#define PRId64 "I64i" -#endif -#ifndef PRIu64 -#define PRIu64 "I64u" -#endif -#endif - -/* Derive the maximum representable value of signed integer type T using the - * formula 2^(N - 1) - 1 where N is the number of bits in type T. This assumes - * T is represented using two's complement. */ -#define BSON_NUMERIC_LIMITS_MAX_SIGNED(T) ((T) ((((size_t) 0x01u) << (sizeof (T) * (size_t) CHAR_BIT - 1u)) - 1u)) - -/* Derive the minimum representable value of signed integer type T as one less - * than the negation of its maximum representable value. This assumes T is - * represented using two's complement. */ -#define BSON_NUMERIC_LIMITS_MIN_SIGNED(T, max) ((T) ((-(max)) - 1)) - -/* Derive the maximum representable value of unsigned integer type T by flipping - * all its bits to 1. */ -#define BSON_NUMERIC_LIMITS_MAX_UNSIGNED(T) ((T) (~((T) 0))) - -#ifndef SSIZE_MAX -#define SSIZE_MAX BSON_NUMERIC_LIMITS_MAX_SIGNED (ssize_t) -#endif - -#ifndef SSIZE_MIN -#define SSIZE_MIN BSON_NUMERIC_LIMITS_MIN_SIGNED (ssize_t, SSIZE_MAX) -#endif - -#if defined(__MINGW32__) && !defined(INIT_ONCE_STATIC_INIT) -#define INIT_ONCE_STATIC_INIT RTL_RUN_ONCE_INIT -typedef RTL_RUN_ONCE INIT_ONCE; -#endif - -#ifdef BSON_HAVE_STDBOOL_H -#include -#elif !defined(__bool_true_false_are_defined) -#ifndef __cplusplus -typedef signed char bool; -#define false 0 -#define true 1 -#endif -#define __bool_true_false_are_defined 1 -#endif - - -#if defined(__GNUC__) -#if (__GNUC__ > 4) || (__GNUC__ == 4 && __GNUC_MINOR__ >= 1) -#define bson_sync_synchronize() __sync_synchronize () -#elif defined(__i386__) || defined(__i486__) || defined(__i586__) || defined(__i686__) || defined(__x86_64__) -#define bson_sync_synchronize() asm volatile ("mfence" ::: "memory") -#else -#define bson_sync_synchronize() asm volatile ("sync" ::: "memory") -#endif -#elif defined(_MSC_VER) -#define bson_sync_synchronize() MemoryBarrier () -#endif - - -#if !defined(va_copy) && defined(__va_copy) -#define va_copy(dst, src) __va_copy (dst, src) -#endif - - -#if !defined(va_copy) -#define va_copy(dst, src) ((dst) = (src)) -#endif - - -#ifdef _MSC_VER -/** Expands the arguments if compiling with MSVC, otherwise empty */ -#define BSON_IF_MSVC(...) __VA_ARGS__ -/** Expands the arguments if compiling with GCC or Clang, otherwise empty */ -#define BSON_IF_GNU_LIKE(...) -#elif defined(__GNUC__) || defined(__clang__) -/** Expands the arguments if compiling with MSVC, otherwise empty */ -#define BSON_IF_MSVC(...) -/** Expands the arguments if compiling with GCC or Clang, otherwise empty */ -#define BSON_IF_GNU_LIKE(...) __VA_ARGS__ -#endif - -#ifdef BSON_OS_WIN32 -/** Expands the arguments if compiling for Windows, otherwise empty */ -#define BSON_IF_WINDOWS(...) __VA_ARGS__ -/** Expands the arguments if compiling for POSIX, otherwise empty */ -#define BSON_IF_POSIX(...) -#elif defined(BSON_OS_UNIX) -/** Expands the arguments if compiling for Windows, otherwise empty */ -#define BSON_IF_WINDOWS(...) -/** Expands the arguments if compiling for POSIX, otherwise empty */ -#define BSON_IF_POSIX(...) __VA_ARGS__ -#endif - - -BSON_END_DECLS - - -#endif /* BSON_COMPAT_H */ diff --git a/bsonjs/bson/bson-config.h b/bsonjs/bson/bson-config.h deleted file mode 100644 index baf7e5b..0000000 --- a/bsonjs/bson/bson-config.h +++ /dev/null @@ -1,164 +0,0 @@ -/* - * Copyright 2018-present MongoDB, Inc. - * - * 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 !defined(BSON_INSIDE) && !defined(BSON_COMPILATION) -#error "Only can be included directly." -#endif - -#ifndef BSON_CONFIG_H -#define BSON_CONFIG_H - -#define PY_SSIZE_T_CLEAN /* Make "s#" use Py_ssize_t rather than int. */ - -/* - * Rely on CPython to make libbson portable - */ -#include - - -/* - * Define to 1234 for Little Endian, 4321 for Big Endian. - */ -#ifdef WORDS_BIGENDIAN -# define BSON_BYTE_ORDER 4321 -#else -# define BSON_BYTE_ORDER 1234 -#endif - - -/* - * Define to 1 if you have stdbool.h - */ -#define BSON_HAVE_STDBOOL_H 1 -#if BSON_HAVE_STDBOOL_H != 1 -# undef BSON_HAVE_STDBOOL_H -#endif - - -/* - * Define to 1 for POSIX-like systems, 2 for Windows. - */ -#ifdef MS_WINDOWS -# define BSON_OS 2 -#else -# define BSON_OS 1 -#endif - - -/* - * Define to 1 if you have clock_gettime() available. - */ -#ifdef HAVE_CLOCK_GETTIME -# define BSON_HAVE_CLOCK_GETTIME 1 -#endif - -#if BSON_HAVE_CLOCK_GETTIME != 1 -# undef BSON_HAVE_CLOCK_GETTIME -#endif - - -/* - * Define to 1 if you have strings.h available on your platform. - */ -#define BSON_HAVE_STRINGS_H 0 -#if BSON_HAVE_STRINGS_H != 1 -# undef BSON_HAVE_STRINGS_H -#endif - - -/* - * Define to 1 if you have strnlen available on your platform. - */ -#define BSON_HAVE_STRNLEN 0 -#if BSON_HAVE_STRNLEN != 1 -# undef BSON_HAVE_STRNLEN -#endif - - -/* - * Define to 1 if you have snprintf available on your platform. - */ -#ifdef MS_WINDOWS -# define BSON_HAVE_SNPRINTF 0 -#else -# define BSON_HAVE_SNPRINTF 1 -#endif - -#if BSON_HAVE_SNPRINTF != 1 -# undef BSON_HAVE_SNPRINTF -#endif - - -/* - * Define to 1 if you have gmtime_r available on your platform. - */ -#ifdef MS_WINDOWS -# define BSON_HAVE_GMTIME_R 0 -#else -# define BSON_HAVE_GMTIME_R 1 -#endif - -#if BSON_HAVE_GMTIME_R != 1 -# undef BSON_HAVE_GMTIME_R -#endif - - -/* - * Define to 1 if you have struct timespec available on your platform. - */ -#ifdef HAVE_CLOCK_GETTIME -# define BSON_HAVE_TIMESPEC 1 -#endif - -#if BSON_HAVE_TIMESPEC != 1 -# undef BSON_HAVE_TIMESPEC -#endif - - -/* - * Define to 1 if you want extra aligned types in libbson - */ -#define BSON_EXTRA_ALIGN 1 -#if BSON_EXTRA_ALIGN != 1 -# undef BSON_EXTRA_ALIGN -#endif - - -/* - * Define to 1 if you have SYS_gettid syscall - */ -#define BSON_HAVE_SYSCALL_TID 0 -#if BSON_HAVE_SYSCALL_TID != 1 -# undef BSON_HAVE_SYSCALL_TID -#endif - - -#ifdef MS_WINDOWS -# define BSON_HAVE_RAND_R 0 -#else -# define BSON_HAVE_RAND_R 1 -#endif -#if BSON_HAVE_RAND_R != 1 -# undef BSON_HAVE_RAND_R -#endif - - -#define BSON_HAVE_STRLCPY 0 -#if BSON_HAVE_STRLCPY != 1 -# undef BSON_HAVE_STRLCPY -#endif - -#endif /* BSON_CONFIG_H */ diff --git a/bsonjs/bson/bson-context-private.h b/bsonjs/bson/bson-context-private.h deleted file mode 100644 index 0434973..0000000 --- a/bsonjs/bson/bson-context-private.h +++ /dev/null @@ -1,84 +0,0 @@ -/* - * Copyright 2014 MongoDB, Inc. - * - * 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. - */ - -#include - - -#ifndef BSON_CONTEXT_PRIVATE_H -#define BSON_CONTEXT_PRIVATE_H - - -#include -#include "common-thread-private.h" - - -BSON_BEGIN_DECLS - - -enum { - BSON_OID_RANDOMESS_OFFSET = 4, - BSON_OID_RANDOMNESS_SIZE = 5, - BSON_OID_SEQ32_OFFSET = 9, - BSON_OID_SEQ32_SIZE = 3, - BSON_OID_SEQ64_OFFSET = 4, - BSON_OID_SEQ64_SIZE = 8 -}; - -struct _bson_context_t { - /* flags are defined in bson_context_flags_t */ - int flags; - uint32_t seq32; - uint64_t seq64; - uint8_t randomness[BSON_OID_RANDOMNESS_SIZE]; - uint64_t pid; -}; - -/** - * @brief Insert the context's randomness data into the given OID - * - * @param context A context for some random data - * @param oid The OID to update. - */ -void -_bson_context_set_oid_rand (bson_context_t *context, bson_oid_t *oid); - -/** - * @brief Insert the context's sequence counter into the given OID. Increments - * the context's sequence counter. - * - * @param context The context with the counter to get+update - * @param oid The OID to modify - */ -void -_bson_context_set_oid_seq32 (bson_context_t *context, bson_oid_t *oid); - -/** - * @brief Write a 64-bit counter from the given context into the OID. Increments - * the context's sequence counter. - * - * @param context The context with the counter to get+update - * @param oid The OID to modify - * - * @note Only used by the deprecated @ref bson_oid_init_sequence - */ -void -_bson_context_set_oid_seq64 (bson_context_t *context, bson_oid_t *oid); - - -BSON_END_DECLS - - -#endif /* BSON_CONTEXT_PRIVATE_H */ diff --git a/bsonjs/bson/bson-context.c b/bsonjs/bson/bson-context.c deleted file mode 100644 index f9f545f..0000000 --- a/bsonjs/bson/bson-context.c +++ /dev/null @@ -1,368 +0,0 @@ -/* - * Copyright 2013 MongoDB, Inc. - * - * 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. - */ - -#include - -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include "common-thread-private.h" - - -#ifndef HOST_NAME_MAX -#define HOST_NAME_MAX 256 -#endif - - -/* - * Globals. - */ -static bson_context_t gContextDefault; - -static BSON_INLINE uint64_t -_bson_getpid (void) -{ - uint64_t pid; -#ifdef BSON_OS_WIN32 - DWORD real_pid; - - real_pid = GetCurrentProcessId (); - pid = (real_pid & 0xFFFF) ^ ((real_pid >> 16) & 0xFFFF); -#else - pid = (uint64_t) getpid (); -#endif - - return pid; -} - - -void -_bson_context_set_oid_seq32 (bson_context_t *context, /* IN */ - bson_oid_t *oid) /* OUT */ -{ - uint32_t seq = (uint32_t) bson_atomic_int32_fetch_add ( - (DECL_ATOMIC_INTEGRAL_INT32 *) &context->seq32, 1, bson_memory_order_seq_cst); - seq = BSON_UINT32_TO_BE (seq); - memcpy (&oid->bytes[BSON_OID_SEQ32_OFFSET], ((uint8_t *) &seq) + 1, BSON_OID_SEQ32_SIZE); -} - - -void -_bson_context_set_oid_seq64 (bson_context_t *context, /* IN */ - bson_oid_t *oid) /* OUT */ -{ - uint64_t seq = (uint64_t) bson_atomic_int64_fetch_add ((int64_t *) &context->seq64, 1, bson_memory_order_seq_cst); - - seq = BSON_UINT64_TO_BE (seq); - memcpy (&oid->bytes[BSON_OID_SEQ64_OFFSET], &seq, BSON_OID_SEQ64_SIZE); -} - -/* - * -------------------------------------------------------------------------- - * - * _bson_context_get_hostname - * - * Gets the hostname of the machine, logs a warning on failure. "out" - * must be an array of HOST_NAME_MAX bytes. - * - * -------------------------------------------------------------------------- - */ -static void -_bson_context_get_hostname (char out[HOST_NAME_MAX]) -{ - if (gethostname (out, HOST_NAME_MAX) != 0) { - if (errno == ENAMETOOLONG) { - fprintf (stderr, "hostname exceeds %d characters, truncating.", HOST_NAME_MAX); - } else { - fprintf (stderr, "unable to get hostname: %d", errno); - } - } - out[HOST_NAME_MAX - 1] = '\0'; -} - - -/*** ======================================== - * The below SipHash implementation is based on the original public-domain - * reference implementation from Jean-Philippe Aumasson and DJB - * (https://github.com/veorq/SipHash). - */ - -/* in-place rotate a 64bit number */ -void -_bson_rotl_u64 (uint64_t *p, int nbits) -{ - *p = (*p << nbits) | (*p >> (64 - nbits)); -} - -/* Write the little-endian representation of 'val' into 'out' */ -void -_u64_into_u8x8_le (uint8_t out[8], uint64_t val) -{ - val = BSON_UINT64_TO_LE (val); - memcpy (out, &val, sizeof val); -} - -/* Read a little-endian representation of a 64bit number from 'in' */ -uint64_t -_u8x8_le_to_u64 (const uint8_t in[8]) -{ - uint64_t r; - memcpy (&r, in, sizeof r); - return BSON_UINT64_FROM_LE (r); -} - -/* Perform one SipHash round */ -void -_sip_round (uint64_t *v0, uint64_t *v1, uint64_t *v2, uint64_t *v3) -{ - *v0 += *v1; - _bson_rotl_u64 (v1, 13); - *v1 ^= *v0; - _bson_rotl_u64 (v0, 32); - *v2 += *v3; - _bson_rotl_u64 (v3, 16); - *v3 ^= *v2; - *v0 += *v3; - _bson_rotl_u64 (v3, 21); - *v3 ^= *v0; - *v2 += *v1; - _bson_rotl_u64 (v1, 17); - *v1 ^= *v2; - _bson_rotl_u64 (v2, 32); -} - -void -_siphash (const void *in, const size_t inlen, const uint64_t key[2], uint64_t digest[2]) -{ - const unsigned char *ni = (const unsigned char *) in; - const unsigned char *kk = (const unsigned char *) key; - uint8_t digest_buf[16] = {0}; - - const int C_ROUNDS = 2; - const int D_ROUNDS = 4; - - uint64_t v0 = UINT64_C (0x736f6d6570736575); - uint64_t v1 = UINT64_C (0x646f72616e646f6d); - uint64_t v2 = UINT64_C (0x6c7967656e657261); - uint64_t v3 = UINT64_C (0x7465646279746573); - uint64_t k0 = _u8x8_le_to_u64 (kk); - uint64_t k1 = _u8x8_le_to_u64 (kk + 8); - uint64_t m; - int i; - const unsigned char *end = ni + inlen - (inlen % sizeof (uint64_t)); - const int left = inlen & 7; - uint64_t b = ((uint64_t) inlen) << 56; - v3 ^= k1; - v2 ^= k0; - v1 ^= k1; - v0 ^= k0; - - v1 ^= 0xee; - - for (; ni != end; ni += 8) { - m = _u8x8_le_to_u64 (ni); - v3 ^= m; - - for (i = 0; i < C_ROUNDS; ++i) - _sip_round (&v0, &v1, &v2, &v3); - - v0 ^= m; - } - - switch (left) { - case 7: - b |= ((uint64_t) ni[6]) << 48; - /* FALLTHRU */ - case 6: - b |= ((uint64_t) ni[5]) << 40; - /* FALLTHRU */ - case 5: - b |= ((uint64_t) ni[4]) << 32; - /* FALLTHRU */ - case 4: - b |= ((uint64_t) ni[3]) << 24; - /* FALLTHRU */ - case 3: - b |= ((uint64_t) ni[2]) << 16; - /* FALLTHRU */ - case 2: - b |= ((uint64_t) ni[1]) << 8; - /* FALLTHRU */ - case 1: - b |= ((uint64_t) ni[0]); - break; - default: - BSON_UNREACHABLE ("Invalid remainder during SipHash"); - case 0: - break; - } - - v3 ^= b; - - for (i = 0; i < C_ROUNDS; ++i) - _sip_round (&v0, &v1, &v2, &v3); - - v0 ^= b; - - v2 ^= 0xee; - - for (i = 0; i < D_ROUNDS; ++i) - _sip_round (&v0, &v1, &v2, &v3); - - b = v0 ^ v1 ^ v2 ^ v3; - _u64_into_u8x8_le (digest_buf, b); - - v1 ^= 0xdd; - - for (i = 0; i < D_ROUNDS; ++i) - _sip_round (&v0, &v1, &v2, &v3); - - b = v0 ^ v1 ^ v2 ^ v3; - _u64_into_u8x8_le (digest_buf + 8, b); - - memcpy (digest, digest_buf, sizeof digest_buf); -} - -/* - * The seed consists of the following hashed together: - * - current time (with microsecond resolution) - * - current pid - * - current hostname - * - The init-call counter - */ -struct _init_rand_params { - struct timeval time; - uint64_t pid; - char hostname[HOST_NAME_MAX]; - int64_t rand_call_counter; -}; - -static void -_bson_context_init_random (bson_context_t *context, bool init_seq) -{ - /* Keep an atomic counter of this function being called. This is used to add - * additional input to the random hash, ensuring no two calls in a single - * process will receive identical hash inputs, even occurring at the same - * microsecond. */ - static int64_t s_rand_call_counter = INT64_MIN; - - /* The message digest of the random params */ - uint64_t digest[2] = {0}; - uint64_t key[2] = {0}; - /* The randomness parameters */ - struct _init_rand_params rand_params; - - /* Init each part of the randomness source: */ - memset (&rand_params, 0, sizeof rand_params); - bson_gettimeofday (&rand_params.time); - rand_params.pid = _bson_getpid (); - _bson_context_get_hostname (rand_params.hostname); - rand_params.rand_call_counter = bson_atomic_int64_fetch_add (&s_rand_call_counter, 1, bson_memory_order_seq_cst); - - /* Generate a SipHash key. We do not care about secrecy or determinism, only - * uniqueness. */ - memcpy (key, &rand_params, sizeof key); - key[1] = ~key[0]; - - /* Hash the param struct */ - _siphash (&rand_params, sizeof rand_params, key, digest); - - /** Initialize the rand and sequence counters with our random digest */ - memcpy (context->randomness, digest, sizeof context->randomness); - if (init_seq) { - memcpy (&context->seq32, digest + 1, sizeof context->seq32); - memcpy (&context->seq64, digest + 1, sizeof context->seq64); - /* Chop off some initial bits for nicer counter behavior. This allows the - * low digit to start at a zero, and prevents immediately wrapping the - * counter in subsequent calls to set_oid_seq. */ - context->seq32 &= ~UINT32_C (0xf0000f); - context->seq64 &= ~UINT64_C (0xf0000f); - } - - /* Remember the PID we saw here. This may change in case of fork() */ - context->pid = rand_params.pid; -} - -static void -_bson_context_init (bson_context_t *context, bson_context_flags_t flags) -{ - context->flags = (int) flags; - _bson_context_init_random (context, true /* Init counters */); -} - - -void -_bson_context_set_oid_rand (bson_context_t *context, bson_oid_t *oid) -{ - BSON_ASSERT (context); - BSON_ASSERT (oid); - - if (context->flags & BSON_CONTEXT_DISABLE_PID_CACHE) { - /* User has requested that we check if our PID has changed. This can occur - * after a call to fork() */ - uint64_t now_pid = _bson_getpid (); - if (now_pid != context->pid) { - _bson_context_init_random (context, false /* Do not update the sequence counters */); - } - } - /* Copy the stored randomness into the OID */ - memcpy (oid->bytes + BSON_OID_RANDOMESS_OFFSET, &context->randomness, BSON_OID_RANDOMNESS_SIZE); -} - - -bson_context_t * -bson_context_new (bson_context_flags_t flags) -{ - bson_context_t *context; - - context = bson_malloc0 (sizeof *context); - _bson_context_init (context, flags); - - return context; -} - - -void -bson_context_destroy (bson_context_t *context) /* IN */ -{ - bson_free (context); -} - - -static BSON_ONCE_FUN (_bson_context_init_default) -{ - _bson_context_init (&gContextDefault, BSON_CONTEXT_DISABLE_PID_CACHE); - BSON_ONCE_RETURN; -} - - -bson_context_t * -bson_context_get_default (void) -{ - static bson_once_t once = BSON_ONCE_INIT; - - bson_once (&once, _bson_context_init_default); - - return &gContextDefault; -} diff --git a/bsonjs/bson/bson-context.h b/bsonjs/bson/bson-context.h deleted file mode 100644 index 8399b57..0000000 --- a/bsonjs/bson/bson-context.h +++ /dev/null @@ -1,64 +0,0 @@ -/* - * Copyright 2013 MongoDB, Inc. - * - * 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. - */ - -#include - - -#ifndef BSON_CONTEXT_H -#define BSON_CONTEXT_H - - -#include -#include - - -BSON_BEGIN_DECLS - - -/** - * @brief Initialize a new context with the given flags - * - * @param flags Flags used to configure the behavior of the context. For most - * cases, this should be BSON_CONTEXT_NONE. - * - * @return A newly allocated context. Must be freed with bson_context_destroy() - * - * @note If you expect your pid to change without notice, such as from an - * unexpected call to fork(), then specify BSON_CONTEXT_DISABLE_PID_CACHE in - * `flags`. - */ -BSON_EXPORT (bson_context_t *) -bson_context_new (bson_context_flags_t flags); - -/** - * @brief Destroy and free a bson_context_t created by bson_context_new() - */ -BSON_EXPORT (void) -bson_context_destroy (bson_context_t *context); - -/** - * @brief Obtain a pointer to the application-default bson_context_t - * - * @note This context_t MUST NOT be passed to bson_context_destroy() - */ -BSON_EXPORT (bson_context_t *) -bson_context_get_default (void); - - -BSON_END_DECLS - - -#endif /* BSON_CONTEXT_H */ diff --git a/bsonjs/bson/bson-decimal128.c b/bsonjs/bson/bson-decimal128.c deleted file mode 100644 index 786963c..0000000 --- a/bsonjs/bson/bson-decimal128.c +++ /dev/null @@ -1,765 +0,0 @@ - -/* - * Copyright 2015 MongoDB, Inc. - * - * 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. - */ - -#include -#include -#include - -#include -#include -#include -#include -#include - - -#define BSON_DECIMAL128_EXPONENT_MAX 6111 -#define BSON_DECIMAL128_EXPONENT_MIN -6176 -#define BSON_DECIMAL128_EXPONENT_BIAS 6176 -#define BSON_DECIMAL128_MAX_DIGITS 34 - -#define BSON_DECIMAL128_SET_NAN(dec) \ - if (1) { \ - (dec).high = 0x7c00000000000000ull; \ - (dec).low = 0; \ - } else \ - (void) 0 -#define BSON_DECIMAL128_SET_INF(dec, isneg) \ - if (1) { \ - (dec).high = 0x7800000000000000ull + 0x8000000000000000ull * (isneg); \ - (dec).low = 0; \ - } else \ - (void) 0 - -/** - * _bson_uint128_t: - * - * This struct represents a 128 bit integer. - */ -typedef struct { - uint32_t parts[4]; /* 32-bit words stored high to low. */ -} _bson_uint128_t; - - -/** - *------------------------------------------------------------------------------ - * - * _bson_uint128_divide1B -- - * - * This function divides a #_bson_uint128_t by 1000000000 (1 billion) and - * computes the quotient and remainder. - * - * The remainder will contain 9 decimal digits for conversion to string. - * - * @value The #_bson_uint128_t operand. - * @quotient A pointer to store the #_bson_uint128_t quotient. - * @rem A pointer to store the #uint64_t remainder. - * - * Returns: - * The quotient at @quotient and the remainder at @rem. - * - * Side effects: - * None. - * - *------------------------------------------------------------------------------ - */ -static void -_bson_uint128_divide1B (_bson_uint128_t value, /* IN */ - _bson_uint128_t *quotient, /* OUT */ - uint32_t *rem) /* OUT */ -{ - const uint32_t DIVISOR = 1000 * 1000 * 1000; - uint64_t _rem = 0; - int i = 0; - - if (!value.parts[0] && !value.parts[1] && !value.parts[2] && !value.parts[3]) { - *quotient = value; - *rem = 0; - return; - } - - - for (i = 0; i <= 3; i++) { - _rem <<= 32; /* Adjust remainder to match value of next dividend */ - _rem += value.parts[i]; /* Add the divided to _rem */ - value.parts[i] = (uint32_t) (_rem / DIVISOR); - _rem %= DIVISOR; /* Store the remainder */ - } - - *quotient = value; - *rem = (uint32_t) _rem; -} - - -/** - *------------------------------------------------------------------------------ - * - * bson_decimal128_to_string -- - * - * This function converts a BID formatted decimal128 value to string, - * accepting a &bson_decimal128_t as @dec. The string is stored at @str. - * - * @dec : The BID formatted decimal to convert. - * @str : The output decimal128 string. At least %BSON_DECIMAL128_STRING - *characters. - * - * Returns: - * None. - * - * Side effects: - * None. - * - *------------------------------------------------------------------------------ - */ -void -bson_decimal128_to_string (const bson_decimal128_t *dec, /* IN */ - char *str) /* OUT */ -{ - uint32_t COMBINATION_MASK = 0x1f; /* Extract least significant 5 bits */ - uint32_t EXPONENT_MASK = 0x3fff; /* Extract least significant 14 bits */ - uint32_t COMBINATION_INFINITY = 30; /* Value of combination field for Inf */ - uint32_t COMBINATION_NAN = 31; /* Value of combination field for NaN */ - uint32_t EXPONENT_BIAS = 6176; /* decimal128 exponent bias */ - - char *str_out = str; /* output pointer in string */ - char significand_str[35]; /* decoded significand digits */ - - - /* Note: bits in this routine are referred to starting at 0, */ - /* from the sign bit, towards the coefficient. */ - uint32_t high; /* bits 0 - 31 */ - uint32_t midh; /* bits 32 - 63 */ - uint32_t midl; /* bits 64 - 95 */ - uint32_t low; /* bits 96 - 127 */ - uint32_t combination; /* bits 1 - 5 */ - uint32_t biased_exponent; /* decoded biased exponent (14 bits) */ - uint32_t significand_digits = 0; /* the number of significand digits */ - uint32_t significand[36] = {0}; /* the base-10 digits in the significand */ - uint32_t *significand_read = significand; /* read pointer into significand */ - int32_t exponent; /* unbiased exponent */ - int32_t scientific_exponent; /* the exponent if scientific notation is - * used */ - bool is_zero = false; /* true if the number is zero */ - - uint8_t significand_msb; /* the most signifcant significand bits (50-46) */ - _bson_uint128_t significand128; /* temporary storage for significand decoding */ - - memset (significand_str, 0, sizeof (significand_str)); - - if ((int64_t) dec->high < 0) { /* negative */ - *(str_out++) = '-'; - } - - low = (uint32_t) dec->low; - midl = (uint32_t) (dec->low >> 32); - midh = (uint32_t) dec->high; - high = (uint32_t) (dec->high >> 32); - - /* Decode combination field and exponent */ - combination = (high >> 26) & COMBINATION_MASK; - - if (BSON_UNLIKELY ((combination >> 3) == 3)) { - /* Check for 'special' values */ - if (combination == COMBINATION_INFINITY) { /* Infinity */ - strcpy (str_out, BSON_DECIMAL128_INF); - return; - } else if (combination == COMBINATION_NAN) { /* NaN */ - /* str, not str_out, to erase the sign */ - strcpy (str, BSON_DECIMAL128_NAN); - /* we don't care about the NaN payload. */ - return; - } else { - biased_exponent = (high >> 15) & EXPONENT_MASK; - significand_msb = 0x8 + ((high >> 14) & 0x1); - } - } else { - significand_msb = (high >> 14) & 0x7; - biased_exponent = (high >> 17) & EXPONENT_MASK; - } - - exponent = biased_exponent - EXPONENT_BIAS; - /* Create string of significand digits */ - - /* Convert the 114-bit binary number represented by */ - /* (high, midh, midl, low) to at most 34 decimal */ - /* digits through modulo and division. */ - significand128.parts[0] = (high & 0x3fff) + ((significand_msb & 0xf) << 14); - significand128.parts[1] = midh; - significand128.parts[2] = midl; - significand128.parts[3] = low; - - if (significand128.parts[0] == 0 && significand128.parts[1] == 0 && significand128.parts[2] == 0 && - significand128.parts[3] == 0) { - is_zero = true; - } else if (significand128.parts[0] >= (1 << 17)) { - /* The significand is non-canonical or zero. - * In order to preserve compatibility with the densely packed decimal - * format, the maximum value for the significand of decimal128 is - * 1e34 - 1. If the value is greater than 1e34 - 1, the IEEE 754 - * standard dictates that the significand is interpreted as zero. - */ - is_zero = true; - } else { - for (int k = 3; k >= 0; k--) { - uint32_t least_digits = 0; - _bson_uint128_divide1B (significand128, &significand128, &least_digits); - - /* We now have the 9 least significant digits (in base 2). */ - /* Convert and output to string. */ - if (!least_digits) { - continue; - } - - for (int j = 8; j >= 0; j--) { - significand[k * 9 + j] = least_digits % 10; - least_digits /= 10; - } - } - } - - /* Output format options: */ - /* Scientific - [-]d.dddE(+/-)dd or [-]dE(+/-)dd */ - /* Regular - ddd.ddd */ - - if (is_zero) { - significand_digits = 1; - *significand_read = 0; - } else { - significand_digits = 36; - while (!(*significand_read)) { - significand_digits--; - significand_read++; - } - } - - scientific_exponent = significand_digits - 1 + exponent; - - /* The scientific exponent checks are dictated by the string conversion - * specification and are somewhat arbitrary cutoffs. - * - * We must check exponent > 0, because if this is the case, the number - * has trailing zeros. However, we *cannot* output these trailing zeros, - * because doing so would change the precision of the value, and would - * change stored data if the string converted number is round tripped. - */ - if (scientific_exponent < -6 || exponent > 0) { - /* Scientific format */ - *(str_out++) = *(significand_read++) + '0'; - significand_digits--; - - if (significand_digits) { - *(str_out++) = '.'; - } - - for (uint32_t i = 0; i < significand_digits && (str_out - str) < 36; i++) { - *(str_out++) = *(significand_read++) + '0'; - } - /* Exponent */ - *(str_out++) = 'E'; - bson_snprintf (str_out, 6, "%+d", scientific_exponent); - } else { - /* Regular format with no decimal place */ - if (exponent >= 0) { - for (uint32_t i = 0; i < significand_digits && (str_out - str) < 36; i++) { - *(str_out++) = *(significand_read++) + '0'; - } - *str_out = '\0'; - } else { - int32_t radix_position = significand_digits + exponent; - - if (radix_position > 0) { /* non-zero digits before radix */ - for (int32_t i = 0; i < radix_position && (str_out - str) < BSON_DECIMAL128_STRING; i++) { - *(str_out++) = *(significand_read++) + '0'; - } - } else { /* leading zero before radix point */ - *(str_out++) = '0'; - } - - *(str_out++) = '.'; - while (radix_position++ < 0) { /* add leading zeros after radix */ - *(str_out++) = '0'; - } - - for (uint32_t i = 0; bson_cmp_greater_us (significand_digits - i, BSON_MAX (radix_position - 1, 0)) && - (str_out - str) < BSON_DECIMAL128_STRING; - i++) { - *(str_out++) = *(significand_read++) + '0'; - } - *str_out = '\0'; - } - } -} - -typedef struct { - uint64_t high, low; -} _bson_uint128_6464_t; - - -/** - *------------------------------------------------------------------------- - * - * mul64x64 -- - * - * This function multiplies two &uint64_t into a &_bson_uint128_6464_t. - * - * Returns: - * The product of @left and @right. - * - * Side Effects: - * None. - * - *------------------------------------------------------------------------- - */ -static void -_mul_64x64 (uint64_t left, /* IN */ - uint64_t right, /* IN */ - _bson_uint128_6464_t *product) /* OUT */ -{ - uint64_t left_high, left_low, right_high, right_low, product_high, product_mid, product_mid2, product_low; - _bson_uint128_6464_t rt = {0}; - - if (!left && !right) { - *product = rt; - return; - } - - left_high = left >> 32; - left_low = (uint32_t) left; - right_high = right >> 32; - right_low = (uint32_t) right; - - product_high = left_high * right_high; - product_mid = left_high * right_low; - product_mid2 = left_low * right_high; - product_low = left_low * right_low; - - product_high += product_mid >> 32; - product_mid = (uint32_t) product_mid + product_mid2 + (product_low >> 32); - - product_high = product_high + (product_mid >> 32); - product_low = (product_mid << 32) + (uint32_t) product_low; - - rt.high = product_high; - rt.low = product_low; - *product = rt; -} - -/** - *------------------------------------------------------------------------------ - * - * _dec128_tolower -- - * - * This function converts the ASCII character @c to lowercase. It is locale - * insensitive (unlike the stdlib tolower). - * - * Returns: - * The lowercased character. - */ -char -_dec128_tolower (char c) -{ - if (isupper (c)) { - c += 32; - } - - return c; -} - -/** - *------------------------------------------------------------------------------ - * - * _dec128_istreq -- - * - * This function compares the null-terminated *ASCII* strings @a and @b - * for case-insensitive equality. - * - * Returns: - * true if the strings are equal, false otherwise. - */ -bool -_dec128_istreq (const char *a, /* IN */ - const char *b /* IN */) -{ - while (*a != '\0' || *b != '\0') { - /* strings are different lengths. */ - if (*a == '\0' || *b == '\0') { - return false; - } - - if (_dec128_tolower (*a) != _dec128_tolower (*b)) { - return false; - } - - a++; - b++; - } - - return true; -} - -/** - *------------------------------------------------------------------------------ - * - * bson_decimal128_from_string -- - * - * This function converts @string in the format [+-]ddd[.]ddd[E][+-]dddd to - * decimal128. Out of range values are converted to +/-Infinity. Invalid - * strings are converted to NaN. - * - * If more digits are provided than the available precision allows, - * round to the nearest expressable decimal128 with ties going to even will - * occur. - * - * Note: @string must be ASCII only! - * - * Returns: - * true on success, or false on failure. @dec will be NaN if @str was invalid - * The &bson_decimal128_t converted from @string at @dec. - * - * Side effects: - * None. - * - *------------------------------------------------------------------------------ - */ -bool -bson_decimal128_from_string (const char *string, /* IN */ - bson_decimal128_t *dec) /* OUT */ -{ - return bson_decimal128_from_string_w_len (string, -1, dec); -} - - -/** - *------------------------------------------------------------------------------ - * - * bson_decimal128_from_string_w_len -- - * - * This function converts @string in the format [+-]ddd[.]ddd[E][+-]dddd to - * decimal128. Out of range values are converted to +/-Infinity. Invalid - * strings are converted to NaN. @len is the length of the string, or -1 - * meaning the string is null-terminated. - * - * If more digits are provided than the available precision allows, - * round to the nearest expressable decimal128 with ties going to even will - * occur. - * - * Note: @string must be ASCII only! - * - * Returns: - * true on success, or false on failure. @dec will be NaN if @str was invalid - * The &bson_decimal128_t converted from @string at @dec. - * - * Side effects: - * None. - * - *------------------------------------------------------------------------------ - */ -bool -bson_decimal128_from_string_w_len (const char *string, /* IN */ - int len, /* IN */ - bson_decimal128_t *dec) /* OUT */ -{ - _bson_uint128_6464_t significand = {0}; - - const char *str_read = string; /* Read pointer for consuming str. */ - - /* Parsing state tracking */ - bool is_negative = false; - bool saw_radix = false; - bool includes_sign = false; /* True if the input string contains a sign. */ - bool found_nonzero = false; - - size_t significant_digits = 0; /* Total number of significant digits - * (no leading or trailing zero) */ - size_t ndigits_read = 0; /* Total number of significand digits read */ - size_t ndigits = 0; /* Total number of digits (no leading zeros) */ - size_t radix_position = 0; /* The number of the digits after radix */ - size_t first_nonzero = 0; /* The index of the first non-zero in *str* */ - - uint16_t digits[BSON_DECIMAL128_MAX_DIGITS] = {0}; - uint16_t ndigits_stored = 0; /* The number of digits in digits */ - uint16_t *digits_insert = digits; /* Insertion pointer for digits */ - size_t first_digit = 0; /* The index of the first non-zero digit */ - size_t last_digit = 0; /* The index of the last digit */ - - int32_t exponent = 0; - uint64_t significand_high = 0; /* The high 17 digits of the significand */ - uint64_t significand_low = 0; /* The low 17 digits of the significand */ - uint16_t biased_exponent = 0; /* The biased exponent */ - - BSON_ASSERT (dec); - dec->high = 0; - dec->low = 0; - - if (*str_read == '+' || *str_read == '-') { - is_negative = *(str_read++) == '-'; - includes_sign = true; - } - - /* Check for Infinity or NaN */ - if (!isdigit (*str_read) && *str_read != '.') { - if (_dec128_istreq (str_read, "inf") || _dec128_istreq (str_read, "infinity")) { - BSON_DECIMAL128_SET_INF (*dec, is_negative); - return true; - } else if (_dec128_istreq (str_read, "nan")) { - BSON_DECIMAL128_SET_NAN (*dec); - return true; - } - - BSON_DECIMAL128_SET_NAN (*dec); - return false; - } - - /* Read digits */ - while (((isdigit (*str_read) || *str_read == '.')) && (len == -1 || str_read < string + len)) { - if (*str_read == '.') { - if (saw_radix) { - BSON_DECIMAL128_SET_NAN (*dec); - return false; - } - - saw_radix = true; - str_read++; - continue; - } - - if (ndigits_stored < BSON_DECIMAL128_MAX_DIGITS) { - if (*str_read != '0' || found_nonzero) { - if (!found_nonzero) { - first_nonzero = ndigits_read; - } - - found_nonzero = true; - *(digits_insert++) = *(str_read) - '0'; /* Only store 34 digits */ - ndigits_stored++; - } - } - - if (found_nonzero) { - ndigits++; - } - - if (saw_radix) { - radix_position++; - } - - ndigits_read++; - str_read++; - } - - if (saw_radix && !ndigits_read) { - BSON_DECIMAL128_SET_NAN (*dec); - return false; - } - - /* Read exponent if exists */ - if (*str_read == 'e' || *str_read == 'E') { - int nread = 0; -#ifdef _MSC_VER -#define SSCANF sscanf_s -#else -#define SSCANF sscanf -#endif - int64_t temp_exponent = 0; - int read_exponent = SSCANF (++str_read, "%" SCNd64 "%n", &temp_exponent, &nread); - str_read += nread; - - if (!read_exponent || nread == 0 || !bson_in_range_int32_t_signed (temp_exponent)) { - BSON_DECIMAL128_SET_NAN (*dec); - return false; - } - - exponent = (int32_t) temp_exponent; -#undef SSCANF - } - - if ((len == -1 || str_read < string + len) && *str_read) { - BSON_DECIMAL128_SET_NAN (*dec); - return false; - } - - /* Done reading input. */ - /* Find first non-zero digit in digits */ - first_digit = 0; - - if (!ndigits_stored) { /* value is zero */ - first_digit = 0; - last_digit = 0; - digits[0] = 0; - ndigits = 1; - ndigits_stored = 1; - significant_digits = 0; - } else { - last_digit = ndigits_stored - 1; - significant_digits = ndigits; - /* Mark trailing zeros as non-significant */ - while (string[first_nonzero + significant_digits - 1 + includes_sign + saw_radix] == '0') { - significant_digits--; - } - } - - - /* Normalization of exponent */ - /* Correct exponent based on radix position, and shift significand as needed - */ - /* to represent user input */ - - /* Overflow prevention */ - if (bson_cmp_less_equal_su (exponent, radix_position) && - bson_cmp_greater_us (radix_position, exponent + (1 << 14))) { - exponent = BSON_DECIMAL128_EXPONENT_MIN; - } else { - BSON_ASSERT (bson_in_range_unsigned (int32_t, radix_position)); - exponent -= (int32_t) radix_position; - } - - /* Attempt to normalize the exponent */ - while (exponent > BSON_DECIMAL128_EXPONENT_MAX) { - /* Shift exponent to significand and decrease */ - last_digit++; - - if (last_digit - first_digit >= BSON_DECIMAL128_MAX_DIGITS) { - /* The exponent is too great to shift into the significand. */ - if (significant_digits == 0) { - /* Value is zero, we are allowed to clamp the exponent. */ - exponent = BSON_DECIMAL128_EXPONENT_MAX; - break; - } - - /* Overflow is not permitted, error. */ - BSON_DECIMAL128_SET_NAN (*dec); - return false; - } - - exponent--; - } - - while (exponent < BSON_DECIMAL128_EXPONENT_MIN || ndigits_stored < ndigits) { - /* Shift last digit */ - if (last_digit == 0) { - /* underflow is not allowed, but zero clamping is */ - if (significant_digits == 0) { - exponent = BSON_DECIMAL128_EXPONENT_MIN; - break; - } - - BSON_DECIMAL128_SET_NAN (*dec); - return false; - } - - if (ndigits_stored < ndigits) { - if (string[ndigits - 1 + includes_sign + saw_radix] - '0' != 0 && significant_digits != 0) { - BSON_DECIMAL128_SET_NAN (*dec); - return false; - } - - ndigits--; /* adjust to match digits not stored */ - } else { - if (digits[last_digit] != 0) { - /* Inexact rounding is not allowed. */ - BSON_DECIMAL128_SET_NAN (*dec); - return false; - } - - - last_digit--; /* adjust to round */ - } - - if (exponent < BSON_DECIMAL128_EXPONENT_MAX) { - exponent++; - } else { - BSON_DECIMAL128_SET_NAN (*dec); - return false; - } - } - - /* Round */ - /* We've normalized the exponent, but might still need to round. */ - if (last_digit - first_digit + 1 < significant_digits) { - uint8_t round_digit; - - /* There are non-zero digits after last_digit that need rounding. */ - /* We round to nearest, ties to even */ - round_digit = string[first_nonzero + last_digit + includes_sign + saw_radix + 1] - '0'; - - if (round_digit != 0) { - /* Inexact (non-zero) rounding is not allowed */ - BSON_DECIMAL128_SET_NAN (*dec); - return false; - } - } - - /* Encode significand */ - - if (significant_digits == 0) { /* read a zero */ - significand_high = 0; - significand_low = 0; - } else if (last_digit - first_digit < 17) { - size_t d_idx = first_digit; - significand_low = digits[d_idx++]; - - for (; d_idx <= last_digit; d_idx++) { - significand_low *= 10; - significand_low += digits[d_idx]; - significand_high = 0; - } - } else { - size_t d_idx = first_digit; - significand_high = digits[d_idx++]; - - for (; d_idx <= last_digit - 17; d_idx++) { - significand_high *= 10; - significand_high += digits[d_idx]; - } - - significand_low = digits[d_idx++]; - - for (; d_idx <= last_digit; d_idx++) { - significand_low *= 10; - significand_low += digits[d_idx]; - } - } - - _mul_64x64 (significand_high, 100000000000000000ull, &significand); - significand.low += significand_low; - - if (significand.low < significand_low) { - significand.high += 1; - } - - - biased_exponent = (exponent + (int16_t) BSON_DECIMAL128_EXPONENT_BIAS); - - /* Encode combination, exponent, and significand. */ - if ((significand.high >> 49) & 1) { - /* Encode '11' into bits 1 to 3 */ - dec->high |= (0x3ull << 61); - dec->high |= (biased_exponent & 0x3fffull) << 47; - dec->high |= significand.high & 0x7fffffffffffull; - } else { - dec->high |= (biased_exponent & 0x3fffull) << 49; - dec->high |= significand.high & 0x1ffffffffffffull; - } - - dec->low = significand.low; - - /* Encode sign */ - if (is_negative) { - dec->high |= 0x8000000000000000ull; - } - - return true; -} diff --git a/bsonjs/bson/bson-decimal128.h b/bsonjs/bson/bson-decimal128.h deleted file mode 100644 index aa1d53a..0000000 --- a/bsonjs/bson/bson-decimal128.h +++ /dev/null @@ -1,62 +0,0 @@ -/* - * Copyright 2015 MongoDB, Inc. - * - * 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. - */ - -#include - - -#ifndef BSON_DECIMAL128_H -#define BSON_DECIMAL128_H - - -#include - -#include -#include -#include - - -/** - * BSON_DECIMAL128_STRING: - * - * The length of a decimal128 string (with null terminator). - * - * 1 for the sign - * 35 for digits and radix - * 2 for exponent indicator and sign - * 4 for exponent digits - */ -#define BSON_DECIMAL128_STRING 43 -#define BSON_DECIMAL128_INF "Infinity" -#define BSON_DECIMAL128_NAN "NaN" - - -BSON_BEGIN_DECLS - -BSON_EXPORT (void) -bson_decimal128_to_string (const bson_decimal128_t *dec, char *str); - - -/* Note: @string must be ASCII characters only! */ -BSON_EXPORT (bool) -bson_decimal128_from_string (const char *string, bson_decimal128_t *dec); - -BSON_EXPORT (bool) -bson_decimal128_from_string_w_len (const char *string, int len, bson_decimal128_t *dec); - -BSON_END_DECLS - - -#endif /* BSON_DECIMAL128_H */ diff --git a/bsonjs/bson/bson-endian.h b/bsonjs/bson/bson-endian.h deleted file mode 100644 index 1527f10..0000000 --- a/bsonjs/bson/bson-endian.h +++ /dev/null @@ -1,221 +0,0 @@ -/* - * Copyright 2013 MongoDB, Inc. - * - * 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. - */ - -#include - - -#ifndef BSON_ENDIAN_H -#define BSON_ENDIAN_H - - -#if defined(__sun) -#include -#endif - -#include -#include -#include - - -BSON_BEGIN_DECLS - - -#define BSON_BIG_ENDIAN 4321 -#define BSON_LITTLE_ENDIAN 1234 - - -#if defined(__sun) -#define BSON_UINT16_SWAP_LE_BE(v) BSWAP_16 ((uint16_t) v) -#define BSON_UINT32_SWAP_LE_BE(v) BSWAP_32 ((uint32_t) v) -#define BSON_UINT64_SWAP_LE_BE(v) BSWAP_64 ((uint64_t) v) -#elif defined(__clang__) && defined(__clang_major__) && defined(__clang_minor__) && (__clang_major__ >= 3) && \ - (__clang_minor__ >= 1) -#if __has_builtin(__builtin_bswap16) -#define BSON_UINT16_SWAP_LE_BE(v) __builtin_bswap16 (v) -#endif -#if __has_builtin(__builtin_bswap32) -#define BSON_UINT32_SWAP_LE_BE(v) __builtin_bswap32 (v) -#endif -#if __has_builtin(__builtin_bswap64) -#define BSON_UINT64_SWAP_LE_BE(v) __builtin_bswap64 (v) -#endif -#elif defined(__GNUC__) && (__GNUC__ >= 4) -#if __GNUC__ > 4 || (defined(__GNUC_MINOR__) && __GNUC_MINOR__ >= 3) -#define BSON_UINT32_SWAP_LE_BE(v) __builtin_bswap32 ((uint32_t) v) -#define BSON_UINT64_SWAP_LE_BE(v) __builtin_bswap64 ((uint64_t) v) -#endif -#if __GNUC__ > 4 || (defined(__GNUC_MINOR__) && __GNUC_MINOR__ >= 8) -#define BSON_UINT16_SWAP_LE_BE(v) __builtin_bswap16 ((uint32_t) v) -#endif -#endif - - -#ifndef BSON_UINT16_SWAP_LE_BE -#define BSON_UINT16_SWAP_LE_BE(v) __bson_uint16_swap_slow ((uint16_t) v) -#endif - - -#ifndef BSON_UINT32_SWAP_LE_BE -#define BSON_UINT32_SWAP_LE_BE(v) __bson_uint32_swap_slow ((uint32_t) v) -#endif - - -#ifndef BSON_UINT64_SWAP_LE_BE -#define BSON_UINT64_SWAP_LE_BE(v) __bson_uint64_swap_slow ((uint64_t) v) -#endif - - -#if BSON_BYTE_ORDER == BSON_LITTLE_ENDIAN -#define BSON_UINT16_FROM_LE(v) ((uint16_t) v) -#define BSON_UINT16_TO_LE(v) ((uint16_t) v) -#define BSON_UINT16_FROM_BE(v) BSON_UINT16_SWAP_LE_BE (v) -#define BSON_UINT16_TO_BE(v) BSON_UINT16_SWAP_LE_BE (v) -#define BSON_UINT32_FROM_LE(v) ((uint32_t) v) -#define BSON_UINT32_TO_LE(v) ((uint32_t) v) -#define BSON_UINT32_FROM_BE(v) BSON_UINT32_SWAP_LE_BE (v) -#define BSON_UINT32_TO_BE(v) BSON_UINT32_SWAP_LE_BE (v) -#define BSON_UINT64_FROM_LE(v) ((uint64_t) v) -#define BSON_UINT64_TO_LE(v) ((uint64_t) v) -#define BSON_UINT64_FROM_BE(v) BSON_UINT64_SWAP_LE_BE (v) -#define BSON_UINT64_TO_BE(v) BSON_UINT64_SWAP_LE_BE (v) -#define BSON_DOUBLE_FROM_LE(v) ((double) v) -#define BSON_DOUBLE_TO_LE(v) ((double) v) -#elif BSON_BYTE_ORDER == BSON_BIG_ENDIAN -#define BSON_UINT16_FROM_LE(v) BSON_UINT16_SWAP_LE_BE (v) -#define BSON_UINT16_TO_LE(v) BSON_UINT16_SWAP_LE_BE (v) -#define BSON_UINT16_FROM_BE(v) ((uint16_t) v) -#define BSON_UINT16_TO_BE(v) ((uint16_t) v) -#define BSON_UINT32_FROM_LE(v) BSON_UINT32_SWAP_LE_BE (v) -#define BSON_UINT32_TO_LE(v) BSON_UINT32_SWAP_LE_BE (v) -#define BSON_UINT32_FROM_BE(v) ((uint32_t) v) -#define BSON_UINT32_TO_BE(v) ((uint32_t) v) -#define BSON_UINT64_FROM_LE(v) BSON_UINT64_SWAP_LE_BE (v) -#define BSON_UINT64_TO_LE(v) BSON_UINT64_SWAP_LE_BE (v) -#define BSON_UINT64_FROM_BE(v) ((uint64_t) v) -#define BSON_UINT64_TO_BE(v) ((uint64_t) v) -#define BSON_DOUBLE_FROM_LE(v) (__bson_double_swap_slow (v)) -#define BSON_DOUBLE_TO_LE(v) (__bson_double_swap_slow (v)) -#else -#error "The endianness of target architecture is unknown." -#endif - - -/* - *-------------------------------------------------------------------------- - * - * __bson_uint16_swap_slow -- - * - * Fallback endianness conversion for 16-bit integers. - * - * Returns: - * The endian swapped version. - * - * Side effects: - * None. - * - *-------------------------------------------------------------------------- - */ - -static BSON_INLINE uint16_t -__bson_uint16_swap_slow (uint16_t v) /* IN */ -{ - return (uint16_t) ((v & 0x00FF) << 8) | (uint16_t) ((v & 0xFF00) >> 8); -} - - -/* - *-------------------------------------------------------------------------- - * - * __bson_uint32_swap_slow -- - * - * Fallback endianness conversion for 32-bit integers. - * - * Returns: - * The endian swapped version. - * - * Side effects: - * None. - * - *-------------------------------------------------------------------------- - */ - -static BSON_INLINE uint32_t -__bson_uint32_swap_slow (uint32_t v) /* IN */ -{ - return ((v & 0x000000FFU) << 24) | ((v & 0x0000FF00U) << 8) | ((v & 0x00FF0000U) >> 8) | ((v & 0xFF000000U) >> 24); -} - - -/* - *-------------------------------------------------------------------------- - * - * __bson_uint64_swap_slow -- - * - * Fallback endianness conversion for 64-bit integers. - * - * Returns: - * The endian swapped version. - * - * Side effects: - * None. - * - *-------------------------------------------------------------------------- - */ - -static BSON_INLINE uint64_t -__bson_uint64_swap_slow (uint64_t v) /* IN */ -{ - return ((v & 0x00000000000000FFULL) << 56) | ((v & 0x000000000000FF00ULL) << 40) | - ((v & 0x0000000000FF0000ULL) << 24) | ((v & 0x00000000FF000000ULL) << 8) | - ((v & 0x000000FF00000000ULL) >> 8) | ((v & 0x0000FF0000000000ULL) >> 24) | - ((v & 0x00FF000000000000ULL) >> 40) | ((v & 0xFF00000000000000ULL) >> 56); -} - - -/* - *-------------------------------------------------------------------------- - * - * __bson_double_swap_slow -- - * - * Fallback endianness conversion for double floating point. - * - * Returns: - * The endian swapped version. - * - * Side effects: - * None. - * - *-------------------------------------------------------------------------- - */ - -BSON_STATIC_ASSERT2 (sizeof_uint64_t, sizeof (double) == sizeof (uint64_t)); - -static BSON_INLINE double -__bson_double_swap_slow (double v) /* IN */ -{ - uint64_t uv; - - memcpy (&uv, &v, sizeof (v)); - uv = BSON_UINT64_SWAP_LE_BE (uv); - memcpy (&v, &uv, sizeof (v)); - - return v; -} - -BSON_END_DECLS - - -#endif /* BSON_ENDIAN_H */ diff --git a/bsonjs/bson/bson-error.c b/bsonjs/bson/bson-error.c deleted file mode 100644 index 0c6257b..0000000 --- a/bsonjs/bson/bson-error.c +++ /dev/null @@ -1,183 +0,0 @@ -/* - * Copyright 2013 MongoDB, Inc. - * - * 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. - */ - - -#include -#include - -#include -#include -#include -#include -#include -#include - -// See `bson_strerror_r()` definition below. -#if !defined(_WIN32) && !defined(__APPLE__) -#include // uselocale() -#endif - - -/* - *-------------------------------------------------------------------------- - * - * bson_set_error -- - * - * Initializes @error using the parameters specified. - * - * @domain is an application specific error domain which should - * describe which module initiated the error. Think of this as the - * exception type. - * - * @code is the @domain specific error code. - * - * @format is used to generate the format string. It uses vsnprintf() - * internally so the format should match what you would use there. - * - * Parameters: - * @error: A #bson_error_t. - * @domain: The error domain. - * @code: The error code. - * @format: A printf style format string. - * - * Returns: - * None. - * - * Side effects: - * @error is initialized. - * - *-------------------------------------------------------------------------- - */ - -void -bson_set_error (bson_error_t *error, /* OUT */ - uint32_t domain, /* IN */ - uint32_t code, /* IN */ - const char *format, /* IN */ - ...) /* IN */ -{ - va_list args; - - if (error) { - error->domain = domain; - error->code = code; - - va_start (args, format); - bson_vsnprintf (error->message, sizeof error->message, format, args); - va_end (args); - - error->message[sizeof error->message - 1] = '\0'; - } -} - - -/* - *-------------------------------------------------------------------------- - * - * bson_strerror_r -- - * - * This is a reentrant safe macro for strerror. - * - * The resulting string may be stored in @buf. - * - * Returns: - * A pointer to a static string or @buf. - * - * Side effects: - * None. - * - *-------------------------------------------------------------------------- - */ - -char * -bson_strerror_r (int err_code, /* IN */ - char *buf BSON_MAYBE_UNUSED, /* IN */ - size_t buflen BSON_MAYBE_UNUSED) /* IN */ -{ - static const char *unknown_msg = "Unknown error"; - char *ret = NULL; - -#if defined(_WIN32) - // Windows does not provide `strerror_l` or `strerror_r`, but it does - // unconditionally provide `strerror_s`. - if (strerror_s (buf, buflen, err_code) != 0) { - ret = buf; - } -#elif defined(_AIX) - // AIX does not provide strerror_l, and its strerror_r isn't glibc's. - // But it does provide a glibc compatible one called __linux_strerror_r - ret = __linux_strerror_r (err_code, buf, buflen); -#elif defined(__APPLE__) - // Apple does not provide `strerror_l`, but it does unconditionally provide - // the XSI-compliant `strerror_r`, but only when compiling with Apple Clang. - // GNU extensions may still be a problem if we are being compiled with GCC on - // Apple. Avoid the compatibility headaches with GNU extensions and the musl - // library by assuming the implementation will not cause UB when reading the - // error message string even when `strerror_r` fails, as encouraged (but not - // required) by the POSIX spec (see: - // https://pubs.opengroup.org/onlinepubs/9699919799/functions/strerror.html#tag_16_574_08). - (void) strerror_r (err_code, buf, buflen); -#elif defined(_XOPEN_SOURCE) && _XOPEN_SOURCE >= 700 - // The behavior (of `strerror_l`) is undefined if the locale argument to - // `strerror_l()` is the special locale object LC_GLOBAL_LOCALE or is not a - // valid locale object handle. - locale_t locale = uselocale ((locale_t) 0); - // No need to test for error (it can only be [EINVAL]). - if (locale == LC_GLOBAL_LOCALE) { - // Only use our own locale if a thread-local locale was not already set. - // This is just to satisfy `strerror_l`. We do NOT want to unconditionally - // set a thread-local locale. - locale = newlocale (LC_MESSAGES_MASK, "C", (locale_t) 0); - } - BSON_ASSERT (locale != LC_GLOBAL_LOCALE); - - // Avoid `strerror_r` compatibility headaches with GNU extensions and the - // musl library by using `strerror_l` instead. Furthermore, `strerror_r` is - // scheduled to be marked as obsolete in favor of `strerror_l` in the - // upcoming POSIX Issue 8 (see: - // https://www.austingroupbugs.net/view.php?id=655). - // - // POSIX Spec: since strerror_l() is required to return a string for some - // errors, an application wishing to check for all error situations should - // set errno to 0, then call strerror_l(), then check errno. - if (locale != (locale_t) 0) { - errno = 0; - ret = strerror_l (err_code, locale); - - if (errno != 0) { - ret = NULL; - } - - freelocale (locale); - } else { - // Could not obtain a valid `locale_t` object to satisfy `strerror_l`. - // Fallback to `bson_strncpy` below. - } -#elif defined(_GNU_SOURCE) - // Unlikely, but continue supporting use of GNU extension in cases where the - // C Driver is being built without _XOPEN_SOURCE=700. - ret = strerror_r (err_code, buf, buflen); -#else -#error "Unable to find a supported strerror_r candidate" -#endif - - if (!ret) { - bson_strncpy (buf, unknown_msg, buflen); - ret = buf; - } - - return ret; -} diff --git a/bsonjs/bson/bson-error.h b/bsonjs/bson/bson-error.h deleted file mode 100644 index 7d17b84..0000000 --- a/bsonjs/bson/bson-error.h +++ /dev/null @@ -1,46 +0,0 @@ -/* - * Copyright 2013 MongoDB, Inc. - * - * 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. - */ - -#include - - -#ifndef BSON_ERROR_H -#define BSON_ERROR_H - - -#include -#include -#include - - -BSON_BEGIN_DECLS - - -#define BSON_ERROR_JSON 1 -#define BSON_ERROR_READER 2 -#define BSON_ERROR_INVALID 3 - - -BSON_EXPORT (void) -bson_set_error (bson_error_t *error, uint32_t domain, uint32_t code, const char *format, ...) BSON_GNUC_PRINTF (4, 5); -BSON_EXPORT (char *) -bson_strerror_r (int err_code, char *buf, size_t buflen); - - -BSON_END_DECLS - - -#endif /* BSON_ERROR_H */ diff --git a/bsonjs/bson/bson-iso8601-private.h b/bsonjs/bson/bson-iso8601-private.h deleted file mode 100644 index 81909a7..0000000 --- a/bsonjs/bson/bson-iso8601-private.h +++ /dev/null @@ -1,47 +0,0 @@ -/* - * Copyright 2014 MongoDB, Inc. - * - * 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. - */ - -#include - - -#ifndef BSON_ISO8601_PRIVATE_H -#define BSON_ISO8601_PRIVATE_H - - -#include -#include -#include - - -BSON_BEGIN_DECLS - -bool -_bson_iso8601_date_parse (const char *str, int32_t len, int64_t *out, bson_error_t *error); - -/** - * _bson_iso8601_date_format: - * @msecs_since_epoch: A positive number of milliseconds since Jan 1, 1970. - * @str: The string to append the ISO8601-formatted to. - * - * Appends a date formatted like "2012-12-24T12:15:30.500Z" to @str. - */ -void -_bson_iso8601_date_format (int64_t msecs_since_epoch, bson_string_t *str); - -BSON_END_DECLS - - -#endif /* BSON_ISO8601_PRIVATE_H */ diff --git a/bsonjs/bson/bson-iso8601.c b/bsonjs/bson/bson-iso8601.c deleted file mode 100644 index 47687ce..0000000 --- a/bsonjs/bson/bson-iso8601.c +++ /dev/null @@ -1,317 +0,0 @@ -/* - * Copyright 2013 MongoDB, Inc. - * - * 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. - */ - - -#include -#include -#include -#include -#include -#include - - -static bool -get_tok (const char *terminals, const char **ptr, int32_t *remaining, const char **out, int32_t *out_len) -{ - const char *terminal; - bool found_terminal = false; - - if (!*remaining) { - *out = ""; - *out_len = 0; - } - - *out = *ptr; - *out_len = -1; - - for (; *remaining && !found_terminal; (*ptr)++, (*remaining)--, (*out_len)++) { - for (terminal = terminals; *terminal; terminal++) { - if (**ptr == *terminal) { - found_terminal = true; - break; - } - } - } - - if (!found_terminal) { - (*out_len)++; - } - - return found_terminal; -} - -static bool -digits_only (const char *str, int32_t len) -{ - int i; - - for (i = 0; i < len; i++) { - if (!isdigit (str[i])) { - return false; - } - } - - return true; -} - -static bool -parse_num (const char *str, int32_t len, int32_t digits, int32_t min, int32_t max, int32_t *out) -{ - int i; - int magnitude = 1; - int32_t value = 0; - - if ((digits >= 0 && len != digits) || !digits_only (str, len)) { - return false; - } - - for (i = 1; i <= len; i++, magnitude *= 10) { - value += (str[len - i] - '0') * magnitude; - } - - if (value < min || value > max) { - return false; - } - - *out = value; - - return true; -} - -bool -_bson_iso8601_date_parse (const char *str, int32_t len, int64_t *out, bson_error_t *error) -{ - const char *ptr; - int32_t remaining = len; - - const char *year_ptr = NULL; - const char *month_ptr = NULL; - const char *day_ptr = NULL; - const char *hour_ptr = NULL; - const char *min_ptr = NULL; - const char *sec_ptr = NULL; - const char *millis_ptr = NULL; - const char *tz_ptr = NULL; - - int32_t year_len = 0; - int32_t month_len = 0; - int32_t day_len = 0; - int32_t hour_len = 0; - int32_t min_len = 0; - int32_t sec_len = 0; - int32_t millis_len = 0; - int32_t tz_len = 0; - - int32_t year; - int32_t month; - int32_t day; - int32_t hour; - int32_t min; - int32_t sec = 0; - int64_t millis = 0; - int32_t tz_adjustment = 0; - - struct bson_tm posix_date = {0}; - -#define DATE_PARSE_ERR(msg) \ - bson_set_error ( \ - error, BSON_ERROR_JSON, BSON_JSON_ERROR_READ_INVALID_PARAM, "Could not parse \"%s\" as date: " msg, str); \ - return false - -#define DEFAULT_DATE_PARSE_ERR \ - DATE_PARSE_ERR ("use ISO8601 format yyyy-mm-ddThh:mm plus timezone, either" \ - " \"Z\" or like \"+0500\" or like \"+05:00\"") - - ptr = str; - - /* we have to match at least yyyy-mm-ddThh:mm */ - if (!(get_tok ("-", &ptr, &remaining, &year_ptr, &year_len) && - get_tok ("-", &ptr, &remaining, &month_ptr, &month_len) && - get_tok ("T", &ptr, &remaining, &day_ptr, &day_len) && get_tok (":", &ptr, &remaining, &hour_ptr, &hour_len) && - get_tok (":+-Z", &ptr, &remaining, &min_ptr, &min_len))) { - DEFAULT_DATE_PARSE_ERR; - } - - /* if the minute has a ':' at the end look for seconds */ - if (min_ptr[min_len] == ':') { - if (remaining < 2) { - DATE_PARSE_ERR ("reached end of date while looking for seconds"); - } - - get_tok (".+-Z", &ptr, &remaining, &sec_ptr, &sec_len); - - if (!sec_len) { - DATE_PARSE_ERR ("minute ends in \":\" seconds is required"); - } - } - - /* if we had a second and it is followed by a '.' look for milliseconds */ - if (sec_len && sec_ptr[sec_len] == '.') { - if (remaining < 2) { - DATE_PARSE_ERR ("reached end of date while looking for milliseconds"); - } - - get_tok ("+-Z", &ptr, &remaining, &millis_ptr, &millis_len); - - if (!millis_len) { - DATE_PARSE_ERR ("seconds ends in \".\", milliseconds is required"); - } - } - - /* backtrack by 1 to put ptr on the timezone */ - ptr--; - remaining++; - - get_tok ("", &ptr, &remaining, &tz_ptr, &tz_len); - - if (!parse_num (year_ptr, year_len, 4, -9999, 9999, &year)) { - DATE_PARSE_ERR ("year must be an integer"); - } - - /* values are as in struct tm */ - year -= 1900; - - if (!parse_num (month_ptr, month_len, 2, 1, 12, &month)) { - DATE_PARSE_ERR ("month must be an integer"); - } - - /* values are as in struct tm */ - month -= 1; - - if (!parse_num (day_ptr, day_len, 2, 1, 31, &day)) { - DATE_PARSE_ERR ("day must be an integer"); - } - - if (!parse_num (hour_ptr, hour_len, 2, 0, 23, &hour)) { - DATE_PARSE_ERR ("hour must be an integer"); - } - - if (!parse_num (min_ptr, min_len, 2, 0, 59, &min)) { - DATE_PARSE_ERR ("minute must be an integer"); - } - - if (sec_len && !parse_num (sec_ptr, sec_len, 2, 0, 60, &sec)) { - DATE_PARSE_ERR ("seconds must be an integer"); - } - - if (tz_len > 0) { - if (tz_ptr[0] == 'Z' && tz_len == 1) { - /* valid */ - } else if (tz_ptr[0] == '+' || tz_ptr[0] == '-') { - int32_t tz_hour; - int32_t tz_min; - - if ((tz_len != 5 || !digits_only (tz_ptr + 1, 4)) && - (tz_len != 6 || !digits_only (tz_ptr + 1, 2) || tz_ptr[3] != ':' || !digits_only (tz_ptr + 4, 2))) { - DATE_PARSE_ERR ("could not parse timezone"); - } - - if (!parse_num (tz_ptr + 1, 2, -1, -23, 23, &tz_hour)) { - DATE_PARSE_ERR ("timezone hour must be at most 23"); - } - - int32_t tz_min_offset = tz_ptr[3] == ':' ? 1 : 0; - if (!parse_num (tz_ptr + 3 + tz_min_offset, 2, -1, 0, 59, &tz_min)) { - DATE_PARSE_ERR ("timezone minute must be at most 59"); - } - - /* we inflect the meaning of a 'positive' timezone. Those are hours - * we have to subtract, and vice versa */ - tz_adjustment = (tz_ptr[0] == '-' ? 1 : -1) * ((tz_min * 60) + (tz_hour * 60 * 60)); - - if (!(tz_adjustment > -86400 && tz_adjustment < 86400)) { - DATE_PARSE_ERR ("timezone offset must be less than 24 hours"); - } - } else { - DATE_PARSE_ERR ("timezone is required"); - } - } - - if (millis_len > 0) { - int i; - int magnitude; - millis = 0; - - if (millis_len > 3 || !digits_only (millis_ptr, millis_len)) { - DATE_PARSE_ERR ("milliseconds must be an integer"); - } - - for (i = 1, magnitude = 1; i <= millis_len; i++, magnitude *= 10) { - millis += (millis_ptr[millis_len - i] - '0') * magnitude; - } - - if (millis_len == 1) { - millis *= 100; - } else if (millis_len == 2) { - millis *= 10; - } - - if (millis < 0 || millis > 1000) { - DATE_PARSE_ERR ("milliseconds must be at least 0 and less than 1000"); - } - } - - posix_date.tm_sec = sec; - posix_date.tm_min = min; - posix_date.tm_hour = hour; - posix_date.tm_mday = day; - posix_date.tm_mon = month; - posix_date.tm_year = year; - posix_date.tm_wday = 0; - posix_date.tm_yday = 0; - - millis = 1000 * _bson_timegm (&posix_date) + millis; - millis += tz_adjustment * 1000; - *out = millis; - - return true; -} - - -void -_bson_iso8601_date_format (int64_t msec_since_epoch, bson_string_t *str) -{ - time_t t; - int64_t msecs_part; - char buf[64]; - - msecs_part = msec_since_epoch % 1000; - t = (time_t) (msec_since_epoch / 1000); - -#ifdef BSON_HAVE_GMTIME_R - { - struct tm posix_date; - gmtime_r (&t, &posix_date); - strftime (buf, sizeof buf, "%Y-%m-%dT%H:%M:%S", &posix_date); - } -#elif defined(_MSC_VER) - { - /* Windows gmtime_s is thread-safe */ - struct tm time_buf; - gmtime_s (&time_buf, &t); - strftime (buf, sizeof buf, "%Y-%m-%dT%H:%M:%S", &time_buf); - } -#else - strftime (buf, sizeof buf, "%Y-%m-%dT%H:%M:%S", gmtime (&t)); -#endif - - if (msecs_part) { - bson_string_append_printf (str, "%s.%03" PRId64 "Z", buf, msecs_part); - } else { - bson_string_append (str, buf); - bson_string_append_c (str, 'Z'); - } -} diff --git a/bsonjs/bson/bson-iter.c b/bsonjs/bson/bson-iter.c deleted file mode 100644 index 0925b02..0000000 --- a/bsonjs/bson/bson-iter.c +++ /dev/null @@ -1,2519 +0,0 @@ -/* - * Copyright 2013-2014 MongoDB, Inc. - * - * 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. - */ - - -#include -#include -#include -#include - -#define ITER_TYPE(i) ((bson_type_t) * ((i)->raw + (i)->type)) - - -/* - *-------------------------------------------------------------------------- - * - * bson_iter_init -- - * - * Initializes @iter to be used to iterate @bson. - * - * Returns: - * true if bson_iter_t was initialized. otherwise false. - * - * Side effects: - * @iter is initialized. - * - *-------------------------------------------------------------------------- - */ - -bool -bson_iter_init (bson_iter_t *iter, /* OUT */ - const bson_t *bson) /* IN */ -{ - BSON_ASSERT (iter); - BSON_ASSERT (bson); - - if (BSON_UNLIKELY (bson->len < 5)) { - memset (iter, 0, sizeof *iter); - return false; - } - - iter->raw = bson_get_data (bson); - iter->len = bson->len; - iter->off = 0; - iter->type = 0; - iter->key = 0; - iter->d1 = 0; - iter->d2 = 0; - iter->d3 = 0; - iter->d4 = 0; - iter->next_off = 4; - iter->err_off = 0; - - return true; -} - - -/* - *-------------------------------------------------------------------------- - * - * bson_iter_init_from_data -- - * - * Initializes @iter to be used to iterate @data of length @length - * - * Returns: - * true if bson_iter_t was initialized. otherwise false. - * - * Side effects: - * @iter is initialized. - * - *-------------------------------------------------------------------------- - */ - -bool -bson_iter_init_from_data (bson_iter_t *iter, /* OUT */ - const uint8_t *data, /* IN */ - size_t length) /* IN */ -{ - uint32_t len_le; - - BSON_ASSERT (iter); - BSON_ASSERT (data); - - if (BSON_UNLIKELY ((length < 5) || (length > INT_MAX))) { - memset (iter, 0, sizeof *iter); - return false; - } - - memcpy (&len_le, data, sizeof (len_le)); - - if (BSON_UNLIKELY ((size_t) BSON_UINT32_FROM_LE (len_le) != length)) { - memset (iter, 0, sizeof *iter); - return false; - } - - if (BSON_UNLIKELY (data[length - 1])) { - memset (iter, 0, sizeof *iter); - return false; - } - - if (BSON_UNLIKELY (!bson_in_range_unsigned (uint32_t, length))) { - memset (iter, 0, sizeof *iter); - return false; - } - - iter->raw = (uint8_t *) data; - iter->len = (uint32_t) length; - iter->off = 0; - iter->type = 0; - iter->key = 0; - iter->d1 = 0; - iter->d2 = 0; - iter->d3 = 0; - iter->d4 = 0; - iter->next_off = 4; - iter->err_off = 0; - - return true; -} - - -/* - *-------------------------------------------------------------------------- - * - * bson_iter_recurse -- - * - * Creates a new sub-iter looking at the document or array that @iter - * is currently pointing at. - * - * Returns: - * true if successful and @child was initialized. - * - * Side effects: - * @child is initialized. - * - *-------------------------------------------------------------------------- - */ - -bool -bson_iter_recurse (const bson_iter_t *iter, /* IN */ - bson_iter_t *child) /* OUT */ -{ - const uint8_t *data = NULL; - uint32_t len = 0; - - BSON_ASSERT (iter); - BSON_ASSERT (child); - - if (ITER_TYPE (iter) == BSON_TYPE_DOCUMENT) { - bson_iter_document (iter, &len, &data); - } else if (ITER_TYPE (iter) == BSON_TYPE_ARRAY) { - bson_iter_array (iter, &len, &data); - } else { - return false; - } - - child->raw = data; - child->len = len; - child->off = 0; - child->type = 0; - child->key = 0; - child->d1 = 0; - child->d2 = 0; - child->d3 = 0; - child->d4 = 0; - child->next_off = 4; - child->err_off = 0; - - return true; -} - - -/* - *-------------------------------------------------------------------------- - * - * bson_iter_init_find -- - * - * Initializes a #bson_iter_t and moves the iter to the first field - * matching @key. - * - * Returns: - * true if the field named @key was found; otherwise false. - * - * Side effects: - * None. - * - *-------------------------------------------------------------------------- - */ - -bool -bson_iter_init_find (bson_iter_t *iter, /* INOUT */ - const bson_t *bson, /* IN */ - const char *key) /* IN */ -{ - BSON_ASSERT (iter); - BSON_ASSERT (bson); - BSON_ASSERT (key); - - return bson_iter_init (iter, bson) && bson_iter_find (iter, key); -} - - -/* - *-------------------------------------------------------------------------- - * - * bson_iter_init_find_w_len -- - * - * Initializes a #bson_iter_t and moves the iter to the first field - * matching @key. - * - * Returns: - * true if the field named @key was found; otherwise false. - * - * Side effects: - * None. - * - *-------------------------------------------------------------------------- - */ - -bool -bson_iter_init_find_w_len (bson_iter_t *iter, /* INOUT */ - const bson_t *bson, /* IN */ - const char *key, /* IN */ - int keylen) /* IN */ -{ - BSON_ASSERT (iter); - BSON_ASSERT (bson); - BSON_ASSERT (key); - - return bson_iter_init (iter, bson) && bson_iter_find_w_len (iter, key, keylen); -} - - -/* - *-------------------------------------------------------------------------- - * - * bson_iter_init_find_case -- - * - * A case-insensitive version of bson_iter_init_find(). - * - * Returns: - * true if the field was found and @iter is observing that field. - * - * Side effects: - * None. - * - *-------------------------------------------------------------------------- - */ - -bool -bson_iter_init_find_case (bson_iter_t *iter, /* INOUT */ - const bson_t *bson, /* IN */ - const char *key) /* IN */ -{ - BSON_ASSERT (iter); - BSON_ASSERT (bson); - BSON_ASSERT (key); - - return bson_iter_init (iter, bson) && bson_iter_find_case (iter, key); -} - - -/* - *-------------------------------------------------------------------------- - * - * bson_iter_find_w_len -- - * - * Searches through @iter starting from the current position for a key - * matching @key. @keylen indicates the length of @key, or -1 to - * determine the length with strlen(). - * - * Returns: - * true if the field @key was found. - * - * Side effects: - * None. - * - *-------------------------------------------------------------------------- - */ - -bool -bson_iter_find_w_len (bson_iter_t *iter, /* INOUT */ - const char *key, /* IN */ - int keylen) /* IN */ -{ - const char *ikey; - - if (keylen < 0) { - keylen = (int) strlen (key); - } - - while (bson_iter_next (iter)) { - ikey = bson_iter_key (iter); - - if ((0 == strncmp (key, ikey, keylen)) && (ikey[keylen] == '\0')) { - return true; - } - } - - return false; -} - - -/* - *-------------------------------------------------------------------------- - * - * bson_iter_find -- - * - * Searches through @iter starting from the current position for a key - * matching @key. This is a case-sensitive search meaning "KEY" and - * "key" would NOT match. - * - * Returns: - * true if @key is found. - * - * Side effects: - * None. - * - *-------------------------------------------------------------------------- - */ - -bool -bson_iter_find (bson_iter_t *iter, /* INOUT */ - const char *key) /* IN */ -{ - BSON_ASSERT (iter); - BSON_ASSERT (key); - - return bson_iter_find_w_len (iter, key, -1); -} - - -/* - *-------------------------------------------------------------------------- - * - * bson_iter_find_case -- - * - * Searches through @iter starting from the current position for a key - * matching @key. This is a case-insensitive search meaning "KEY" and - * "key" would match. - * - * Returns: - * true if @key is found. - * - * Side effects: - * None. - * - *-------------------------------------------------------------------------- - */ - -bool -bson_iter_find_case (bson_iter_t *iter, /* INOUT */ - const char *key) /* IN */ -{ - BSON_ASSERT (iter); - BSON_ASSERT (key); - - while (bson_iter_next (iter)) { - if (!bson_strcasecmp (key, bson_iter_key (iter))) { - return true; - } - } - - return false; -} - - -/* - *-------------------------------------------------------------------------- - * - * bson_iter_find_descendant -- - * - * Locates a descendant using the "parent.child.key" notation. This - * operates similar to bson_iter_find() except that it can recurse - * into children documents using the dot notation. - * - * Returns: - * true if the descendant was found and @descendant was initialized. - * - * Side effects: - * @descendant may be initialized. - * - *-------------------------------------------------------------------------- - */ - -bool -bson_iter_find_descendant (bson_iter_t *iter, /* INOUT */ - const char *dotkey, /* IN */ - bson_iter_t *descendant) /* OUT */ -{ - bson_iter_t tmp; - const char *dot; - size_t sublen; - - BSON_ASSERT (iter); - BSON_ASSERT (dotkey); - BSON_ASSERT (descendant); - - if ((dot = strchr (dotkey, '.'))) { - sublen = dot - dotkey; - } else { - sublen = strlen (dotkey); - } - - if (bson_iter_find_w_len (iter, dotkey, (int) sublen)) { - if (!dot) { - *descendant = *iter; - return true; - } - - if (BSON_ITER_HOLDS_DOCUMENT (iter) || BSON_ITER_HOLDS_ARRAY (iter)) { - if (bson_iter_recurse (iter, &tmp)) { - return bson_iter_find_descendant (&tmp, dot + 1, descendant); - } - } - } - - return false; -} - - -/* - *-------------------------------------------------------------------------- - * - * bson_iter_key -- - * - * Retrieves the key of the current field. The resulting key is valid - * while @iter is valid. - * - * Returns: - * A string that should not be modified or freed. - * - * Side effects: - * None. - * - *-------------------------------------------------------------------------- - */ - -const char * -bson_iter_key (const bson_iter_t *iter) /* IN */ -{ - BSON_ASSERT (iter); - - return bson_iter_key_unsafe (iter); -} - - -/* - *-------------------------------------------------------------------------- - * - * bson_iter_type -- - * - * Retrieves the type of the current field. It may be useful to check - * the type using the BSON_ITER_HOLDS_*() macros. - * - * Returns: - * A bson_type_t. - * - * Side effects: - * None. - * - *-------------------------------------------------------------------------- - */ - -bson_type_t -bson_iter_type (const bson_iter_t *iter) /* IN */ -{ - BSON_ASSERT (iter); - BSON_ASSERT (iter->raw); - BSON_ASSERT (iter->len); - - return bson_iter_type_unsafe (iter); -} - - -/* - *-------------------------------------------------------------------------- - * - * _bson_iter_next_internal -- - * - * Internal function to advance @iter to the next field and retrieve - * the key and BSON type before error-checking. @next_keylen is - * the key length of the next field being iterated or 0 if this is - * not known. - * - * Return: - * true if an element was decoded, else false. - * - * Side effects: - * @key and @bson_type are set. - * - * If the return value is false: - * - @iter is invalidated: @iter->raw is NULLed - * - @unsupported is set to true if the bson type is unsupported - * - otherwise if the BSON is corrupt, @iter->err_off is nonzero - * - otherwise @bson_type is set to BSON_TYPE_EOD - * - *-------------------------------------------------------------------------- - */ - -static bool -_bson_iter_next_internal (bson_iter_t *iter, /* INOUT */ - uint32_t next_keylen, /* IN */ - const char **key, /* OUT */ - uint32_t *bson_type, /* OUT */ - bool *unsupported) /* OUT */ -{ - const uint8_t *data; - uint32_t o; - unsigned int len; - - BSON_ASSERT (iter); - - *unsupported = false; - - if (!iter->raw) { - *key = NULL; - *bson_type = BSON_TYPE_EOD; - return false; - } - - data = iter->raw; - len = iter->len; - - iter->off = iter->next_off; - iter->type = iter->off; - iter->key = iter->off + 1; - iter->d1 = 0; - iter->d2 = 0; - iter->d3 = 0; - iter->d4 = 0; - - if (next_keylen == 0) { - /* iterate from start to end of NULL-terminated key string */ - for (o = iter->key; o < len; o++) { - if (!data[o]) { - iter->d1 = ++o; - goto fill_data_fields; - } - } - } else { - o = iter->key + next_keylen + 1; - iter->d1 = o; - goto fill_data_fields; - } - - goto mark_invalid; - -fill_data_fields: - - *key = bson_iter_key_unsafe (iter); - *bson_type = ITER_TYPE (iter); - - switch (*bson_type) { - case BSON_TYPE_DATE_TIME: - case BSON_TYPE_DOUBLE: - case BSON_TYPE_INT64: - case BSON_TYPE_TIMESTAMP: - iter->next_off = o + 8; - break; - case BSON_TYPE_CODE: - case BSON_TYPE_SYMBOL: - case BSON_TYPE_UTF8: { - uint32_t l; - - if ((o + 4) >= len) { - iter->err_off = o; - goto mark_invalid; - } - - iter->d2 = o + 4; - memcpy (&l, iter->raw + iter->d1, sizeof (l)); - l = BSON_UINT32_FROM_LE (l); - - if (l > (len - (o + 4))) { - iter->err_off = o; - goto mark_invalid; - } - - iter->next_off = o + 4 + l; - - /* - * Make sure the string length includes the NUL byte. - */ - if (BSON_UNLIKELY ((l == 0) || (iter->next_off >= len))) { - iter->err_off = o; - goto mark_invalid; - } - - /* - * Make sure the last byte is a NUL byte. - */ - if (BSON_UNLIKELY ((iter->raw + iter->d2)[l - 1] != '\0')) { - iter->err_off = o + 4 + l - 1; - goto mark_invalid; - } - } break; - case BSON_TYPE_BINARY: { - bson_subtype_t subtype; - uint32_t l; - - if (o >= (len - 4)) { - iter->err_off = o; - goto mark_invalid; - } - - iter->d2 = o + 4; - iter->d3 = o + 5; - - memcpy (&l, iter->raw + iter->d1, sizeof (l)); - l = BSON_UINT32_FROM_LE (l); - - if (l >= (len - o - 4)) { - iter->err_off = o; - goto mark_invalid; - } - - subtype = *(iter->raw + iter->d2); - - if (subtype == BSON_SUBTYPE_BINARY_DEPRECATED) { - int32_t binary_len; - - if (l < 4) { - iter->err_off = o; - goto mark_invalid; - } - - /* subtype 2 has a redundant length header in the data */ - memcpy (&binary_len, (iter->raw + iter->d3), sizeof (binary_len)); - binary_len = BSON_UINT32_FROM_LE (binary_len); - if (binary_len + 4 != l) { - iter->err_off = iter->d3; - goto mark_invalid; - } - } - - iter->next_off = o + 5 + l; - } break; - case BSON_TYPE_ARRAY: - case BSON_TYPE_DOCUMENT: { - uint32_t l; - - if (o >= (len - 4)) { - iter->err_off = o; - goto mark_invalid; - } - - memcpy (&l, iter->raw + iter->d1, sizeof (l)); - l = BSON_UINT32_FROM_LE (l); - - if ((l > len) || (l > (len - o))) { - iter->err_off = o; - goto mark_invalid; - } - - iter->next_off = o + l; - } break; - case BSON_TYPE_OID: - iter->next_off = o + 12; - break; - case BSON_TYPE_BOOL: { - char val; - - if (iter->d1 >= len) { - iter->err_off = o; - goto mark_invalid; - } - - memcpy (&val, iter->raw + iter->d1, 1); - if (val != 0x00 && val != 0x01) { - iter->err_off = o; - goto mark_invalid; - } - - iter->next_off = o + 1; - } break; - case BSON_TYPE_REGEX: { - bool eor = false; - bool eoo = false; - - for (; o < len; o++) { - if (!data[o]) { - iter->d2 = ++o; - eor = true; - break; - } - } - - if (!eor) { - iter->err_off = iter->next_off; - goto mark_invalid; - } - - for (; o < len; o++) { - if (!data[o]) { - eoo = true; - break; - } - } - - if (!eoo) { - iter->err_off = iter->next_off; - goto mark_invalid; - } - - iter->next_off = o + 1; - } break; - case BSON_TYPE_DBPOINTER: { - uint32_t l; - - if (o >= (len - 4)) { - iter->err_off = o; - goto mark_invalid; - } - - iter->d2 = o + 4; - memcpy (&l, iter->raw + iter->d1, sizeof (l)); - l = BSON_UINT32_FROM_LE (l); - - /* Check valid string length. l counts '\0' but not 4 bytes for itself. */ - if (l == 0 || l > (len - o - 4)) { - iter->err_off = o; - goto mark_invalid; - } - - if (*(iter->raw + o + l + 3)) { - /* not null terminated */ - iter->err_off = o + l + 3; - goto mark_invalid; - } - - iter->d3 = o + 4 + l; - iter->next_off = o + 4 + l + 12; - } break; - case BSON_TYPE_CODEWSCOPE: { - uint32_t l; - uint32_t doclen; - - if ((len < 19) || (o >= (len - 14))) { - iter->err_off = o; - goto mark_invalid; - } - - iter->d2 = o + 4; - iter->d3 = o + 8; - - memcpy (&l, iter->raw + iter->d1, sizeof (l)); - l = BSON_UINT32_FROM_LE (l); - - if ((l < 14) || (l >= (len - o))) { - iter->err_off = o; - goto mark_invalid; - } - - iter->next_off = o + l; - - if (iter->next_off >= len) { - iter->err_off = o; - goto mark_invalid; - } - - memcpy (&l, iter->raw + iter->d2, sizeof (l)); - l = BSON_UINT32_FROM_LE (l); - - if (l == 0 || l >= (len - o - 4 - 4)) { - iter->err_off = o; - goto mark_invalid; - } - - if ((o + 4 + 4 + l + 4) >= iter->next_off) { - iter->err_off = o + 4; - goto mark_invalid; - } - - iter->d4 = o + 4 + 4 + l; - memcpy (&doclen, iter->raw + iter->d4, sizeof (doclen)); - doclen = BSON_UINT32_FROM_LE (doclen); - - if ((o + 4 + 4 + l + doclen) != iter->next_off) { - iter->err_off = o + 4 + 4 + l; - goto mark_invalid; - } - } break; - case BSON_TYPE_INT32: - iter->next_off = o + 4; - break; - case BSON_TYPE_DECIMAL128: - iter->next_off = o + 16; - break; - case BSON_TYPE_MAXKEY: - case BSON_TYPE_MINKEY: - case BSON_TYPE_NULL: - case BSON_TYPE_UNDEFINED: - iter->next_off = o; - break; - default: - *unsupported = true; - /* FALL THROUGH */ - case BSON_TYPE_EOD: - iter->err_off = o; - goto mark_invalid; - } - - /* - * Check to see if any of the field locations would overflow the - * current BSON buffer. If so, set the error location to the offset - * of where the field starts. - */ - if (iter->next_off >= len) { - iter->err_off = o; - goto mark_invalid; - } - - iter->err_off = 0; - - return true; - -mark_invalid: - iter->raw = NULL; - iter->len = 0; - iter->next_off = 0; - - return false; -} - - -/* - *-------------------------------------------------------------------------- - * - * bson_iter_next -- - * - * Advances @iter to the next field of the underlying BSON document. - * If all fields have been exhausted, then %false is returned. - * - * It is a programming error to use @iter after this function has - * returned false. - * - * Returns: - * true if the iter was advanced to the next record. - * otherwise false and @iter should be considered invalid. - * - * Side effects: - * @iter may be invalidated. - * - *-------------------------------------------------------------------------- - */ - -bool -bson_iter_next (bson_iter_t *iter) /* INOUT */ -{ - uint32_t bson_type; - const char *key; - bool unsupported; - - return _bson_iter_next_internal (iter, 0, &key, &bson_type, &unsupported); -} - - -/* - *-------------------------------------------------------------------------- - * - * bson_iter_binary -- - * - * Retrieves the BSON_TYPE_BINARY field. The subtype is stored in - * @subtype. The length of @binary in bytes is stored in @binary_len. - * - * @binary should not be modified or freed and is only valid while - * @iter's bson_t is valid and unmodified. - * - * Parameters: - * @iter: A bson_iter_t - * @subtype: A location for the binary subtype. - * @binary_len: A location for the length of @binary. - * @binary: A location for a pointer to the binary data. - * - * Returns: - * None. - * - * Side effects: - * None. - * - *-------------------------------------------------------------------------- - */ - -void -bson_iter_binary (const bson_iter_t *iter, /* IN */ - bson_subtype_t *subtype, /* OUT */ - uint32_t *binary_len, /* OUT */ - const uint8_t **binary) /* OUT */ -{ - bson_subtype_t backup; - - BSON_ASSERT (iter); - BSON_ASSERT (!binary || binary_len); - - if (ITER_TYPE (iter) == BSON_TYPE_BINARY) { - if (!subtype) { - subtype = &backup; - } - - *subtype = (bson_subtype_t) * (iter->raw + iter->d2); - - if (binary) { - memcpy (binary_len, (iter->raw + iter->d1), sizeof (*binary_len)); - *binary_len = BSON_UINT32_FROM_LE (*binary_len); - *binary = iter->raw + iter->d3; - - if (*subtype == BSON_SUBTYPE_BINARY_DEPRECATED) { - *binary_len -= sizeof (int32_t); - *binary += sizeof (int32_t); - } - } - - return; - } - - if (binary) { - *binary = NULL; - } - - if (binary_len) { - *binary_len = 0; - } - - if (subtype) { - *subtype = BSON_SUBTYPE_BINARY; - } -} - - -/* - *-------------------------------------------------------------------------- - * - * bson_iter_bool -- - * - * Retrieves the current field of type BSON_TYPE_BOOL. - * - * Returns: - * true or false, dependent on bson document. - * - * Side effects: - * None. - * - *-------------------------------------------------------------------------- - */ - -bool -bson_iter_bool (const bson_iter_t *iter) /* IN */ -{ - BSON_ASSERT (iter); - - if (ITER_TYPE (iter) == BSON_TYPE_BOOL) { - return bson_iter_bool_unsafe (iter); - } - - return false; -} - - -/* - *-------------------------------------------------------------------------- - * - * bson_iter_as_bool -- - * - * If @iter is on a boolean field, returns the boolean. If it is on a - * non-boolean field such as int32, int64, or double, it will convert - * the value to a boolean. - * - * Zero is false, and non-zero is true. - * - * Returns: - * true or false, dependent on field type. - * - * Side effects: - * None. - * - *-------------------------------------------------------------------------- - */ - -bool -bson_iter_as_bool (const bson_iter_t *iter) /* IN */ -{ - BSON_ASSERT (iter); - - switch ((int) ITER_TYPE (iter)) { - case BSON_TYPE_BOOL: - return bson_iter_bool (iter); - case BSON_TYPE_DOUBLE: - return !(bson_iter_double (iter) == 0.0); - case BSON_TYPE_INT64: - return !(bson_iter_int64 (iter) == 0); - case BSON_TYPE_INT32: - return !(bson_iter_int32 (iter) == 0); - case BSON_TYPE_UTF8: - return true; - case BSON_TYPE_NULL: - case BSON_TYPE_UNDEFINED: - return false; - default: - return true; - } -} - - -/* - *-------------------------------------------------------------------------- - * - * bson_iter_double -- - * - * Retrieves the current field of type BSON_TYPE_DOUBLE. - * - * Returns: - * A double. - * - * Side effects: - * None. - * - *-------------------------------------------------------------------------- - */ - -double -bson_iter_double (const bson_iter_t *iter) /* IN */ -{ - BSON_ASSERT (iter); - - if (ITER_TYPE (iter) == BSON_TYPE_DOUBLE) { - return bson_iter_double_unsafe (iter); - } - - return 0; -} - - -/* - *-------------------------------------------------------------------------- - * - * bson_iter_as_double -- - * - * If @iter is on a field of type BSON_TYPE_DOUBLE, - * returns the double. If it is on an integer field - * such as int32, int64, or bool, it will convert - * the value to a double. - * - * - * Returns: - * A double. - * - * Side effects: - * None. - * - *-------------------------------------------------------------------------- - */ - -double -bson_iter_as_double (const bson_iter_t *iter) /* IN */ -{ - BSON_ASSERT (iter); - - switch ((int) ITER_TYPE (iter)) { - case BSON_TYPE_BOOL: - return (double) bson_iter_bool (iter); - case BSON_TYPE_DOUBLE: - return bson_iter_double (iter); - case BSON_TYPE_INT32: - return (double) bson_iter_int32 (iter); - case BSON_TYPE_INT64: - return (double) bson_iter_int64 (iter); - default: - return 0; - } -} - - -/* - *-------------------------------------------------------------------------- - * - * bson_iter_int32 -- - * - * Retrieves the value of the field of type BSON_TYPE_INT32. - * - * Returns: - * A 32-bit signed integer. - * - * Side effects: - * None. - * - *-------------------------------------------------------------------------- - */ - -int32_t -bson_iter_int32 (const bson_iter_t *iter) /* IN */ -{ - BSON_ASSERT (iter); - - if (ITER_TYPE (iter) == BSON_TYPE_INT32) { - return bson_iter_int32_unsafe (iter); - } - - return 0; -} - -/* - *-------------------------------------------------------------------------- - * - * bson_iter_int64 -- - * - * Retrieves a 64-bit signed integer for the current BSON_TYPE_INT64 - * field. - * - * Returns: - * A 64-bit signed integer. - * - * Side effects: - * None. - * - *-------------------------------------------------------------------------- - */ - -int64_t -bson_iter_int64 (const bson_iter_t *iter) /* IN */ -{ - BSON_ASSERT (iter); - - if (ITER_TYPE (iter) == BSON_TYPE_INT64) { - return bson_iter_int64_unsafe (iter); - } - - return 0; -} - - -/* - *-------------------------------------------------------------------------- - * - * bson_iter_as_int64 -- - * - * If @iter is not an int64 field, it will try to convert the value to - * an int64. Such field types include: - * - * - bool - * - double - * - int32 - * - * Returns: - * An int64_t. - * - * Side effects: - * None. - * - *-------------------------------------------------------------------------- - */ - -int64_t -bson_iter_as_int64 (const bson_iter_t *iter) /* IN */ -{ - BSON_ASSERT (iter); - - switch ((int) ITER_TYPE (iter)) { - case BSON_TYPE_BOOL: - return (int64_t) bson_iter_bool (iter); - case BSON_TYPE_DOUBLE: - return (int64_t) bson_iter_double (iter); - case BSON_TYPE_INT64: - return bson_iter_int64 (iter); - case BSON_TYPE_INT32: - return (int64_t) bson_iter_int32 (iter); - default: - return 0; - } -} - - -/* - *-------------------------------------------------------------------------- - * - * bson_iter_decimal128 -- - * - * This function retrieves the current field of type - *%BSON_TYPE_DECIMAL128. - * The result is valid while @iter is valid, and is stored in @dec. - * - * Returns: - * - * True on success, false on failure. - * - * Side Effects: - * None. - * - *-------------------------------------------------------------------------- - */ -bool -bson_iter_decimal128 (const bson_iter_t *iter, /* IN */ - bson_decimal128_t *dec) /* OUT */ -{ - BSON_ASSERT (iter); - - if (ITER_TYPE (iter) == BSON_TYPE_DECIMAL128) { - bson_iter_decimal128_unsafe (iter, dec); - return true; - } - - return false; -} - - -/* - *-------------------------------------------------------------------------- - * - * bson_iter_oid -- - * - * Retrieves the current field of type %BSON_TYPE_OID. The result is - * valid while @iter is valid. - * - * Returns: - * A bson_oid_t that should not be modified or freed. - * - * Side effects: - * None. - * - *-------------------------------------------------------------------------- - */ - -const bson_oid_t * -bson_iter_oid (const bson_iter_t *iter) /* IN */ -{ - BSON_ASSERT (iter); - - if (ITER_TYPE (iter) == BSON_TYPE_OID) { - return bson_iter_oid_unsafe (iter); - } - - return NULL; -} - - -/* - *-------------------------------------------------------------------------- - * - * bson_iter_regex -- - * - * Fetches the current field from the iter which should be of type - * BSON_TYPE_REGEX. - * - * Returns: - * Regex from @iter. This should not be modified or freed. - * - * Side effects: - * None. - * - *-------------------------------------------------------------------------- - */ - -const char * -bson_iter_regex (const bson_iter_t *iter, /* IN */ - const char **options) /* IN */ -{ - const char *ret = NULL; - const char *ret_options = NULL; - - BSON_ASSERT (iter); - - if (ITER_TYPE (iter) == BSON_TYPE_REGEX) { - ret = (const char *) (iter->raw + iter->d1); - ret_options = (const char *) (iter->raw + iter->d2); - } - - if (options) { - *options = ret_options; - } - - return ret; -} - - -/* - *-------------------------------------------------------------------------- - * - * bson_iter_utf8 -- - * - * Retrieves the current field of type %BSON_TYPE_UTF8 as a UTF-8 - * encoded string. - * - * Parameters: - * @iter: A bson_iter_t. - * @length: A location for the length of the string. - * - * Returns: - * A string that should not be modified or freed. - * - * Side effects: - * @length will be set to the result strings length if non-NULL. - * - *-------------------------------------------------------------------------- - */ - -const char * -bson_iter_utf8 (const bson_iter_t *iter, /* IN */ - uint32_t *length) /* OUT */ -{ - BSON_ASSERT (iter); - - if (ITER_TYPE (iter) == BSON_TYPE_UTF8) { - if (length) { - *length = bson_iter_utf8_len_unsafe (iter); - } - - return (const char *) (iter->raw + iter->d2); - } - - if (length) { - *length = 0; - } - - return NULL; -} - - -/* - *-------------------------------------------------------------------------- - * - * bson_iter_dup_utf8 -- - * - * Copies the current UTF-8 element into a newly allocated string. The - * string should be freed using bson_free() when the caller is - * finished with it. - * - * Returns: - * A newly allocated char* that should be freed with bson_free(). - * - * Side effects: - * @length will be set to the result strings length if non-NULL. - * - *-------------------------------------------------------------------------- - */ - -char * -bson_iter_dup_utf8 (const bson_iter_t *iter, /* IN */ - uint32_t *length) /* OUT */ -{ - uint32_t local_length = 0; - const char *str; - char *ret = NULL; - - BSON_ASSERT (iter); - - if ((str = bson_iter_utf8 (iter, &local_length))) { - ret = bson_malloc0 (local_length + 1); - memcpy (ret, str, local_length); - ret[local_length] = '\0'; - } - - if (length) { - *length = local_length; - } - - return ret; -} - - -/* - *-------------------------------------------------------------------------- - * - * bson_iter_code -- - * - * Retrieves the current field of type %BSON_TYPE_CODE. The length of - * the resulting string is stored in @length. - * - * Parameters: - * @iter: A bson_iter_t. - * @length: A location for the code length. - * - * Returns: - * A NUL-terminated string containing the code which should not be - * modified or freed. - * - * Side effects: - * None. - * - *-------------------------------------------------------------------------- - */ - -const char * -bson_iter_code (const bson_iter_t *iter, /* IN */ - uint32_t *length) /* OUT */ -{ - BSON_ASSERT (iter); - - if (ITER_TYPE (iter) == BSON_TYPE_CODE) { - if (length) { - *length = bson_iter_utf8_len_unsafe (iter); - } - - return (const char *) (iter->raw + iter->d2); - } - - if (length) { - *length = 0; - } - - return NULL; -} - - -/* - *-------------------------------------------------------------------------- - * - * bson_iter_codewscope -- - * - * Similar to bson_iter_code() but with a scope associated encoded as - * a BSON document. @scope should not be modified or freed. It is - * valid while @iter is valid. - * - * Parameters: - * @iter: A #bson_iter_t. - * @length: A location for the length of resulting string. - * @scope_len: A location for the length of @scope. - * @scope: A location for the scope encoded as BSON. - * - * Returns: - * A NUL-terminated string that should not be modified or freed. - * - * Side effects: - * @length is set to the resulting string length in bytes. - * @scope_len is set to the length of @scope in bytes. - * @scope is set to the scope documents buffer which can be - * turned into a bson document with bson_init_static(). - * - *-------------------------------------------------------------------------- - */ - -const char * -bson_iter_codewscope (const bson_iter_t *iter, /* IN */ - uint32_t *length, /* OUT */ - uint32_t *scope_len, /* OUT */ - const uint8_t **scope) /* OUT */ -{ - uint32_t len; - - BSON_ASSERT (iter); - - if (ITER_TYPE (iter) == BSON_TYPE_CODEWSCOPE) { - if (length) { - memcpy (&len, iter->raw + iter->d2, sizeof (len)); - /* The string length was checked > 0 in _bson_iter_next_internal. */ - len = BSON_UINT32_FROM_LE (len); - BSON_ASSERT (len > 0); - *length = len - 1; - } - - memcpy (&len, iter->raw + iter->d4, sizeof (len)); - *scope_len = BSON_UINT32_FROM_LE (len); - *scope = iter->raw + iter->d4; - return (const char *) (iter->raw + iter->d3); - } - - if (length) { - *length = 0; - } - - if (scope_len) { - *scope_len = 0; - } - - if (scope) { - *scope = NULL; - } - - return NULL; -} - - -/* - *-------------------------------------------------------------------------- - * - * bson_iter_dbpointer -- - * - * Retrieves a BSON_TYPE_DBPOINTER field. @collection_len will be set - * to the length of the collection name. The collection name will be - * placed into @collection. The oid will be placed into @oid. - * - * @collection and @oid should not be modified. - * - * Parameters: - * @iter: A #bson_iter_t. - * @collection_len: A location for the length of @collection. - * @collection: A location for the collection name. - * @oid: A location for the oid. - * - * Returns: - * None. - * - * Side effects: - * @collection_len is set to the length of @collection in bytes - * excluding the null byte. - * @collection is set to the collection name, including a terminating - * null byte. - * @oid is initialized with the oid. - * - *-------------------------------------------------------------------------- - */ - -void -bson_iter_dbpointer (const bson_iter_t *iter, /* IN */ - uint32_t *collection_len, /* OUT */ - const char **collection, /* OUT */ - const bson_oid_t **oid) /* OUT */ -{ - BSON_ASSERT (iter); - - if (collection) { - *collection = NULL; - } - - if (oid) { - *oid = NULL; - } - - if (ITER_TYPE (iter) == BSON_TYPE_DBPOINTER) { - if (collection_len) { - memcpy (collection_len, (iter->raw + iter->d1), sizeof (*collection_len)); - *collection_len = BSON_UINT32_FROM_LE (*collection_len); - - if ((*collection_len) > 0) { - (*collection_len)--; - } - } - - if (collection) { - *collection = (const char *) (iter->raw + iter->d2); - } - - if (oid) { - *oid = (const bson_oid_t *) (iter->raw + iter->d3); - } - } -} - - -/* - *-------------------------------------------------------------------------- - * - * bson_iter_symbol -- - * - * Retrieves the symbol of the current field of type BSON_TYPE_SYMBOL. - * - * Parameters: - * @iter: A bson_iter_t. - * @length: A location for the length of the symbol. - * - * Returns: - * A string containing the symbol as UTF-8. The value should not be - * modified or freed. - * - * Side effects: - * @length is set to the resulting strings length in bytes, - * excluding the null byte. - * - *-------------------------------------------------------------------------- - */ - -const char * -bson_iter_symbol (const bson_iter_t *iter, /* IN */ - uint32_t *length) /* OUT */ -{ - const char *ret = NULL; - uint32_t ret_length = 0; - - BSON_ASSERT (iter); - - if (ITER_TYPE (iter) == BSON_TYPE_SYMBOL) { - ret = (const char *) (iter->raw + iter->d2); - ret_length = bson_iter_utf8_len_unsafe (iter); - } - - if (length) { - *length = ret_length; - } - - return ret; -} - - -/* - *-------------------------------------------------------------------------- - * - * bson_iter_date_time -- - * - * Fetches the number of milliseconds elapsed since the UNIX epoch. - * This value can be negative as times before 1970 are valid. - * - * Returns: - * A signed 64-bit integer containing the number of milliseconds. - * - * Side effects: - * None. - * - *-------------------------------------------------------------------------- - */ - -int64_t -bson_iter_date_time (const bson_iter_t *iter) /* IN */ -{ - BSON_ASSERT (iter); - - if (ITER_TYPE (iter) == BSON_TYPE_DATE_TIME) { - return bson_iter_int64_unsafe (iter); - } - - return 0; -} - - -/* - *-------------------------------------------------------------------------- - * - * bson_iter_time_t -- - * - * Retrieves the current field of type BSON_TYPE_DATE_TIME as a - * time_t. - * - * Returns: - * A #time_t of the number of seconds since UNIX epoch in UTC. - * - * Side effects: - * None. - * - *-------------------------------------------------------------------------- - */ - -time_t -bson_iter_time_t (const bson_iter_t *iter) /* IN */ -{ - BSON_ASSERT (iter); - - if (ITER_TYPE (iter) == BSON_TYPE_DATE_TIME) { - return bson_iter_time_t_unsafe (iter); - } - - return 0; -} - - -/* - *-------------------------------------------------------------------------- - * - * bson_iter_timestamp -- - * - * Fetches the current field if it is a BSON_TYPE_TIMESTAMP. - * - * Parameters: - * @iter: A #bson_iter_t. - * @timestamp: a location for the timestamp. - * @increment: A location for the increment. - * - * Returns: - * None. - * - * Side effects: - * @timestamp is initialized. - * @increment is initialized. - * - *-------------------------------------------------------------------------- - */ - -void -bson_iter_timestamp (const bson_iter_t *iter, /* IN */ - uint32_t *timestamp, /* OUT */ - uint32_t *increment) /* OUT */ -{ - uint64_t encoded; - uint32_t ret_timestamp = 0; - uint32_t ret_increment = 0; - - BSON_ASSERT (iter); - - if (ITER_TYPE (iter) == BSON_TYPE_TIMESTAMP) { - memcpy (&encoded, iter->raw + iter->d1, sizeof (encoded)); - encoded = BSON_UINT64_FROM_LE (encoded); - ret_timestamp = (encoded >> 32) & 0xFFFFFFFF; - ret_increment = encoded & 0xFFFFFFFF; - } - - if (timestamp) { - *timestamp = ret_timestamp; - } - - if (increment) { - *increment = ret_increment; - } -} - - -/* - *-------------------------------------------------------------------------- - * - * bson_iter_timeval -- - * - * Retrieves the current field of type BSON_TYPE_DATE_TIME and stores - * it into the struct timeval provided. tv->tv_sec is set to the - * number of seconds since the UNIX epoch in UTC. - * - * Since BSON_TYPE_DATE_TIME does not support fractions of a second, - * tv->tv_usec will always be set to zero. - * - * Returns: - * None. - * - * Side effects: - * @tv is initialized. - * - *-------------------------------------------------------------------------- - */ - -void -bson_iter_timeval (const bson_iter_t *iter, /* IN */ - struct timeval *tv) /* OUT */ -{ - BSON_ASSERT (iter); - - if (ITER_TYPE (iter) == BSON_TYPE_DATE_TIME) { - bson_iter_timeval_unsafe (iter, tv); - return; - } - - memset (tv, 0, sizeof *tv); -} - - -/** - * bson_iter_document: - * @iter: a bson_iter_t. - * @document_len: A location for the document length. - * @document: A location for a pointer to the document buffer. - * - */ -/* - *-------------------------------------------------------------------------- - * - * bson_iter_document -- - * - * Retrieves the data to the document BSON structure and stores the - * length of the document buffer in @document_len and the document - * buffer in @document. - * - * If you would like to iterate over the child contents, you might - * consider creating a bson_t on the stack such as the following. It - * allows you to call functions taking a const bson_t* only. - * - * bson_t b; - * uint32_t len; - * const uint8_t *data; - * - * bson_iter_document(iter, &len, &data); - * - * if (bson_init_static (&b, data, len)) { - * ... - * } - * - * There is no need to cleanup the bson_t structure as no data can be - * modified in the process of its use (as it is static/const). - * - * Returns: - * None. - * - * Side effects: - * @document_len is initialized. - * @document is initialized. - * - *-------------------------------------------------------------------------- - */ - -void -bson_iter_document (const bson_iter_t *iter, /* IN */ - uint32_t *document_len, /* OUT */ - const uint8_t **document) /* OUT */ -{ - BSON_ASSERT (iter); - BSON_ASSERT (document_len); - BSON_ASSERT (document); - - *document = NULL; - *document_len = 0; - - if (ITER_TYPE (iter) == BSON_TYPE_DOCUMENT) { - memcpy (document_len, (iter->raw + iter->d1), sizeof (*document_len)); - *document_len = BSON_UINT32_FROM_LE (*document_len); - *document = (iter->raw + iter->d1); - } -} - - -/** - * bson_iter_array: - * @iter: a #bson_iter_t. - * @array_len: A location for the array length. - * @array: A location for a pointer to the array buffer. - */ -/* - *-------------------------------------------------------------------------- - * - * bson_iter_array -- - * - * Retrieves the data to the array BSON structure and stores the - * length of the array buffer in @array_len and the array buffer in - * @array. - * - * If you would like to iterate over the child contents, you might - * consider creating a bson_t on the stack such as the following. It - * allows you to call functions taking a const bson_t* only. - * - * bson_t b; - * uint32_t len; - * const uint8_t *data; - * - * bson_iter_array (iter, &len, &data); - * - * if (bson_init_static (&b, data, len)) { - * ... - * } - * - * There is no need to cleanup the #bson_t structure as no data can be - * modified in the process of its use. - * - * Returns: - * None. - * - * Side effects: - * @array_len is initialized. - * @array is initialized. - * - *-------------------------------------------------------------------------- - */ - -void -bson_iter_array (const bson_iter_t *iter, /* IN */ - uint32_t *array_len, /* OUT */ - const uint8_t **array) /* OUT */ -{ - BSON_ASSERT (iter); - BSON_ASSERT (array_len); - BSON_ASSERT (array); - - *array = NULL; - *array_len = 0; - - if (ITER_TYPE (iter) == BSON_TYPE_ARRAY) { - memcpy (array_len, (iter->raw + iter->d1), sizeof (*array_len)); - *array_len = BSON_UINT32_FROM_LE (*array_len); - *array = (iter->raw + iter->d1); - } -} - - -#define VISIT_FIELD(name) visitor->visit_##name && visitor->visit_##name -#define VISIT_AFTER VISIT_FIELD (after) -#define VISIT_BEFORE VISIT_FIELD (before) -#define VISIT_CORRUPT \ - if (visitor->visit_corrupt) \ - visitor->visit_corrupt -#define VISIT_DOUBLE VISIT_FIELD (double) -#define VISIT_UTF8 VISIT_FIELD (utf8) -#define VISIT_DOCUMENT VISIT_FIELD (document) -#define VISIT_ARRAY VISIT_FIELD (array) -#define VISIT_BINARY VISIT_FIELD (binary) -#define VISIT_UNDEFINED VISIT_FIELD (undefined) -#define VISIT_OID VISIT_FIELD (oid) -#define VISIT_BOOL VISIT_FIELD (bool) -#define VISIT_DATE_TIME VISIT_FIELD (date_time) -#define VISIT_NULL VISIT_FIELD (null) -#define VISIT_REGEX VISIT_FIELD (regex) -#define VISIT_DBPOINTER VISIT_FIELD (dbpointer) -#define VISIT_CODE VISIT_FIELD (code) -#define VISIT_SYMBOL VISIT_FIELD (symbol) -#define VISIT_CODEWSCOPE VISIT_FIELD (codewscope) -#define VISIT_INT32 VISIT_FIELD (int32) -#define VISIT_TIMESTAMP VISIT_FIELD (timestamp) -#define VISIT_INT64 VISIT_FIELD (int64) -#define VISIT_DECIMAL128 VISIT_FIELD (decimal128) -#define VISIT_MAXKEY VISIT_FIELD (maxkey) -#define VISIT_MINKEY VISIT_FIELD (minkey) - - -bool -bson_iter_visit_all (bson_iter_t *iter, /* INOUT */ - const bson_visitor_t *visitor, /* IN */ - void *data) /* IN */ -{ - uint32_t bson_type = 0; - const char *key = NULL; - bool unsupported; - - BSON_ASSERT (iter); - BSON_ASSERT (visitor); - - while (_bson_iter_next_internal (iter, 0, &key, &bson_type, &unsupported)) { - if (*key && !bson_utf8_validate (key, strlen (key), false)) { - iter->err_off = iter->off; - break; - } - - if (VISIT_BEFORE (iter, key, data)) { - return true; - } - - switch (bson_type) { - case BSON_TYPE_DOUBLE: - - if (VISIT_DOUBLE (iter, key, bson_iter_double (iter), data)) { - return true; - } - - break; - case BSON_TYPE_UTF8: { - uint32_t utf8_len; - const char *utf8; - - utf8 = bson_iter_utf8 (iter, &utf8_len); - - if (!bson_utf8_validate (utf8, utf8_len, true)) { - iter->err_off = iter->off; - return true; - } - - if (VISIT_UTF8 (iter, key, utf8_len, utf8, data)) { - return true; - } - } break; - case BSON_TYPE_DOCUMENT: { - const uint8_t *docbuf = NULL; - uint32_t doclen = 0; - bson_t b; - - bson_iter_document (iter, &doclen, &docbuf); - - if (!bson_init_static (&b, docbuf, doclen)) { - iter->err_off = iter->off; - break; - } - if (VISIT_DOCUMENT (iter, key, &b, data)) { - return true; - } - } break; - case BSON_TYPE_ARRAY: { - const uint8_t *docbuf = NULL; - uint32_t doclen = 0; - bson_t b; - - bson_iter_array (iter, &doclen, &docbuf); - - if (!bson_init_static (&b, docbuf, doclen)) { - iter->err_off = iter->off; - break; - } - if (VISIT_ARRAY (iter, key, &b, data)) { - return true; - } - } break; - case BSON_TYPE_BINARY: { - const uint8_t *binary = NULL; - bson_subtype_t subtype = BSON_SUBTYPE_BINARY; - uint32_t binary_len = 0; - - bson_iter_binary (iter, &subtype, &binary_len, &binary); - - if (VISIT_BINARY (iter, key, subtype, binary_len, binary, data)) { - return true; - } - } break; - case BSON_TYPE_UNDEFINED: - - if (VISIT_UNDEFINED (iter, key, data)) { - return true; - } - - break; - case BSON_TYPE_OID: - - if (VISIT_OID (iter, key, bson_iter_oid (iter), data)) { - return true; - } - - break; - case BSON_TYPE_BOOL: - - if (VISIT_BOOL (iter, key, bson_iter_bool (iter), data)) { - return true; - } - - break; - case BSON_TYPE_DATE_TIME: - - if (VISIT_DATE_TIME (iter, key, bson_iter_date_time (iter), data)) { - return true; - } - - break; - case BSON_TYPE_NULL: - - if (VISIT_NULL (iter, key, data)) { - return true; - } - - break; - case BSON_TYPE_REGEX: { - const char *regex = NULL; - const char *options = NULL; - regex = bson_iter_regex (iter, &options); - - if (!bson_utf8_validate (regex, strlen (regex), true)) { - iter->err_off = iter->off; - return true; - } - - if (VISIT_REGEX (iter, key, regex, options, data)) { - return true; - } - } break; - case BSON_TYPE_DBPOINTER: { - uint32_t collection_len = 0; - const char *collection = NULL; - const bson_oid_t *oid = NULL; - - bson_iter_dbpointer (iter, &collection_len, &collection, &oid); - - if (!bson_utf8_validate (collection, collection_len, true)) { - iter->err_off = iter->off; - return true; - } - - if (VISIT_DBPOINTER (iter, key, collection_len, collection, oid, data)) { - return true; - } - } break; - case BSON_TYPE_CODE: { - uint32_t code_len; - const char *code; - - code = bson_iter_code (iter, &code_len); - - if (!bson_utf8_validate (code, code_len, true)) { - iter->err_off = iter->off; - return true; - } - - if (VISIT_CODE (iter, key, code_len, code, data)) { - return true; - } - } break; - case BSON_TYPE_SYMBOL: { - uint32_t symbol_len; - const char *symbol; - - symbol = bson_iter_symbol (iter, &symbol_len); - - if (!bson_utf8_validate (symbol, symbol_len, true)) { - iter->err_off = iter->off; - return true; - } - - if (VISIT_SYMBOL (iter, key, symbol_len, symbol, data)) { - return true; - } - } break; - case BSON_TYPE_CODEWSCOPE: { - uint32_t length = 0; - const char *code; - const uint8_t *docbuf = NULL; - uint32_t doclen = 0; - bson_t b; - - code = bson_iter_codewscope (iter, &length, &doclen, &docbuf); - - if (!bson_utf8_validate (code, length, true)) { - iter->err_off = iter->off; - return true; - } - - if (!bson_init_static (&b, docbuf, doclen)) { - iter->err_off = iter->off; - break; - } - if (VISIT_CODEWSCOPE (iter, key, length, code, &b, data)) { - return true; - } - } break; - case BSON_TYPE_INT32: - - if (VISIT_INT32 (iter, key, bson_iter_int32 (iter), data)) { - return true; - } - - break; - case BSON_TYPE_TIMESTAMP: { - uint32_t timestamp; - uint32_t increment; - bson_iter_timestamp (iter, ×tamp, &increment); - - if (VISIT_TIMESTAMP (iter, key, timestamp, increment, data)) { - return true; - } - } break; - case BSON_TYPE_INT64: - - if (VISIT_INT64 (iter, key, bson_iter_int64 (iter), data)) { - return true; - } - - break; - case BSON_TYPE_DECIMAL128: { - bson_decimal128_t dec; - bson_iter_decimal128 (iter, &dec); - - if (VISIT_DECIMAL128 (iter, key, &dec, data)) { - return true; - } - } break; - case BSON_TYPE_MAXKEY: - - if (VISIT_MAXKEY (iter, bson_iter_key_unsafe (iter), data)) { - return true; - } - - break; - case BSON_TYPE_MINKEY: - - if (VISIT_MINKEY (iter, bson_iter_key_unsafe (iter), data)) { - return true; - } - - break; - case BSON_TYPE_EOD: - default: - break; - } - - if (VISIT_AFTER (iter, bson_iter_key_unsafe (iter), data)) { - return true; - } - } - - if (iter->err_off) { - if (unsupported && visitor->visit_unsupported_type && bson_utf8_validate (key, strlen (key), false)) { - visitor->visit_unsupported_type (iter, key, bson_type, data); - return false; - } - - VISIT_CORRUPT (iter, data); - } - -#undef VISIT_FIELD - - return false; -} - - -/* - *-------------------------------------------------------------------------- - * - * bson_iter_overwrite_bool -- - * - * Overwrites the current BSON_TYPE_BOOLEAN field with a new value. - * This is performed in-place and therefore no keys are moved. - * - * Returns: - * None. - * - * Side effects: - * None. - * - *-------------------------------------------------------------------------- - */ - -void -bson_iter_overwrite_bool (bson_iter_t *iter, /* IN */ - bool value) /* IN */ -{ - BSON_ASSERT (iter); - - if (ITER_TYPE (iter) == BSON_TYPE_BOOL) { - memcpy ((void *) (iter->raw + iter->d1), &value, 1); - } -} - - -void -bson_iter_overwrite_oid (bson_iter_t *iter, const bson_oid_t *value) -{ - BSON_ASSERT (iter); - - if (ITER_TYPE (iter) == BSON_TYPE_OID) { - memcpy ((void *) (iter->raw + iter->d1), value->bytes, sizeof (value->bytes)); - } -} - - -void -bson_iter_overwrite_timestamp (bson_iter_t *iter, uint32_t timestamp, uint32_t increment) -{ - uint64_t value; - BSON_ASSERT (iter); - - if (ITER_TYPE (iter) == BSON_TYPE_TIMESTAMP) { - value = ((((uint64_t) timestamp) << 32U) | ((uint64_t) increment)); - value = BSON_UINT64_TO_LE (value); - memcpy ((void *) (iter->raw + iter->d1), &value, sizeof (value)); - } -} - - -void -bson_iter_overwrite_date_time (bson_iter_t *iter, int64_t value) -{ - BSON_ASSERT (iter); - - if (ITER_TYPE (iter) == BSON_TYPE_DATE_TIME) { - value = BSON_UINT64_TO_LE (value); - memcpy ((void *) (iter->raw + iter->d1), &value, sizeof (value)); - } -} - - -/* - *-------------------------------------------------------------------------- - * - * bson_iter_overwrite_int32 -- - * - * Overwrites the current BSON_TYPE_INT32 field with a new value. - * This is performed in-place and therefore no keys are moved. - * - * Returns: - * None. - * - * Side effects: - * None. - * - *-------------------------------------------------------------------------- - */ - -void -bson_iter_overwrite_int32 (bson_iter_t *iter, /* IN */ - int32_t value) /* IN */ -{ - BSON_ASSERT (iter); - - if (ITER_TYPE (iter) == BSON_TYPE_INT32) { -#if BSON_BYTE_ORDER != BSON_LITTLE_ENDIAN - value = BSON_UINT32_TO_LE (value); -#endif - memcpy ((void *) (iter->raw + iter->d1), &value, sizeof (value)); - } -} - - -/* - *-------------------------------------------------------------------------- - * - * bson_iter_overwrite_int64 -- - * - * Overwrites the current BSON_TYPE_INT64 field with a new value. - * This is performed in-place and therefore no keys are moved. - * - * Returns: - * None. - * - * Side effects: - * None. - * - *-------------------------------------------------------------------------- - */ - -void -bson_iter_overwrite_int64 (bson_iter_t *iter, /* IN */ - int64_t value) /* IN */ -{ - BSON_ASSERT (iter); - - if (ITER_TYPE (iter) == BSON_TYPE_INT64) { -#if BSON_BYTE_ORDER != BSON_LITTLE_ENDIAN - value = BSON_UINT64_TO_LE (value); -#endif - memcpy ((void *) (iter->raw + iter->d1), &value, sizeof (value)); - } -} - - -/* - *-------------------------------------------------------------------------- - * - * bson_iter_overwrite_double -- - * - * Overwrites the current BSON_TYPE_DOUBLE field with a new value. - * This is performed in-place and therefore no keys are moved. - * - * Returns: - * None. - * - * Side effects: - * None. - * - *-------------------------------------------------------------------------- - */ - -void -bson_iter_overwrite_double (bson_iter_t *iter, /* IN */ - double value) /* IN */ -{ - BSON_ASSERT (iter); - - if (ITER_TYPE (iter) == BSON_TYPE_DOUBLE) { - value = BSON_DOUBLE_TO_LE (value); - memcpy ((void *) (iter->raw + iter->d1), &value, sizeof (value)); - } -} - - -/* - *-------------------------------------------------------------------------- - * - * bson_iter_overwrite_decimal128 -- - * - * Overwrites the current BSON_TYPE_DECIMAL128 field with a new value. - * This is performed in-place and therefore no keys are moved. - * - * Returns: - * None. - * - * Side effects: - * None. - * - *-------------------------------------------------------------------------- - */ -void -bson_iter_overwrite_decimal128 (bson_iter_t *iter, /* IN */ - const bson_decimal128_t *value) /* IN */ -{ - BSON_ASSERT (iter); - - if (ITER_TYPE (iter) == BSON_TYPE_DECIMAL128) { -#if BSON_BYTE_ORDER != BSON_LITTLE_ENDIAN - uint64_t data[2]; - data[0] = BSON_UINT64_TO_LE (value->low); - data[1] = BSON_UINT64_TO_LE (value->high); - memcpy ((void *) (iter->raw + iter->d1), data, sizeof (data)); -#else - memcpy ((void *) (iter->raw + iter->d1), value, sizeof (*value)); -#endif - } -} - - -/* - *-------------------------------------------------------------------------- - * - * bson_iter_value -- - * - * Retrieves a bson_value_t containing the boxed value of the current - * element. The result of this function valid until the state of - * iter has been changed (through the use of bson_iter_next()). - * - * Returns: - * A bson_value_t that should not be modified or freed. If you need - * to hold on to the value, use bson_value_copy(). - * - * Side effects: - * None. - * - *-------------------------------------------------------------------------- - */ - -const bson_value_t * -bson_iter_value (bson_iter_t *iter) /* IN */ -{ - bson_value_t *value; - - BSON_ASSERT (iter); - - value = &iter->value; - value->value_type = ITER_TYPE (iter); - - switch (value->value_type) { - case BSON_TYPE_DOUBLE: - value->value.v_double = bson_iter_double (iter); - break; - case BSON_TYPE_UTF8: - value->value.v_utf8.str = (char *) bson_iter_utf8 (iter, &value->value.v_utf8.len); - break; - case BSON_TYPE_DOCUMENT: - bson_iter_document (iter, &value->value.v_doc.data_len, (const uint8_t **) &value->value.v_doc.data); - break; - case BSON_TYPE_ARRAY: - bson_iter_array (iter, &value->value.v_doc.data_len, (const uint8_t **) &value->value.v_doc.data); - break; - case BSON_TYPE_BINARY: - bson_iter_binary (iter, - &value->value.v_binary.subtype, - &value->value.v_binary.data_len, - (const uint8_t **) &value->value.v_binary.data); - break; - case BSON_TYPE_OID: - bson_oid_copy (bson_iter_oid (iter), &value->value.v_oid); - break; - case BSON_TYPE_BOOL: - value->value.v_bool = bson_iter_bool (iter); - break; - case BSON_TYPE_DATE_TIME: - value->value.v_datetime = bson_iter_date_time (iter); - break; - case BSON_TYPE_REGEX: - value->value.v_regex.regex = (char *) bson_iter_regex (iter, (const char **) &value->value.v_regex.options); - break; - case BSON_TYPE_DBPOINTER: { - const bson_oid_t *oid; - - bson_iter_dbpointer ( - iter, &value->value.v_dbpointer.collection_len, (const char **) &value->value.v_dbpointer.collection, &oid); - bson_oid_copy (oid, &value->value.v_dbpointer.oid); - break; - } - case BSON_TYPE_CODE: - value->value.v_code.code = (char *) bson_iter_code (iter, &value->value.v_code.code_len); - break; - case BSON_TYPE_SYMBOL: - value->value.v_symbol.symbol = (char *) bson_iter_symbol (iter, &value->value.v_symbol.len); - break; - case BSON_TYPE_CODEWSCOPE: - value->value.v_codewscope.code = - (char *) bson_iter_codewscope (iter, - &value->value.v_codewscope.code_len, - &value->value.v_codewscope.scope_len, - (const uint8_t **) &value->value.v_codewscope.scope_data); - break; - case BSON_TYPE_INT32: - value->value.v_int32 = bson_iter_int32 (iter); - break; - case BSON_TYPE_TIMESTAMP: - bson_iter_timestamp (iter, &value->value.v_timestamp.timestamp, &value->value.v_timestamp.increment); - break; - case BSON_TYPE_INT64: - value->value.v_int64 = bson_iter_int64 (iter); - break; - case BSON_TYPE_DECIMAL128: - bson_iter_decimal128 (iter, &(value->value.v_decimal128)); - break; - case BSON_TYPE_NULL: - case BSON_TYPE_UNDEFINED: - case BSON_TYPE_MAXKEY: - case BSON_TYPE_MINKEY: - break; - case BSON_TYPE_EOD: - default: - return NULL; - } - - return value; -} - -uint32_t -bson_iter_key_len (const bson_iter_t *iter) -{ - /* - * f i e l d n a m e \0 _ - * ^ ^ - * | | - * iter->key iter->d1 - * - */ - BSON_ASSERT (iter->d1 > iter->key); - return iter->d1 - iter->key - 1; -} - -bool -bson_iter_init_from_data_at_offset ( - bson_iter_t *iter, const uint8_t *data, size_t length, uint32_t offset, uint32_t keylen) -{ - const char *key; - uint32_t bson_type; - bool unsupported; - - BSON_ASSERT (iter); - BSON_ASSERT (data); - - if (BSON_UNLIKELY ((length < 5) || (length > INT_MAX))) { - memset (iter, 0, sizeof *iter); - return false; - } - - iter->raw = (uint8_t *) data; - iter->len = (uint32_t) length; - iter->off = 0; - iter->type = 0; - iter->key = 0; - iter->next_off = offset; - iter->err_off = 0; - - if (!_bson_iter_next_internal (iter, keylen, &key, &bson_type, &unsupported)) { - memset (iter, 0, sizeof *iter); - return false; - } - - return true; -} - -uint32_t -bson_iter_offset (bson_iter_t *iter) -{ - return iter->off; -} diff --git a/bsonjs/bson/bson-iter.h b/bsonjs/bson/bson-iter.h deleted file mode 100644 index 5370922..0000000 --- a/bsonjs/bson/bson-iter.h +++ /dev/null @@ -1,517 +0,0 @@ -/* - * Copyright 2013 MongoDB, Inc. - * - * 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. - */ - -#include - - -#ifndef BSON_ITER_H -#define BSON_ITER_H - - -#include "bson.h" -#include -#include -#include - - -BSON_BEGIN_DECLS - - -#define BSON_ITER_HOLDS_DOUBLE(iter) (bson_iter_type ((iter)) == BSON_TYPE_DOUBLE) - -#define BSON_ITER_HOLDS_UTF8(iter) (bson_iter_type ((iter)) == BSON_TYPE_UTF8) - -#define BSON_ITER_HOLDS_DOCUMENT(iter) (bson_iter_type ((iter)) == BSON_TYPE_DOCUMENT) - -#define BSON_ITER_HOLDS_ARRAY(iter) (bson_iter_type ((iter)) == BSON_TYPE_ARRAY) - -#define BSON_ITER_HOLDS_BINARY(iter) (bson_iter_type ((iter)) == BSON_TYPE_BINARY) - -#define BSON_ITER_HOLDS_UNDEFINED(iter) (bson_iter_type ((iter)) == BSON_TYPE_UNDEFINED) - -#define BSON_ITER_HOLDS_OID(iter) (bson_iter_type ((iter)) == BSON_TYPE_OID) - -#define BSON_ITER_HOLDS_BOOL(iter) (bson_iter_type ((iter)) == BSON_TYPE_BOOL) - -#define BSON_ITER_HOLDS_DATE_TIME(iter) (bson_iter_type ((iter)) == BSON_TYPE_DATE_TIME) - -#define BSON_ITER_HOLDS_NULL(iter) (bson_iter_type ((iter)) == BSON_TYPE_NULL) - -#define BSON_ITER_HOLDS_REGEX(iter) (bson_iter_type ((iter)) == BSON_TYPE_REGEX) - -#define BSON_ITER_HOLDS_DBPOINTER(iter) (bson_iter_type ((iter)) == BSON_TYPE_DBPOINTER) - -#define BSON_ITER_HOLDS_CODE(iter) (bson_iter_type ((iter)) == BSON_TYPE_CODE) - -#define BSON_ITER_HOLDS_SYMBOL(iter) (bson_iter_type ((iter)) == BSON_TYPE_SYMBOL) - -#define BSON_ITER_HOLDS_CODEWSCOPE(iter) (bson_iter_type ((iter)) == BSON_TYPE_CODEWSCOPE) - -#define BSON_ITER_HOLDS_INT32(iter) (bson_iter_type ((iter)) == BSON_TYPE_INT32) - -#define BSON_ITER_HOLDS_TIMESTAMP(iter) (bson_iter_type ((iter)) == BSON_TYPE_TIMESTAMP) - -#define BSON_ITER_HOLDS_INT64(iter) (bson_iter_type ((iter)) == BSON_TYPE_INT64) - -#define BSON_ITER_HOLDS_DECIMAL128(iter) (bson_iter_type ((iter)) == BSON_TYPE_DECIMAL128) - -#define BSON_ITER_HOLDS_MAXKEY(iter) (bson_iter_type ((iter)) == BSON_TYPE_MAXKEY) - -#define BSON_ITER_HOLDS_MINKEY(iter) (bson_iter_type ((iter)) == BSON_TYPE_MINKEY) - -#define BSON_ITER_HOLDS_INT(iter) (BSON_ITER_HOLDS_INT32 (iter) || BSON_ITER_HOLDS_INT64 (iter)) - -#define BSON_ITER_HOLDS_NUMBER(iter) (BSON_ITER_HOLDS_INT (iter) || BSON_ITER_HOLDS_DOUBLE (iter)) - -#define BSON_ITER_IS_KEY(iter, key) (0 == strcmp ((key), bson_iter_key ((iter)))) - - -BSON_EXPORT (const bson_value_t *) -bson_iter_value (bson_iter_t *iter); - - -/** - * bson_iter_utf8_len_unsafe: - * @iter: a bson_iter_t. - * - * Returns the length of a string currently pointed to by @iter. This performs - * no validation so the is responsible for knowing the BSON is valid. Calling - * bson_validate() is one way to do this ahead of time. - */ -static BSON_INLINE uint32_t -bson_iter_utf8_len_unsafe (const bson_iter_t *iter) -{ - uint32_t raw; - memcpy (&raw, iter->raw + iter->d1, sizeof (raw)); - - const uint32_t native = BSON_UINT32_FROM_LE (raw); - - int32_t len; - memcpy (&len, &native, sizeof (len)); - - return len <= 0 ? 0u : (uint32_t) (len - 1); -} - - -BSON_EXPORT (void) -bson_iter_array (const bson_iter_t *iter, uint32_t *array_len, const uint8_t **array); - - -BSON_EXPORT (void) -bson_iter_binary (const bson_iter_t *iter, bson_subtype_t *subtype, uint32_t *binary_len, const uint8_t **binary); - - -BSON_EXPORT (const char *) -bson_iter_code (const bson_iter_t *iter, uint32_t *length); - - -/** - * bson_iter_code_unsafe: - * @iter: A bson_iter_t. - * @length: A location for the length of the resulting string. - * - * Like bson_iter_code() but performs no integrity checks. - * - * Returns: A string that should not be modified or freed. - */ -static BSON_INLINE const char * -bson_iter_code_unsafe (const bson_iter_t *iter, uint32_t *length) -{ - *length = bson_iter_utf8_len_unsafe (iter); - return (const char *) (iter->raw + iter->d2); -} - - -BSON_EXPORT (const char *) -bson_iter_codewscope (const bson_iter_t *iter, uint32_t *length, uint32_t *scope_len, const uint8_t **scope); - - -BSON_EXPORT (void) -bson_iter_dbpointer (const bson_iter_t *iter, - uint32_t *collection_len, - const char **collection, - const bson_oid_t **oid); - - -BSON_EXPORT (void) -bson_iter_document (const bson_iter_t *iter, uint32_t *document_len, const uint8_t **document); - - -BSON_EXPORT (double) -bson_iter_double (const bson_iter_t *iter); - -BSON_EXPORT (double) -bson_iter_as_double (const bson_iter_t *iter); - -/** - * bson_iter_double_unsafe: - * @iter: A bson_iter_t. - * - * Similar to bson_iter_double() but does not perform an integrity checking. - * - * Returns: A double. - */ -static BSON_INLINE double -bson_iter_double_unsafe (const bson_iter_t *iter) -{ - double val; - - memcpy (&val, iter->raw + iter->d1, sizeof (val)); - return BSON_DOUBLE_FROM_LE (val); -} - - -BSON_EXPORT (bool) -bson_iter_init (bson_iter_t *iter, const bson_t *bson); - -BSON_EXPORT (bool) -bson_iter_init_from_data (bson_iter_t *iter, const uint8_t *data, size_t length); - - -BSON_EXPORT (bool) -bson_iter_init_find (bson_iter_t *iter, const bson_t *bson, const char *key); - - -BSON_EXPORT (bool) -bson_iter_init_find_w_len (bson_iter_t *iter, const bson_t *bson, const char *key, int keylen); - - -BSON_EXPORT (bool) -bson_iter_init_find_case (bson_iter_t *iter, const bson_t *bson, const char *key); - -BSON_EXPORT (bool) -bson_iter_init_from_data_at_offset ( - bson_iter_t *iter, const uint8_t *data, size_t length, uint32_t offset, uint32_t keylen); - -BSON_EXPORT (int32_t) -bson_iter_int32 (const bson_iter_t *iter); - - -/** - * bson_iter_int32_unsafe: - * @iter: A bson_iter_t. - * - * Similar to bson_iter_int32() but with no integrity checking. - * - * Returns: A 32-bit signed integer. - */ -static BSON_INLINE int32_t -bson_iter_int32_unsafe (const bson_iter_t *iter) -{ - uint32_t raw; - memcpy (&raw, iter->raw + iter->d1, sizeof (raw)); - - const uint32_t native = BSON_UINT32_FROM_LE (raw); - - int32_t res; - memcpy (&res, &native, sizeof (res)); - return res; -} - - -BSON_EXPORT (int64_t) -bson_iter_int64 (const bson_iter_t *iter); - - -BSON_EXPORT (int64_t) -bson_iter_as_int64 (const bson_iter_t *iter); - - -/** - * bson_iter_int64_unsafe: - * @iter: a bson_iter_t. - * - * Similar to bson_iter_int64() but without integrity checking. - * - * Returns: A 64-bit signed integer. - */ -static BSON_INLINE int64_t -bson_iter_int64_unsafe (const bson_iter_t *iter) -{ - uint64_t raw; - memcpy (&raw, iter->raw + iter->d1, sizeof (raw)); - - const uint64_t native = BSON_UINT64_FROM_LE (raw); - - int64_t res; - memcpy (&res, &native, sizeof (res)); - return res; -} - - -BSON_EXPORT (bool) -bson_iter_find (bson_iter_t *iter, const char *key); - - -BSON_EXPORT (bool) -bson_iter_find_w_len (bson_iter_t *iter, const char *key, int keylen); - - -BSON_EXPORT (bool) -bson_iter_find_case (bson_iter_t *iter, const char *key); - - -BSON_EXPORT (bool) -bson_iter_find_descendant (bson_iter_t *iter, const char *dotkey, bson_iter_t *descendant); - - -BSON_EXPORT (bool) -bson_iter_next (bson_iter_t *iter); - - -BSON_EXPORT (const bson_oid_t *) -bson_iter_oid (const bson_iter_t *iter); - - -/** - * bson_iter_oid_unsafe: - * @iter: A #bson_iter_t. - * - * Similar to bson_iter_oid() but performs no integrity checks. - * - * Returns: A #bson_oid_t that should not be modified or freed. - */ -static BSON_INLINE const bson_oid_t * -bson_iter_oid_unsafe (const bson_iter_t *iter) -{ - return (const bson_oid_t *) (iter->raw + iter->d1); -} - - -BSON_EXPORT (bool) -bson_iter_decimal128 (const bson_iter_t *iter, bson_decimal128_t *dec); - - -/** - * bson_iter_decimal128_unsafe: - * @iter: A #bson_iter_t. - * - * Similar to bson_iter_decimal128() but performs no integrity checks. - * - * Returns: A #bson_decimal128_t. - */ -static BSON_INLINE void -bson_iter_decimal128_unsafe (const bson_iter_t *iter, bson_decimal128_t *dec) -{ - uint64_t low_le; - uint64_t high_le; - - memcpy (&low_le, iter->raw + iter->d1, sizeof (low_le)); - memcpy (&high_le, iter->raw + iter->d1 + 8, sizeof (high_le)); - - dec->low = BSON_UINT64_FROM_LE (low_le); - dec->high = BSON_UINT64_FROM_LE (high_le); -} - - -BSON_EXPORT (const char *) -bson_iter_key (const bson_iter_t *iter); - -BSON_EXPORT (uint32_t) -bson_iter_key_len (const bson_iter_t *iter); - - -/** - * bson_iter_key_unsafe: - * @iter: A bson_iter_t. - * - * Similar to bson_iter_key() but performs no integrity checking. - * - * Returns: A string that should not be modified or freed. - */ -static BSON_INLINE const char * -bson_iter_key_unsafe (const bson_iter_t *iter) -{ - return (const char *) (iter->raw + iter->key); -} - - -BSON_EXPORT (const char *) -bson_iter_utf8 (const bson_iter_t *iter, uint32_t *length); - - -/** - * bson_iter_utf8_unsafe: - * - * Similar to bson_iter_utf8() but performs no integrity checking. - * - * Returns: A string that should not be modified or freed. - */ -static BSON_INLINE const char * -bson_iter_utf8_unsafe (const bson_iter_t *iter, size_t *length) -{ - *length = bson_iter_utf8_len_unsafe (iter); - return (const char *) (iter->raw + iter->d2); -} - - -BSON_EXPORT (char *) -bson_iter_dup_utf8 (const bson_iter_t *iter, uint32_t *length); - - -BSON_EXPORT (int64_t) -bson_iter_date_time (const bson_iter_t *iter); - - -BSON_EXPORT (time_t) -bson_iter_time_t (const bson_iter_t *iter); - - -/** - * bson_iter_time_t_unsafe: - * @iter: A bson_iter_t. - * - * Similar to bson_iter_time_t() but performs no integrity checking. - * - * Returns: A time_t containing the number of seconds since UNIX epoch - * in UTC. - */ -static BSON_INLINE time_t -bson_iter_time_t_unsafe (const bson_iter_t *iter) -{ - return (time_t) (bson_iter_int64_unsafe (iter) / 1000); -} - - -BSON_EXPORT (void) -bson_iter_timeval (const bson_iter_t *iter, struct timeval *tv); - - -/** - * bson_iter_timeval_unsafe: - * @iter: A bson_iter_t. - * @tv: A struct timeval. - * - * Similar to bson_iter_timeval() but performs no integrity checking. - */ -static BSON_INLINE void -bson_iter_timeval_unsafe (const bson_iter_t *iter, struct timeval *tv) -{ - int64_t value = bson_iter_int64_unsafe (iter); -#ifdef BSON_OS_WIN32 - tv->tv_sec = (long) (value / 1000); - tv->tv_usec = (long) (value % 1000) * 1000; -#else - tv->tv_sec = (time_t) (value / 1000); - tv->tv_usec = (suseconds_t) (value % 1000) * 1000; -#endif -} - - -BSON_EXPORT (void) -bson_iter_timestamp (const bson_iter_t *iter, uint32_t *timestamp, uint32_t *increment); - - -BSON_EXPORT (bool) -bson_iter_bool (const bson_iter_t *iter); - - -/** - * bson_iter_bool_unsafe: - * @iter: A bson_iter_t. - * - * Similar to bson_iter_bool() but performs no integrity checking. - * - * Returns: true or false. - */ -static BSON_INLINE bool -bson_iter_bool_unsafe (const bson_iter_t *iter) -{ - char val; - - memcpy (&val, iter->raw + iter->d1, 1); - return !!val; -} - - -BSON_EXPORT (bool) -bson_iter_as_bool (const bson_iter_t *iter); - - -BSON_EXPORT (const char *) -bson_iter_regex (const bson_iter_t *iter, const char **options); - - -BSON_EXPORT (const char *) -bson_iter_symbol (const bson_iter_t *iter, uint32_t *length); - - -BSON_EXPORT (bson_type_t) -bson_iter_type (const bson_iter_t *iter); - - -/** - * bson_iter_type_unsafe: - * @iter: A bson_iter_t. - * - * Similar to bson_iter_type() but performs no integrity checking. - * - * Returns: A bson_type_t. - */ -static BSON_INLINE bson_type_t -bson_iter_type_unsafe (const bson_iter_t *iter) -{ - return (bson_type_t) (iter->raw + iter->type)[0]; -} - - -BSON_EXPORT (bool) -bson_iter_recurse (const bson_iter_t *iter, bson_iter_t *child); - - -BSON_EXPORT (void) -bson_iter_overwrite_int32 (bson_iter_t *iter, int32_t value); - - -BSON_EXPORT (void) -bson_iter_overwrite_int64 (bson_iter_t *iter, int64_t value); - - -BSON_EXPORT (void) -bson_iter_overwrite_double (bson_iter_t *iter, double value); - - -BSON_EXPORT (void) -bson_iter_overwrite_decimal128 (bson_iter_t *iter, const bson_decimal128_t *value); - - -BSON_EXPORT (void) -bson_iter_overwrite_bool (bson_iter_t *iter, bool value); - - -BSON_EXPORT (void) -bson_iter_overwrite_oid (bson_iter_t *iter, const bson_oid_t *value); - - -BSON_EXPORT (void) -bson_iter_overwrite_timestamp (bson_iter_t *iter, uint32_t timestamp, uint32_t increment); - - -BSON_EXPORT (void) -bson_iter_overwrite_date_time (bson_iter_t *iter, int64_t value); - - -BSON_EXPORT (bool) -bson_iter_visit_all (bson_iter_t *iter, const bson_visitor_t *visitor, void *data); - -BSON_EXPORT (uint32_t) -bson_iter_offset (bson_iter_t *iter); - - -BSON_END_DECLS - - -#endif /* BSON_ITER_H */ diff --git a/bsonjs/bson/bson-json-private.h b/bsonjs/bson/bson-json-private.h deleted file mode 100644 index 7a562a2..0000000 --- a/bsonjs/bson/bson-json-private.h +++ /dev/null @@ -1,30 +0,0 @@ -/* - * Copyright 2020 MongoDB, Inc. - * - * 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. - */ - -#include - -#ifndef BSON_JSON_PRIVATE_H -#define BSON_JSON_PRIVATE_H - - -struct _bson_json_opts_t { - bson_json_mode_t mode; - int32_t max_len; - bool is_outermost_array; -}; - - -#endif /* BSON_JSON_PRIVATE_H */ diff --git a/bsonjs/bson/bson-json.c b/bsonjs/bson/bson-json.c deleted file mode 100644 index a2e3537..0000000 --- a/bsonjs/bson/bson-json.c +++ /dev/null @@ -1,2350 +0,0 @@ -/* - * Copyright 2014 MongoDB, Inc. - * - * 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. - */ - - -#include -#include -#include -#include - -#include "bson.h" -#include -#include -#include -#include - -#include "common-b64-private.h" -#include "jsonsl/jsonsl.h" - -#ifdef _WIN32 -#include -#include -#endif - -#ifndef _MSC_VER -#include -#endif - -#ifdef _MSC_VER -#define SSCANF sscanf_s -#else -#define SSCANF sscanf -#endif - -#define STACK_MAX 100 -#define BSON_JSON_DEFAULT_BUF_SIZE (1 << 14) -#define AT_LEAST_0(x) ((x) >= 0 ? (x) : 0) - - -#define READ_STATE_ENUM(ENUM) BSON_JSON_##ENUM, -#define GENERATE_STRING(STRING) #STRING, - -#define FOREACH_READ_STATE(RS) \ - RS (REGULAR) \ - RS (DONE) \ - RS (ERROR) \ - RS (IN_START_MAP) \ - RS (IN_BSON_TYPE) \ - RS (IN_BSON_TYPE_DATE_NUMBERLONG) \ - RS (IN_BSON_TYPE_DATE_ENDMAP) \ - RS (IN_BSON_TYPE_TIMESTAMP_STARTMAP) \ - RS (IN_BSON_TYPE_TIMESTAMP_VALUES) \ - RS (IN_BSON_TYPE_TIMESTAMP_ENDMAP) \ - RS (IN_BSON_TYPE_REGEX_STARTMAP) \ - RS (IN_BSON_TYPE_REGEX_VALUES) \ - RS (IN_BSON_TYPE_REGEX_ENDMAP) \ - RS (IN_BSON_TYPE_BINARY_VALUES) \ - RS (IN_BSON_TYPE_BINARY_ENDMAP) \ - RS (IN_BSON_TYPE_SCOPE_STARTMAP) \ - RS (IN_BSON_TYPE_DBPOINTER_STARTMAP) \ - RS (IN_SCOPE) \ - RS (IN_DBPOINTER) - -typedef enum { FOREACH_READ_STATE (READ_STATE_ENUM) } bson_json_read_state_t; - -static const char *read_state_names[] = {FOREACH_READ_STATE (GENERATE_STRING)}; - -#define BSON_STATE_ENUM(ENUM) BSON_JSON_LF_##ENUM, - -#define FOREACH_BSON_STATE(BS) \ - /* legacy {$regex: "...", $options: "..."} */ \ - BS (REGEX) \ - BS (OPTIONS) \ - /* modern $regularExpression: {pattern: "...", options: "..."} */ \ - BS (REGULAR_EXPRESSION_PATTERN) \ - BS (REGULAR_EXPRESSION_OPTIONS) \ - BS (CODE) \ - BS (SCOPE) \ - BS (OID) \ - BS (BINARY) \ - BS (TYPE) \ - BS (DATE) \ - BS (TIMESTAMP_T) \ - BS (TIMESTAMP_I) \ - BS (UNDEFINED) \ - BS (MINKEY) \ - BS (MAXKEY) \ - BS (INT32) \ - BS (INT64) \ - BS (DOUBLE) \ - BS (DECIMAL128) \ - BS (DBPOINTER) \ - BS (SYMBOL) \ - BS (UUID) - -typedef enum { FOREACH_BSON_STATE (BSON_STATE_ENUM) } bson_json_read_bson_state_t; - -static const char *bson_state_names[] = {FOREACH_BSON_STATE (GENERATE_STRING)}; - -typedef struct { - uint8_t *buf; - size_t n_bytes; - size_t len; -} bson_json_buf_t; - - -typedef enum { - BSON_JSON_FRAME_INITIAL = 0, - BSON_JSON_FRAME_ARRAY, - BSON_JSON_FRAME_DOC, - BSON_JSON_FRAME_SCOPE, - BSON_JSON_FRAME_DBPOINTER, -} bson_json_frame_type_t; - - -typedef struct { - int i; - bson_json_frame_type_t type; - bson_t bson; -} bson_json_stack_frame_t; - - -typedef union { - struct { - bool has_pattern; - bool has_options; - bool is_legacy; - } regex; - struct { - bool has_oid; - bson_oid_t oid; - } oid; - struct { - bool has_binary; - bool has_subtype; - bson_subtype_t type; - bool is_legacy; - } binary; - struct { - bool has_date; - int64_t date; - } date; - struct { - bool has_t; - bool has_i; - uint32_t t; - uint32_t i; - } timestamp; - struct { - bool has_undefined; - } undefined; - struct { - bool has_minkey; - } minkey; - struct { - bool has_maxkey; - } maxkey; - struct { - int32_t value; - } v_int32; - struct { - int64_t value; - } v_int64; - struct { - double value; - } v_double; - struct { - bson_decimal128_t value; - } v_decimal128; -} bson_json_bson_data_t; - - -/* collect info while parsing a {$code: "...", $scope: {...}} object */ -typedef struct { - bool has_code; - bool has_scope; - bool in_scope; - bson_json_buf_t key_buf; - bson_json_buf_t code_buf; -} bson_json_code_t; - - -static void -_bson_json_code_cleanup (bson_json_code_t *code_data) -{ - bson_free (code_data->key_buf.buf); - bson_free (code_data->code_buf.buf); -} - - -typedef struct { - bson_t *bson; - bson_json_stack_frame_t stack[STACK_MAX]; - int n; - const char *key; - bson_json_buf_t key_buf; - bson_json_buf_t unescaped; - bson_json_read_state_t read_state; - bson_json_read_bson_state_t bson_state; - bson_type_t bson_type; - bson_json_buf_t bson_type_buf[3]; - bson_json_bson_data_t bson_type_data; - bson_json_code_t code_data; - bson_json_buf_t dbpointer_key; -} bson_json_reader_bson_t; - - -typedef struct { - void *data; - bson_json_reader_cb cb; - bson_json_destroy_cb dcb; - uint8_t *buf; - size_t buf_size; - size_t bytes_read; - size_t bytes_parsed; - bool all_whitespace; -} bson_json_reader_producer_t; - - -struct _bson_json_reader_t { - bson_json_reader_producer_t producer; - bson_json_reader_bson_t bson; - jsonsl_t json; - ssize_t json_text_pos; - bool should_reset; - ssize_t advance; - bson_json_buf_t tok_accumulator; - bson_error_t *error; -}; - - -typedef struct { - int fd; - bool do_close; -} bson_json_reader_handle_fd_t; - - -/* forward decl */ -static void -_bson_json_save_map_key (bson_json_reader_bson_t *bson, const uint8_t *val, size_t len); - - -static void -_noop (void) -{ -} - -#define STACK_ELE(_delta, _name) (bson->stack[(_delta) + bson->n]._name) -#define STACK_BSON(_delta) (((_delta) + bson->n) == 0 ? bson->bson : &STACK_ELE (_delta, bson)) -#define STACK_BSON_PARENT STACK_BSON (-1) -#define STACK_BSON_CHILD STACK_BSON (0) -#define STACK_I STACK_ELE (0, i) -#define STACK_FRAME_TYPE STACK_ELE (0, type) -#define STACK_IS_INITIAL (STACK_FRAME_TYPE == BSON_JSON_FRAME_INITIAL) -#define STACK_IS_ARRAY (STACK_FRAME_TYPE == BSON_JSON_FRAME_ARRAY) -#define STACK_IS_DOC (STACK_FRAME_TYPE == BSON_JSON_FRAME_DOC) -#define STACK_IS_SCOPE (STACK_FRAME_TYPE == BSON_JSON_FRAME_SCOPE) -#define STACK_IS_DBPOINTER (STACK_FRAME_TYPE == BSON_JSON_FRAME_DBPOINTER) -#define FRAME_TYPE_HAS_BSON(_type) ((_type) == BSON_JSON_FRAME_SCOPE || (_type) == BSON_JSON_FRAME_DBPOINTER) -#define STACK_HAS_BSON FRAME_TYPE_HAS_BSON (STACK_FRAME_TYPE) -#define STACK_PUSH(frame_type) \ - do { \ - if (bson->n >= (STACK_MAX - 1)) { \ - return; \ - } \ - bson->n++; \ - if (STACK_HAS_BSON) { \ - if (FRAME_TYPE_HAS_BSON (frame_type)) { \ - bson_reinit (STACK_BSON_CHILD); \ - } else { \ - bson_destroy (STACK_BSON_CHILD); \ - } \ - } else if (FRAME_TYPE_HAS_BSON (frame_type)) { \ - bson_init (STACK_BSON_CHILD); \ - } \ - STACK_FRAME_TYPE = frame_type; \ - } while (0) -#define STACK_PUSH_ARRAY(statement) \ - do { \ - STACK_PUSH (BSON_JSON_FRAME_ARRAY); \ - STACK_I = 0; \ - if (bson->n != 0) { \ - statement; \ - } \ - } while (0) -#define STACK_PUSH_DOC(statement) \ - do { \ - STACK_PUSH (BSON_JSON_FRAME_DOC); \ - if (bson->n != 0) { \ - statement; \ - } \ - } while (0) -#define STACK_PUSH_SCOPE \ - do { \ - STACK_PUSH (BSON_JSON_FRAME_SCOPE); \ - bson->code_data.in_scope = true; \ - } while (0) -#define STACK_PUSH_DBPOINTER \ - do { \ - STACK_PUSH (BSON_JSON_FRAME_DBPOINTER); \ - } while (0) -#define STACK_POP_ARRAY(statement) \ - do { \ - if (!STACK_IS_ARRAY) { \ - return; \ - } \ - if (bson->n < 0) { \ - return; \ - } \ - if (bson->n > 0) { \ - statement; \ - } \ - bson->n--; \ - } while (0) -#define STACK_POP_DOC(statement) \ - do { \ - if (STACK_IS_ARRAY) { \ - return; \ - } \ - if (bson->n < 0) { \ - return; \ - } \ - if (bson->n > 0) { \ - statement; \ - } \ - bson->n--; \ - } while (0) -#define STACK_POP_SCOPE \ - do { \ - STACK_POP_DOC (_noop ()); \ - bson->code_data.in_scope = false; \ - } while (0) -#define STACK_POP_DBPOINTER STACK_POP_DOC (_noop ()) -#define BASIC_CB_PREAMBLE \ - const char *key; \ - size_t len; \ - bson_json_reader_bson_t *bson = &reader->bson; \ - _bson_json_read_fixup_key (bson); \ - key = bson->key; \ - len = bson->key_buf.len; \ - (void) 0 -#define BASIC_CB_BAIL_IF_NOT_NORMAL(_type) \ - if (bson->read_state != BSON_JSON_REGULAR) { \ - _bson_json_read_set_error ( \ - reader, "Invalid read of %s in state %s", (_type), read_state_names[bson->read_state]); \ - return; \ - } else if (!key) { \ - _bson_json_read_set_error ( \ - reader, "Invalid read of %s without key in state %s", (_type), read_state_names[bson->read_state]); \ - return; \ - } else \ - (void) 0 -#define HANDLE_OPTION(_selection_statement, _key, _type, _state) \ - _selection_statement (len == strlen (_key) && strncmp ((const char *) val, (_key), len) == 0) \ - { \ - if (bson->bson_type && bson->bson_type != (_type)) { \ - _bson_json_read_set_error (reader, \ - "Invalid key \"%s\". Looking for values " \ - "for type \"%s\", got \"%s\"", \ - (_key), \ - _bson_json_type_name (bson->bson_type), \ - _bson_json_type_name (_type)); \ - return; \ - } \ - bson->bson_type = (_type); \ - bson->bson_state = (_state); \ - } - - -bson_json_opts_t * -bson_json_opts_new (bson_json_mode_t mode, int32_t max_len) -{ - bson_json_opts_t *opts; - - opts = (bson_json_opts_t *) bson_malloc (sizeof *opts); - *opts = (bson_json_opts_t){ - .mode = mode, - .max_len = max_len, - .is_outermost_array = false, - }; - - return opts; -} - -void -bson_json_opts_destroy (bson_json_opts_t *opts) -{ - bson_free (opts); -} - -static void -_bson_json_read_set_error (bson_json_reader_t *reader, const char *fmt, ...) BSON_GNUC_PRINTF (2, 3); - - -static void -_bson_json_read_set_error (bson_json_reader_t *reader, /* IN */ - const char *fmt, /* IN */ - ...) -{ - va_list ap; - - if (reader->error) { - reader->error->domain = BSON_ERROR_JSON; - reader->error->code = BSON_JSON_ERROR_READ_INVALID_PARAM; - va_start (ap, fmt); - bson_vsnprintf (reader->error->message, sizeof reader->error->message, fmt, ap); - va_end (ap); - reader->error->message[sizeof reader->error->message - 1] = '\0'; - } - - reader->bson.read_state = BSON_JSON_ERROR; - jsonsl_stop (reader->json); -} - - -static void -_bson_json_read_corrupt (bson_json_reader_t *reader, const char *fmt, ...) BSON_GNUC_PRINTF (2, 3); - - -static void -_bson_json_read_corrupt (bson_json_reader_t *reader, /* IN */ - const char *fmt, /* IN */ - ...) -{ - va_list ap; - - if (reader->error) { - reader->error->domain = BSON_ERROR_JSON; - reader->error->code = BSON_JSON_ERROR_READ_CORRUPT_JS; - va_start (ap, fmt); - bson_vsnprintf (reader->error->message, sizeof reader->error->message, fmt, ap); - va_end (ap); - reader->error->message[sizeof reader->error->message - 1] = '\0'; - } - - reader->bson.read_state = BSON_JSON_ERROR; - jsonsl_stop (reader->json); -} - - -static void -_bson_json_buf_ensure (bson_json_buf_t *buf, /* IN */ - size_t len) /* IN */ -{ - if (buf->n_bytes < len) { - bson_free (buf->buf); - - buf->n_bytes = bson_next_power_of_two (len); - buf->buf = bson_malloc (buf->n_bytes); - } -} - - -static void -_bson_json_buf_set (bson_json_buf_t *buf, const void *from, size_t len) -{ - _bson_json_buf_ensure (buf, len + 1); - memcpy (buf->buf, from, len); - buf->buf[len] = '\0'; - buf->len = len; -} - - -static void -_bson_json_buf_append (bson_json_buf_t *buf, const void *from, size_t len) -{ - size_t len_with_null = len + 1; - - if (buf->len == 0) { - _bson_json_buf_ensure (buf, len_with_null); - } else if (buf->n_bytes < buf->len + len_with_null) { - buf->n_bytes = bson_next_power_of_two (buf->len + len_with_null); - buf->buf = bson_realloc (buf->buf, buf->n_bytes); - } - - memcpy (buf->buf + buf->len, from, len); - buf->len += len; - buf->buf[buf->len] = '\0'; -} - - -static const char * -_bson_json_type_name (bson_type_t type) -{ - switch (type) { - case BSON_TYPE_EOD: - return "end of document"; - case BSON_TYPE_DOUBLE: - return "double"; - case BSON_TYPE_UTF8: - return "utf-8"; - case BSON_TYPE_DOCUMENT: - return "document"; - case BSON_TYPE_ARRAY: - return "array"; - case BSON_TYPE_BINARY: - return "binary"; - case BSON_TYPE_UNDEFINED: - return "undefined"; - case BSON_TYPE_OID: - return "objectid"; - case BSON_TYPE_BOOL: - return "bool"; - case BSON_TYPE_DATE_TIME: - return "datetime"; - case BSON_TYPE_NULL: - return "null"; - case BSON_TYPE_REGEX: - return "regex"; - case BSON_TYPE_DBPOINTER: - return "dbpointer"; - case BSON_TYPE_CODE: - return "code"; - case BSON_TYPE_SYMBOL: - return "symbol"; - case BSON_TYPE_CODEWSCOPE: - return "code with scope"; - case BSON_TYPE_INT32: - return "int32"; - case BSON_TYPE_TIMESTAMP: - return "timestamp"; - case BSON_TYPE_INT64: - return "int64"; - case BSON_TYPE_DECIMAL128: - return "decimal128"; - case BSON_TYPE_MAXKEY: - return "maxkey"; - case BSON_TYPE_MINKEY: - return "minkey"; - default: - return ""; - } -} - - -static void -_bson_json_read_fixup_key (bson_json_reader_bson_t *bson) /* IN */ -{ - bson_json_read_state_t rs = bson->read_state; - - if (bson->n >= 0 && STACK_IS_ARRAY && rs == BSON_JSON_REGULAR) { - _bson_json_buf_ensure (&bson->key_buf, 12); - bson->key_buf.len = bson_uint32_to_string (STACK_I, &bson->key, (char *) bson->key_buf.buf, 12); - STACK_I++; - } -} - - -static void -_bson_json_read_null (bson_json_reader_t *reader) -{ - BASIC_CB_PREAMBLE; - BASIC_CB_BAIL_IF_NOT_NORMAL ("null"); - - bson_append_null (STACK_BSON_CHILD, key, (int) len); -} - - -static void -_bson_json_read_boolean (bson_json_reader_t *reader, /* IN */ - int val) /* IN */ -{ - BASIC_CB_PREAMBLE; - - if (bson->read_state == BSON_JSON_IN_BSON_TYPE && bson->bson_state == BSON_JSON_LF_UNDEFINED) { - bson->bson_type_data.undefined.has_undefined = true; - return; - } - - BASIC_CB_BAIL_IF_NOT_NORMAL ("boolean"); - - bson_append_bool (STACK_BSON_CHILD, key, (int) len, val); -} - - -/* sign is -1 or 1 */ -static void -_bson_json_read_integer (bson_json_reader_t *reader, uint64_t val, int64_t sign) -{ - bson_json_read_state_t rs; - bson_json_read_bson_state_t bs; - - BASIC_CB_PREAMBLE; - - if (sign == 1 && val > INT64_MAX) { - _bson_json_read_set_error (reader, "Number \"%" PRIu64 "\" is out of range", val); - - return; - } else if (sign == -1 && val > ((uint64_t) INT64_MAX + 1)) { - _bson_json_read_set_error (reader, "Number \"-%" PRIu64 "\" is out of range", val); - - return; - } - - rs = bson->read_state; - bs = bson->bson_state; - - if (rs == BSON_JSON_REGULAR) { - BASIC_CB_BAIL_IF_NOT_NORMAL ("integer"); - - if (val <= INT32_MAX || (sign == -1 && val <= (uint64_t) INT32_MAX + 1)) { - bson_append_int32 (STACK_BSON_CHILD, key, (int) len, (int) (val * sign)); - } else if (sign == -1) { -#if defined(_WIN32) && !defined(__MINGW32__) - // Unary negation of unsigned integer is deliberate. -#pragma warning(suppress : 4146) - bson_append_int64 (STACK_BSON_CHILD, key, (int) len, (int64_t) -val); -#else - bson_append_int64 (STACK_BSON_CHILD, key, (int) len, (int64_t) -val); -#endif // defined(_WIN32) && !defined(__MINGW32__) - } else { - bson_append_int64 (STACK_BSON_CHILD, key, (int) len, (int64_t) val); - } - } else if (rs == BSON_JSON_IN_BSON_TYPE || rs == BSON_JSON_IN_BSON_TYPE_TIMESTAMP_VALUES) { - switch (bs) { - case BSON_JSON_LF_DATE: - bson->bson_type_data.date.has_date = true; - bson->bson_type_data.date.date = sign * val; - break; - case BSON_JSON_LF_TIMESTAMP_T: - if (sign == -1) { - _bson_json_read_set_error (reader, "Invalid timestamp value: \"-%" PRIu64 "\"", val); - return; - } - - bson->bson_type_data.timestamp.has_t = true; - bson->bson_type_data.timestamp.t = (uint32_t) val; - break; - case BSON_JSON_LF_TIMESTAMP_I: - if (sign == -1) { - _bson_json_read_set_error (reader, "Invalid timestamp value: \"-%" PRIu64 "\"", val); - return; - } - - bson->bson_type_data.timestamp.has_i = true; - bson->bson_type_data.timestamp.i = (uint32_t) val; - break; - case BSON_JSON_LF_MINKEY: - if (sign == -1) { - _bson_json_read_set_error (reader, "Invalid MinKey value: \"-%" PRIu64 "\"", val); - return; - } else if (val != 1) { - _bson_json_read_set_error (reader, "Invalid MinKey value: \"%" PRIu64 "\"", val); - } - - bson->bson_type_data.minkey.has_minkey = true; - break; - case BSON_JSON_LF_MAXKEY: - if (sign == -1) { - _bson_json_read_set_error (reader, "Invalid MinKey value: \"-%" PRIu64 "\"", val); - return; - } else if (val != 1) { - _bson_json_read_set_error (reader, "Invalid MinKey value: \"%" PRIu64 "\"", val); - } - - bson->bson_type_data.maxkey.has_maxkey = true; - break; - case BSON_JSON_LF_INT32: - case BSON_JSON_LF_INT64: - _bson_json_read_set_error (reader, - "Invalid state for integer read: %s, " - "expected number as quoted string like \"123\"", - bson_state_names[bs]); - break; - case BSON_JSON_LF_REGEX: - case BSON_JSON_LF_OPTIONS: - case BSON_JSON_LF_REGULAR_EXPRESSION_PATTERN: - case BSON_JSON_LF_REGULAR_EXPRESSION_OPTIONS: - case BSON_JSON_LF_CODE: - case BSON_JSON_LF_SCOPE: - case BSON_JSON_LF_OID: - case BSON_JSON_LF_BINARY: - case BSON_JSON_LF_TYPE: - case BSON_JSON_LF_UUID: - case BSON_JSON_LF_UNDEFINED: - case BSON_JSON_LF_DOUBLE: - case BSON_JSON_LF_DECIMAL128: - case BSON_JSON_LF_DBPOINTER: - case BSON_JSON_LF_SYMBOL: - default: - _bson_json_read_set_error (reader, - "Unexpected integer %s%" PRIu64 " in type \"%s\"", - sign == -1 ? "-" : "", - val, - _bson_json_type_name (bson->bson_type)); - } - } else { - _bson_json_read_set_error ( - reader, "Unexpected integer %s%" PRIu64 " in state \"%s\"", sign == -1 ? "-" : "", val, read_state_names[rs]); - } -} - - -static bool -_bson_json_parse_double (bson_json_reader_t *reader, const char *val, size_t vlen, double *d) -{ - errno = 0; - *d = strtod (val, NULL); - -#ifdef _MSC_VER - const double pos_inf = INFINITY; - const double neg_inf = -pos_inf; - - /* Microsoft's strtod parses "NaN", "Infinity", "-Infinity" as 0 */ - if (*d == 0.0) { - if (!_strnicmp (val, "nan", vlen)) { - *d = NAN; - return true; - } else if (!_strnicmp (val, "infinity", vlen)) { - *d = pos_inf; - return true; - } else if (!_strnicmp (val, "-infinity", vlen)) { - *d = neg_inf; - return true; - } - } - - if ((*d == HUGE_VAL || *d == -HUGE_VAL) && errno == ERANGE) { - _bson_json_read_set_error (reader, "Number \"%.*s\" is out of range", (int) vlen, val); - - return false; - } -#else - /* not MSVC - set err on overflow, but avoid err for infinity */ - if ((*d == HUGE_VAL || *d == -HUGE_VAL) && errno == ERANGE && strncasecmp (val, "infinity", vlen) && - strncasecmp (val, "-infinity", vlen)) { - _bson_json_read_set_error (reader, "Number \"%.*s\" is out of range", (int) vlen, val); - - return false; - } - -#endif /* _MSC_VER */ - return true; -} - - -static void -_bson_json_read_double (bson_json_reader_t *reader, /* IN */ - double val) /* IN */ -{ - BASIC_CB_PREAMBLE; - BASIC_CB_BAIL_IF_NOT_NORMAL ("double"); - - if (!bson_append_double (STACK_BSON_CHILD, key, (int) len, val)) { - _bson_json_read_set_error (reader, "Cannot append double value %g", val); - } -} - - -static bool -_bson_json_read_int64_or_set_error (bson_json_reader_t *reader, /* IN */ - const unsigned char *val, /* IN */ - size_t vlen, /* IN */ - int64_t *v64) /* OUT */ -{ - bson_json_reader_bson_t *bson = &reader->bson; - char *endptr = NULL; - - _bson_json_read_fixup_key (bson); - errno = 0; - *v64 = bson_ascii_strtoll ((const char *) val, &endptr, 10); - - if (((*v64 == INT64_MIN) || (*v64 == INT64_MAX)) && (errno == ERANGE)) { - _bson_json_read_set_error (reader, "Number \"%s\" is out of range", val); - return false; - } - - if (endptr != ((const char *) val + vlen)) { - _bson_json_read_set_error (reader, "Number \"%s\" is invalid", val); - return false; - } - - return true; -} - -static bool -_unhexlify_uuid (const char *uuid, uint8_t *out, size_t max) -{ - unsigned int byte; - size_t x = 0; - int i = 0; - - BSON_ASSERT (strlen (uuid) == 32); - - while (SSCANF (&uuid[i], "%2x", &byte) == 1) { - if (x >= max) { - return false; - } - - out[x++] = (uint8_t) byte; - i += 2; - } - - return i == 32; -} - -/* parse a value for "base64", "subType", legacy "$binary" or "$type", or - * "$uuid" */ -static void -_bson_json_parse_binary_elem (bson_json_reader_t *reader, const char *val_w_null, size_t vlen) -{ - bson_json_read_bson_state_t bs; - bson_json_bson_data_t *data; - int binary_len; - - BASIC_CB_PREAMBLE; - - bs = bson->bson_state; - data = &bson->bson_type_data; - - if (bs == BSON_JSON_LF_BINARY) { - data->binary.has_binary = true; - binary_len = mcommon_b64_pton (val_w_null, NULL, 0); - if (binary_len < 0) { - _bson_json_read_set_error ( - reader, "Invalid input string \"%s\", looking for base64-encoded binary", val_w_null); - } - - _bson_json_buf_ensure (&bson->bson_type_buf[0], (size_t) binary_len + 1); - if (mcommon_b64_pton (val_w_null, bson->bson_type_buf[0].buf, (size_t) binary_len + 1) < 0) { - _bson_json_read_set_error ( - reader, "Invalid input string \"%s\", looking for base64-encoded binary", val_w_null); - } - - bson->bson_type_buf[0].len = (size_t) binary_len; - } else if (bs == BSON_JSON_LF_TYPE) { - data->binary.has_subtype = true; - - if (SSCANF (val_w_null, "%02x", &data->binary.type) != 1) { - if (!data->binary.is_legacy || data->binary.has_binary) { - /* misformatted subtype, like {$binary: {base64: "", subType: "x"}}, - * or legacy {$binary: "", $type: "x"} */ - _bson_json_read_set_error (reader, "Invalid input string \"%s\", looking for binary subtype", val_w_null); - } else { - /* actually a query operator: {x: {$type: "array"}}*/ - bson->read_state = BSON_JSON_REGULAR; - STACK_PUSH_DOC (bson_append_document_begin (STACK_BSON_PARENT, key, (int) len, STACK_BSON_CHILD)); - - bson_append_utf8 (STACK_BSON_CHILD, "$type", 5, (const char *) val_w_null, (int) vlen); - } - } - } else if (bs == BSON_JSON_LF_UUID) { - int nread = 0; - char uuid[33]; - - data->binary.has_binary = true; - data->binary.has_subtype = true; - data->binary.type = BSON_SUBTYPE_UUID; - - /* Validate the UUID and extract relevant portions */ - /* We can't use %x here as it allows +, -, and 0x prefixes */ -#ifdef _MSC_VER - SSCANF (val_w_null, - "%8c-%4c-%4c-%4c-%12c%n", - &uuid[0], - 8, - &uuid[8], - 4, - &uuid[12], - 4, - &uuid[16], - 4, - &uuid[20], - 12, - &nread); -#else - SSCANF (val_w_null, "%8c-%4c-%4c-%4c-%12c%n", &uuid[0], &uuid[8], &uuid[12], &uuid[16], &uuid[20], &nread); -#endif - - uuid[32] = '\0'; - - if (nread != 36 || val_w_null[nread] != '\0') { - _bson_json_read_set_error (reader, - "Invalid input string \"%s\", looking for " - "a dash-separated UUID string", - val_w_null); - - return; - } - - binary_len = 16; - _bson_json_buf_ensure (&bson->bson_type_buf[0], (size_t) binary_len + 1); - - if (!_unhexlify_uuid (&uuid[0], bson->bson_type_buf[0].buf, (size_t) binary_len)) { - _bson_json_read_set_error (reader, - "Invalid input string \"%s\", looking for " - "a dash-separated UUID string", - val_w_null); - } - - bson->bson_type_buf[0].len = (size_t) binary_len; - } -} - -static bool -_bson_json_allow_embedded_nulls (bson_json_reader_t const *reader) -{ - const bson_json_read_state_t read_state = reader->bson.read_state; - const bson_json_read_bson_state_t bson_state = reader->bson.bson_state; - - if (read_state == BSON_JSON_IN_BSON_TYPE_REGEX_VALUES) { - if (bson_state == BSON_JSON_LF_REGULAR_EXPRESSION_PATTERN || - bson_state == BSON_JSON_LF_REGULAR_EXPRESSION_OPTIONS) { - /* Prohibit embedded NULL bytes for canonical extended regex: - * { $regularExpression: { pattern: "pattern", options: "options" } } - */ - return false; - } - } - - if (read_state == BSON_JSON_IN_BSON_TYPE) { - if (bson_state == BSON_JSON_LF_REGEX || bson_state == BSON_JSON_LF_OPTIONS) { - /* Prohibit embedded NULL bytes for legacy regex: - * { $regex: "pattern", $options: "options" } */ - return false; - } - } - - /* Embedded nulls are okay in any other context */ - return true; -} - -static void -_bson_json_read_string (bson_json_reader_t *reader, /* IN */ - const unsigned char *val, /* IN */ - size_t vlen) /* IN */ -{ - bson_json_read_state_t rs; - bson_json_read_bson_state_t bs; - const bool allow_null = _bson_json_allow_embedded_nulls (reader); - - BASIC_CB_PREAMBLE; - - rs = bson->read_state; - bs = bson->bson_state; - - if (!bson_utf8_validate ((const char *) val, vlen, allow_null)) { - _bson_json_read_corrupt (reader, "invalid bytes in UTF8 string"); - return; - } - - if (rs == BSON_JSON_REGULAR) { - BASIC_CB_BAIL_IF_NOT_NORMAL ("string"); - bson_append_utf8 (STACK_BSON_CHILD, key, (int) len, (const char *) val, (int) vlen); - } else if (rs == BSON_JSON_IN_BSON_TYPE_SCOPE_STARTMAP || rs == BSON_JSON_IN_BSON_TYPE_DBPOINTER_STARTMAP) { - _bson_json_read_set_error (reader, "Invalid read of \"%s\" in state \"%s\"", val, read_state_names[rs]); - } else if (rs == BSON_JSON_IN_BSON_TYPE_BINARY_VALUES) { - const char *val_w_null; - _bson_json_buf_set (&bson->bson_type_buf[2], val, vlen); - val_w_null = (const char *) bson->bson_type_buf[2].buf; - - _bson_json_parse_binary_elem (reader, val_w_null, vlen); - } else if (rs == BSON_JSON_IN_BSON_TYPE || rs == BSON_JSON_IN_BSON_TYPE_TIMESTAMP_VALUES || - rs == BSON_JSON_IN_BSON_TYPE_REGEX_VALUES || rs == BSON_JSON_IN_BSON_TYPE_DATE_NUMBERLONG) { - const char *val_w_null; - _bson_json_buf_set (&bson->bson_type_buf[2], val, vlen); - val_w_null = (const char *) bson->bson_type_buf[2].buf; - - switch (bs) { - case BSON_JSON_LF_REGEX: - bson->bson_type_data.regex.is_legacy = true; - /* FALL THROUGH */ - case BSON_JSON_LF_REGULAR_EXPRESSION_PATTERN: - bson->bson_type_data.regex.has_pattern = true; - _bson_json_buf_set (&bson->bson_type_buf[0], val, vlen); - break; - case BSON_JSON_LF_OPTIONS: - bson->bson_type_data.regex.is_legacy = true; - /* FALL THROUGH */ - case BSON_JSON_LF_REGULAR_EXPRESSION_OPTIONS: - bson->bson_type_data.regex.has_options = true; - _bson_json_buf_set (&bson->bson_type_buf[1], val, vlen); - break; - case BSON_JSON_LF_OID: - - if (vlen != 24) { - goto BAD_PARSE; - } - - bson->bson_type_data.oid.has_oid = true; - bson_oid_init_from_string (&bson->bson_type_data.oid.oid, val_w_null); - break; - case BSON_JSON_LF_BINARY: - case BSON_JSON_LF_TYPE: - bson->bson_type_data.binary.is_legacy = true; - /* FALL THROUGH */ - case BSON_JSON_LF_UUID: - _bson_json_parse_binary_elem (reader, val_w_null, vlen); - break; - case BSON_JSON_LF_INT32: { - int64_t v64; - if (!_bson_json_read_int64_or_set_error (reader, val, vlen, &v64)) { - /* the error is set, return and let the reader exit */ - return; - } - - if (v64 < INT32_MIN || v64 > INT32_MAX) { - goto BAD_PARSE; - } - - if (bson->read_state == BSON_JSON_IN_BSON_TYPE) { - bson->bson_type_data.v_int32.value = (int32_t) v64; - } else { - goto BAD_PARSE; - } - } break; - case BSON_JSON_LF_INT64: { - int64_t v64; - if (!_bson_json_read_int64_or_set_error (reader, val, vlen, &v64)) { - /* the error is set, return and let the reader exit */ - return; - } - - if (bson->read_state == BSON_JSON_IN_BSON_TYPE) { - bson->bson_type_data.v_int64.value = v64; - } else if (bson->read_state == BSON_JSON_IN_BSON_TYPE_DATE_NUMBERLONG) { - bson->bson_type_data.date.has_date = true; - bson->bson_type_data.date.date = v64; - } else { - goto BAD_PARSE; - } - } break; - case BSON_JSON_LF_DOUBLE: { - if (!_bson_json_parse_double (reader, (const char *) val, vlen, &bson->bson_type_data.v_double.value)) { - /* the error is set, return and let the reader exit */ - return; - } - } break; - case BSON_JSON_LF_DATE: { - int64_t v64; - - if (!_bson_iso8601_date_parse ((char *) val, (int) vlen, &v64, reader->error)) { - jsonsl_stop (reader->json); - } else { - bson->bson_type_data.date.has_date = true; - bson->bson_type_data.date.date = v64; - } - } break; - case BSON_JSON_LF_DECIMAL128: { - bson_decimal128_t decimal128; - - if (bson_decimal128_from_string (val_w_null, &decimal128) && bson->read_state == BSON_JSON_IN_BSON_TYPE) { - bson->bson_type_data.v_decimal128.value = decimal128; - } else { - goto BAD_PARSE; - } - } break; - case BSON_JSON_LF_CODE: - _bson_json_buf_set (&bson->code_data.code_buf, val, vlen); - break; - case BSON_JSON_LF_SYMBOL: - bson_append_symbol (STACK_BSON_CHILD, key, (int) len, (const char *) val, (int) vlen); - break; - case BSON_JSON_LF_SCOPE: - case BSON_JSON_LF_TIMESTAMP_T: - case BSON_JSON_LF_TIMESTAMP_I: - case BSON_JSON_LF_UNDEFINED: - case BSON_JSON_LF_MINKEY: - case BSON_JSON_LF_MAXKEY: - case BSON_JSON_LF_DBPOINTER: - default: - goto BAD_PARSE; - } - - return; - BAD_PARSE: - _bson_json_read_set_error ( - reader, "Invalid input string \"%s\", looking for %s", val_w_null, bson_state_names[bs]); - } else { - _bson_json_read_set_error (reader, "Invalid state to look for string: %s", read_state_names[rs]); - } -} - - -static void -_bson_json_read_start_map (bson_json_reader_t *reader) /* IN */ -{ - BASIC_CB_PREAMBLE; - - if (bson->read_state == BSON_JSON_IN_BSON_TYPE) { - switch (bson->bson_state) { - case BSON_JSON_LF_DATE: - bson->read_state = BSON_JSON_IN_BSON_TYPE_DATE_NUMBERLONG; - break; - case BSON_JSON_LF_BINARY: - bson->read_state = BSON_JSON_IN_BSON_TYPE_BINARY_VALUES; - break; - case BSON_JSON_LF_TYPE: - /* special case, we started parsing {$type: {$numberInt: "2"}} and we - * expected a legacy Binary format. now we see the second "{", so - * backtrack and parse $type query operator. */ - bson->read_state = BSON_JSON_IN_START_MAP; - BSON_ASSERT (bson_in_range_unsigned (int, len)); - STACK_PUSH_DOC (bson_append_document_begin (STACK_BSON_PARENT, key, (int) len, STACK_BSON_CHILD)); - _bson_json_save_map_key (bson, (const uint8_t *) "$type", 5); - break; - case BSON_JSON_LF_CODE: - case BSON_JSON_LF_DECIMAL128: - case BSON_JSON_LF_DOUBLE: - case BSON_JSON_LF_INT32: - case BSON_JSON_LF_INT64: - case BSON_JSON_LF_MAXKEY: - case BSON_JSON_LF_MINKEY: - case BSON_JSON_LF_OID: - case BSON_JSON_LF_OPTIONS: - case BSON_JSON_LF_REGEX: - /** - * NOTE: A read_state of BSON_JSON_IN_BSON_TYPE is used when "$regex" is - * found, but BSON_JSON_IN_BSON_TYPE_REGEX_STARTMAP is used for - * "$regularExpression", which will instead go to a below 'if else' branch - * instead of this switch statement. They're both called "regex" in their - * respective enumerators, but they behave differently when parsing. - */ - // fallthrough - case BSON_JSON_LF_REGULAR_EXPRESSION_OPTIONS: - case BSON_JSON_LF_REGULAR_EXPRESSION_PATTERN: - case BSON_JSON_LF_SYMBOL: - case BSON_JSON_LF_UNDEFINED: - case BSON_JSON_LF_UUID: - // These special keys do not expect objects as their values. Fail. - _bson_json_read_set_error ( - reader, "Unexpected nested object value for \"%s\" key", reader->bson.unescaped.buf); - break; - case BSON_JSON_LF_DBPOINTER: - case BSON_JSON_LF_SCOPE: - case BSON_JSON_LF_TIMESTAMP_I: - case BSON_JSON_LF_TIMESTAMP_T: - default: - // These special LF keys aren't handled with BSON_JSON_IN_BSON_TYPE - BSON_UNREACHABLE ("These LF values are handled with a different read_state"); - } - } else if (bson->read_state == BSON_JSON_IN_BSON_TYPE_TIMESTAMP_STARTMAP) { - bson->read_state = BSON_JSON_IN_BSON_TYPE_TIMESTAMP_VALUES; - } else if (bson->read_state == BSON_JSON_IN_BSON_TYPE_SCOPE_STARTMAP) { - bson->read_state = BSON_JSON_IN_SCOPE; - } else if (bson->read_state == BSON_JSON_IN_BSON_TYPE_DBPOINTER_STARTMAP) { - bson->read_state = BSON_JSON_IN_DBPOINTER; - } else if (bson->read_state == BSON_JSON_IN_BSON_TYPE_REGEX_STARTMAP) { - bson->read_state = BSON_JSON_IN_BSON_TYPE_REGEX_VALUES; - } else { - bson->read_state = BSON_JSON_IN_START_MAP; - } - - /* silence some warnings */ - (void) len; - (void) key; -} - - -static bool -_is_known_key (const char *key, size_t len) -{ - bool ret; - -#define IS_KEY(k) (len == strlen (k) && (0 == memcmp (k, key, len))) - - ret = (IS_KEY ("$regularExpression") || IS_KEY ("$regex") || IS_KEY ("$options") || IS_KEY ("$code") || - IS_KEY ("$scope") || IS_KEY ("$oid") || IS_KEY ("$binary") || IS_KEY ("$type") || IS_KEY ("$date") || - IS_KEY ("$undefined") || IS_KEY ("$maxKey") || IS_KEY ("$minKey") || IS_KEY ("$timestamp") || - IS_KEY ("$numberInt") || IS_KEY ("$numberLong") || IS_KEY ("$numberDouble") || IS_KEY ("$numberDecimal") || - IS_KEY ("$numberInt") || IS_KEY ("$numberLong") || IS_KEY ("$numberDouble") || IS_KEY ("$numberDecimal") || - IS_KEY ("$dbPointer") || IS_KEY ("$symbol") || IS_KEY ("$uuid")); - -#undef IS_KEY - - return ret; -} - -static void -_bson_json_save_map_key (bson_json_reader_bson_t *bson, const uint8_t *val, size_t len) -{ - _bson_json_buf_set (&bson->key_buf, val, len); - bson->key = (const char *) bson->key_buf.buf; -} - - -static void -_bson_json_read_code_or_scope_key (bson_json_reader_bson_t *bson, bool is_scope, const uint8_t *val, size_t len) -{ - bson_json_code_t *code = &bson->code_data; - - if (code->in_scope) { - /* we're reading something weirdly nested, e.g. we just read "$code" in - * "$scope: {x: {$code: {}}}". just create the subdoc within the scope. */ - bson->read_state = BSON_JSON_REGULAR; - STACK_PUSH_DOC ( - bson_append_document_begin (STACK_BSON_PARENT, bson->key, (int) bson->key_buf.len, STACK_BSON_CHILD)); - _bson_json_save_map_key (bson, val, len); - } else { - if (!bson->code_data.key_buf.len) { - /* save the key, e.g. {"key": {"$code": "return x", "$scope":{"x":1}}}, - * in case it is overwritten while parsing scope sub-object */ - _bson_json_buf_set (&bson->code_data.key_buf, bson->key, bson->key_buf.len); - } - - if (is_scope) { - bson->bson_type = BSON_TYPE_CODEWSCOPE; - bson->read_state = BSON_JSON_IN_BSON_TYPE_SCOPE_STARTMAP; - bson->bson_state = BSON_JSON_LF_SCOPE; - bson->code_data.has_scope = true; - } else { - bson->bson_type = BSON_TYPE_CODE; - bson->bson_state = BSON_JSON_LF_CODE; - bson->code_data.has_code = true; - } - } -} - - -static void -_bson_json_bad_key_in_type (bson_json_reader_t *reader, /* IN */ - const uint8_t *val) /* IN */ -{ - bson_json_reader_bson_t *bson = &reader->bson; - - _bson_json_read_set_error ( - reader, "Invalid key \"%s\". Looking for values for type \"%s\"", val, _bson_json_type_name (bson->bson_type)); -} - - -static void -_bson_json_read_map_key (bson_json_reader_t *reader, /* IN */ - const uint8_t *val, /* IN */ - size_t len) /* IN */ -{ - bson_json_reader_bson_t *bson = &reader->bson; - - if (!bson_utf8_validate ((const char *) val, len, false /* allow null */)) { - _bson_json_read_corrupt (reader, "invalid bytes in UTF8 string"); - return; - } - - if (bson->read_state == BSON_JSON_IN_START_MAP) { - if (len > 0 && val[0] == '$' && _is_known_key ((const char *) val, len) && - bson->n >= 0 /* key is in subdocument */) { - bson->read_state = BSON_JSON_IN_BSON_TYPE; - bson->bson_type = (bson_type_t) 0; - memset (&bson->bson_type_data, 0, sizeof bson->bson_type_data); - } else { - bson->read_state = BSON_JSON_REGULAR; - STACK_PUSH_DOC ( - bson_append_document_begin (STACK_BSON_PARENT, bson->key, (int) bson->key_buf.len, STACK_BSON_CHILD)); - } - } else if (bson->read_state == BSON_JSON_IN_SCOPE) { - /* we've read "key" in {$code: "", $scope: {key: ""}}*/ - bson->read_state = BSON_JSON_REGULAR; - STACK_PUSH_SCOPE; - _bson_json_save_map_key (bson, val, len); - } else if (bson->read_state == BSON_JSON_IN_DBPOINTER) { - /* we've read "$ref" or "$id" in {$dbPointer: {$ref: ..., $id: ...}} */ - bson->read_state = BSON_JSON_REGULAR; - STACK_PUSH_DBPOINTER; - _bson_json_save_map_key (bson, val, len); - } - - if (bson->read_state == BSON_JSON_IN_BSON_TYPE) { - HANDLE_OPTION (if, "$regex", BSON_TYPE_REGEX, BSON_JSON_LF_REGEX) - HANDLE_OPTION (else if, "$options", BSON_TYPE_REGEX, BSON_JSON_LF_OPTIONS) - HANDLE_OPTION (else if, "$oid", BSON_TYPE_OID, BSON_JSON_LF_OID) - HANDLE_OPTION (else if, "$binary", BSON_TYPE_BINARY, BSON_JSON_LF_BINARY) - HANDLE_OPTION (else if, "$type", BSON_TYPE_BINARY, BSON_JSON_LF_TYPE) - HANDLE_OPTION (else if, "$uuid", BSON_TYPE_BINARY, BSON_JSON_LF_UUID) - HANDLE_OPTION (else if, "$date", BSON_TYPE_DATE_TIME, BSON_JSON_LF_DATE) - HANDLE_OPTION (else if, "$undefined", BSON_TYPE_UNDEFINED, BSON_JSON_LF_UNDEFINED) - HANDLE_OPTION (else if, "$minKey", BSON_TYPE_MINKEY, BSON_JSON_LF_MINKEY) - HANDLE_OPTION (else if, "$maxKey", BSON_TYPE_MAXKEY, BSON_JSON_LF_MAXKEY) - HANDLE_OPTION (else if, "$numberInt", BSON_TYPE_INT32, BSON_JSON_LF_INT32) - HANDLE_OPTION (else if, "$numberLong", BSON_TYPE_INT64, BSON_JSON_LF_INT64) - HANDLE_OPTION (else if, "$numberDouble", BSON_TYPE_DOUBLE, BSON_JSON_LF_DOUBLE) - HANDLE_OPTION (else if, "$symbol", BSON_TYPE_SYMBOL, BSON_JSON_LF_SYMBOL) - HANDLE_OPTION (else if, "$numberDecimal", BSON_TYPE_DECIMAL128, BSON_JSON_LF_DECIMAL128) - else if (!strcmp ("$timestamp", (const char *) val)) - { - bson->bson_type = BSON_TYPE_TIMESTAMP; - bson->read_state = BSON_JSON_IN_BSON_TYPE_TIMESTAMP_STARTMAP; - } - else if (!strcmp ("$regularExpression", (const char *) val)) - { - bson->bson_type = BSON_TYPE_REGEX; - bson->read_state = BSON_JSON_IN_BSON_TYPE_REGEX_STARTMAP; - } - else if (!strcmp ("$dbPointer", (const char *) val)) - { - /* start parsing "key": {"$dbPointer": {...}}, save "key" for later */ - _bson_json_buf_set (&bson->dbpointer_key, bson->key, bson->key_buf.len); - - bson->bson_type = BSON_TYPE_DBPOINTER; - bson->read_state = BSON_JSON_IN_BSON_TYPE_DBPOINTER_STARTMAP; - } - else if (!strcmp ("$code", (const char *) val)) - { - _bson_json_read_code_or_scope_key (bson, false /* is_scope */, val, len); - } - else if (!strcmp ("$scope", (const char *) val)) - { - _bson_json_read_code_or_scope_key (bson, true /* is_scope */, val, len); - } - else - { - _bson_json_bad_key_in_type (reader, val); - } - } else if (bson->read_state == BSON_JSON_IN_BSON_TYPE_DATE_NUMBERLONG) { - HANDLE_OPTION (if, "$numberLong", BSON_TYPE_DATE_TIME, BSON_JSON_LF_INT64) - else - { - _bson_json_bad_key_in_type (reader, val); - } - } else if (bson->read_state == BSON_JSON_IN_BSON_TYPE_TIMESTAMP_VALUES) { - HANDLE_OPTION (if, "t", BSON_TYPE_TIMESTAMP, BSON_JSON_LF_TIMESTAMP_T) - HANDLE_OPTION (else if, "i", BSON_TYPE_TIMESTAMP, BSON_JSON_LF_TIMESTAMP_I) - else - { - _bson_json_bad_key_in_type (reader, val); - } - } else if (bson->read_state == BSON_JSON_IN_BSON_TYPE_REGEX_VALUES) { - HANDLE_OPTION (if, "pattern", BSON_TYPE_REGEX, BSON_JSON_LF_REGULAR_EXPRESSION_PATTERN) - HANDLE_OPTION (else if, "options", BSON_TYPE_REGEX, BSON_JSON_LF_REGULAR_EXPRESSION_OPTIONS) - else - { - _bson_json_bad_key_in_type (reader, val); - } - } else if (bson->read_state == BSON_JSON_IN_BSON_TYPE_BINARY_VALUES) { - HANDLE_OPTION (if, "base64", BSON_TYPE_BINARY, BSON_JSON_LF_BINARY) - HANDLE_OPTION (else if, "subType", BSON_TYPE_BINARY, BSON_JSON_LF_TYPE) - else - { - _bson_json_bad_key_in_type (reader, val); - } - } else { - _bson_json_save_map_key (bson, val, len); - } -} - - -static void -_bson_json_read_append_binary (bson_json_reader_t *reader, /* IN */ - bson_json_reader_bson_t *bson) /* IN */ -{ - bson_json_bson_data_t *data = &bson->bson_type_data; - - if (data->binary.is_legacy) { - if (!data->binary.has_binary) { - _bson_json_read_set_error (reader, "Missing \"$binary\" after \"$type\" reading type \"binary\""); - return; - } else if (!data->binary.has_subtype) { - _bson_json_read_set_error (reader, "Missing \"$type\" after \"$binary\" reading type \"binary\""); - return; - } - } else { - if (!data->binary.has_binary) { - _bson_json_read_set_error (reader, "Missing \"base64\" after \"subType\" reading type \"binary\""); - return; - } else if (!data->binary.has_subtype) { - _bson_json_read_set_error (reader, "Missing \"subType\" after \"base64\" reading type \"binary\""); - return; - } - } - - if (!bson_append_binary (STACK_BSON_CHILD, - bson->key, - (int) bson->key_buf.len, - data->binary.type, - bson->bson_type_buf[0].buf, - (uint32_t) bson->bson_type_buf[0].len)) { - _bson_json_read_set_error (reader, "Error storing binary data"); - } -} - - -static void -_bson_json_read_append_regex (bson_json_reader_t *reader, /* IN */ - bson_json_reader_bson_t *bson) /* IN */ -{ - bson_json_bson_data_t *data = &bson->bson_type_data; - if (data->regex.is_legacy) { - if (!data->regex.has_pattern) { - _bson_json_read_set_error (reader, "Missing \"$regex\" after \"$options\""); - return; - } - } else if (!data->regex.has_pattern) { - _bson_json_read_set_error (reader, "Missing \"pattern\" after \"options\" in regular expression"); - return; - } else if (!data->regex.has_options) { - _bson_json_read_set_error (reader, "Missing \"options\" after \"pattern\" in regular expression"); - return; - } - - if (!bson_append_regex (STACK_BSON_CHILD, - bson->key, - (int) bson->key_buf.len, - (char *) bson->bson_type_buf[0].buf, - (char *) bson->bson_type_buf[1].buf)) { - _bson_json_read_set_error (reader, "Error storing regex"); - } -} - - -static void -_bson_json_read_append_code (bson_json_reader_t *reader, /* IN */ - bson_json_reader_bson_t *bson) /* IN */ -{ - bson_json_code_t *code_data; - char *code = NULL; - bson_t *scope = NULL; - bool r; - - code_data = &bson->code_data; - - BSON_ASSERT (!code_data->in_scope); - - if (!code_data->has_code) { - _bson_json_read_set_error (reader, "Missing $code after $scope"); - return; - } - - code = (char *) code_data->code_buf.buf; - - if (code_data->has_scope) { - scope = STACK_BSON (1); - } - - /* creates BSON "code" elem, or "code with scope" if scope is not NULL */ - r = bson_append_code_with_scope ( - STACK_BSON_CHILD, (const char *) code_data->key_buf.buf, (int) code_data->key_buf.len, code, scope); - - if (!r) { - _bson_json_read_set_error (reader, "Error storing Javascript code"); - } - - /* keep the buffer but truncate it */ - code_data->key_buf.len = 0; - code_data->has_code = code_data->has_scope = false; -} - - -static void -_bson_json_read_append_dbpointer (bson_json_reader_t *reader, /* IN */ - bson_json_reader_bson_t *bson) /* IN */ -{ - bson_t *db_pointer; - bson_iter_t iter; - const char *ns = NULL; - const bson_oid_t *oid = NULL; - bool r; - - BSON_ASSERT (reader->bson.dbpointer_key.buf); - - db_pointer = STACK_BSON (1); - if (!bson_iter_init (&iter, db_pointer)) { - _bson_json_read_set_error (reader, "Error storing DBPointer"); - return; - } - - while (bson_iter_next (&iter)) { - if (!strcmp (bson_iter_key (&iter), "$id")) { - if (!BSON_ITER_HOLDS_OID (&iter)) { - _bson_json_read_set_error (reader, "$dbPointer.$id must be like {\"$oid\": ...\"}"); - return; - } - - oid = bson_iter_oid (&iter); - } else if (!strcmp (bson_iter_key (&iter), "$ref")) { - if (!BSON_ITER_HOLDS_UTF8 (&iter)) { - _bson_json_read_set_error (reader, "$dbPointer.$ref must be a string like \"db.collection\""); - return; - } - - ns = bson_iter_utf8 (&iter, NULL); - } else { - _bson_json_read_set_error (reader, "$dbPointer contains invalid key: \"%s\"", bson_iter_key (&iter)); - return; - } - } - - if (!oid || !ns) { - _bson_json_read_set_error (reader, "$dbPointer requires both $id and $ref"); - return; - } - - r = bson_append_dbpointer ( - STACK_BSON_CHILD, (char *) reader->bson.dbpointer_key.buf, (int) reader->bson.dbpointer_key.len, ns, oid); - - if (!r) { - _bson_json_read_set_error (reader, "Error storing DBPointer"); - } -} - - -static void -_bson_json_read_append_oid (bson_json_reader_t *reader, /* IN */ - bson_json_reader_bson_t *bson) /* IN */ -{ - if (!bson_append_oid (STACK_BSON_CHILD, bson->key, (int) bson->key_buf.len, &bson->bson_type_data.oid.oid)) { - _bson_json_read_set_error (reader, "Error storing ObjectId"); - } -} - - -static void -_bson_json_read_append_date_time (bson_json_reader_t *reader, /* IN */ - bson_json_reader_bson_t *bson) /* IN */ -{ - if (!bson_append_date_time (STACK_BSON_CHILD, bson->key, (int) bson->key_buf.len, bson->bson_type_data.date.date)) { - _bson_json_read_set_error (reader, "Error storing datetime"); - } -} - - -static void -_bson_json_read_append_timestamp (bson_json_reader_t *reader, /* IN */ - bson_json_reader_bson_t *bson) /* IN */ -{ - if (!bson->bson_type_data.timestamp.has_t) { - _bson_json_read_set_error (reader, "Missing t after $timestamp in BSON_TYPE_TIMESTAMP"); - return; - } else if (!bson->bson_type_data.timestamp.has_i) { - _bson_json_read_set_error (reader, "Missing i after $timestamp in BSON_TYPE_TIMESTAMP"); - return; - } - - bson_append_timestamp (STACK_BSON_CHILD, - bson->key, - (int) bson->key_buf.len, - bson->bson_type_data.timestamp.t, - bson->bson_type_data.timestamp.i); -} - - -static void -_bad_extended_json (bson_json_reader_t *reader) -{ - _bson_json_read_corrupt (reader, "Invalid MongoDB extended JSON"); -} - - -static void -_bson_json_read_end_map (bson_json_reader_t *reader) /* IN */ -{ - bson_json_reader_bson_t *bson = &reader->bson; - bool r = true; - - if (bson->read_state == BSON_JSON_IN_START_MAP) { - bson->read_state = BSON_JSON_REGULAR; - STACK_PUSH_DOC ( - bson_append_document_begin (STACK_BSON_PARENT, bson->key, (int) bson->key_buf.len, STACK_BSON_CHILD)); - } else if (bson->read_state == BSON_JSON_IN_BSON_TYPE_SCOPE_STARTMAP) { - bson->read_state = BSON_JSON_REGULAR; - STACK_PUSH_SCOPE; - } else if (bson->read_state == BSON_JSON_IN_BSON_TYPE_DBPOINTER_STARTMAP) { - /* we've read last "}" in "{$dbPointer: {$id: ..., $ref: ...}}" */ - _bson_json_read_append_dbpointer (reader, bson); - bson->read_state = BSON_JSON_REGULAR; - return; - } - - if (bson->read_state == BSON_JSON_IN_BSON_TYPE) { - if (!bson->key) { - /* invalid, like {$numberLong: "1"} at the document top level */ - _bad_extended_json (reader); - return; - } - - bson->read_state = BSON_JSON_REGULAR; - switch (bson->bson_type) { - case BSON_TYPE_REGEX: - _bson_json_read_append_regex (reader, bson); - break; - case BSON_TYPE_CODE: - case BSON_TYPE_CODEWSCOPE: - /* we've read the closing "}" in "{$code: ..., $scope: ...}" */ - _bson_json_read_append_code (reader, bson); - break; - case BSON_TYPE_OID: - _bson_json_read_append_oid (reader, bson); - break; - case BSON_TYPE_BINARY: - _bson_json_read_append_binary (reader, bson); - break; - case BSON_TYPE_DATE_TIME: - _bson_json_read_append_date_time (reader, bson); - break; - case BSON_TYPE_UNDEFINED: - r = bson_append_undefined (STACK_BSON_CHILD, bson->key, (int) bson->key_buf.len); - break; - case BSON_TYPE_MINKEY: - r = bson_append_minkey (STACK_BSON_CHILD, bson->key, (int) bson->key_buf.len); - break; - case BSON_TYPE_MAXKEY: - r = bson_append_maxkey (STACK_BSON_CHILD, bson->key, (int) bson->key_buf.len); - break; - case BSON_TYPE_INT32: - r = bson_append_int32 ( - STACK_BSON_CHILD, bson->key, (int) bson->key_buf.len, bson->bson_type_data.v_int32.value); - break; - case BSON_TYPE_INT64: - r = bson_append_int64 ( - STACK_BSON_CHILD, bson->key, (int) bson->key_buf.len, bson->bson_type_data.v_int64.value); - break; - case BSON_TYPE_DOUBLE: - r = bson_append_double ( - STACK_BSON_CHILD, bson->key, (int) bson->key_buf.len, bson->bson_type_data.v_double.value); - break; - case BSON_TYPE_DECIMAL128: - r = bson_append_decimal128 ( - STACK_BSON_CHILD, bson->key, (int) bson->key_buf.len, &bson->bson_type_data.v_decimal128.value); - break; - case BSON_TYPE_DBPOINTER: - /* shouldn't set type to DBPointer unless inside $dbPointer: {...} */ - _bson_json_read_set_error (reader, "Internal error: shouldn't be in state BSON_TYPE_DBPOINTER"); - break; - case BSON_TYPE_SYMBOL: - break; - case BSON_TYPE_EOD: - case BSON_TYPE_UTF8: - case BSON_TYPE_DOCUMENT: - case BSON_TYPE_ARRAY: - case BSON_TYPE_BOOL: - case BSON_TYPE_NULL: - case BSON_TYPE_TIMESTAMP: - default: - _bson_json_read_set_error ( - reader, "Internal error: can't parse JSON wrapper for type \"%s\"", _bson_json_type_name (bson->bson_type)); - break; - } - - if (!r) { - _bson_json_read_set_error (reader, "Cannot append value at end of JSON object for key %s", bson->key); - } - - } else if (bson->read_state == BSON_JSON_IN_BSON_TYPE_TIMESTAMP_VALUES) { - if (!bson->key) { - _bad_extended_json (reader); - return; - } - - bson->read_state = BSON_JSON_IN_BSON_TYPE_TIMESTAMP_ENDMAP; - _bson_json_read_append_timestamp (reader, bson); - return; - } else if (bson->read_state == BSON_JSON_IN_BSON_TYPE_REGEX_VALUES) { - if (!bson->key) { - _bad_extended_json (reader); - return; - } - - bson->read_state = BSON_JSON_IN_BSON_TYPE_REGEX_ENDMAP; - _bson_json_read_append_regex (reader, bson); - return; - } else if (bson->read_state == BSON_JSON_IN_BSON_TYPE_BINARY_VALUES) { - if (!bson->key) { - _bad_extended_json (reader); - return; - } - - bson->read_state = BSON_JSON_IN_BSON_TYPE_BINARY_ENDMAP; - _bson_json_read_append_binary (reader, bson); - return; - } else if (bson->read_state == BSON_JSON_IN_BSON_TYPE_TIMESTAMP_ENDMAP) { - bson->read_state = BSON_JSON_REGULAR; - } else if (bson->read_state == BSON_JSON_IN_BSON_TYPE_REGEX_ENDMAP) { - bson->read_state = BSON_JSON_REGULAR; - } else if (bson->read_state == BSON_JSON_IN_BSON_TYPE_BINARY_ENDMAP) { - bson->read_state = BSON_JSON_REGULAR; - } else if (bson->read_state == BSON_JSON_IN_BSON_TYPE_DATE_NUMBERLONG) { - if (!bson->key) { - _bad_extended_json (reader); - return; - } - - bson->read_state = BSON_JSON_IN_BSON_TYPE_DATE_ENDMAP; - - _bson_json_read_append_date_time (reader, bson); - return; - } else if (bson->read_state == BSON_JSON_IN_BSON_TYPE_DATE_ENDMAP) { - bson->read_state = BSON_JSON_REGULAR; - } else if (bson->read_state == BSON_JSON_REGULAR) { - if (STACK_IS_SCOPE) { - bson->read_state = BSON_JSON_IN_BSON_TYPE; - bson->bson_type = BSON_TYPE_CODE; - STACK_POP_SCOPE; - } else if (STACK_IS_DBPOINTER) { - bson->read_state = BSON_JSON_IN_BSON_TYPE_DBPOINTER_STARTMAP; - STACK_POP_DBPOINTER; - } else { - STACK_POP_DOC (bson_append_document_end (STACK_BSON_PARENT, STACK_BSON_CHILD)); - } - - if (bson->n == -1) { - bson->read_state = BSON_JSON_DONE; - } - } else if (bson->read_state == BSON_JSON_IN_SCOPE) { - /* empty $scope */ - BSON_ASSERT (bson->code_data.has_scope); - STACK_PUSH_SCOPE; - STACK_POP_SCOPE; - bson->read_state = BSON_JSON_IN_BSON_TYPE; - bson->bson_type = BSON_TYPE_CODE; - } else if (bson->read_state == BSON_JSON_IN_DBPOINTER) { - /* empty $dbPointer??? */ - _bson_json_read_set_error (reader, "Empty $dbPointer"); - } else { - _bson_json_read_set_error (reader, "Invalid state \"%s\"", read_state_names[bson->read_state]); - } -} - - -static void -_bson_json_read_start_array (bson_json_reader_t *reader) /* IN */ -{ - const char *key; - size_t len; - bson_json_reader_bson_t *bson = &reader->bson; - - if (bson->read_state != BSON_JSON_REGULAR) { - _bson_json_read_set_error (reader, "Invalid read of \"[\" in state \"%s\"", read_state_names[bson->read_state]); - return; - } - - if (bson->n == -1) { - STACK_PUSH_ARRAY (_noop ()); - } else { - _bson_json_read_fixup_key (bson); - key = bson->key; - len = bson->key_buf.len; - - STACK_PUSH_ARRAY (bson_append_array_begin (STACK_BSON_PARENT, key, (int) len, STACK_BSON_CHILD)); - } -} - - -static void -_bson_json_read_end_array (bson_json_reader_t *reader) /* IN */ -{ - bson_json_reader_bson_t *bson = &reader->bson; - - if (bson->read_state != BSON_JSON_REGULAR) { - _bson_json_read_set_error (reader, "Invalid read of \"]\" in state \"%s\"", read_state_names[bson->read_state]); - return; - } - - STACK_POP_ARRAY (bson_append_array_end (STACK_BSON_PARENT, STACK_BSON_CHILD)); - if (bson->n == -1) { - bson->read_state = BSON_JSON_DONE; - } -} - - -/* put unescaped text in reader->bson.unescaped, or set reader->error. - * json_text has length len and it is not null-terminated. */ -static bool -_bson_json_unescape (bson_json_reader_t *reader, struct jsonsl_state_st *state, const char *json_text, ssize_t len) -{ - bson_json_reader_bson_t *reader_bson; - jsonsl_error_t err; - - reader_bson = &reader->bson; - - /* add 1 for NULL */ - _bson_json_buf_ensure (&reader_bson->unescaped, (size_t) len + 1); - - /* length of unescaped str is always <= len */ - reader_bson->unescaped.len = - jsonsl_util_unescape (json_text, (char *) reader_bson->unescaped.buf, (size_t) len, NULL, &err); - - if (err != JSONSL_ERROR_SUCCESS) { - bson_set_error (reader->error, - BSON_ERROR_JSON, - BSON_JSON_ERROR_READ_CORRUPT_JS, - "error near position %d: \"%s\"", - (int) state->pos_begin, - jsonsl_strerror (err)); - return false; - } - - reader_bson->unescaped.buf[reader_bson->unescaped.len] = '\0'; - - return true; -} - - -/* read the buffered JSON plus new data, and fill out @len with its length */ -static const char * -_get_json_text (jsonsl_t json, /* IN */ - struct jsonsl_state_st *state, /* IN */ - const char *buf /* IN */, - ssize_t *len /* OUT */) -{ - bson_json_reader_t *reader; - ssize_t bytes_available; - - reader = (bson_json_reader_t *) json->data; - - BSON_ASSERT (state->pos_cur > state->pos_begin); - - *len = (ssize_t) (state->pos_cur - state->pos_begin); - - bytes_available = buf - json->base; - - if (*len <= bytes_available) { - /* read directly from stream, not from saved JSON */ - return buf - (size_t) *len; - } else { - /* combine saved text with new data from the jsonsl_t */ - ssize_t append = buf - json->base; - - if (append > 0) { - _bson_json_buf_append (&reader->tok_accumulator, buf - append, (size_t) append); - } - - return (const char *) reader->tok_accumulator.buf; - } -} - - -static void -_push_callback (jsonsl_t json, jsonsl_action_t action, struct jsonsl_state_st *state, const char *buf) -{ - bson_json_reader_t *reader = (bson_json_reader_t *) json->data; - - BSON_UNUSED (action); - BSON_UNUSED (buf); - - switch (state->type) { - case JSONSL_T_STRING: - case JSONSL_T_HKEY: - case JSONSL_T_SPECIAL: - case JSONSL_T_UESCAPE: - reader->json_text_pos = state->pos_begin; - break; - case JSONSL_T_OBJECT: - _bson_json_read_start_map (reader); - break; - case JSONSL_T_LIST: - _bson_json_read_start_array (reader); - break; - default: - break; - } -} - - -static void -_pop_callback (jsonsl_t json, jsonsl_action_t action, struct jsonsl_state_st *state, const char *buf) -{ - bson_json_reader_t *reader; - bson_json_reader_bson_t *reader_bson; - ssize_t len; - double d; - const char *obj_text; - - BSON_UNUSED (action); - - reader = (bson_json_reader_t *) json->data; - reader_bson = &reader->bson; - - switch (state->type) { - case JSONSL_T_HKEY: - case JSONSL_T_STRING: - obj_text = _get_json_text (json, state, buf, &len); - BSON_ASSERT (obj_text[0] == '"'); - - /* remove start/end quotes, replace backslash-escapes, null-terminate */ - /* you'd think it would be faster to check if state->nescapes > 0 first, - * but tests show no improvement */ - if (!_bson_json_unescape (reader, state, obj_text + 1, len - 1)) { - /* reader->error is set */ - jsonsl_stop (json); - break; - } - - if (state->type == JSONSL_T_HKEY) { - _bson_json_read_map_key (reader, reader_bson->unescaped.buf, reader_bson->unescaped.len); - } else { - _bson_json_read_string (reader, reader_bson->unescaped.buf, reader_bson->unescaped.len); - } - break; - case JSONSL_T_OBJECT: - _bson_json_read_end_map (reader); - break; - case JSONSL_T_LIST: - _bson_json_read_end_array (reader); - break; - case JSONSL_T_SPECIAL: - obj_text = _get_json_text (json, state, buf, &len); - if (state->special_flags & JSONSL_SPECIALf_NUMNOINT) { - if (_bson_json_parse_double (reader, obj_text, (size_t) len, &d)) { - _bson_json_read_double (reader, d); - } - } else if (state->special_flags & JSONSL_SPECIALf_NUMERIC) { - /* jsonsl puts the unsigned value in state->nelem */ - _bson_json_read_integer (reader, state->nelem, state->special_flags & JSONSL_SPECIALf_SIGNED ? -1 : 1); - } else if (state->special_flags & JSONSL_SPECIALf_BOOLEAN) { - _bson_json_read_boolean (reader, obj_text[0] == 't' ? 1 : 0); - } else if (state->special_flags & JSONSL_SPECIALf_NULL) { - _bson_json_read_null (reader); - } - break; - default: - break; - } - - reader->json_text_pos = -1; - reader->tok_accumulator.len = 0; -} - - -static int -_error_callback (jsonsl_t json, jsonsl_error_t err, struct jsonsl_state_st *state, char *errat) -{ - bson_json_reader_t *reader = (bson_json_reader_t *) json->data; - - BSON_UNUSED (state); - - if (err == JSONSL_ERROR_CANT_INSERT && *errat == '{') { - /* start the next document */ - reader->should_reset = true; - reader->advance = errat - json->base; - return 0; - } - - bson_set_error (reader->error, - BSON_ERROR_JSON, - BSON_JSON_ERROR_READ_CORRUPT_JS, - "Got parse error at \"%c\", position %d: \"%s\"", - *errat, - (int) json->pos, - jsonsl_strerror (err)); - - return 0; -} - - -/* - *-------------------------------------------------------------------------- - * - * bson_json_reader_read -- - * - * Read the next json document from @reader and write its value - * into @bson. @bson will be allocated as part of this process. - * - * @bson MUST be initialized before calling this function as it - * will not be initialized automatically. The reasoning for this - * is so that you can chain together bson_json_reader_t with - * other components like bson_writer_t. - * - * Returns: - * 1 if successful and data was read. - * 0 if successful and no data was read. - * -1 if there was an error and @error is set. - * - * Side effects: - * @error may be set. - * - *-------------------------------------------------------------------------- - */ - -int -bson_json_reader_read (bson_json_reader_t *reader, /* IN */ - bson_t *bson, /* IN */ - bson_error_t *error) /* OUT */ -{ - bson_json_reader_producer_t *p; - ssize_t start_pos; - ssize_t r; - ssize_t buf_offset; - ssize_t accum; - bson_error_t error_tmp; - int ret = 0; - - BSON_ASSERT (reader); - BSON_ASSERT (bson); - - p = &reader->producer; - - reader->bson.bson = bson; - reader->bson.n = -1; - reader->bson.read_state = BSON_JSON_REGULAR; - reader->error = error ? error : &error_tmp; - memset (reader->error, 0, sizeof (bson_error_t)); - - for (;;) { - start_pos = reader->json->pos; - - if (p->bytes_read > 0) { - /* leftover data from previous JSON doc in the stream */ - r = p->bytes_read; - } else { - /* read a chunk of bytes by executing the callback */ - r = p->cb (p->data, p->buf, p->buf_size); - } - - if (r < 0) { - if (error) { - bson_set_error (error, BSON_ERROR_JSON, BSON_JSON_ERROR_READ_CB_FAILURE, "reader cb failed"); - } - ret = -1; - goto cleanup; - } else if (r == 0) { - break; - } else { - ret = 1; - p->bytes_read = (size_t) r; - - jsonsl_feed (reader->json, (const jsonsl_char_t *) p->buf, (size_t) r); - - if (reader->should_reset) { - /* end of a document */ - jsonsl_reset (reader->json); - reader->should_reset = false; - - /* advance past already-parsed data */ - memmove (p->buf, p->buf + reader->advance, r - reader->advance); - p->bytes_read -= reader->advance; - ret = 1; - goto cleanup; - } - - if (reader->error->domain) { - ret = -1; - goto cleanup; - } - - /* accumulate a key or string value */ - if (reader->json_text_pos != -1) { - if (bson_cmp_less_su (reader->json_text_pos, reader->json->pos)) { - BSON_ASSERT (bson_in_range_unsigned (ssize_t, reader->json->pos)); - accum = BSON_MIN ((ssize_t) reader->json->pos - reader->json_text_pos, r); - /* if this chunk stopped mid-token, buf_offset is how far into - * our current chunk the token begins. */ - buf_offset = AT_LEAST_0 (reader->json_text_pos - start_pos); - _bson_json_buf_append (&reader->tok_accumulator, p->buf + buf_offset, (size_t) accum); - } - } - - p->bytes_read = 0; - } - } - -cleanup: - if (ret == 1 && reader->bson.read_state != BSON_JSON_DONE) { - /* data ended in the middle */ - _bson_json_read_corrupt (reader, "%s", "Incomplete JSON"); - return -1; - } - - return ret; -} - - -bson_json_reader_t * -bson_json_reader_new (void *data, /* IN */ - bson_json_reader_cb cb, /* IN */ - bson_json_destroy_cb dcb, /* IN */ - bool allow_multiple, /* unused */ - size_t buf_size) /* IN */ -{ - bson_json_reader_t *r; - bson_json_reader_producer_t *p; - - BSON_UNUSED (allow_multiple); - - r = BSON_ALIGNED_ALLOC0 (bson_json_reader_t); - r->json = jsonsl_new (STACK_MAX); - r->json->error_callback = _error_callback; - r->json->action_callback_PUSH = _push_callback; - r->json->action_callback_POP = _pop_callback; - r->json->data = r; - r->json_text_pos = -1; - jsonsl_enable_all_callbacks (r->json); - - p = &r->producer; - - p->data = data; - p->cb = cb; - p->dcb = dcb; - p->buf_size = buf_size ? buf_size : BSON_JSON_DEFAULT_BUF_SIZE; - p->buf = bson_malloc (p->buf_size); - - return r; -} - - -void -bson_json_reader_destroy (bson_json_reader_t *reader) /* IN */ -{ - int i; - bson_json_reader_producer_t *p; - bson_json_reader_bson_t *b; - - if (!reader) { - return; - } - - p = &reader->producer; - b = &reader->bson; - - if (reader->producer.dcb) { - reader->producer.dcb (reader->producer.data); - } - - bson_free (p->buf); - bson_free (b->key_buf.buf); - bson_free (b->unescaped.buf); - bson_free (b->dbpointer_key.buf); - - /* destroy each bson_t initialized in parser stack frames */ - for (i = 1; i < STACK_MAX; i++) { - if (b->stack[i].type == BSON_JSON_FRAME_INITIAL) { - /* highest the stack grew */ - break; - } - - if (FRAME_TYPE_HAS_BSON (b->stack[i].type)) { - bson_destroy (&b->stack[i].bson); - } - } - - for (i = 0; i < 3; i++) { - bson_free (b->bson_type_buf[i].buf); - } - - _bson_json_code_cleanup (&b->code_data); - - jsonsl_destroy (reader->json); - bson_free (reader->tok_accumulator.buf); - bson_free (reader); -} - - -void -bson_json_opts_set_outermost_array (bson_json_opts_t *opts, bool is_outermost_array) -{ - opts->is_outermost_array = is_outermost_array; -} - - -typedef struct { - const uint8_t *data; - size_t len; - size_t bytes_parsed; -} bson_json_data_reader_t; - - -static ssize_t -_bson_json_data_reader_cb (void *_ctx, uint8_t *buf, size_t len) -{ - size_t bytes; - bson_json_data_reader_t *ctx = (bson_json_data_reader_t *) _ctx; - - if (!ctx->data) { - return -1; - } - - bytes = BSON_MIN (len, ctx->len - ctx->bytes_parsed); - - memcpy (buf, ctx->data + ctx->bytes_parsed, bytes); - - ctx->bytes_parsed += bytes; - - return bytes; -} - - -bson_json_reader_t * -bson_json_data_reader_new (bool allow_multiple, /* IN */ - size_t size) /* IN */ -{ - bson_json_data_reader_t *dr = bson_malloc0 (sizeof *dr); - - return bson_json_reader_new (dr, &_bson_json_data_reader_cb, &bson_free, allow_multiple, size); -} - - -void -bson_json_data_reader_ingest (bson_json_reader_t *reader, /* IN */ - const uint8_t *data, /* IN */ - size_t len) /* IN */ -{ - bson_json_data_reader_t *ctx = (bson_json_data_reader_t *) reader->producer.data; - - ctx->data = data; - ctx->len = len; - ctx->bytes_parsed = 0; -} - - -bson_t * -bson_new_from_json (const uint8_t *data, /* IN */ - ssize_t len, /* IN */ - bson_error_t *error) /* OUT */ -{ - bson_json_reader_t *reader; - bson_t *bson; - int r; - - BSON_ASSERT (data); - - if (len < 0) { - len = (ssize_t) strlen ((const char *) data); - } - - bson = bson_new (); - reader = bson_json_data_reader_new (false, BSON_JSON_DEFAULT_BUF_SIZE); - bson_json_data_reader_ingest (reader, data, len); - r = bson_json_reader_read (reader, bson, error); - bson_json_reader_destroy (reader); - - if (r == 0) { - bson_set_error (error, BSON_ERROR_JSON, BSON_JSON_ERROR_READ_INVALID_PARAM, "Empty JSON string"); - } - - if (r != 1) { - bson_destroy (bson); - return NULL; - } - - return bson; -} - - -bool -bson_init_from_json (bson_t *bson, /* OUT */ - const char *data, /* IN */ - ssize_t len, /* IN */ - bson_error_t *error) /* OUT */ -{ - bson_json_reader_t *reader; - int r; - - BSON_ASSERT (bson); - BSON_ASSERT (data); - - if (len < 0) { - len = strlen (data); - } - - bson_init (bson); - - reader = bson_json_data_reader_new (false, BSON_JSON_DEFAULT_BUF_SIZE); - bson_json_data_reader_ingest (reader, (const uint8_t *) data, len); - r = bson_json_reader_read (reader, bson, error); - bson_json_reader_destroy (reader); - - if (r == 0) { - bson_set_error (error, BSON_ERROR_JSON, BSON_JSON_ERROR_READ_INVALID_PARAM, "Empty JSON string"); - } - - if (r != 1) { - bson_destroy (bson); - return false; - } - - return true; -} - - -static void -_bson_json_reader_handle_fd_destroy (void *handle) /* IN */ -{ - bson_json_reader_handle_fd_t *fd = handle; - - if (fd) { - if ((fd->fd != -1) && fd->do_close) { -#ifdef _WIN32 - _close (fd->fd); -#else - close (fd->fd); -#endif - } - bson_free (fd); - } -} - - -static ssize_t -_bson_json_reader_handle_fd_read (void *handle, /* IN */ - uint8_t *buf, /* IN */ - size_t len) /* IN */ -{ - bson_json_reader_handle_fd_t *fd = handle; - ssize_t ret = -1; - - if (fd && (fd->fd != -1)) { - again: -#ifdef BSON_OS_WIN32 - ret = _read (fd->fd, buf, (unsigned int) len); -#else - ret = read (fd->fd, buf, len); -#endif - if ((ret == -1) && (errno == EAGAIN)) { - goto again; - } - } - - return ret; -} - - -bson_json_reader_t * -bson_json_reader_new_from_fd (int fd, /* IN */ - bool close_on_destroy) /* IN */ -{ - bson_json_reader_handle_fd_t *handle; - - BSON_ASSERT (fd != -1); - - handle = bson_malloc0 (sizeof *handle); - handle->fd = fd; - handle->do_close = close_on_destroy; - - return bson_json_reader_new ( - handle, _bson_json_reader_handle_fd_read, _bson_json_reader_handle_fd_destroy, true, BSON_JSON_DEFAULT_BUF_SIZE); -} - - -bson_json_reader_t * -bson_json_reader_new_from_file (const char *path, /* IN */ - bson_error_t *error) /* OUT */ -{ - char errmsg_buf[BSON_ERROR_BUFFER_SIZE]; - char *errmsg; - int fd = -1; - - BSON_ASSERT (path); - -#ifdef BSON_OS_WIN32 - _sopen_s (&fd, path, (_O_RDONLY | _O_BINARY), _SH_DENYNO, _S_IREAD); -#else - fd = open (path, O_RDONLY); -#endif - - if (fd == -1) { - errmsg = bson_strerror_r (errno, errmsg_buf, sizeof errmsg_buf); - bson_set_error (error, BSON_ERROR_READER, BSON_ERROR_READER_BADFD, "%s", errmsg); - return NULL; - } - - return bson_json_reader_new_from_fd (fd, true); -} diff --git a/bsonjs/bson/bson-json.h b/bsonjs/bson/bson-json.h deleted file mode 100644 index 57f14a7..0000000 --- a/bsonjs/bson/bson-json.h +++ /dev/null @@ -1,91 +0,0 @@ -/* - * Copyright 2014 MongoDB, Inc. - * - * 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. - */ - -#include - - -#ifndef BSON_JSON_H -#define BSON_JSON_H - - -#include "bson.h" - - -BSON_BEGIN_DECLS - - -typedef struct _bson_json_reader_t bson_json_reader_t; - - -typedef enum { - BSON_JSON_ERROR_READ_CORRUPT_JS = 1, - BSON_JSON_ERROR_READ_INVALID_PARAM, - BSON_JSON_ERROR_READ_CB_FAILURE, -} bson_json_error_code_t; - - -/** - * BSON_MAX_LEN_UNLIMITED - * - * Denotes unlimited length limit when converting BSON to JSON. - */ -#define BSON_MAX_LEN_UNLIMITED -1 - -/** - * bson_json_mode_t: - * - * This enumeration contains the different modes to serialize BSON into extended - * JSON. - */ -typedef enum { - BSON_JSON_MODE_LEGACY, - BSON_JSON_MODE_CANONICAL, - BSON_JSON_MODE_RELAXED, -} bson_json_mode_t; - - -BSON_EXPORT (bson_json_opts_t *) -bson_json_opts_new (bson_json_mode_t mode, int32_t max_len); -BSON_EXPORT (void) -bson_json_opts_destroy (bson_json_opts_t *opts); -BSON_EXPORT (void) -bson_json_opts_set_outermost_array (bson_json_opts_t *opts, bool is_outermost_array); - -typedef ssize_t (*bson_json_reader_cb) (void *handle, uint8_t *buf, size_t count); -typedef void (*bson_json_destroy_cb) (void *handle); - - -BSON_EXPORT (bson_json_reader_t *) -bson_json_reader_new ( - void *data, bson_json_reader_cb cb, bson_json_destroy_cb dcb, bool allow_multiple, size_t buf_size); -BSON_EXPORT (bson_json_reader_t *) -bson_json_reader_new_from_fd (int fd, bool close_on_destroy); -BSON_EXPORT (bson_json_reader_t *) -bson_json_reader_new_from_file (const char *filename, bson_error_t *error); -BSON_EXPORT (void) -bson_json_reader_destroy (bson_json_reader_t *reader); -BSON_EXPORT (int) -bson_json_reader_read (bson_json_reader_t *reader, bson_t *bson, bson_error_t *error); -BSON_EXPORT (bson_json_reader_t *) -bson_json_data_reader_new (bool allow_multiple, size_t size); -BSON_EXPORT (void) -bson_json_data_reader_ingest (bson_json_reader_t *reader, const uint8_t *data, size_t len); - - -BSON_END_DECLS - - -#endif /* BSON_JSON_H */ diff --git a/bsonjs/bson/bson-keys.c b/bsonjs/bson/bson-keys.c deleted file mode 100644 index 9ba141c..0000000 --- a/bsonjs/bson/bson-keys.c +++ /dev/null @@ -1,145 +0,0 @@ -/* - * Copyright 2013 MongoDB, Inc. - * - * 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. - */ - - -#include - -#include -#include - - -static const char *gUint32Strs[] = { - "0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "10", "11", "12", "13", "14", "15", - "16", "17", "18", "19", "20", "21", "22", "23", "24", "25", "26", "27", "28", "29", "30", "31", - "32", "33", "34", "35", "36", "37", "38", "39", "40", "41", "42", "43", "44", "45", "46", "47", - "48", "49", "50", "51", "52", "53", "54", "55", "56", "57", "58", "59", "60", "61", "62", "63", - "64", "65", "66", "67", "68", "69", "70", "71", "72", "73", "74", "75", "76", "77", "78", "79", - "80", "81", "82", "83", "84", "85", "86", "87", "88", "89", "90", "91", "92", "93", "94", "95", - "96", "97", "98", "99", "100", "101", "102", "103", "104", "105", "106", "107", "108", "109", "110", "111", - "112", "113", "114", "115", "116", "117", "118", "119", "120", "121", "122", "123", "124", "125", "126", "127", - "128", "129", "130", "131", "132", "133", "134", "135", "136", "137", "138", "139", "140", "141", "142", "143", - "144", "145", "146", "147", "148", "149", "150", "151", "152", "153", "154", "155", "156", "157", "158", "159", - "160", "161", "162", "163", "164", "165", "166", "167", "168", "169", "170", "171", "172", "173", "174", "175", - "176", "177", "178", "179", "180", "181", "182", "183", "184", "185", "186", "187", "188", "189", "190", "191", - "192", "193", "194", "195", "196", "197", "198", "199", "200", "201", "202", "203", "204", "205", "206", "207", - "208", "209", "210", "211", "212", "213", "214", "215", "216", "217", "218", "219", "220", "221", "222", "223", - "224", "225", "226", "227", "228", "229", "230", "231", "232", "233", "234", "235", "236", "237", "238", "239", - "240", "241", "242", "243", "244", "245", "246", "247", "248", "249", "250", "251", "252", "253", "254", "255", - "256", "257", "258", "259", "260", "261", "262", "263", "264", "265", "266", "267", "268", "269", "270", "271", - "272", "273", "274", "275", "276", "277", "278", "279", "280", "281", "282", "283", "284", "285", "286", "287", - "288", "289", "290", "291", "292", "293", "294", "295", "296", "297", "298", "299", "300", "301", "302", "303", - "304", "305", "306", "307", "308", "309", "310", "311", "312", "313", "314", "315", "316", "317", "318", "319", - "320", "321", "322", "323", "324", "325", "326", "327", "328", "329", "330", "331", "332", "333", "334", "335", - "336", "337", "338", "339", "340", "341", "342", "343", "344", "345", "346", "347", "348", "349", "350", "351", - "352", "353", "354", "355", "356", "357", "358", "359", "360", "361", "362", "363", "364", "365", "366", "367", - "368", "369", "370", "371", "372", "373", "374", "375", "376", "377", "378", "379", "380", "381", "382", "383", - "384", "385", "386", "387", "388", "389", "390", "391", "392", "393", "394", "395", "396", "397", "398", "399", - "400", "401", "402", "403", "404", "405", "406", "407", "408", "409", "410", "411", "412", "413", "414", "415", - "416", "417", "418", "419", "420", "421", "422", "423", "424", "425", "426", "427", "428", "429", "430", "431", - "432", "433", "434", "435", "436", "437", "438", "439", "440", "441", "442", "443", "444", "445", "446", "447", - "448", "449", "450", "451", "452", "453", "454", "455", "456", "457", "458", "459", "460", "461", "462", "463", - "464", "465", "466", "467", "468", "469", "470", "471", "472", "473", "474", "475", "476", "477", "478", "479", - "480", "481", "482", "483", "484", "485", "486", "487", "488", "489", "490", "491", "492", "493", "494", "495", - "496", "497", "498", "499", "500", "501", "502", "503", "504", "505", "506", "507", "508", "509", "510", "511", - "512", "513", "514", "515", "516", "517", "518", "519", "520", "521", "522", "523", "524", "525", "526", "527", - "528", "529", "530", "531", "532", "533", "534", "535", "536", "537", "538", "539", "540", "541", "542", "543", - "544", "545", "546", "547", "548", "549", "550", "551", "552", "553", "554", "555", "556", "557", "558", "559", - "560", "561", "562", "563", "564", "565", "566", "567", "568", "569", "570", "571", "572", "573", "574", "575", - "576", "577", "578", "579", "580", "581", "582", "583", "584", "585", "586", "587", "588", "589", "590", "591", - "592", "593", "594", "595", "596", "597", "598", "599", "600", "601", "602", "603", "604", "605", "606", "607", - "608", "609", "610", "611", "612", "613", "614", "615", "616", "617", "618", "619", "620", "621", "622", "623", - "624", "625", "626", "627", "628", "629", "630", "631", "632", "633", "634", "635", "636", "637", "638", "639", - "640", "641", "642", "643", "644", "645", "646", "647", "648", "649", "650", "651", "652", "653", "654", "655", - "656", "657", "658", "659", "660", "661", "662", "663", "664", "665", "666", "667", "668", "669", "670", "671", - "672", "673", "674", "675", "676", "677", "678", "679", "680", "681", "682", "683", "684", "685", "686", "687", - "688", "689", "690", "691", "692", "693", "694", "695", "696", "697", "698", "699", "700", "701", "702", "703", - "704", "705", "706", "707", "708", "709", "710", "711", "712", "713", "714", "715", "716", "717", "718", "719", - "720", "721", "722", "723", "724", "725", "726", "727", "728", "729", "730", "731", "732", "733", "734", "735", - "736", "737", "738", "739", "740", "741", "742", "743", "744", "745", "746", "747", "748", "749", "750", "751", - "752", "753", "754", "755", "756", "757", "758", "759", "760", "761", "762", "763", "764", "765", "766", "767", - "768", "769", "770", "771", "772", "773", "774", "775", "776", "777", "778", "779", "780", "781", "782", "783", - "784", "785", "786", "787", "788", "789", "790", "791", "792", "793", "794", "795", "796", "797", "798", "799", - "800", "801", "802", "803", "804", "805", "806", "807", "808", "809", "810", "811", "812", "813", "814", "815", - "816", "817", "818", "819", "820", "821", "822", "823", "824", "825", "826", "827", "828", "829", "830", "831", - "832", "833", "834", "835", "836", "837", "838", "839", "840", "841", "842", "843", "844", "845", "846", "847", - "848", "849", "850", "851", "852", "853", "854", "855", "856", "857", "858", "859", "860", "861", "862", "863", - "864", "865", "866", "867", "868", "869", "870", "871", "872", "873", "874", "875", "876", "877", "878", "879", - "880", "881", "882", "883", "884", "885", "886", "887", "888", "889", "890", "891", "892", "893", "894", "895", - "896", "897", "898", "899", "900", "901", "902", "903", "904", "905", "906", "907", "908", "909", "910", "911", - "912", "913", "914", "915", "916", "917", "918", "919", "920", "921", "922", "923", "924", "925", "926", "927", - "928", "929", "930", "931", "932", "933", "934", "935", "936", "937", "938", "939", "940", "941", "942", "943", - "944", "945", "946", "947", "948", "949", "950", "951", "952", "953", "954", "955", "956", "957", "958", "959", - "960", "961", "962", "963", "964", "965", "966", "967", "968", "969", "970", "971", "972", "973", "974", "975", - "976", "977", "978", "979", "980", "981", "982", "983", "984", "985", "986", "987", "988", "989", "990", "991", - "992", "993", "994", "995", "996", "997", "998", "999"}; - - -/* - *-------------------------------------------------------------------------- - * - * bson_uint32_to_string -- - * - * Converts @value to a string. - * - * If @value is from 0 to 1000, it will use a constant string in the - * data section of the library. - * - * If not, a string will be formatted using @str and snprintf(). This - * is much slower, of course and therefore we try to optimize it out. - * - * @strptr will always be set. It will either point to @str or a - * constant string. You will want to use this as your key. - * - * Parameters: - * @value: A #uint32_t to convert to string. - * @strptr: (out): A pointer to the resulting string. - * @str: (out): Storage for a string made with snprintf. - * @size: Size of @str. - * - * Returns: - * The number of bytes in the resulting string excluding the NULL - * terminator. If the output requires more than @size bytes, then @size - * bytes are written and the result is the number of bytes required - * (excluding the NULL terminator) - * - * Side effects: - * None. - * - *-------------------------------------------------------------------------- - */ - -size_t -bson_uint32_to_string (uint32_t value, /* IN */ - const char **strptr, /* OUT */ - char *str, /* OUT */ - size_t size) /* IN */ -{ - if (value < 1000) { - *strptr = gUint32Strs[value]; - - if (value < 10) { - return 1; - } else if (value < 100) { - return 2; - } else { - return 3; - } - } - - *strptr = str; - - return bson_snprintf (str, size, "%u", value); -} diff --git a/bsonjs/bson/bson-keys.h b/bsonjs/bson/bson-keys.h deleted file mode 100644 index 14f19f3..0000000 --- a/bsonjs/bson/bson-keys.h +++ /dev/null @@ -1,38 +0,0 @@ -/* - * Copyright 2013 MongoDB, Inc. - * - * 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. - */ - -#include - - -#ifndef BSON_KEYS_H -#define BSON_KEYS_H - - -#include -#include - - -BSON_BEGIN_DECLS - - -BSON_EXPORT (size_t) -bson_uint32_to_string (uint32_t value, const char **strptr, char *str, size_t size); - - -BSON_END_DECLS - - -#endif /* BSON_KEYS_H */ diff --git a/bsonjs/bson/bson-macros.h b/bsonjs/bson/bson-macros.h deleted file mode 100644 index f926391..0000000 --- a/bsonjs/bson/bson-macros.h +++ /dev/null @@ -1,365 +0,0 @@ -/* - * Copyright 2013 MongoDB, Inc. - * - * 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. - */ - -#include - - -#ifndef BSON_MACROS_H -#define BSON_MACROS_H - - -#include - -#ifdef __cplusplus -#include -#endif - -#include - - -#if BSON_OS == 1 -#define BSON_OS_UNIX -#elif BSON_OS == 2 -#define BSON_OS_WIN32 -#else -#error "Unknown operating system." -#endif - - -#ifdef __cplusplus -#define BSON_BEGIN_DECLS extern "C" { -#define BSON_END_DECLS } -#else -#define BSON_BEGIN_DECLS -#define BSON_END_DECLS -#endif - - -#if defined(__GNUC__) -#define BSON_GNUC_CHECK_VERSION(major, minor) \ - ((__GNUC__ > (major)) || ((__GNUC__ == (major)) && (__GNUC_MINOR__ >= (minor)))) -#else -#define BSON_GNUC_CHECK_VERSION(major, minor) 0 -#endif - - -#if defined(__GNUC__) -#define BSON_GNUC_IS_VERSION(major, minor) ((__GNUC__ == (major)) && (__GNUC_MINOR__ == (minor))) -#else -#define BSON_GNUC_IS_VERSION(major, minor) 0 -#endif - - -/* Decorate public functions: - * - if BSON_STATIC, we're compiling a static libbson or a program - * that uses libbson as a static library. Don't decorate functions. - * - else if BSON_COMPILATION, we're compiling a shared libbson, mark - * public functions for export from the shared lib - * - else, we're compiling a program that uses libbson as a shared library, - * mark public functions as DLL imports for Microsoft Visual C - */ - -#ifdef _MSC_VER -/* - * Microsoft Visual C - */ -#ifdef BSON_STATIC -#define BSON_API -#elif defined(BSON_COMPILATION) -#define BSON_API __declspec (dllexport) -#else -#define BSON_API __declspec (dllimport) -#endif -#define BSON_CALL __cdecl - -#elif defined(__GNUC__) -/* - * GCC - */ -#ifdef BSON_STATIC -#define BSON_API -#elif defined(BSON_COMPILATION) -#define BSON_API __attribute__ ((visibility ("default"))) -#else -#define BSON_API -#endif -#define BSON_CALL - -#else -/* - * Other compilers - */ -#define BSON_API -#define BSON_CALL - -#endif - -#define BSON_EXPORT(type) BSON_API type BSON_CALL - - -#ifdef MIN -#define BSON_MIN MIN -#elif defined(__cplusplus) -#define BSON_MIN(a, b) ((std::min) (a, b)) -#elif defined(_MSC_VER) -#define BSON_MIN(a, b) ((a) < (b) ? (a) : (b)) -#else -#define BSON_MIN(a, b) (((a) < (b)) ? (a) : (b)) -#endif - - -#ifdef MAX -#define BSON_MAX MAX -#elif defined(__cplusplus) -#define BSON_MAX(a, b) ((std::max) (a, b)) -#elif defined(_MSC_VER) -#define BSON_MAX(a, b) ((a) > (b) ? (a) : (b)) -#else -#define BSON_MAX(a, b) (((a) > (b)) ? (a) : (b)) -#endif - - -#ifdef ABS -#define BSON_ABS ABS -#else -#define BSON_ABS(a) (((a) < 0) ? ((a) * -1) : (a)) -#endif - -#if defined(__cplusplus) && (__cplusplus >= 201103L || defined(_MSVC_LANG)) -#define BSON_ALIGNOF(expr) alignof (expr) -#elif defined(__STDC_VERSION__) && __STDC_VERSION__ >= 201112L -#define BSON_ALIGNOF(expr) _Alignof (expr) -#else -#if defined(_MSC_VER) -#define BSON_ALIGNOF(expr) __alignof (expr) -#else -#define BSON_ALIGNOF(expr) __alignof__ (expr) -#endif -#endif // __STDC_VERSION__ >= 201112L - -#ifdef _MSC_VER -// __declspec (align (_N)) only permits integer literals as _N. -#ifdef _WIN64 -#define BSON_ALIGN_OF_PTR 8 -#else -#define BSON_ALIGN_OF_PTR 4 -#endif -#else -#define BSON_ALIGN_OF_PTR (BSON_ALIGNOF (void *)) -#endif - -#ifdef BSON_EXTRA_ALIGN -#if defined(_MSC_VER) -#define BSON_ALIGNED_BEGIN(_N) __declspec (align (_N)) -#define BSON_ALIGNED_END(_N) -#else -#define BSON_ALIGNED_BEGIN(_N) -#define BSON_ALIGNED_END(_N) __attribute__ ((aligned (_N))) -#endif -#else -#if defined(_MSC_VER) -#define BSON_ALIGNED_BEGIN(_N) __declspec (align (BSON_ALIGN_OF_PTR)) -#define BSON_ALIGNED_END(_N) -#else -#define BSON_ALIGNED_BEGIN(_N) -#define BSON_ALIGNED_END(_N) __attribute__ ((aligned ((_N) > BSON_ALIGN_OF_PTR ? BSON_ALIGN_OF_PTR : (_N)))) -#endif -#endif - - -#define bson_str_empty(s) (!s[0]) -#define bson_str_empty0(s) (!s || !s[0]) - - -#if defined(_MSC_VER) -#define BSON_FUNC __FUNCTION__ -#else -#define BSON_FUNC __func__ -#endif - -#define BSON_ASSERT(test) \ - do { \ - if (!(BSON_LIKELY (test))) { \ - fprintf (stderr, "%s:%d %s(): precondition failed: %s\n", __FILE__, __LINE__, BSON_FUNC, #test); \ - abort (); \ - } \ - } while (0) - -/** - * @brief Assert the expression `Assertion`, and evaluates to `Value` on - * success. - */ -#define BSON_ASSERT_INLINE(Assertion, Value) \ - ((void) ((Assertion) \ - ? (0) \ - : ((fprintf (stderr, "%s:%d %s(): Assertion '%s' failed", __FILE__, __LINE__, BSON_FUNC, #Assertion), \ - abort ()), \ - 0)), \ - Value) - -/** - * @brief Assert that the given pointer is non-NULL, while also evaluating to - * that pointer. - * - * Can be used to inline assertions with a pointer dereference: - * - * ``` - * foo* f = get_foo(); - * bar* b = BSON_ASSERT_PTR_INLINE(f)->bar_value; - * ``` - */ -#define BSON_ASSERT_PTR_INLINE(Pointer) BSON_ASSERT_INLINE ((Pointer) != NULL, (Pointer)) - -/* Used for asserting parameters to provide a more precise error message */ -#define BSON_ASSERT_PARAM(param) \ - do { \ - if ((BSON_UNLIKELY (param == NULL))) { \ - fprintf (stderr, "The parameter: %s, in function %s, cannot be NULL\n", #param, BSON_FUNC); \ - abort (); \ - } \ - } while (0) - -/* obsolete macros, preserved for compatibility */ -#define BSON_STATIC_ASSERT(s) BSON_STATIC_ASSERT_ (s, __LINE__) -#define BSON_STATIC_ASSERT_JOIN(a, b) BSON_STATIC_ASSERT_JOIN2 (a, b) -#define BSON_STATIC_ASSERT_JOIN2(a, b) a##b -#define BSON_STATIC_ASSERT_(s, l) typedef char BSON_STATIC_ASSERT_JOIN (static_assert_test_, __LINE__)[(s) ? 1 : -1] - -/* modern macros */ -#define BSON_STATIC_ASSERT2(_name, _s) BSON_STATIC_ASSERT2_ (_s, __LINE__, _name) -#define BSON_STATIC_ASSERT_JOIN3(_a, _b, _name) BSON_STATIC_ASSERT_JOIN4 (_a, _b, _name) -#define BSON_STATIC_ASSERT_JOIN4(_a, _b, _name) _a##_b##_name -#define BSON_STATIC_ASSERT2_(_s, _l, _name) \ - typedef char BSON_STATIC_ASSERT_JOIN3 (static_assert_test_, __LINE__, _name)[(_s) ? 1 : -1] - - -#if defined(__GNUC__) -#define BSON_GNUC_PURE __attribute__ ((pure)) -#define BSON_GNUC_WARN_UNUSED_RESULT __attribute__ ((warn_unused_result)) -#else -#define BSON_GNUC_PURE -#define BSON_GNUC_WARN_UNUSED_RESULT -#endif - - -#if BSON_GNUC_CHECK_VERSION(4, 0) && !defined(_WIN32) -#define BSON_GNUC_NULL_TERMINATED __attribute__ ((sentinel)) -#define BSON_GNUC_INTERNAL __attribute__ ((visibility ("hidden"))) -#else -#define BSON_GNUC_NULL_TERMINATED -#define BSON_GNUC_INTERNAL -#endif - - -#if defined(__GNUC__) -#define BSON_LIKELY(x) __builtin_expect (!!(x), 1) -#define BSON_UNLIKELY(x) __builtin_expect (!!(x), 0) -#else -#define BSON_LIKELY(v) v -#define BSON_UNLIKELY(v) v -#endif - - -#if defined(__clang__) -#define BSON_GNUC_PRINTF(f, v) __attribute__ ((format (printf, f, v))) -#elif BSON_GNUC_CHECK_VERSION(4, 4) -#define BSON_GNUC_PRINTF(f, v) __attribute__ ((format (gnu_printf, f, v))) -#else -#define BSON_GNUC_PRINTF(f, v) -#endif - - -#if defined(__LP64__) || defined(_LP64) -#define BSON_WORD_SIZE 64 -#else -#define BSON_WORD_SIZE 32 -#endif - - -#if defined(_MSC_VER) -#define BSON_INLINE __inline -#else -#define BSON_INLINE __inline__ -#endif - - -#ifdef _MSC_VER -#define BSON_ENSURE_ARRAY_PARAM_SIZE(_n) -#define BSON_TYPEOF decltype -#else -#define BSON_ENSURE_ARRAY_PARAM_SIZE(_n) static (_n) -#define BSON_TYPEOF typeof -#endif - - -#if BSON_GNUC_CHECK_VERSION(3, 1) -#define BSON_GNUC_DEPRECATED __attribute__ ((__deprecated__)) -#else -#define BSON_GNUC_DEPRECATED -#endif - -#define BSON_CONCAT_IMPL(a, ...) a##__VA_ARGS__ -#define BSON_CONCAT(a, ...) BSON_CONCAT_IMPL (a, __VA_ARGS__) -#define BSON_CONCAT3(a, b, c) BSON_CONCAT (a, BSON_CONCAT (b, c)) -#define BSON_CONCAT4(a, b, c, d) BSON_CONCAT (BSON_CONCAT (a, b), BSON_CONCAT (c, d)) - -#if BSON_GNUC_CHECK_VERSION(4, 5) -#define BSON_GNUC_DEPRECATED_FOR(f) __attribute__ ((deprecated ("Use " #f " instead"))) -#else -#define BSON_GNUC_DEPRECATED_FOR(f) BSON_GNUC_DEPRECATED -#endif - -/** - * @brief String-ify the given argument - */ -#define BSON_STR(...) #__VA_ARGS__ - -/** - * @brief Mark the attached declared entity as "possibly-unused." - * - * Does nothing on MSVC. - */ -#if defined(__GNUC__) || defined(__clang__) -#define BSON_MAYBE_UNUSED __attribute__ ((unused)) -#else -#define BSON_MAYBE_UNUSED /* Nothing for other compilers */ -#endif - -/** - * @brief Mark a point in the code as unreachable. If the point is reached, the - * program will abort with an error message. - * - * @param What A string to include in the error message if this point is ever - * executed. - */ -#define BSON_UNREACHABLE(What) \ - do { \ - fprintf (stderr, "%s:%d %s(): Unreachable code reached: %s\n", __FILE__, __LINE__, BSON_FUNC, What); \ - abort (); \ - } while (0) - -/** - * @brief Silence warnings for deliberately unused variables or parameters. - * - * @param expr An unused variable or parameter. - * - */ -#define BSON_UNUSED(expr) \ - do { \ - (void) (expr); \ - } while (0) - -#endif /* BSON_MACROS_H */ diff --git a/bsonjs/bson/bson-md5.c b/bsonjs/bson/bson-md5.c deleted file mode 100644 index 5c736cf..0000000 --- a/bsonjs/bson/bson-md5.c +++ /dev/null @@ -1,24 +0,0 @@ -#include - -#include -#include "common-md5-private.h" - - -void -bson_md5_init (bson_md5_t *pms) -{ - mcommon_md5_init (pms); -} - - -void -bson_md5_append (bson_md5_t *pms, const uint8_t *data, uint32_t nbytes) -{ - mcommon_md5_append (pms, data, nbytes); -} - -void -bson_md5_finish (bson_md5_t *pms, uint8_t digest[16]) -{ - mcommon_md5_finish (pms, digest); -} diff --git a/bsonjs/bson/bson-md5.h b/bsonjs/bson/bson-md5.h deleted file mode 100644 index 77a1677..0000000 --- a/bsonjs/bson/bson-md5.h +++ /dev/null @@ -1,87 +0,0 @@ -/* - Copyright (C) 1999, 2002 Aladdin Enterprises. All rights reserved. - - This software is provided 'as-is', without any express or implied - warranty. In no event will the authors be held liable for any damages - arising from the use of this software. - - Permission is granted to anyone to use this software for any purpose, - including commercial applications, and to alter it and redistribute it - freely, subject to the following restrictions: - - 1. The origin of this software must not be misrepresented; you must not - claim that you wrote the original software. If you use this software - in a product, an acknowledgement in the product documentation would be - appreciated but is not required. - 2. Altered source versions must be plainly marked as such, and must not be - misrepresented as being the original software. - 3. This notice may not be removed or altered from any source distribution. - - L. Peter Deutsch - ghost@aladdin.com - - */ -/* $Id: md5.h,v 1.4 2002/04/13 19:20:28 lpd Exp $ */ -/* - Independent implementation of MD5 (RFC 1321). - - This code implements the MD5 Algorithm defined in RFC 1321, whose - text is available at - http://www.ietf.org/rfc/rfc1321.txt - The code is derived from the text of the RFC, including the test suite - (section A.5) but excluding the rest of Appendix A. It does not include - any code or documentation that is identified in the RFC as being - copyrighted. - - The original and principal author of md5.h is L. Peter Deutsch - . Other authors are noted in the change history - that follows (in reverse chronological order): - - 2002-04-13 lpd Removed support for non-ANSI compilers; removed - references to Ghostscript; clarified derivation from RFC 1321; - now handles byte order either statically or dynamically. - 1999-11-04 lpd Edited comments slightly for automatic TOC extraction. - 1999-10-18 lpd Fixed typo in header comment (ansi2knr rather than md5); - added conditionalization for C++ compilation from Martin - Purschke . - 1999-05-03 lpd Original version. - */ - - -/* - * The following MD5 implementation has been modified to use types as - * specified in libbson. - */ - -#include - - -#ifndef BSON_MD5_H -#define BSON_MD5_H - - -#include - - -BSON_BEGIN_DECLS - - -typedef struct { - uint32_t count[2]; /* message length in bits, lsw first */ - uint32_t abcd[4]; /* digest buffer */ - uint8_t buf[64]; /* accumulate block */ -} bson_md5_t; - - -BSON_EXPORT (void) -bson_md5_init (bson_md5_t *pms) BSON_GNUC_DEPRECATED; -BSON_EXPORT (void) -bson_md5_append (bson_md5_t *pms, const uint8_t *data, uint32_t nbytes) BSON_GNUC_DEPRECATED; -BSON_EXPORT (void) -bson_md5_finish (bson_md5_t *pms, uint8_t digest[16]) BSON_GNUC_DEPRECATED; - - -BSON_END_DECLS - - -#endif /* BSON_MD5_H */ diff --git a/bsonjs/bson/bson-memory.c b/bsonjs/bson/bson-memory.c deleted file mode 100644 index 6c37003..0000000 --- a/bsonjs/bson/bson-memory.c +++ /dev/null @@ -1,432 +0,0 @@ -/* - * Copyright 2013 MongoDB, Inc. - * - * 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. - */ - - -#include -#include -#include -#include - -#include -#include -#include - - -// Ensure size of exported structs are stable. -BSON_STATIC_ASSERT2 (bson_mem_vtable_t, sizeof (bson_mem_vtable_t) == sizeof (void *) * 8u); - - -// For compatibility with C standards prior to C11. -static void * -_aligned_alloc_impl (size_t alignment, size_t num_bytes) -#if defined(__STDC_VERSION__) && __STDC_VERSION__ >= 201112L && !defined(_WIN32) && !defined(__ANDROID__) && \ - !defined(_AIX) -{ - return aligned_alloc (alignment, num_bytes); -} -#elif defined(_POSIX_C_SOURCE) && _POSIX_C_SOURCE >= 200112L -{ - void *mem = NULL; - - // Workaround for https://gcc.gnu.org/bugzilla/show_bug.cgi?id=66425. - BSON_MAYBE_UNUSED int ret = posix_memalign (&mem, alignment, num_bytes); - - return mem; -} -#else -{ - // Fallback to simple malloc even if it does not satisfy alignment - // requirements. Note: Visual C++ _aligned_malloc requires using - // _aligned_free instead of free and modifies errno on failure, both of which - // breaks symmetry with C11 aligned_alloc, so it is deliberately not used. - BSON_UNUSED (alignment); - return malloc (num_bytes); -} -#endif - - -static bson_mem_vtable_t gMemVtable = {.malloc = malloc, - .calloc = calloc, - .realloc = realloc, - .free = free, - .aligned_alloc = _aligned_alloc_impl, - .padding = {0}}; - - -/* - *-------------------------------------------------------------------------- - * - * bson_malloc -- - * - * Allocates @num_bytes of memory and returns a pointer to it. If - * malloc failed to allocate the memory, abort() is called. - * - * Libbson does not try to handle OOM conditions as it is beyond the - * scope of this library to handle so appropriately. - * - * Parameters: - * @num_bytes: The number of bytes to allocate. - * - * Returns: - * A pointer if successful; otherwise abort() is called and this - * function will never return. - * - * Side effects: - * None. - * - *-------------------------------------------------------------------------- - */ - -void * -bson_malloc (size_t num_bytes) /* IN */ -{ - void *mem = NULL; - - if (BSON_LIKELY (num_bytes)) { - if (BSON_UNLIKELY (!(mem = gMemVtable.malloc (num_bytes)))) { - fprintf (stderr, "Failure to allocate memory in bson_malloc(). errno: %d.\n", errno); - abort (); - } - } - - return mem; -} - - -/* - *-------------------------------------------------------------------------- - * - * bson_malloc0 -- - * - * Like bson_malloc() except the memory is zeroed first. This is - * similar to calloc() except that abort() is called in case of - * failure to allocate memory. - * - * Parameters: - * @num_bytes: The number of bytes to allocate. - * - * Returns: - * A pointer if successful; otherwise abort() is called and this - * function will never return. - * - * Side effects: - * None. - * - *-------------------------------------------------------------------------- - */ - -void * -bson_malloc0 (size_t num_bytes) /* IN */ -{ - void *mem = NULL; - - if (BSON_LIKELY (num_bytes)) { - if (BSON_UNLIKELY (!(mem = gMemVtable.calloc (1, num_bytes)))) { - fprintf (stderr, "Failure to allocate memory in bson_malloc0(). errno: %d.\n", errno); - abort (); - } - } - - return mem; -} - - -/* - *-------------------------------------------------------------------------- - * - * bson_aligned_alloc -- - * - * Allocates @num_bytes of memory with an alignment of @alignment and - * returns a pointer to it. If malloc failed to allocate the memory, - * abort() is called. - * - * Libbson does not try to handle OOM conditions as it is beyond the - * scope of this library to handle so appropriately. - * - * Parameters: - * @alignment: The alignment of the allocated bytes of memory. - * @num_bytes: The number of bytes to allocate. - * - * Returns: - * A pointer if successful; otherwise abort() is called and this - * function will never return. - * - * Side effects: - * None. - * - *-------------------------------------------------------------------------- - */ - -void * -bson_aligned_alloc (size_t alignment /* IN */, size_t num_bytes /* IN */) -{ - void *mem = NULL; - - if (BSON_LIKELY (num_bytes)) { - if (BSON_UNLIKELY (!(mem = gMemVtable.aligned_alloc (alignment, num_bytes)))) { - fprintf (stderr, "Failure to allocate memory in bson_aligned_alloc()\n"); - abort (); - } - } - - return mem; -} - - -/* - *-------------------------------------------------------------------------- - * - * bson_aligned_alloc0 -- - * - * Like bson_aligned_alloc() except the memory is zeroed after allocation - * for convenience. - * - * Parameters: - * @alignment: The alignment of the allocated bytes of memory. - * @num_bytes: The number of bytes to allocate. - * - * Returns: - * A pointer if successful; otherwise abort() is called and this - * function will never return. - * - * Side effects: - * None. - * - *-------------------------------------------------------------------------- - */ - -void * -bson_aligned_alloc0 (size_t alignment /* IN */, size_t num_bytes /* IN */) -{ - void *mem = NULL; - - if (BSON_LIKELY (num_bytes)) { - if (BSON_UNLIKELY (!(mem = gMemVtable.aligned_alloc (alignment, num_bytes)))) { - fprintf (stderr, "Failure to allocate memory in bson_aligned_alloc0()\n"); - abort (); - } - memset (mem, 0, num_bytes); - } - - return mem; -} - - -/* - *-------------------------------------------------------------------------- - * - * bson_realloc -- - * - * This function behaves similar to realloc() except that if there is - * a failure abort() is called. - * - * Parameters: - * @mem: The memory to realloc, or NULL. - * @num_bytes: The size of the new allocation or 0 to free. - * - * Returns: - * The new allocation if successful; otherwise abort() is called and - * this function never returns. - * - * Side effects: - * None. - * - *-------------------------------------------------------------------------- - */ - -void * -bson_realloc (void *mem, /* IN */ - size_t num_bytes) /* IN */ -{ - /* - * Not all platforms are guaranteed to free() the memory if a call to - * realloc() with a size of zero occurs. Windows, Linux, and FreeBSD do, - * however, OS X does not. - */ - if (BSON_UNLIKELY (num_bytes == 0)) { - gMemVtable.free (mem); - return NULL; - } - - mem = gMemVtable.realloc (mem, num_bytes); - - if (BSON_UNLIKELY (!mem)) { - fprintf (stderr, "Failure to re-allocate memory in bson_realloc(). errno: %d.\n", errno); - abort (); - } - - return mem; -} - - -/* - *-------------------------------------------------------------------------- - * - * bson_realloc_ctx -- - * - * This wraps bson_realloc and provides a compatible api for similar - * functions with a context - * - * Parameters: - * @mem: The memory to realloc, or NULL. - * @num_bytes: The size of the new allocation or 0 to free. - * @ctx: Ignored - * - * Returns: - * The new allocation if successful; otherwise abort() is called and - * this function never returns. - * - * Side effects: - * None. - * - *-------------------------------------------------------------------------- - */ - - -void * -bson_realloc_ctx (void *mem, /* IN */ - size_t num_bytes, /* IN */ - void *ctx) /* IN */ -{ - BSON_UNUSED (ctx); - - return bson_realloc (mem, num_bytes); -} - - -/* - *-------------------------------------------------------------------------- - * - * bson_free -- - * - * Frees @mem using the underlying allocator. - * - * Currently, this only calls free() directly, but that is subject to - * change. - * - * Parameters: - * @mem: An allocation to free. - * - * Returns: - * None. - * - * Side effects: - * None. - * - *-------------------------------------------------------------------------- - */ - -void -bson_free (void *mem) /* IN */ -{ - gMemVtable.free (mem); -} - - -/* - *-------------------------------------------------------------------------- - * - * bson_zero_free -- - * - * Frees @mem using the underlying allocator. @size bytes of @mem will - * be zeroed before freeing the memory. This is useful in scenarios - * where @mem contains passwords or other sensitive information. - * - * Parameters: - * @mem: An allocation to free. - * @size: The number of bytes in @mem. - * - * Returns: - * None. - * - * Side effects: - * None. - * - *-------------------------------------------------------------------------- - */ - -void -bson_zero_free (void *mem, /* IN */ - size_t size) /* IN */ -{ - if (BSON_LIKELY (mem)) { - memset (mem, 0, size); - gMemVtable.free (mem); - } -} - - -static void * -_aligned_alloc_as_malloc (size_t alignment, size_t num_bytes) -{ - BSON_UNUSED (alignment); - - return gMemVtable.malloc (num_bytes); -} - - -/* - *-------------------------------------------------------------------------- - * - * bson_mem_set_vtable -- - * - * This function will change our allocation vtable. - * - * It is imperative that this is called at the beginning of the - * process before any memory has been allocated by the default - * allocator. - * - * Returns: - * None. - * - * Side effects: - * None. - * - *-------------------------------------------------------------------------- - */ - -void -bson_mem_set_vtable (const bson_mem_vtable_t *vtable) -{ - BSON_ASSERT (vtable); - - if (!vtable->malloc || !vtable->calloc || !vtable->realloc || !vtable->free) { - fprintf (stderr, - "Failure to install BSON vtable, " - "missing functions.\n"); - return; - } - - gMemVtable = *vtable; - - // Backwards compatibility with code prior to addition of aligned_alloc. - if (!gMemVtable.aligned_alloc) { - gMemVtable.aligned_alloc = _aligned_alloc_as_malloc; - } -} - -void -bson_mem_restore_vtable (void) -{ - bson_mem_vtable_t vtable = {.malloc = malloc, - .calloc = calloc, - .realloc = realloc, - .free = free, - .aligned_alloc = _aligned_alloc_impl, - .padding = {0}}; - - bson_mem_set_vtable (&vtable); -} diff --git a/bsonjs/bson/bson-memory.h b/bsonjs/bson/bson-memory.h deleted file mode 100644 index bde15ed..0000000 --- a/bsonjs/bson/bson-memory.h +++ /dev/null @@ -1,73 +0,0 @@ -/* - * Copyright 2013 MongoDB, Inc. - * - * 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. - */ - -#include - - -#ifndef BSON_MEMORY_H -#define BSON_MEMORY_H - - -#include -#include - - -BSON_BEGIN_DECLS - - -typedef void *(*bson_realloc_func) (void *mem, size_t num_bytes, void *ctx); - - -typedef struct _bson_mem_vtable_t { - void *(*malloc) (size_t num_bytes); - void *(*calloc) (size_t n_members, size_t num_bytes); - void *(*realloc) (void *mem, size_t num_bytes); - void (*free) (void *mem); - void *(*aligned_alloc) (size_t alignment, size_t num_bytes); - void *padding[3]; -} bson_mem_vtable_t; - - -BSON_EXPORT (void) -bson_mem_set_vtable (const bson_mem_vtable_t *vtable); -BSON_EXPORT (void) -bson_mem_restore_vtable (void); -BSON_EXPORT (void *) -bson_malloc (size_t num_bytes); -BSON_EXPORT (void *) -bson_malloc0 (size_t num_bytes); -BSON_EXPORT (void *) -bson_aligned_alloc (size_t alignment, size_t num_bytes); -BSON_EXPORT (void *) -bson_aligned_alloc0 (size_t alignment, size_t num_bytes); -BSON_EXPORT (void *) -bson_realloc (void *mem, size_t num_bytes); -BSON_EXPORT (void *) -bson_realloc_ctx (void *mem, size_t num_bytes, void *ctx); -BSON_EXPORT (void) -bson_free (void *mem); -BSON_EXPORT (void) -bson_zero_free (void *mem, size_t size); - - -#define BSON_ALIGNED_ALLOC(T) ((T *) (bson_aligned_alloc (BSON_ALIGNOF (T), sizeof (T)))) -#define BSON_ALIGNED_ALLOC0(T) ((T *) (bson_aligned_alloc0 (BSON_ALIGNOF (T), sizeof (T)))) - - -BSON_END_DECLS - - -#endif /* BSON_MEMORY_H */ diff --git a/bsonjs/bson/bson-oid.c b/bsonjs/bson/bson-oid.c deleted file mode 100644 index e4171c7..0000000 --- a/bsonjs/bson/bson-oid.c +++ /dev/null @@ -1,280 +0,0 @@ -/* - * Copyright 2013 MongoDB, Inc. - * - * 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. - */ - -#include - -#include -#include -#include -#include - -#include -#include -#include - - -/* - * This table contains an array of two character pairs for every possible - * uint8_t. It is used as a lookup table when encoding a bson_oid_t - * to hex formatted ASCII. Performing two characters at a time roughly - * reduces the number of operations by one-half. - */ -BSON_MAYBE_UNUSED static const uint16_t gHexCharPairs[] = { -#if BSON_BYTE_ORDER == BSON_BIG_ENDIAN - 12336, 12337, 12338, 12339, 12340, 12341, 12342, 12343, 12344, 12345, 12385, 12386, 12387, 12388, 12389, - 12390, 12592, 12593, 12594, 12595, 12596, 12597, 12598, 12599, 12600, 12601, 12641, 12642, 12643, 12644, - 12645, 12646, 12848, 12849, 12850, 12851, 12852, 12853, 12854, 12855, 12856, 12857, 12897, 12898, 12899, - 12900, 12901, 12902, 13104, 13105, 13106, 13107, 13108, 13109, 13110, 13111, 13112, 13113, 13153, 13154, - 13155, 13156, 13157, 13158, 13360, 13361, 13362, 13363, 13364, 13365, 13366, 13367, 13368, 13369, 13409, - 13410, 13411, 13412, 13413, 13414, 13616, 13617, 13618, 13619, 13620, 13621, 13622, 13623, 13624, 13625, - 13665, 13666, 13667, 13668, 13669, 13670, 13872, 13873, 13874, 13875, 13876, 13877, 13878, 13879, 13880, - 13881, 13921, 13922, 13923, 13924, 13925, 13926, 14128, 14129, 14130, 14131, 14132, 14133, 14134, 14135, - 14136, 14137, 14177, 14178, 14179, 14180, 14181, 14182, 14384, 14385, 14386, 14387, 14388, 14389, 14390, - 14391, 14392, 14393, 14433, 14434, 14435, 14436, 14437, 14438, 14640, 14641, 14642, 14643, 14644, 14645, - 14646, 14647, 14648, 14649, 14689, 14690, 14691, 14692, 14693, 14694, 24880, 24881, 24882, 24883, 24884, - 24885, 24886, 24887, 24888, 24889, 24929, 24930, 24931, 24932, 24933, 24934, 25136, 25137, 25138, 25139, - 25140, 25141, 25142, 25143, 25144, 25145, 25185, 25186, 25187, 25188, 25189, 25190, 25392, 25393, 25394, - 25395, 25396, 25397, 25398, 25399, 25400, 25401, 25441, 25442, 25443, 25444, 25445, 25446, 25648, 25649, - 25650, 25651, 25652, 25653, 25654, 25655, 25656, 25657, 25697, 25698, 25699, 25700, 25701, 25702, 25904, - 25905, 25906, 25907, 25908, 25909, 25910, 25911, 25912, 25913, 25953, 25954, 25955, 25956, 25957, 25958, - 26160, 26161, 26162, 26163, 26164, 26165, 26166, 26167, 26168, 26169, 26209, 26210, 26211, 26212, 26213, - 26214 -#else - 12336, 12592, 12848, 13104, 13360, 13616, 13872, 14128, 14384, 14640, 24880, 25136, 25392, 25648, 25904, - 26160, 12337, 12593, 12849, 13105, 13361, 13617, 13873, 14129, 14385, 14641, 24881, 25137, 25393, 25649, - 25905, 26161, 12338, 12594, 12850, 13106, 13362, 13618, 13874, 14130, 14386, 14642, 24882, 25138, 25394, - 25650, 25906, 26162, 12339, 12595, 12851, 13107, 13363, 13619, 13875, 14131, 14387, 14643, 24883, 25139, - 25395, 25651, 25907, 26163, 12340, 12596, 12852, 13108, 13364, 13620, 13876, 14132, 14388, 14644, 24884, - 25140, 25396, 25652, 25908, 26164, 12341, 12597, 12853, 13109, 13365, 13621, 13877, 14133, 14389, 14645, - 24885, 25141, 25397, 25653, 25909, 26165, 12342, 12598, 12854, 13110, 13366, 13622, 13878, 14134, 14390, - 14646, 24886, 25142, 25398, 25654, 25910, 26166, 12343, 12599, 12855, 13111, 13367, 13623, 13879, 14135, - 14391, 14647, 24887, 25143, 25399, 25655, 25911, 26167, 12344, 12600, 12856, 13112, 13368, 13624, 13880, - 14136, 14392, 14648, 24888, 25144, 25400, 25656, 25912, 26168, 12345, 12601, 12857, 13113, 13369, 13625, - 13881, 14137, 14393, 14649, 24889, 25145, 25401, 25657, 25913, 26169, 12385, 12641, 12897, 13153, 13409, - 13665, 13921, 14177, 14433, 14689, 24929, 25185, 25441, 25697, 25953, 26209, 12386, 12642, 12898, 13154, - 13410, 13666, 13922, 14178, 14434, 14690, 24930, 25186, 25442, 25698, 25954, 26210, 12387, 12643, 12899, - 13155, 13411, 13667, 13923, 14179, 14435, 14691, 24931, 25187, 25443, 25699, 25955, 26211, 12388, 12644, - 12900, 13156, 13412, 13668, 13924, 14180, 14436, 14692, 24932, 25188, 25444, 25700, 25956, 26212, 12389, - 12645, 12901, 13157, 13413, 13669, 13925, 14181, 14437, 14693, 24933, 25189, 25445, 25701, 25957, 26213, - 12390, 12646, 12902, 13158, 13414, 13670, 13926, 14182, 14438, 14694, 24934, 25190, 25446, 25702, 25958, - 26214 -#endif -}; - - -void -bson_oid_init_sequence (bson_oid_t *oid, /* OUT */ - bson_context_t *context) /* IN */ -{ - uint32_t now = (uint32_t) (time (NULL)); - - if (!context) { - context = bson_context_get_default (); - } - - now = BSON_UINT32_TO_BE (now); - memcpy (&oid->bytes[0], &now, sizeof (now)); - _bson_context_set_oid_seq64 (context, oid); -} - - -void -bson_oid_init (bson_oid_t *oid, /* OUT */ - bson_context_t *context) /* IN */ -{ - uint32_t now = (uint32_t) (time (NULL)); - - BSON_ASSERT (oid); - - if (!context) { - context = bson_context_get_default (); - } - - now = BSON_UINT32_TO_BE (now); - memcpy (&oid->bytes[0], &now, sizeof (now)); - _bson_context_set_oid_rand (context, oid); - _bson_context_set_oid_seq32 (context, oid); -} - - -void -bson_oid_init_from_data (bson_oid_t *oid, /* OUT */ - const uint8_t *data) /* IN */ -{ - BSON_ASSERT (oid); - BSON_ASSERT (data); - - memcpy (oid, data, 12); -} - - -void -bson_oid_init_from_string (bson_oid_t *oid, /* OUT */ - const char *str) /* IN */ -{ - BSON_ASSERT (oid); - BSON_ASSERT (str); - - bson_oid_init_from_string_unsafe (oid, str); -} - - -time_t -bson_oid_get_time_t (const bson_oid_t *oid) /* IN */ -{ - BSON_ASSERT (oid); - - return bson_oid_get_time_t_unsafe (oid); -} - - -void -bson_oid_to_string (const bson_oid_t *oid, /* IN */ - char str[BSON_ENSURE_ARRAY_PARAM_SIZE (25)]) /* OUT */ -{ -#if !defined(__i386__) && !defined(__x86_64__) && !defined(_M_IX86) && !defined(_M_X64) - BSON_ASSERT (oid); - BSON_ASSERT (str); - - bson_snprintf (str, - 25, - "%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x", - oid->bytes[0], - oid->bytes[1], - oid->bytes[2], - oid->bytes[3], - oid->bytes[4], - oid->bytes[5], - oid->bytes[6], - oid->bytes[7], - oid->bytes[8], - oid->bytes[9], - oid->bytes[10], - oid->bytes[11]); -#else - uint16_t *dst; - uint8_t *id = (uint8_t *) oid; - - BSON_ASSERT (oid); - BSON_ASSERT (str); - - dst = (uint16_t *) (void *) str; - dst[0] = gHexCharPairs[id[0]]; - dst[1] = gHexCharPairs[id[1]]; - dst[2] = gHexCharPairs[id[2]]; - dst[3] = gHexCharPairs[id[3]]; - dst[4] = gHexCharPairs[id[4]]; - dst[5] = gHexCharPairs[id[5]]; - dst[6] = gHexCharPairs[id[6]]; - dst[7] = gHexCharPairs[id[7]]; - dst[8] = gHexCharPairs[id[8]]; - dst[9] = gHexCharPairs[id[9]]; - dst[10] = gHexCharPairs[id[10]]; - dst[11] = gHexCharPairs[id[11]]; - str[24] = '\0'; -#endif -} - - -uint32_t -bson_oid_hash (const bson_oid_t *oid) /* IN */ -{ - BSON_ASSERT (oid); - - return bson_oid_hash_unsafe (oid); -} - - -int -bson_oid_compare (const bson_oid_t *oid1, /* IN */ - const bson_oid_t *oid2) /* IN */ -{ - BSON_ASSERT (oid1); - BSON_ASSERT (oid2); - - return bson_oid_compare_unsafe (oid1, oid2); -} - - -bool -bson_oid_equal (const bson_oid_t *oid1, /* IN */ - const bson_oid_t *oid2) /* IN */ -{ - BSON_ASSERT (oid1); - BSON_ASSERT (oid2); - - return bson_oid_equal_unsafe (oid1, oid2); -} - - -void -bson_oid_copy (const bson_oid_t *src, /* IN */ - bson_oid_t *dst) /* OUT */ -{ - BSON_ASSERT (src); - BSON_ASSERT (dst); - - bson_oid_copy_unsafe (src, dst); -} - - -bool -bson_oid_is_valid (const char *str, /* IN */ - size_t length) /* IN */ -{ - size_t i; - - BSON_ASSERT (str); - - if ((length == 25) && (str[24] == '\0')) { - length = 24; - } - - if (length == 24) { - for (i = 0; i < length; i++) { - switch (str[i]) { - case '0': - case '1': - case '2': - case '3': - case '4': - case '5': - case '6': - case '7': - case '8': - case '9': - case 'a': - case 'b': - case 'c': - case 'd': - case 'e': - case 'f': - case 'A': - case 'B': - case 'C': - case 'D': - case 'E': - case 'F': - break; - default: - return false; - } - } - return true; - } - - return false; -} diff --git a/bsonjs/bson/bson-oid.h b/bsonjs/bson/bson-oid.h deleted file mode 100644 index 4829e28..0000000 --- a/bsonjs/bson/bson-oid.h +++ /dev/null @@ -1,243 +0,0 @@ -/* - * Copyright 2013 MongoDB, Inc. - * - * 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. - */ - -#include - - -#ifndef BSON_OID_H -#define BSON_OID_H - - -#include - -#include -#include -#include -#include - - -BSON_BEGIN_DECLS - - -BSON_EXPORT (int) -bson_oid_compare (const bson_oid_t *oid1, const bson_oid_t *oid2); -BSON_EXPORT (void) -bson_oid_copy (const bson_oid_t *src, bson_oid_t *dst); -BSON_EXPORT (bool) -bson_oid_equal (const bson_oid_t *oid1, const bson_oid_t *oid2); -BSON_EXPORT (bool) -bson_oid_is_valid (const char *str, size_t length); -BSON_EXPORT (time_t) -bson_oid_get_time_t (const bson_oid_t *oid); -BSON_EXPORT (uint32_t) -bson_oid_hash (const bson_oid_t *oid); -BSON_EXPORT (void) -bson_oid_init (bson_oid_t *oid, bson_context_t *context); -BSON_EXPORT (void) -bson_oid_init_from_data (bson_oid_t *oid, const uint8_t *data); -BSON_EXPORT (void) -bson_oid_init_from_string (bson_oid_t *oid, const char *str); -BSON_EXPORT (void) -bson_oid_init_sequence (bson_oid_t *oid, bson_context_t *context) BSON_GNUC_DEPRECATED_FOR (bson_oid_init); -BSON_EXPORT (void) -bson_oid_to_string (const bson_oid_t *oid, char str[25]); - - -/** - * bson_oid_compare_unsafe: - * @oid1: A bson_oid_t. - * @oid2: A bson_oid_t. - * - * Performs a qsort() style comparison between @oid1 and @oid2. - * - * This function is meant to be as fast as possible and therefore performs - * no argument validation. That is the callers responsibility. - * - * Returns: An integer < 0 if @oid1 is less than @oid2. Zero if they are equal. - * An integer > 0 if @oid1 is greater than @oid2. - */ -static BSON_INLINE int -bson_oid_compare_unsafe (const bson_oid_t *oid1, const bson_oid_t *oid2) -{ - return memcmp (oid1, oid2, sizeof *oid1); -} - - -/** - * bson_oid_equal_unsafe: - * @oid1: A bson_oid_t. - * @oid2: A bson_oid_t. - * - * Checks the equality of @oid1 and @oid2. - * - * This function is meant to be as fast as possible and therefore performs - * no checks for argument validity. That is the callers responsibility. - * - * Returns: true if @oid1 and @oid2 are equal; otherwise false. - */ -static BSON_INLINE bool -bson_oid_equal_unsafe (const bson_oid_t *oid1, const bson_oid_t *oid2) -{ - return !memcmp (oid1, oid2, sizeof *oid1); -} - -/** - * bson_oid_hash_unsafe: - * @oid: A bson_oid_t. - * - * This function performs a DJB style hash upon the bytes contained in @oid. - * The result is a hash key suitable for use in a hashtable. - * - * This function is meant to be as fast as possible and therefore performs no - * validation of arguments. The caller is responsible to ensure they are - * passing valid arguments. - * - * Returns: A uint32_t containing a hash code. - */ -static BSON_INLINE uint32_t -bson_oid_hash_unsafe (const bson_oid_t *oid) -{ - uint32_t hash = 5381; - uint32_t i; - - for (i = 0; i < sizeof oid->bytes; i++) { - hash = ((hash << 5) + hash) + oid->bytes[i]; - } - - return hash; -} - - -/** - * bson_oid_copy_unsafe: - * @src: A bson_oid_t to copy from. - * @dst: A bson_oid_t to copy into. - * - * Copies the contents of @src into @dst. This function is meant to be as - * fast as possible and therefore performs no argument checking. It is the - * callers responsibility to ensure they are passing valid data into the - * function. - */ -static BSON_INLINE void -bson_oid_copy_unsafe (const bson_oid_t *src, bson_oid_t *dst) -{ - memcpy (dst, src, sizeof *src); -} - - -/** - * bson_oid_parse_hex_char: - * @hex: A character to parse to its integer value. - * - * This function contains a jump table to return the integer value for a - * character containing a hexadecimal value (0-9, a-f, A-F). If the character - * is not a hexadecimal character then zero is returned. - * - * Returns: An integer between 0 and 15. - */ -static BSON_INLINE uint8_t -bson_oid_parse_hex_char (char hex) -{ - switch (hex) { - case '0': - return 0; - case '1': - return 1; - case '2': - return 2; - case '3': - return 3; - case '4': - return 4; - case '5': - return 5; - case '6': - return 6; - case '7': - return 7; - case '8': - return 8; - case '9': - return 9; - case 'a': - case 'A': - return 0xa; - case 'b': - case 'B': - return 0xb; - case 'c': - case 'C': - return 0xc; - case 'd': - case 'D': - return 0xd; - case 'e': - case 'E': - return 0xe; - case 'f': - case 'F': - return 0xf; - default: - return 0; - } -} - - -/** - * bson_oid_init_from_string_unsafe: - * @oid: A bson_oid_t to store the result. - * @str: A 24-character hexadecimal encoded string. - * - * Parses a string containing 24 hexadecimal encoded bytes into a bson_oid_t. - * This function is meant to be as fast as possible and inlined into your - * code. For that purpose, the function does not perform any sort of bounds - * checking and it is the callers responsibility to ensure they are passing - * valid input to the function. - */ -static BSON_INLINE void -bson_oid_init_from_string_unsafe (bson_oid_t *oid, const char *str) -{ - int i; - - for (i = 0; i < 12; i++) { - oid->bytes[i] = - (uint8_t) ((bson_oid_parse_hex_char (str[2 * i]) << 4) | (bson_oid_parse_hex_char (str[2 * i + 1]))); - } -} - - -/** - * bson_oid_get_time_t_unsafe: - * @oid: A bson_oid_t. - * - * Fetches the time @oid was generated. - * - * Returns: A time_t containing the UNIX timestamp of generation. - */ -static BSON_INLINE time_t -bson_oid_get_time_t_unsafe (const bson_oid_t *oid) -{ - uint32_t t; - - memcpy (&t, oid, sizeof (t)); - return BSON_UINT32_FROM_BE (t); -} - - -BSON_END_DECLS - - -#endif /* BSON_OID_H */ diff --git a/bsonjs/bson/bson-prelude.h b/bsonjs/bson/bson-prelude.h deleted file mode 100644 index 2469125..0000000 --- a/bsonjs/bson/bson-prelude.h +++ /dev/null @@ -1,19 +0,0 @@ -/* - * Copyright 2018-present MongoDB, Inc. - * - * 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 !defined(BSON_INSIDE) && !defined(BSON_COMPILATION) -#error "Only can be included directly." -#endif diff --git a/bsonjs/bson/bson-private.h b/bsonjs/bson/bson-private.h deleted file mode 100644 index 3b006a3..0000000 --- a/bsonjs/bson/bson-private.h +++ /dev/null @@ -1,106 +0,0 @@ -/* - * Copyright 2013 MongoDB, Inc. - * - * 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. - */ - -#include - - -#ifndef BSON_PRIVATE_H -#define BSON_PRIVATE_H - - -#include -#include -#include - - -#if (__GNUC__ > 4) || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6) -#define BEGIN_IGNORE_DEPRECATIONS \ - _Pragma ("GCC diagnostic push") _Pragma ("GCC diagnostic ignored \"-Wdeprecated-declarations\"") -#define END_IGNORE_DEPRECATIONS _Pragma ("GCC diagnostic pop") -#elif defined(__clang__) -#define BEGIN_IGNORE_DEPRECATIONS \ - _Pragma ("clang diagnostic push") _Pragma ("clang diagnostic ignored \"-Wdeprecated-declarations\"") -#define END_IGNORE_DEPRECATIONS _Pragma ("clang diagnostic pop") -#else -#define BEGIN_IGNORE_DEPRECATIONS -#define END_IGNORE_DEPRECATIONS -#endif - - -BSON_BEGIN_DECLS - - -typedef enum { - BSON_FLAG_NONE = 0, - BSON_FLAG_INLINE = (1 << 0), - BSON_FLAG_STATIC = (1 << 1), - BSON_FLAG_RDONLY = (1 << 2), - BSON_FLAG_CHILD = (1 << 3), - BSON_FLAG_IN_CHILD = (1 << 4), - BSON_FLAG_NO_FREE = (1 << 5), -} bson_flags_t; - - -#ifdef BSON_MEMCHECK -#define BSON_INLINE_DATA_SIZE (120 - sizeof (char *)) -#else -#define BSON_INLINE_DATA_SIZE 120 -#endif - - -BSON_ALIGNED_BEGIN (128) -typedef struct { - bson_flags_t flags; - uint32_t len; -#ifdef BSON_MEMCHECK - char *canary; -#endif - uint8_t data[BSON_INLINE_DATA_SIZE]; -} bson_impl_inline_t BSON_ALIGNED_END (128); - - -BSON_STATIC_ASSERT2 (impl_inline_t, sizeof (bson_impl_inline_t) == 128); - - -BSON_ALIGNED_BEGIN (128) -typedef struct { - bson_flags_t flags; /* flags describing the bson_t */ - /* len is part of the public bson_t declaration. It is not - * exposed through an accessor function. Plus, it's redundant since - * BSON self describes the length in the first four bytes of the - * buffer. */ - uint32_t len; /* length of bson document in bytes */ - bson_t *parent; /* parent bson if a child */ - uint32_t depth; /* Subdocument depth. */ - uint8_t **buf; /* pointer to buffer pointer */ - size_t *buflen; /* pointer to buffer length */ - size_t offset; /* our offset inside *buf */ - uint8_t *alloc; /* buffer that we own. */ - size_t alloclen; /* length of buffer that we own. */ - bson_realloc_func realloc; /* our realloc implementation */ - void *realloc_func_ctx; /* context for our realloc func */ -} bson_impl_alloc_t BSON_ALIGNED_END (128); - - -BSON_STATIC_ASSERT2 (impl_alloc_t, sizeof (bson_impl_alloc_t) <= 128); - - -#define BSON_REGEX_OPTIONS_SORTED "ilmsux" - -BSON_END_DECLS - - -#endif /* BSON_PRIVATE_H */ diff --git a/bsonjs/bson/bson-reader.c b/bsonjs/bson/bson-reader.c deleted file mode 100644 index 84ade05..0000000 --- a/bsonjs/bson/bson-reader.c +++ /dev/null @@ -1,821 +0,0 @@ -/* - * Copyright 2013 MongoDB, Inc. - * - * 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. - */ - -#include "bson.h" - -#include -#include -#ifdef BSON_OS_WIN32 -#include -#include -#endif -#include -#include -#include -#include - -#include -#include - - -typedef enum { - BSON_READER_HANDLE = 1, - BSON_READER_DATA = 2, -} bson_reader_type_t; - - -typedef struct { - bson_reader_type_t type; - void *handle; - bool done : 1; - bool failed : 1; - size_t end; - size_t len; - size_t offset; - size_t bytes_read; - bson_t inline_bson; - uint8_t *data; - bson_reader_read_func_t read_func; - bson_reader_destroy_func_t destroy_func; -} bson_reader_handle_t; - - -typedef struct { - int fd; - bool do_close; -} bson_reader_handle_fd_t; - - -typedef struct { - bson_reader_type_t type; - const uint8_t *data; - size_t length; - size_t offset; - bson_t inline_bson; -} bson_reader_data_t; - - -/* - *-------------------------------------------------------------------------- - * - * _bson_reader_handle_fill_buffer -- - * - * Attempt to read as much as possible until the underlying buffer - * in @reader is filled or we have reached end-of-stream or - * read failure. - * - * Returns: - * None. - * - * Side effects: - * None. - * - *-------------------------------------------------------------------------- - */ - -static void -_bson_reader_handle_fill_buffer (bson_reader_handle_t *reader) /* IN */ -{ - ssize_t ret; - - /* - * Handle first read specially. - */ - if ((!reader->done) && (!reader->offset) && (!reader->end)) { - ret = reader->read_func (reader->handle, &reader->data[0], reader->len); - - if (ret <= 0) { - reader->done = true; - return; - } - reader->bytes_read += ret; - - reader->end = ret; - return; - } - - /* - * Move valid data to head. - */ - memmove (&reader->data[0], &reader->data[reader->offset], reader->end - reader->offset); - reader->end = reader->end - reader->offset; - reader->offset = 0; - - /* - * Read in data to fill the buffer. - */ - ret = reader->read_func (reader->handle, &reader->data[reader->end], reader->len - reader->end); - - if (ret <= 0) { - reader->done = true; - reader->failed = (ret < 0); - } else { - reader->bytes_read += ret; - reader->end += ret; - } - - BSON_ASSERT (reader->offset == 0); - BSON_ASSERT (reader->end <= reader->len); -} - - -/* - *-------------------------------------------------------------------------- - * - * bson_reader_new_from_handle -- - * - * Allocates and initializes a new bson_reader_t using the opaque - * handle provided. - * - * Parameters: - * @handle: an opaque handle to use to read data. - * @rf: a function to perform reads on @handle. - * @df: a function to release @handle, or NULL. - * - * Returns: - * A newly allocated bson_reader_t if successful, otherwise NULL. - * Free the successful result with bson_reader_destroy(). - * - * Side effects: - * None. - * - *-------------------------------------------------------------------------- - */ - -bson_reader_t * -bson_reader_new_from_handle (void *handle, bson_reader_read_func_t rf, bson_reader_destroy_func_t df) -{ - bson_reader_handle_t *real; - - BSON_ASSERT (handle); - BSON_ASSERT (rf); - - real = BSON_ALIGNED_ALLOC0 (bson_reader_handle_t); - real->type = BSON_READER_HANDLE; - real->data = bson_malloc0 (1024); - real->handle = handle; - real->len = 1024; - real->offset = 0; - - bson_reader_set_read_func ((bson_reader_t *) real, rf); - - if (df) { - bson_reader_set_destroy_func ((bson_reader_t *) real, df); - } - - _bson_reader_handle_fill_buffer (real); - - return (bson_reader_t *) real; -} - - -/* - *-------------------------------------------------------------------------- - * - * _bson_reader_handle_fd_destroy -- - * - * Cleanup allocations associated with state created in - * bson_reader_new_from_fd(). - * - * Returns: - * None. - * - * Side effects: - * None. - * - *-------------------------------------------------------------------------- - */ - -static void -_bson_reader_handle_fd_destroy (void *handle) /* IN */ -{ - bson_reader_handle_fd_t *fd = handle; - - if (fd) { - if ((fd->fd != -1) && fd->do_close) { -#ifdef _WIN32 - _close (fd->fd); -#else - close (fd->fd); -#endif - } - bson_free (fd); - } -} - - -/* - *-------------------------------------------------------------------------- - * - * _bson_reader_handle_fd_read -- - * - * Perform read on opaque handle created in - * bson_reader_new_from_fd(). - * - * The underlying file descriptor is read from the current position - * using the bson_reader_handle_fd_t allocated. - * - * Returns: - * -1 on failure. - * 0 on end of stream. - * Greater than zero on success. - * - * Side effects: - * None. - * - *-------------------------------------------------------------------------- - */ - -static ssize_t -_bson_reader_handle_fd_read (void *handle, /* IN */ - void *buf, /* IN */ - size_t len) /* IN */ -{ - bson_reader_handle_fd_t *fd = handle; - ssize_t ret = -1; - - if (fd && (fd->fd != -1)) { - again: -#ifdef BSON_OS_WIN32 - ret = _read (fd->fd, buf, (unsigned int) len); -#else - ret = read (fd->fd, buf, len); -#endif - if ((ret == -1) && (errno == EAGAIN)) { - goto again; - } - } - - return ret; -} - - -/* - *-------------------------------------------------------------------------- - * - * bson_reader_new_from_fd -- - * - * Create a new bson_reader_t using the file-descriptor provided. - * - * Parameters: - * @fd: a libc style file-descriptor. - * @close_on_destroy: if close() should be called on @fd when - * bson_reader_destroy() is called. - * - * Returns: - * A newly allocated bson_reader_t on success; otherwise NULL. - * - * Side effects: - * None. - * - *-------------------------------------------------------------------------- - */ - -bson_reader_t * -bson_reader_new_from_fd (int fd, /* IN */ - bool close_on_destroy) /* IN */ -{ - bson_reader_handle_fd_t *handle; - - BSON_ASSERT (fd != -1); - - handle = bson_malloc0 (sizeof *handle); - handle->fd = fd; - handle->do_close = close_on_destroy; - - return bson_reader_new_from_handle (handle, _bson_reader_handle_fd_read, _bson_reader_handle_fd_destroy); -} - - -/** - * bson_reader_set_read_func: - * @reader: A bson_reader_t. - * - * Note that @reader must be initialized by bson_reader_init_from_handle(), or - * data - * will be destroyed. - */ -/* - *-------------------------------------------------------------------------- - * - * bson_reader_set_read_func -- - * - * Set the read func to be provided for @reader. - * - * You probably want to use bson_reader_new_from_handle() or - * bson_reader_new_from_fd() instead. - * - * Returns: - * None. - * - * Side effects: - * None. - * - *-------------------------------------------------------------------------- - */ - -void -bson_reader_set_read_func (bson_reader_t *reader, /* IN */ - bson_reader_read_func_t func) /* IN */ -{ - bson_reader_handle_t *real = (bson_reader_handle_t *) reader; - - BSON_ASSERT (reader->type == BSON_READER_HANDLE); - - real->read_func = func; -} - - -/* - *-------------------------------------------------------------------------- - * - * bson_reader_set_destroy_func -- - * - * Set the function to cleanup state when @reader is destroyed. - * - * You probably want bson_reader_new_from_fd() or - * bson_reader_new_from_handle() instead. - * - * Returns: - * None. - * - * Side effects: - * None. - * - *-------------------------------------------------------------------------- - */ - -void -bson_reader_set_destroy_func (bson_reader_t *reader, /* IN */ - bson_reader_destroy_func_t func) /* IN */ -{ - bson_reader_handle_t *real = (bson_reader_handle_t *) reader; - - BSON_ASSERT (reader->type == BSON_READER_HANDLE); - - real->destroy_func = func; -} - - -/* - *-------------------------------------------------------------------------- - * - * _bson_reader_handle_grow_buffer -- - * - * Grow the buffer to the next power of two. - * - * Returns: - * None. - * - * Side effects: - * None. - * - *-------------------------------------------------------------------------- - */ - -static void -_bson_reader_handle_grow_buffer (bson_reader_handle_t *reader) /* IN */ -{ - size_t size; - - size = reader->len * 2; - reader->data = bson_realloc (reader->data, size); - reader->len = size; -} - - -/* - *-------------------------------------------------------------------------- - * - * _bson_reader_handle_tell -- - * - * Tell the current position within the underlying file-descriptor. - * - * Returns: - * An off_t containing the current offset. - * - * Side effects: - * None. - * - *-------------------------------------------------------------------------- - */ - -static off_t -_bson_reader_handle_tell (bson_reader_handle_t *reader) /* IN */ -{ - off_t off; - - off = (off_t) reader->bytes_read; - off -= (off_t) reader->end; - off += (off_t) reader->offset; - - return off; -} - - -/* - *-------------------------------------------------------------------------- - * - * _bson_reader_handle_read -- - * - * Read the next chunk of data from the underlying file descriptor - * and return a bson_t which should not be modified. - * - * There was a failure if NULL is returned and @reached_eof is - * not set to true. - * - * Returns: - * NULL on failure or end of stream. - * - * Side effects: - * @reached_eof is set if non-NULL. - * - *-------------------------------------------------------------------------- - */ - -static const bson_t * -_bson_reader_handle_read (bson_reader_handle_t *reader, /* IN */ - bool *reached_eof) /* IN */ -{ - int32_t blen; - - if (reached_eof) { - *reached_eof = false; - } - - while (!reader->done) { - if ((reader->end - reader->offset) < 4) { - _bson_reader_handle_fill_buffer (reader); - continue; - } - - memcpy (&blen, &reader->data[reader->offset], sizeof blen); - blen = BSON_UINT32_FROM_LE (blen); - - if (blen < 5) { - return NULL; - } - - if (blen > (int32_t) (reader->end - reader->offset)) { - if (blen > (int32_t) reader->len) { - _bson_reader_handle_grow_buffer (reader); - } - - _bson_reader_handle_fill_buffer (reader); - continue; - } - - if (!bson_init_static (&reader->inline_bson, &reader->data[reader->offset], (uint32_t) blen)) { - return NULL; - } - - reader->offset += blen; - - return &reader->inline_bson; - } - - if (reached_eof) { - *reached_eof = reader->done && !reader->failed; - } - - return NULL; -} - - -/* - *-------------------------------------------------------------------------- - * - * bson_reader_new_from_data -- - * - * Allocates and initializes a new bson_reader_t that reads the memory - * provided as a stream of BSON documents. - * - * Parameters: - * @data: A buffer to read BSON documents from. - * @length: The length of @data. - * - * Returns: - * A newly allocated bson_reader_t that should be freed with - * bson_reader_destroy(). - * - * Side effects: - * None. - * - *-------------------------------------------------------------------------- - */ - -bson_reader_t * -bson_reader_new_from_data (const uint8_t *data, /* IN */ - size_t length) /* IN */ -{ - bson_reader_data_t *real; - - BSON_ASSERT (data); - - real = BSON_ALIGNED_ALLOC0 (bson_reader_data_t); - real->type = BSON_READER_DATA; - real->data = data; - real->length = length; - real->offset = 0; - - return (bson_reader_t *) real; -} - - -/* - *-------------------------------------------------------------------------- - * - * _bson_reader_data_read -- - * - * Read the next document from the underlying buffer. - * - * Returns: - * NULL on failure or end of stream. - * a bson_t which should not be modified. - * - * Side effects: - * None. - * - *-------------------------------------------------------------------------- - */ - -static const bson_t * -_bson_reader_data_read (bson_reader_data_t *reader, /* IN */ - bool *reached_eof) /* IN */ -{ - int32_t blen; - - if (reached_eof) { - *reached_eof = false; - } - - if ((reader->offset + 4) < reader->length) { - memcpy (&blen, &reader->data[reader->offset], sizeof blen); - blen = BSON_UINT32_FROM_LE (blen); - - if (blen < 5) { - return NULL; - } - - if (blen > (int32_t) (reader->length - reader->offset)) { - return NULL; - } - - if (!bson_init_static (&reader->inline_bson, &reader->data[reader->offset], (uint32_t) blen)) { - return NULL; - } - - reader->offset += blen; - - return &reader->inline_bson; - } - - if (reached_eof) { - *reached_eof = (reader->offset == reader->length); - } - - return NULL; -} - - -/* - *-------------------------------------------------------------------------- - * - * _bson_reader_data_tell -- - * - * Tell the current position in the underlying buffer. - * - * Returns: - * An off_t of the current offset. - * - * Side effects: - * None. - * - *-------------------------------------------------------------------------- - */ - -static off_t -_bson_reader_data_tell (bson_reader_data_t *reader) /* IN */ -{ - return (off_t) reader->offset; -} - - -/* - *-------------------------------------------------------------------------- - * - * bson_reader_destroy -- - * - * Release a bson_reader_t created with bson_reader_new_from_data(), - * bson_reader_new_from_fd(), or bson_reader_new_from_handle(). - * - * Returns: - * None. - * - * Side effects: - * None. - * - *-------------------------------------------------------------------------- - */ - -void -bson_reader_destroy (bson_reader_t *reader) /* IN */ -{ - if (!reader) { - return; - } - - switch (reader->type) { - case 0: - break; - case BSON_READER_HANDLE: { - bson_reader_handle_t *handle = (bson_reader_handle_t *) reader; - - if (handle->destroy_func) { - handle->destroy_func (handle->handle); - } - - bson_free (handle->data); - } break; - case BSON_READER_DATA: - break; - default: - fprintf (stderr, "No such reader type: %02x\n", reader->type); - break; - } - - reader->type = 0; - - bson_free (reader); -} - - -/* - *-------------------------------------------------------------------------- - * - * bson_reader_read -- - * - * Reads the next bson_t in the underlying memory or storage. The - * resulting bson_t should not be modified or freed. You may copy it - * and iterate over it. Functions that take a const bson_t* are safe - * to use. - * - * This structure does not survive calls to bson_reader_read() or - * bson_reader_destroy() as it uses memory allocated by the reader or - * underlying storage/memory. - * - * If NULL is returned then @reached_eof will be set to true if the - * end of the file or buffer was reached. This indicates if there was - * an error parsing the document stream. - * - * Returns: - * A const bson_t that should not be modified or freed. - * NULL on failure or end of stream. - * - * Side effects: - * @reached_eof is set if non-NULL. - * - *-------------------------------------------------------------------------- - */ - -const bson_t * -bson_reader_read (bson_reader_t *reader, /* IN */ - bool *reached_eof) /* OUT */ -{ - BSON_ASSERT (reader); - - switch (reader->type) { - case BSON_READER_HANDLE: - return _bson_reader_handle_read ((bson_reader_handle_t *) reader, reached_eof); - - case BSON_READER_DATA: - return _bson_reader_data_read ((bson_reader_data_t *) reader, reached_eof); - - default: - fprintf (stderr, "No such reader type: %02x\n", reader->type); - break; - } - - return NULL; -} - - -/* - *-------------------------------------------------------------------------- - * - * bson_reader_tell -- - * - * Return the current position in the underlying reader. This will - * always be at the beginning of a bson document or end of file. - * - * Returns: - * An off_t containing the current offset. - * - * Side effects: - * None. - * - *-------------------------------------------------------------------------- - */ - -off_t -bson_reader_tell (bson_reader_t *reader) /* IN */ -{ - BSON_ASSERT (reader); - - switch (reader->type) { - case BSON_READER_HANDLE: - return _bson_reader_handle_tell ((bson_reader_handle_t *) reader); - - case BSON_READER_DATA: - return _bson_reader_data_tell ((bson_reader_data_t *) reader); - - default: - fprintf (stderr, "No such reader type: %02x\n", reader->type); - return -1; - } -} - - -/* - *-------------------------------------------------------------------------- - * - * bson_reader_new_from_file -- - * - * A convenience function to open a file containing sequential - * bson documents and read them using bson_reader_t. - * - * Returns: - * A new bson_reader_t if successful, otherwise NULL and - * @error is set. Free the non-NULL result with - * bson_reader_destroy(). - * - * Side effects: - * @error may be set. - * - *-------------------------------------------------------------------------- - */ - -bson_reader_t * -bson_reader_new_from_file (const char *path, /* IN */ - bson_error_t *error) /* OUT */ -{ - char errmsg_buf[BSON_ERROR_BUFFER_SIZE]; - char *errmsg; - int fd; - - BSON_ASSERT (path); - -#ifdef BSON_OS_WIN32 - if (_sopen_s (&fd, path, (_O_RDONLY | _O_BINARY), _SH_DENYNO, 0) != 0) { - fd = -1; - } -#else - fd = open (path, O_RDONLY); -#endif - - if (fd == -1) { - errmsg = bson_strerror_r (errno, errmsg_buf, sizeof errmsg_buf); - bson_set_error (error, BSON_ERROR_READER, BSON_ERROR_READER_BADFD, "%s", errmsg); - return NULL; - } - - return bson_reader_new_from_fd (fd, true); -} - - -/* - *-------------------------------------------------------------------------- - * - * bson_reader_reset -- - * - * Restore the reader to its initial state. Valid only for readers - * created with bson_reader_new_from_data. - * - *-------------------------------------------------------------------------- - */ - -void -bson_reader_reset (bson_reader_t *reader) -{ - bson_reader_data_t *real = (bson_reader_data_t *) reader; - - if (real->type != BSON_READER_DATA) { - fprintf (stderr, "Reader type cannot be reset\n"); - return; - } - - real->offset = 0; -} diff --git a/bsonjs/bson/bson-reader.h b/bsonjs/bson/bson-reader.h deleted file mode 100644 index 827b0fe..0000000 --- a/bsonjs/bson/bson-reader.h +++ /dev/null @@ -1,114 +0,0 @@ -/* - * Copyright 2013 MongoDB, Inc. - * - * 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. - */ - -#include - - -#ifndef BSON_READER_H -#define BSON_READER_H - - -#include -#include -#include - - -BSON_BEGIN_DECLS - - -#define BSON_ERROR_READER_BADFD 1 - - -/* - *-------------------------------------------------------------------------- - * - * bson_reader_read_func_t -- - * - * This function is a callback used by bson_reader_t to read the - * next chunk of data from the underlying opaque file descriptor. - * - * This function is meant to operate similar to the read() function - * as part of libc on UNIX-like systems. - * - * Parameters: - * @handle: The handle to read from. - * @buf: The buffer to read into. - * @count: The number of bytes to read. - * - * Returns: - * 0 for end of stream. - * -1 for read failure. - * Greater than zero for number of bytes read into @buf. - * - * Side effects: - * None. - * - *-------------------------------------------------------------------------- - */ - -typedef ssize_t (*bson_reader_read_func_t) (void *handle, /* IN */ - void *buf, /* IN */ - size_t count); /* IN */ - - -/* - *-------------------------------------------------------------------------- - * - * bson_reader_destroy_func_t -- - * - * Destroy callback to release any resources associated with the - * opaque handle. - * - * Parameters: - * @handle: the handle provided to bson_reader_new_from_handle(). - * - * Returns: - * None. - * - * Side effects: - * None. - * - *-------------------------------------------------------------------------- - */ - -typedef void (*bson_reader_destroy_func_t) (void *handle); /* IN */ - - -BSON_EXPORT (bson_reader_t *) -bson_reader_new_from_handle (void *handle, bson_reader_read_func_t rf, bson_reader_destroy_func_t df); -BSON_EXPORT (bson_reader_t *) -bson_reader_new_from_fd (int fd, bool close_on_destroy); -BSON_EXPORT (bson_reader_t *) -bson_reader_new_from_file (const char *path, bson_error_t *error); -BSON_EXPORT (bson_reader_t *) -bson_reader_new_from_data (const uint8_t *data, size_t length); -BSON_EXPORT (void) -bson_reader_destroy (bson_reader_t *reader); -BSON_EXPORT (void) -bson_reader_set_read_func (bson_reader_t *reader, bson_reader_read_func_t func); -BSON_EXPORT (void) -bson_reader_set_destroy_func (bson_reader_t *reader, bson_reader_destroy_func_t func); -BSON_EXPORT (const bson_t *) -bson_reader_read (bson_reader_t *reader, bool *reached_eof); -BSON_EXPORT (off_t) -bson_reader_tell (bson_reader_t *reader); -BSON_EXPORT (void) -bson_reader_reset (bson_reader_t *reader); - -BSON_END_DECLS - - -#endif /* BSON_READER_H */ diff --git a/bsonjs/bson/bson-string.c b/bsonjs/bson/bson-string.c deleted file mode 100644 index f9b564a..0000000 --- a/bsonjs/bson/bson-string.c +++ /dev/null @@ -1,836 +0,0 @@ -/* - * Copyright 2013 MongoDB, Inc. - * - * 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. - */ - - -#include -#include - -#include -#include -#include -#include -#include -#include - -#ifdef BSON_HAVE_STRINGS_H -#include -#else -#include -#endif - -/* - *-------------------------------------------------------------------------- - * - * bson_string_new -- - * - * Create a new bson_string_t. - * - * bson_string_t is a power-of-2 allocation growing string. Every - * time data is appended the next power of two size is chosen for - * the allocation. Pretty standard stuff. - * - * It is UTF-8 aware through the use of bson_string_append_unichar(). - * The proper UTF-8 character sequence will be used. - * - * Parameters: - * @str: a string to copy or NULL. - * - * Returns: - * A newly allocated bson_string_t that should be freed with - * bson_string_free(). - * - * Side effects: - * None. - * - *-------------------------------------------------------------------------- - */ - -bson_string_t * -bson_string_new (const char *str) /* IN */ -{ - bson_string_t *ret; - size_t len_sz; - - ret = bson_malloc0 (sizeof *ret); - if (str) { - len_sz = strlen (str); - BSON_ASSERT (len_sz <= UINT32_MAX); - ret->len = (uint32_t) len_sz; - } else { - ret->len = 0; - } - ret->alloc = ret->len + 1; - - if (!bson_is_power_of_two (ret->alloc)) { - len_sz = bson_next_power_of_two ((size_t) ret->alloc); - BSON_ASSERT (len_sz <= UINT32_MAX); - ret->alloc = (uint32_t) len_sz; - } - - BSON_ASSERT (ret->alloc >= ret->len + 1); - - ret->str = bson_malloc (ret->alloc); - - if (str) { - memcpy (ret->str, str, ret->len); - } - - ret->str[ret->len] = '\0'; - - return ret; -} - -char * -bson_string_free (bson_string_t *string, /* IN */ - bool free_segment) /* IN */ -{ - char *ret = NULL; - - if (!string) { - return NULL; - } - - if (!free_segment) { - ret = string->str; - } else { - bson_free (string->str); - } - - bson_free (string); - - return ret; -} - - -/* - *-------------------------------------------------------------------------- - * - * bson_string_append -- - * - * Append the UTF-8 string @str to @string. - * - * Returns: - * None. - * - * Side effects: - * None. - * - *-------------------------------------------------------------------------- - */ - -void -bson_string_append (bson_string_t *string, /* IN */ - const char *str) /* IN */ -{ - uint32_t len; - size_t len_sz; - - BSON_ASSERT (string); - BSON_ASSERT (str); - - len_sz = strlen (str); - BSON_ASSERT (bson_in_range_unsigned (uint32_t, len_sz)); - len = (uint32_t) len_sz; - - if ((string->alloc - string->len - 1) < len) { - BSON_ASSERT (string->alloc <= UINT32_MAX - len); - string->alloc += len; - if (!bson_is_power_of_two (string->alloc)) { - len_sz = bson_next_power_of_two ((size_t) string->alloc); - BSON_ASSERT (len_sz <= UINT32_MAX); - string->alloc = (uint32_t) len_sz; - } - BSON_ASSERT (string->alloc >= string->len + len); - string->str = bson_realloc (string->str, string->alloc); - } - - memcpy (string->str + string->len, str, len); - string->len += len; - string->str[string->len] = '\0'; -} - - -/* - *-------------------------------------------------------------------------- - * - * bson_string_append_c -- - * - * Append the ASCII character @c to @string. - * - * Do not use this if you are working with UTF-8 sequences, - * use bson_string_append_unichar(). - * - * Returns: - * None. - * - * Side effects: - * None. - * - *-------------------------------------------------------------------------- - */ - -void -bson_string_append_c (bson_string_t *string, /* IN */ - char c) /* IN */ -{ - char cc[2]; - - BSON_ASSERT (string); - - if (BSON_UNLIKELY (string->alloc == (string->len + 1))) { - cc[0] = c; - cc[1] = '\0'; - bson_string_append (string, cc); - return; - } - - string->str[string->len++] = c; - string->str[string->len] = '\0'; -} - - -/* - *-------------------------------------------------------------------------- - * - * bson_string_append_unichar -- - * - * Append the bson_unichar_t @unichar to the string @string. - * - * Returns: - * None. - * - * Side effects: - * None. - * - *-------------------------------------------------------------------------- - */ - -void -bson_string_append_unichar (bson_string_t *string, /* IN */ - bson_unichar_t unichar) /* IN */ -{ - uint32_t len; - char str[8]; - - BSON_ASSERT (string); - BSON_ASSERT (unichar); - - bson_utf8_from_unichar (unichar, str, &len); - - if (len <= 6) { - str[len] = '\0'; - bson_string_append (string, str); - } -} - - -/* - *-------------------------------------------------------------------------- - * - * bson_string_append_printf -- - * - * Format a string according to @format and append it to @string. - * - * Returns: - * None. - * - * Side effects: - * None. - * - *-------------------------------------------------------------------------- - */ - -void -bson_string_append_printf (bson_string_t *string, const char *format, ...) -{ - va_list args; - char *ret; - - BSON_ASSERT (string); - BSON_ASSERT (format); - - va_start (args, format); - ret = bson_strdupv_printf (format, args); - va_end (args); - bson_string_append (string, ret); - bson_free (ret); -} - - -/* - *-------------------------------------------------------------------------- - * - * bson_string_truncate -- - * - * Truncate the string @string to @len bytes. - * - * The underlying memory will be released via realloc() down to - * the minimum required size specified by @len. - * - * Returns: - * None. - * - * Side effects: - * None. - * - *-------------------------------------------------------------------------- - */ - -void -bson_string_truncate (bson_string_t *string, /* IN */ - uint32_t len) /* IN */ -{ - uint32_t alloc; - - BSON_ASSERT (string); - BSON_ASSERT (len < INT_MAX); - - alloc = len + 1; - - if (alloc < 16) { - alloc = 16; - } - - if (!bson_is_power_of_two (alloc)) { - alloc = (uint32_t) bson_next_power_of_two ((size_t) alloc); - } - - string->str = bson_realloc (string->str, alloc); - string->alloc = alloc; - string->len = len; - - string->str[string->len] = '\0'; -} - - -/* - *-------------------------------------------------------------------------- - * - * bson_strdup -- - * - * Portable strdup(). - * - * Returns: - * A newly allocated string that should be freed with bson_free(). - * - * Side effects: - * None. - * - *-------------------------------------------------------------------------- - */ - -char * -bson_strdup (const char *str) /* IN */ -{ - long len; - char *out; - - if (!str) { - return NULL; - } - - len = (long) strlen (str); - out = bson_malloc (len + 1); - - if (!out) { - return NULL; - } - - memcpy (out, str, len + 1); - - return out; -} - - -/* - *-------------------------------------------------------------------------- - * - * bson_strdupv_printf -- - * - * Like bson_strdup_printf() but takes a va_list. - * - * Returns: - * A newly allocated string that should be freed with bson_free(). - * - * Side effects: - * None. - * - *-------------------------------------------------------------------------- - */ - -char * -bson_strdupv_printf (const char *format, /* IN */ - va_list args) /* IN */ -{ - va_list my_args; - char *buf; - int len = 32; - int n; - - BSON_ASSERT (format); - - buf = bson_malloc0 (len); - - while (true) { - va_copy (my_args, args); - n = bson_vsnprintf (buf, len, format, my_args); - va_end (my_args); - - if (n > -1 && n < len) { - return buf; - } - - if (n > -1) { - len = n + 1; - } else { - len *= 2; - } - - buf = bson_realloc (buf, len); - } -} - - -/* - *-------------------------------------------------------------------------- - * - * bson_strdup_printf -- - * - * Convenience function that formats a string according to @format - * and returns a copy of it. - * - * Returns: - * A newly created string that should be freed with bson_free(). - * - * Side effects: - * None. - * - *-------------------------------------------------------------------------- - */ - -char * -bson_strdup_printf (const char *format, /* IN */ - ...) /* IN */ -{ - va_list args; - char *ret; - - BSON_ASSERT (format); - - va_start (args, format); - ret = bson_strdupv_printf (format, args); - va_end (args); - - return ret; -} - - -/* - *-------------------------------------------------------------------------- - * - * bson_strndup -- - * - * A portable strndup(). - * - * Returns: - * A newly allocated string that should be freed with bson_free(). - * - * Side effects: - * None. - * - *-------------------------------------------------------------------------- - */ - -char * -bson_strndup (const char *str, /* IN */ - size_t n_bytes) /* IN */ -{ - char *ret; - - BSON_ASSERT (str); - - ret = bson_malloc (n_bytes + 1); - bson_strncpy (ret, str, n_bytes + 1); - - return ret; -} - - -/* - *-------------------------------------------------------------------------- - * - * bson_strfreev -- - * - * Frees each string in a NULL terminated array of strings. - * This also frees the underlying array. - * - * Returns: - * None. - * - * Side effects: - * None. - * - *-------------------------------------------------------------------------- - */ - -void -bson_strfreev (char **str) /* IN */ -{ - if (str) { - for (char **ptr = str; *ptr != NULL; ++ptr) { - bson_free (*ptr); - } - - bson_free (str); - } -} - - -/* - *-------------------------------------------------------------------------- - * - * bson_strnlen -- - * - * A portable strnlen(). - * - * Returns: - * The length of @s up to @maxlen. - * - * Side effects: - * None. - * - *-------------------------------------------------------------------------- - */ - -size_t -bson_strnlen (const char *s, /* IN */ - size_t maxlen) /* IN */ -{ -#ifdef BSON_HAVE_STRNLEN - return strnlen (s, maxlen); -#else - size_t i; - - for (i = 0; i < maxlen; i++) { - if (s[i] == '\0') { - return i; - } - } - - return maxlen; -#endif -} - - -/* - *-------------------------------------------------------------------------- - * - * bson_strncpy -- - * - * A portable strncpy. - * - * Copies @src into @dst, which must be @size bytes or larger. - * The result is guaranteed to be \0 terminated. - * - * Returns: - * None. - * - * Side effects: - * None. - * - *-------------------------------------------------------------------------- - */ - -void -bson_strncpy (char *dst, /* IN */ - const char *src, /* IN */ - size_t size) /* IN */ -{ - if (size == 0) { - return; - } - -/* Prefer strncpy_s for MSVC, or strlcpy, which has additional checks and only - * adds one trailing \0 */ -#ifdef _MSC_VER - strncpy_s (dst, size, src, _TRUNCATE); -#elif defined(BSON_HAVE_STRLCPY) - strlcpy (dst, src, size); -#else - strncpy (dst, src, size); - dst[size - 1] = '\0'; -#endif -} - - -/* - *-------------------------------------------------------------------------- - * - * bson_vsnprintf -- - * - * A portable vsnprintf. - * - * If more than @size bytes are required (exluding the null byte), - * then @size bytes will be written to @string and the return value - * is the number of bytes required. - * - * This function will always return a NULL terminated string. - * - * Returns: - * The number of bytes required for @format excluding the null byte. - * - * Side effects: - * @str is initialized with the formatted string. - * - *-------------------------------------------------------------------------- - */ - -int -bson_vsnprintf (char *str, /* IN */ - size_t size, /* IN */ - const char *format, /* IN */ - va_list ap) /* IN */ -{ -#ifdef _MSC_VER - int r = -1; - - BSON_ASSERT (str); - - if (size == 0) { - return 0; - } - - r = _vsnprintf_s (str, size, _TRUNCATE, format, ap); - if (r == -1) { - r = _vscprintf (format, ap); - } - - str[size - 1] = '\0'; - - return r; -#else - int r; - - BSON_ASSERT (str); - - if (size == 0) { - return 0; - } - - r = vsnprintf (str, size, format, ap); - str[size - 1] = '\0'; - return r; -#endif -} - - -/* - *-------------------------------------------------------------------------- - * - * bson_snprintf -- - * - * A portable snprintf. - * - * If @format requires more than @size bytes, then @size bytes are - * written and the result is the number of bytes required (excluding - * the null byte). - * - * This function will always return a NULL terminated string. - * - * Returns: - * The number of bytes required for @format. - * - * Side effects: - * @str is initialized. - * - *-------------------------------------------------------------------------- - */ - -int -bson_snprintf (char *str, /* IN */ - size_t size, /* IN */ - const char *format, /* IN */ - ...) -{ - int r; - va_list ap; - - BSON_ASSERT (str); - - va_start (ap, format); - r = bson_vsnprintf (str, size, format, ap); - va_end (ap); - - return r; -} - - -/* - *-------------------------------------------------------------------------- - * - * bson_ascii_strtoll -- - * - * A portable strtoll. - * - * Convert a string to a 64-bit signed integer according to the given - * @base, which must be 16, 10, or 8. Leading whitespace will be ignored. - * - * If base is 0 is passed in, the base is inferred from the string's - * leading characters. Base-16 numbers start with "0x" or "0X", base-8 - * numbers start with "0", base-10 numbers start with a digit from 1 to 9. - * - * If @e is not NULL, it will be assigned the address of the first invalid - * character of @s, or its null terminating byte if the entire string was - * valid. - * - * If an invalid value is encountered, errno will be set to EINVAL and - * zero will be returned. If the number is out of range, errno is set to - * ERANGE and LLONG_MAX or LLONG_MIN is returned. - * - * Returns: - * The result of the conversion. - * - * Side effects: - * errno will be set on error. - * - *-------------------------------------------------------------------------- - */ - -int64_t -bson_ascii_strtoll (const char *s, char **e, int base) -{ - char *tok = (char *) s; - char *digits_start; - char c; - int64_t number = 0; - int64_t sign = 1; - int64_t cutoff; - int64_t cutlim; - - errno = 0; - - if (!s) { - errno = EINVAL; - return 0; - } - - c = *tok; - - while (bson_isspace (c)) { - c = *++tok; - } - - if (c == '-') { - sign = -1; - c = *++tok; - } else if (c == '+') { - c = *++tok; - } else if (!isdigit (c)) { - errno = EINVAL; - return 0; - } - - /* from here down, inspired by NetBSD's strtoll */ - if ((base == 0 || base == 16) && c == '0' && (tok[1] == 'x' || tok[1] == 'X')) { - tok += 2; - c = *tok; - base = 16; - } - - if (base == 0) { - base = c == '0' ? 8 : 10; - } - - /* Cutoff is the greatest magnitude we'll be able to multiply by base without - * range error. If the current number is past cutoff and we see valid digit, - * fail. If the number is *equal* to cutoff, then the next digit must be less - * than cutlim, otherwise fail. - */ - cutoff = sign == -1 ? INT64_MIN : INT64_MAX; - cutlim = (int) (cutoff % base); - cutoff /= base; - if (sign == -1) { - if (cutlim > 0) { - cutlim -= base; - cutoff += 1; - } - cutlim = -cutlim; - } - - digits_start = tok; - - while ((c = *tok)) { - if (isdigit (c)) { - c -= '0'; - } else if (isalpha (c)) { - c -= isupper (c) ? 'A' - 10 : 'a' - 10; - } else { - /* end of number string */ - break; - } - - if (c >= base) { - break; - } - - if (sign == -1) { - if (number < cutoff || (number == cutoff && c > cutlim)) { - number = INT64_MIN; - errno = ERANGE; - break; - } else { - number *= base; - number -= c; - } - } else { - if (number > cutoff || (number == cutoff && c > cutlim)) { - number = INT64_MAX; - errno = ERANGE; - break; - } else { - number *= base; - number += c; - } - } - - tok++; - } - - /* did we parse any digits at all? */ - if (e != NULL && tok > digits_start) { - *e = tok; - } - - return number; -} - - -int -bson_strcasecmp (const char *s1, const char *s2) -{ -#ifdef BSON_OS_WIN32 - return _stricmp (s1, s2); -#else - return strcasecmp (s1, s2); -#endif -} - - -bool -bson_isspace (int c) -{ - return c >= -1 && c <= 255 && isspace (c); -} diff --git a/bsonjs/bson/bson-string.h b/bsonjs/bson/bson-string.h deleted file mode 100644 index 3759aff..0000000 --- a/bsonjs/bson/bson-string.h +++ /dev/null @@ -1,83 +0,0 @@ -/* - * Copyright 2013 MongoDB, Inc. - * - * 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. - */ - -#include - - -#ifndef BSON_STRING_H -#define BSON_STRING_H - - -#include - -#include -#include - - -BSON_BEGIN_DECLS - - -typedef struct { - char *str; - uint32_t len; - uint32_t alloc; -} bson_string_t; - - -BSON_EXPORT (bson_string_t *) -bson_string_new (const char *str); -BSON_EXPORT (char *) -bson_string_free (bson_string_t *string, bool free_segment); -BSON_EXPORT (void) -bson_string_append (bson_string_t *string, const char *str); -BSON_EXPORT (void) -bson_string_append_c (bson_string_t *string, char str); -BSON_EXPORT (void) -bson_string_append_unichar (bson_string_t *string, bson_unichar_t unichar); -BSON_EXPORT (void) -bson_string_append_printf (bson_string_t *string, const char *format, ...) BSON_GNUC_PRINTF (2, 3); -BSON_EXPORT (void) -bson_string_truncate (bson_string_t *string, uint32_t len); -BSON_EXPORT (char *) -bson_strdup (const char *str); -BSON_EXPORT (char *) -bson_strdup_printf (const char *format, ...) BSON_GNUC_PRINTF (1, 2); -BSON_EXPORT (char *) -bson_strdupv_printf (const char *format, va_list args) BSON_GNUC_PRINTF (1, 0); -BSON_EXPORT (char *) -bson_strndup (const char *str, size_t n_bytes); -BSON_EXPORT (void) -bson_strncpy (char *dst, const char *src, size_t size); -BSON_EXPORT (int) -bson_vsnprintf (char *str, size_t size, const char *format, va_list ap) BSON_GNUC_PRINTF (3, 0); -BSON_EXPORT (int) -bson_snprintf (char *str, size_t size, const char *format, ...) BSON_GNUC_PRINTF (3, 4); -BSON_EXPORT (void) -bson_strfreev (char **strv); -BSON_EXPORT (size_t) -bson_strnlen (const char *s, size_t maxlen); -BSON_EXPORT (int64_t) -bson_ascii_strtoll (const char *str, char **endptr, int base); -BSON_EXPORT (int) -bson_strcasecmp (const char *s1, const char *s2); -BSON_EXPORT (bool) -bson_isspace (int c); - - -BSON_END_DECLS - - -#endif /* BSON_STRING_H */ diff --git a/bsonjs/bson/bson-timegm-private.h b/bsonjs/bson/bson-timegm-private.h deleted file mode 100644 index 93d9a8e..0000000 --- a/bsonjs/bson/bson-timegm-private.h +++ /dev/null @@ -1,51 +0,0 @@ -/* - * Copyright 2014 MongoDB, Inc. - * - * 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. - */ - -#include - - -#ifndef BSON_TIMEGM_PRIVATE_H -#define BSON_TIMEGM_PRIVATE_H - - -#include -#include - - -BSON_BEGIN_DECLS - -/* avoid system-dependent struct tm definitions */ -struct bson_tm { - int64_t tm_sec; /* seconds after the minute [0-60] */ - int64_t tm_min; /* minutes after the hour [0-59] */ - int64_t tm_hour; /* hours since midnight [0-23] */ - int64_t tm_mday; /* day of the month [1-31] */ - int64_t tm_mon; /* months since January [0-11] */ - int64_t tm_year; /* years since 1900 */ - int64_t tm_wday; /* days since Sunday [0-6] */ - int64_t tm_yday; /* days since January 1 [0-365] */ - int64_t tm_isdst; /* Daylight Savings Time flag */ - int64_t tm_gmtoff; /* offset from CUT in seconds */ - const char *tm_zone; /* timezone abbreviation */ -}; - -int64_t -_bson_timegm (struct bson_tm *const tmp); - -BSON_END_DECLS - - -#endif /* BSON_TIMEGM_PRIVATE_H */ diff --git a/bsonjs/bson/bson-timegm.c b/bsonjs/bson/bson-timegm.c deleted file mode 100644 index 3753aa9..0000000 --- a/bsonjs/bson/bson-timegm.c +++ /dev/null @@ -1,776 +0,0 @@ -/* -** The original version of this file is in the public domain, so clarified as of -** 1996-06-05 by Arthur David Olson. -*/ - -/* -** Leap second handling from Bradley White. -** POSIX-style TZ environment variable handling from Guy Harris. -** Updated to use int64_t's instead of system-dependent definitions of int64_t -** and struct tm by A. Jesse Jiryu Davis for MongoDB, Inc. -*/ - -#include -#include -#include - -#include "errno.h" -#include "string.h" -#include /* for INT64_MAX and INT64_MIN */ - -/* Unlike 's isdigit, this also works if c < 0 | c > UCHAR_MAX. */ -#define is_digit(c) ((unsigned) (c) - '0' <= 9) - -#if 2 < __GNUC__ + (96 <= __GNUC_MINOR__) -#define ATTRIBUTE_CONST __attribute__ ((const)) -#define ATTRIBUTE_PURE __attribute__ ((__pure__)) -#define ATTRIBUTE_FORMAT(spec) __attribute__ ((__format__ spec)) -#else -#define ATTRIBUTE_CONST /* empty */ -#define ATTRIBUTE_PURE /* empty */ -#define ATTRIBUTE_FORMAT(spec) /* empty */ -#endif - -#if !defined _Noreturn && (!defined(__STDC_VERSION__) || __STDC_VERSION__ < 201112) -#if 2 < __GNUC__ + (8 <= __GNUC_MINOR__) -#define _Noreturn __attribute__ ((__noreturn__)) -#else -#define _Noreturn -#endif -#endif - -#if !defined(__STDC_VERSION__) && !defined restrict -#define restrict /* empty */ -#endif - -#ifdef __clang__ -#pragma clang diagnostic push -#pragma clang diagnostic ignored "-Wunknown-pragmas" -#pragma clang diagnostic push -#pragma clang diagnostic ignored "-Wshift-negative-value" -#endif - -/* The minimum and maximum finite time values. */ -static int64_t const time_t_min = INT64_MIN; -static int64_t const time_t_max = INT64_MAX; - -#ifdef __clang__ -#pragma clang diagnostic pop -#pragma clang diagnostic pop -#endif - -#ifndef TZ_MAX_TIMES -#define TZ_MAX_TIMES 2000 -#endif /* !defined TZ_MAX_TIMES */ - -#ifndef TZ_MAX_TYPES -/* This must be at least 17 for Europe/Samara and Europe/Vilnius. */ -#define TZ_MAX_TYPES 256 /* Limited by what (unsigned char)'s can hold */ -#endif /* !defined TZ_MAX_TYPES */ - -#ifndef TZ_MAX_CHARS -#define TZ_MAX_CHARS 50 /* Maximum number of abbreviation characters */ - /* (limited by what unsigned chars can hold) */ -#endif /* !defined TZ_MAX_CHARS */ - -#ifndef TZ_MAX_LEAPS -#define TZ_MAX_LEAPS 50 /* Maximum number of leap second corrections */ -#endif /* !defined TZ_MAX_LEAPS */ - -#define SECSPERMIN 60 -#define MINSPERHOUR 60 -#define HOURSPERDAY 24 -#define DAYSPERWEEK 7 -#define DAYSPERNYEAR 365 -#define DAYSPERLYEAR 366 -#define SECSPERHOUR (SECSPERMIN * MINSPERHOUR) -#define SECSPERDAY ((int_fast32_t) SECSPERHOUR * HOURSPERDAY) -#define MONSPERYEAR 12 - -#define TM_SUNDAY 0 -#define TM_MONDAY 1 -#define TM_TUESDAY 2 -#define TM_WEDNESDAY 3 -#define TM_THURSDAY 4 -#define TM_FRIDAY 5 -#define TM_SATURDAY 6 - -#define TM_JANUARY 0 -#define TM_FEBRUARY 1 -#define TM_MARCH 2 -#define TM_APRIL 3 -#define TM_MAY 4 -#define TM_JUNE 5 -#define TM_JULY 6 -#define TM_AUGUST 7 -#define TM_SEPTEMBER 8 -#define TM_OCTOBER 9 -#define TM_NOVEMBER 10 -#define TM_DECEMBER 11 - -#define TM_YEAR_BASE 1900 - -#define EPOCH_YEAR 1970 -#define EPOCH_WDAY TM_THURSDAY - -#define isleap(y) (((y) % 4) == 0 && (((y) % 100) != 0 || ((y) % 400) == 0)) - -/* -** Since everything in isleap is modulo 400 (or a factor of 400), we know that -** isleap(y) == isleap(y % 400) -** and so -** isleap(a + b) == isleap((a + b) % 400) -** or -** isleap(a + b) == isleap(a % 400 + b % 400) -** This is true even if % means modulo rather than Fortran remainder -** (which is allowed by C89 but not C99). -** We use this to avoid addition overflow problems. -*/ - -#define isleap_sum(a, b) isleap ((a) % 400 + (b) % 400) - -#ifndef TZ_ABBR_MAX_LEN -#define TZ_ABBR_MAX_LEN 16 -#endif /* !defined TZ_ABBR_MAX_LEN */ - -#ifndef TZ_ABBR_CHAR_SET -#define TZ_ABBR_CHAR_SET "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789 :+-._" -#endif /* !defined TZ_ABBR_CHAR_SET */ - -#ifndef TZ_ABBR_ERR_CHAR -#define TZ_ABBR_ERR_CHAR '_' -#endif /* !defined TZ_ABBR_ERR_CHAR */ - -#ifndef WILDABBR -/* -** Someone might make incorrect use of a time zone abbreviation: -** 1. They might reference tzname[0] before calling tzset (explicitly -** or implicitly). -** 2. They might reference tzname[1] before calling tzset (explicitly -** or implicitly). -** 3. They might reference tzname[1] after setting to a time zone -** in which Daylight Saving Time is never observed. -** 4. They might reference tzname[0] after setting to a time zone -** in which Standard Time is never observed. -** 5. They might reference tm.TM_ZONE after calling offtime. -** What's best to do in the above cases is open to debate; -** for now, we just set things up so that in any of the five cases -** WILDABBR is used. Another possibility: initialize tzname[0] to the -** string "tzname[0] used before set", and similarly for the other cases. -** And another: initialize tzname[0] to "ERA", with an explanation in the -** manual page of what this "time zone abbreviation" means (doing this so -** that tzname[0] has the "normal" length of three characters). -*/ -#define WILDABBR " " -#endif /* !defined WILDABBR */ - -#ifdef TM_ZONE -static const char wildabbr[] = WILDABBR; -static const char gmt[] = "GMT"; -#endif - -struct ttinfo { /* time type information */ - int_fast32_t tt_gmtoff; /* UT offset in seconds */ - int tt_isdst; /* used to set tm_isdst */ - int tt_abbrind; /* abbreviation list index */ - int tt_ttisstd; /* true if transition is std time */ - int tt_ttisgmt; /* true if transition is UT */ -}; - -struct lsinfo { /* leap second information */ - int64_t ls_trans; /* transition time */ - int_fast64_t ls_corr; /* correction to apply */ -}; - -#define BIGGEST(a, b) (((a) > (b)) ? (a) : (b)) - -#ifdef TZNAME_MAX -#define MY_TZNAME_MAX TZNAME_MAX -#endif /* defined TZNAME_MAX */ -#ifndef TZNAME_MAX -#define MY_TZNAME_MAX 255 -#endif /* !defined TZNAME_MAX */ - -struct state { - int leapcnt; - int timecnt; - int typecnt; - int charcnt; - int goback; - int goahead; - int64_t ats[TZ_MAX_TIMES]; - unsigned char types[TZ_MAX_TIMES]; - struct ttinfo ttis[TZ_MAX_TYPES]; - char chars[BIGGEST (TZ_MAX_CHARS + 1, (2 * (MY_TZNAME_MAX + 1)))]; - struct lsinfo lsis[TZ_MAX_LEAPS]; - int defaulttype; /* for early times or if no transitions */ -}; - -struct rule { - int r_type; /* type of rule--see below */ - int r_day; /* day number of rule */ - int r_week; /* week number of rule */ - int r_mon; /* month number of rule */ - int_fast32_t r_time; /* transition time of rule */ -}; - -#define JULIAN_DAY 0 /* Jn - Julian day */ -#define DAY_OF_YEAR 1 /* n - day of year */ -#define MONTH_NTH_DAY_OF_WEEK 2 /* Mm.n.d - month, week, day of week */ - -/* -** Prototypes for static functions. -*/ - -static void -gmtload (struct state *const sp); -static struct bson_tm * -gmtsub (const int64_t *const timep, const int_fast32_t offset, struct bson_tm *const tmp); -static int64_t -increment_overflow (int64_t *const ip, int64_t j); -static int64_t -leaps_thru_end_of (const int64_t y) ATTRIBUTE_PURE; -static int64_t -increment_overflow32 (int_fast32_t *const lp, int64_t const m); -static int64_t -normalize_overflow32 (int_fast32_t *const tensptr, int64_t *const unitsptr, const int64_t base); -static int64_t -normalize_overflow (int64_t *const tensptr, int64_t *const unitsptr, const int64_t base); -static int64_t -time1 (struct bson_tm *const tmp, - struct bson_tm *(*const funcp) (const int64_t *, int_fast32_t, struct bson_tm *), - const int_fast32_t offset); -static int64_t -time2 (struct bson_tm *const tmp, - struct bson_tm *(*const funcp) (const int64_t *, int_fast32_t, struct bson_tm *), - const int_fast32_t offset, - int64_t *const okayp); -static int64_t -time2sub (struct bson_tm *const tmp, - struct bson_tm *(*const funcp) (const int64_t *, int_fast32_t, struct bson_tm *), - const int_fast32_t offset, - int64_t *const okayp, - const int64_t do_norm_secs); -static struct bson_tm * -timesub (const int64_t *const timep, - const int_fast32_t offset, - const struct state *const sp, - struct bson_tm *const tmp); -static int64_t -tmcomp (const struct bson_tm *const atmp, const struct bson_tm *const btmp); - -static struct state gmtmem; -#define gmtptr (&gmtmem) - -static int gmt_is_set; - -static const int mon_lengths[2][MONSPERYEAR] = {{31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}, - {31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}}; - -static const int year_lengths[2] = {DAYSPERNYEAR, DAYSPERLYEAR}; - -static void -gmtload (struct state *const sp) -{ - memset (sp, 0, sizeof (struct state)); - sp->typecnt = 1; - sp->charcnt = 4; - sp->chars[0] = 'G'; - sp->chars[1] = 'M'; - sp->chars[2] = 'T'; -} - -/* -** gmtsub is to gmtime as localsub is to localtime. -*/ - -static struct bson_tm * -gmtsub (const int64_t *const timep, const int_fast32_t offset, struct bson_tm *const tmp) -{ - struct bson_tm *result; - - if (!gmt_is_set) { - gmt_is_set = true; - gmtload (gmtptr); - } - result = timesub (timep, offset, gmtptr, tmp); -#ifdef TM_ZONE - /* - ** Could get fancy here and deliver something such as - ** "UT+xxxx" or "UT-xxxx" if offset is non-zero, - ** but this is no time for a treasure hunt. - */ - tmp->TM_ZONE = offset ? wildabbr : gmtptr ? gmtptr->chars : gmt; -#endif /* defined TM_ZONE */ - return result; -} - -/* -** Return the number of leap years through the end of the given year -** where, to make the math easy, the answer for year zero is defined as zero. -*/ - -static int64_t -leaps_thru_end_of (const int64_t y) -{ - return (y >= 0) ? (y / 4 - y / 100 + y / 400) : -(leaps_thru_end_of (-(y + 1)) + 1); -} - -static struct bson_tm * -timesub (const int64_t *const timep, const int_fast32_t offset, const struct state *const sp, struct bson_tm *const tmp) -{ - const struct lsinfo *lp; - int64_t tdays; - int64_t idays; /* unsigned would be so 2003 */ - int_fast64_t rem; - int64_t y; - const int (*ip)[MONSPERYEAR]; - int_fast64_t corr; - int64_t hit; - int64_t i; - - corr = 0; - hit = 0; - i = (sp == NULL) ? 0 : sp->leapcnt; - while (--i >= 0) { - lp = &sp->lsis[i]; - if (*timep >= lp->ls_trans) { - if (*timep == lp->ls_trans) { - hit = ((i == 0 && lp->ls_corr > 0) || lp->ls_corr > sp->lsis[i - 1].ls_corr); - if (hit) - while (i > 0 && sp->lsis[i].ls_trans == sp->lsis[i - 1].ls_trans + 1 && - sp->lsis[i].ls_corr == sp->lsis[i - 1].ls_corr + 1) { - ++hit; - --i; - } - } - corr = lp->ls_corr; - break; - } - } - y = EPOCH_YEAR; - tdays = *timep / SECSPERDAY; - rem = *timep - tdays * SECSPERDAY; - while (tdays < 0 || tdays >= year_lengths[isleap (y)]) { - int64_t newy; - int64_t tdelta; - int64_t idelta; - int64_t leapdays; - - tdelta = tdays / DAYSPERLYEAR; - idelta = tdelta; - if (idelta == 0) - idelta = (tdays < 0) ? -1 : 1; - newy = y; - if (increment_overflow (&newy, idelta)) - return NULL; - leapdays = leaps_thru_end_of (newy - 1) - leaps_thru_end_of (y - 1); - tdays -= ((int64_t) newy - y) * DAYSPERNYEAR; - tdays -= leapdays; - y = newy; - } - { - int_fast32_t seconds; - - seconds = (int_fast32_t) (tdays * SECSPERDAY); - tdays = seconds / SECSPERDAY; - rem += seconds - tdays * SECSPERDAY; - } - /* - ** Given the range, we can now fearlessly cast... - */ - idays = (int64_t) tdays; - rem += offset - corr; - while (rem < 0) { - rem += SECSPERDAY; - --idays; - } - while (rem >= SECSPERDAY) { - rem -= SECSPERDAY; - ++idays; - } - while (idays < 0) { - if (increment_overflow (&y, -1)) - return NULL; - idays += year_lengths[isleap (y)]; - } - while (idays >= year_lengths[isleap (y)]) { - idays -= year_lengths[isleap (y)]; - if (increment_overflow (&y, 1)) - return NULL; - } - tmp->tm_year = y; - if (increment_overflow (&tmp->tm_year, -TM_YEAR_BASE)) - return NULL; - tmp->tm_yday = idays; - /* - ** The "extra" mods below avoid overflow problems. - */ - tmp->tm_wday = EPOCH_WDAY + ((y - EPOCH_YEAR) % DAYSPERWEEK) * (DAYSPERNYEAR % DAYSPERWEEK) + - leaps_thru_end_of (y - 1) - leaps_thru_end_of (EPOCH_YEAR - 1) + idays; - tmp->tm_wday %= DAYSPERWEEK; - if (tmp->tm_wday < 0) - tmp->tm_wday += DAYSPERWEEK; - tmp->tm_hour = (int64_t) (rem / SECSPERHOUR); - rem %= SECSPERHOUR; - tmp->tm_min = (int64_t) (rem / SECSPERMIN); - /* - ** A positive leap second requires a special - ** representation. This uses "... ??:59:60" et seq. - */ - tmp->tm_sec = (int64_t) (rem % SECSPERMIN) + hit; - ip = mon_lengths + (isleap (y) ? 1 : 0); - tmp->tm_mon = 0; - while (idays >= (*ip)[tmp->tm_mon]) { - idays -= (*ip)[tmp->tm_mon++]; - BSON_ASSERT (tmp->tm_mon < MONSPERYEAR); - } - tmp->tm_mday = (int64_t) (idays + 1); - tmp->tm_isdst = 0; -#ifdef TM_GMTOFF - tmp->TM_GMTOFF = offset; -#endif /* defined TM_GMTOFF */ - return tmp; -} - -/* -** Adapted from code provided by Robert Elz, who writes: -** The "best" way to do mktime I think is based on an idea of Bob -** Kridle's (so its said...) from a long time ago. -** It does a binary search of the int64_t space. Since int64_t's are -** just 32 bits, its a max of 32 iterations (even at 64 bits it -** would still be very reasonable). -*/ - -#ifndef WRONG -#define WRONG (-1) -#endif /* !defined WRONG */ - -/* -** Normalize logic courtesy Paul Eggert. -*/ - -static int64_t -increment_overflow (int64_t *const ip, int64_t j) -{ - int64_t const i = *ip; - - /* - ** If i >= 0 there can only be overflow if i + j > INT_MAX - ** or if j > INT_MAX - i; given i >= 0, INT_MAX - i cannot overflow. - ** If i < 0 there can only be overflow if i + j < INT_MIN - ** or if j < INT_MIN - i; given i < 0, INT_MIN - i cannot overflow. - */ - if ((i >= 0) ? (j > INT_MAX - i) : (j < INT_MIN - i)) - return true; - *ip += j; - return false; -} - -static int64_t -increment_overflow32 (int_fast32_t *const lp, int64_t const m) -{ - int_fast32_t const l = *lp; - - if ((l >= 0) ? (m > INT_FAST32_MAX - l) : (m < INT_FAST32_MIN - l)) - return true; - *lp += (int_fast32_t) m; - return false; -} - -static int64_t -normalize_overflow (int64_t *const tensptr, int64_t *const unitsptr, const int64_t base) -{ - int64_t tensdelta; - - tensdelta = (*unitsptr >= 0) ? (*unitsptr / base) : (-1 - (-1 - *unitsptr) / base); - *unitsptr -= tensdelta * base; - return increment_overflow (tensptr, tensdelta); -} - -static int64_t -normalize_overflow32 (int_fast32_t *const tensptr, int64_t *const unitsptr, const int64_t base) -{ - int64_t tensdelta; - - tensdelta = (*unitsptr >= 0) ? (*unitsptr / base) : (-1 - (-1 - *unitsptr) / base); - *unitsptr -= tensdelta * base; - return increment_overflow32 (tensptr, tensdelta); -} - -static int64_t -tmcomp (const struct bson_tm *const atmp, const struct bson_tm *const btmp) -{ - int64_t result; - - if (atmp->tm_year != btmp->tm_year) - return atmp->tm_year < btmp->tm_year ? -1 : 1; - if ((result = (atmp->tm_mon - btmp->tm_mon)) == 0 && (result = (atmp->tm_mday - btmp->tm_mday)) == 0 && - (result = (atmp->tm_hour - btmp->tm_hour)) == 0 && (result = (atmp->tm_min - btmp->tm_min)) == 0) - result = atmp->tm_sec - btmp->tm_sec; - return result; -} - -static int64_t -time2sub (struct bson_tm *const tmp, - struct bson_tm *(*const funcp) (const int64_t *, int_fast32_t, struct bson_tm *), - const int_fast32_t offset, - int64_t *const okayp, - const int64_t do_norm_secs) -{ - const struct state *sp; - int64_t dir; - int64_t i, j; - int64_t saved_seconds; - int_fast32_t li; - int64_t lo; - int64_t hi; - int_fast32_t y; - int64_t newt; - int64_t t; - struct bson_tm yourtm, mytm; - - *okayp = false; - yourtm = *tmp; - if (do_norm_secs) { - if (normalize_overflow (&yourtm.tm_min, &yourtm.tm_sec, SECSPERMIN)) - return WRONG; - } - if (normalize_overflow (&yourtm.tm_hour, &yourtm.tm_min, MINSPERHOUR)) - return WRONG; - if (normalize_overflow (&yourtm.tm_mday, &yourtm.tm_hour, HOURSPERDAY)) - return WRONG; - y = (int_fast32_t) yourtm.tm_year; - if (normalize_overflow32 (&y, &yourtm.tm_mon, MONSPERYEAR)) - return WRONG; - /* - ** Turn y into an actual year number for now. - ** It is converted back to an offset from TM_YEAR_BASE later. - */ - if (increment_overflow32 (&y, TM_YEAR_BASE)) - return WRONG; - while (yourtm.tm_mday <= 0) { - if (increment_overflow32 (&y, -1)) - return WRONG; - li = y + (1 < yourtm.tm_mon); - yourtm.tm_mday += year_lengths[isleap (li)]; - } - while (yourtm.tm_mday > DAYSPERLYEAR) { - li = y + (1 < yourtm.tm_mon); - yourtm.tm_mday -= year_lengths[isleap (li)]; - if (increment_overflow32 (&y, 1)) - return WRONG; - } - for (;;) { - i = mon_lengths[isleap (y)][yourtm.tm_mon]; - if (yourtm.tm_mday <= i) - break; - yourtm.tm_mday -= i; - if (++yourtm.tm_mon >= MONSPERYEAR) { - yourtm.tm_mon = 0; - if (increment_overflow32 (&y, 1)) - return WRONG; - } - } - if (increment_overflow32 (&y, -TM_YEAR_BASE)) - return WRONG; - yourtm.tm_year = y; - if (yourtm.tm_year != y) - return WRONG; - if (yourtm.tm_sec >= 0 && yourtm.tm_sec < SECSPERMIN) - saved_seconds = 0; - else if (y + TM_YEAR_BASE < EPOCH_YEAR) { - /* - ** We can't set tm_sec to 0, because that might push the - ** time below the minimum representable time. - ** Set tm_sec to 59 instead. - ** This assumes that the minimum representable time is - ** not in the same minute that a leap second was deleted from, - ** which is a safer assumption than using 58 would be. - */ - if (increment_overflow (&yourtm.tm_sec, 1 - SECSPERMIN)) - return WRONG; - saved_seconds = yourtm.tm_sec; - yourtm.tm_sec = SECSPERMIN - 1; - } else { - saved_seconds = yourtm.tm_sec; - yourtm.tm_sec = 0; - } - /* - ** Do a binary search. - */ - lo = INT64_MIN; - hi = INT64_MAX; - - for (;;) { - t = lo / 2 + hi / 2; - if (t < lo) - t = lo; - else if (t > hi) - t = hi; - if ((*funcp) (&t, offset, &mytm) == NULL) { - /* - ** Assume that t is too extreme to be represented in - ** a struct bson_tm; arrange things so that it is less - ** extreme on the next pass. - */ - dir = (t > 0) ? 1 : -1; - } else - dir = tmcomp (&mytm, &yourtm); - if (dir != 0) { - if (t == lo) { - if (t == time_t_max) - return WRONG; - ++t; - ++lo; - } else if (t == hi) { - if (t == time_t_min) - return WRONG; - --t; - --hi; - } - if (lo > hi) - return WRONG; - if (dir > 0) - hi = t; - else - lo = t; - continue; - } - if (yourtm.tm_isdst < 0 || mytm.tm_isdst == yourtm.tm_isdst) - break; - /* - ** Right time, wrong type. - ** Hunt for right time, right type. - ** It's okay to guess wrong since the guess - ** gets checked. - */ - sp = (const struct state *) gmtptr; - if (sp == NULL) - return WRONG; - for (i = sp->typecnt - 1; i >= 0; --i) { - if (sp->ttis[i].tt_isdst != yourtm.tm_isdst) - continue; - for (j = sp->typecnt - 1; j >= 0; --j) { - if (sp->ttis[j].tt_isdst == yourtm.tm_isdst) - continue; - newt = t + sp->ttis[j].tt_gmtoff - sp->ttis[i].tt_gmtoff; - if ((*funcp) (&newt, offset, &mytm) == NULL) - continue; - if (tmcomp (&mytm, &yourtm) != 0) - continue; - if (mytm.tm_isdst != yourtm.tm_isdst) - continue; - /* - ** We have a match. - */ - t = newt; - goto label; - } - } - return WRONG; - } -label: - newt = t + saved_seconds; - if ((newt < t) != (saved_seconds < 0)) - return WRONG; - t = newt; - if ((*funcp) (&t, offset, tmp)) - *okayp = true; - return t; -} - -static int64_t -time2 (struct bson_tm *const tmp, - struct bson_tm *(*const funcp) (const int64_t *, int_fast32_t, struct bson_tm *), - const int_fast32_t offset, - int64_t *const okayp) -{ - int64_t t; - - /* - ** First try without normalization of seconds - ** (in case tm_sec contains a value associated with a leap second). - ** If that fails, try with normalization of seconds. - */ - t = time2sub (tmp, funcp, offset, okayp, false); - return *okayp ? t : time2sub (tmp, funcp, offset, okayp, true); -} - -static int64_t -time1 (struct bson_tm *const tmp, - struct bson_tm *(*const funcp) (const int64_t *, int_fast32_t, struct bson_tm *), - const int_fast32_t offset) -{ - int64_t t; - const struct state *sp; - int64_t samei, otheri; - int64_t sameind, otherind; - int64_t i; - int64_t nseen; - int64_t seen[TZ_MAX_TYPES]; - int64_t types[TZ_MAX_TYPES]; - int64_t okay; - - if (tmp == NULL) { - errno = EINVAL; - return WRONG; - } - if (tmp->tm_isdst > 1) - tmp->tm_isdst = 1; - t = time2 (tmp, funcp, offset, &okay); - if (okay) - return t; - if (tmp->tm_isdst < 0) -#ifdef PCTS - /* - ** POSIX Conformance Test Suite code courtesy Grant Sullivan. - */ - tmp->tm_isdst = 0; /* reset to std and try again */ -#else - return t; -#endif /* !defined PCTS */ - /* - ** We're supposed to assume that somebody took a time of one type - ** and did some math on it that yielded a "struct tm" that's bad. - ** We try to divine the type they started from and adjust to the - ** type they need. - */ - sp = (const struct state *) gmtptr; - if (sp == NULL) - return WRONG; - for (i = 0; i < sp->typecnt; ++i) - seen[i] = false; - nseen = 0; - for (i = sp->timecnt - 1; i >= 0; --i) - if (!seen[sp->types[i]]) { - seen[sp->types[i]] = true; - types[nseen++] = sp->types[i]; - } - for (sameind = 0; sameind < nseen; ++sameind) { - samei = types[sameind]; - if (sp->ttis[samei].tt_isdst != tmp->tm_isdst) - continue; - for (otherind = 0; otherind < nseen; ++otherind) { - otheri = types[otherind]; - if (sp->ttis[otheri].tt_isdst == tmp->tm_isdst) - continue; - tmp->tm_sec += sp->ttis[otheri].tt_gmtoff - sp->ttis[samei].tt_gmtoff; - tmp->tm_isdst = !tmp->tm_isdst; - t = time2 (tmp, funcp, offset, &okay); - if (okay) - return t; - tmp->tm_sec -= sp->ttis[otheri].tt_gmtoff - sp->ttis[samei].tt_gmtoff; - tmp->tm_isdst = !tmp->tm_isdst; - } - } - return WRONG; -} - -int64_t -_bson_timegm (struct bson_tm *const tmp) -{ - if (tmp != NULL) - tmp->tm_isdst = 0; - return time1 (tmp, gmtsub, 0L); -} diff --git a/bsonjs/bson/bson-types.h b/bsonjs/bson/bson-types.h deleted file mode 100644 index 3148668..0000000 --- a/bsonjs/bson/bson-types.h +++ /dev/null @@ -1,521 +0,0 @@ -/* - * Copyright 2013 MongoDB, Inc. - * - * 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. - */ - -#include - - -#ifndef BSON_TYPES_H -#define BSON_TYPES_H - - -#include -#include - -#include -#include -#include -#include - -BSON_BEGIN_DECLS - - -/* - *-------------------------------------------------------------------------- - * - * bson_unichar_t -- - * - * bson_unichar_t provides an unsigned 32-bit type for containing - * unicode characters. When iterating UTF-8 sequences, this should - * be used to avoid losing the high-bits of non-ascii characters. - * - * See also: - * bson_string_append_unichar() - * - *-------------------------------------------------------------------------- - */ - -typedef uint32_t bson_unichar_t; - - -/** - * @brief Flags configuring the creation of a bson_context_t - */ -typedef enum { - /** Use default options */ - BSON_CONTEXT_NONE = 0, - /* Deprecated: Generating new OIDs from a bson_context_t is always - thread-safe */ - BSON_CONTEXT_THREAD_SAFE = (1 << 0), - /* Deprecated: Does nothing and is ignored */ - BSON_CONTEXT_DISABLE_HOST_CACHE = (1 << 1), - /* Call getpid() instead of remembering the result of getpid() when using the - context */ - BSON_CONTEXT_DISABLE_PID_CACHE = (1 << 2), - /* Deprecated: Does nothing */ - BSON_CONTEXT_USE_TASK_ID = (1 << 3), -} bson_context_flags_t; - - -/** - * bson_context_t: - * - * This structure manages context for the bson library. It handles - * configuration for thread-safety and other performance related requirements. - * Consumers will create a context and may use multiple under a variety of - * situations. - * - * If your program calls fork(), you should initialize a new bson_context_t - * using bson_context_init(). - * - * If you are using threading, it is suggested that you use a bson_context_t - * per thread for best performance. Alternatively, you can initialize the - * bson_context_t with BSON_CONTEXT_THREAD_SAFE, although a performance penalty - * will be incurred. - * - * Many functions will require that you provide a bson_context_t such as OID - * generation. - * - * This structure is opaque in that you cannot see the contents of the - * structure. However, it is stack allocatable in that enough padding is - * provided in _bson_context_t to hold the structure. - */ -typedef struct _bson_context_t bson_context_t; - -/** - * bson_json_opts_t: - * - * This structure is used to pass options for serializing BSON into extended - * JSON to the respective serialization methods. - * - * max_len can be either a non-negative integer, or BSON_MAX_LEN_UNLIMITED to - * set no limit for serialization length. - */ -typedef struct _bson_json_opts_t bson_json_opts_t; - - -/** - * bson_t: - * - * This structure manages a buffer whose contents are a properly formatted - * BSON document. You may perform various transforms on the BSON documents. - * Additionally, it can be iterated over using bson_iter_t. - * - * See bson_iter_init() for iterating the contents of a bson_t. - * - * When building a bson_t structure using the various append functions, - * memory allocations may occur. That is performed using power of two - * allocations and realloc(). - * - * See http://bsonspec.org for the BSON document spec. - * - * This structure is meant to fit in two sequential 64-byte cachelines. - */ -#ifdef BSON_MEMCHECK -BSON_ALIGNED_BEGIN (128) typedef struct _bson_t { - uint32_t flags; /* Internal flags for the bson_t. */ - uint32_t len; /* Length of BSON data. */ - char *canary; /* For leak checks. */ - uint8_t padding[120 - sizeof (char *)]; -} bson_t BSON_ALIGNED_END (128); -#else -BSON_ALIGNED_BEGIN (128) typedef struct _bson_t { - uint32_t flags; /* Internal flags for the bson_t. */ - uint32_t len; /* Length of BSON data. */ - uint8_t padding[120]; /* Padding for stack allocation. */ -} bson_t BSON_ALIGNED_END (128); -#endif - -/** - * BSON_INITIALIZER: - * - * This macro can be used to initialize a #bson_t structure on the stack - * without calling bson_init(). - * - * |[ - * bson_t b = BSON_INITIALIZER; - * ]| - */ -#ifdef BSON_MEMCHECK -#define BSON_INITIALIZER \ - { \ - 3, 5, bson_malloc (1), {5}, \ - } -#else -#define BSON_INITIALIZER \ - { \ - 3, 5, \ - { \ - 5 \ - } \ - } -#endif - - -BSON_STATIC_ASSERT2 (bson_t, sizeof (bson_t) == 128); - - -/** - * bson_oid_t: - * - * This structure contains the binary form of a BSON Object Id as specified - * on http://bsonspec.org. If you would like the bson_oid_t in string form - * see bson_oid_to_string() or bson_oid_to_string_r(). - */ -typedef struct { - uint8_t bytes[12]; -} bson_oid_t; - -BSON_STATIC_ASSERT2 (oid_t, sizeof (bson_oid_t) == 12); - -/** - * bson_decimal128_t: - * - * @high The high-order bytes of the decimal128. This field contains sign, - * combination bits, exponent, and part of the coefficient continuation. - * @low The low-order bytes of the decimal128. This field contains the second - * part of the coefficient continuation. - * - * This structure is a boxed type containing the value for the BSON decimal128 - * type. The structure stores the 128 bits such that they correspond to the - * native format for the IEEE decimal128 type, if it is implemented. - **/ -typedef struct { -#if BSON_BYTE_ORDER == BSON_LITTLE_ENDIAN - uint64_t low; - uint64_t high; -#elif BSON_BYTE_ORDER == BSON_BIG_ENDIAN - uint64_t high; - uint64_t low; -#endif -} bson_decimal128_t; - - -/** - * bson_validate_flags_t: - * - * This enumeration is used for validation of BSON documents. It allows - * selective control on what you wish to validate. - * - * %BSON_VALIDATE_NONE: No additional validation occurs. - * %BSON_VALIDATE_UTF8: Check that strings are valid UTF-8. - * %BSON_VALIDATE_DOLLAR_KEYS: Check that keys do not start with $. - * %BSON_VALIDATE_DOT_KEYS: Check that keys do not contain a period. - * %BSON_VALIDATE_UTF8_ALLOW_NULL: Allow NUL bytes in UTF-8 text. - * %BSON_VALIDATE_EMPTY_KEYS: Prohibit zero-length field names - */ -typedef enum { - BSON_VALIDATE_NONE = 0, - BSON_VALIDATE_UTF8 = (1 << 0), - BSON_VALIDATE_DOLLAR_KEYS = (1 << 1), - BSON_VALIDATE_DOT_KEYS = (1 << 2), - BSON_VALIDATE_UTF8_ALLOW_NULL = (1 << 3), - BSON_VALIDATE_EMPTY_KEYS = (1 << 4), -} bson_validate_flags_t; - - -/** - * bson_type_t: - * - * This enumeration contains all of the possible types within a BSON document. - * Use bson_iter_type() to fetch the type of a field while iterating over it. - */ -typedef enum { - BSON_TYPE_EOD = 0x00, - BSON_TYPE_DOUBLE = 0x01, - BSON_TYPE_UTF8 = 0x02, - BSON_TYPE_DOCUMENT = 0x03, - BSON_TYPE_ARRAY = 0x04, - BSON_TYPE_BINARY = 0x05, - BSON_TYPE_UNDEFINED = 0x06, - BSON_TYPE_OID = 0x07, - BSON_TYPE_BOOL = 0x08, - BSON_TYPE_DATE_TIME = 0x09, - BSON_TYPE_NULL = 0x0A, - BSON_TYPE_REGEX = 0x0B, - BSON_TYPE_DBPOINTER = 0x0C, - BSON_TYPE_CODE = 0x0D, - BSON_TYPE_SYMBOL = 0x0E, - BSON_TYPE_CODEWSCOPE = 0x0F, - BSON_TYPE_INT32 = 0x10, - BSON_TYPE_TIMESTAMP = 0x11, - BSON_TYPE_INT64 = 0x12, - BSON_TYPE_DECIMAL128 = 0x13, - BSON_TYPE_MAXKEY = 0x7F, - BSON_TYPE_MINKEY = 0xFF, -} bson_type_t; - - -/** - * bson_subtype_t: - * - * This enumeration contains the various subtypes that may be used in a binary - * field. See http://bsonspec.org for more information. - */ -typedef enum { - BSON_SUBTYPE_BINARY = 0x00, - BSON_SUBTYPE_FUNCTION = 0x01, - BSON_SUBTYPE_BINARY_DEPRECATED = 0x02, - BSON_SUBTYPE_UUID_DEPRECATED = 0x03, - BSON_SUBTYPE_UUID = 0x04, - BSON_SUBTYPE_MD5 = 0x05, - BSON_SUBTYPE_ENCRYPTED = 0x06, - BSON_SUBTYPE_COLUMN = 0x07, - BSON_SUBTYPE_SENSITIVE = 0x08, - BSON_SUBTYPE_USER = 0x80, -} bson_subtype_t; - - -/* - *-------------------------------------------------------------------------- - * - * bson_value_t -- - * - * A boxed type to contain various bson_type_t types. - * - * See also: - * bson_value_copy() - * bson_value_destroy() - * - *-------------------------------------------------------------------------- - */ - -BSON_ALIGNED_BEGIN (8) -typedef struct _bson_value_t { - bson_type_t value_type; - int32_t padding; - union { - bson_oid_t v_oid; - int64_t v_int64; - int32_t v_int32; - int8_t v_int8; - double v_double; - bool v_bool; - int64_t v_datetime; - struct { - uint32_t timestamp; - uint32_t increment; - } v_timestamp; - struct { - char *str; - uint32_t len; - } v_utf8; - struct { - uint8_t *data; - uint32_t data_len; - } v_doc; - struct { - uint8_t *data; - uint32_t data_len; - bson_subtype_t subtype; - } v_binary; - struct { - char *regex; - char *options; - } v_regex; - struct { - char *collection; - uint32_t collection_len; - bson_oid_t oid; - } v_dbpointer; - struct { - char *code; - uint32_t code_len; - } v_code; - struct { - char *code; - uint8_t *scope_data; - uint32_t code_len; - uint32_t scope_len; - } v_codewscope; - struct { - char *symbol; - uint32_t len; - } v_symbol; - bson_decimal128_t v_decimal128; - } value; -} bson_value_t BSON_ALIGNED_END (8); - - -/** - * bson_iter_t: - * - * This structure manages iteration over a bson_t structure. It keeps track - * of the location of the current key and value within the buffer. Using the - * various functions to get the value of the iter will read from these - * locations. - * - * This structure is safe to discard on the stack. No cleanup is necessary - * after using it. - */ -BSON_ALIGNED_BEGIN (128) -typedef struct { - const uint8_t *raw; /* The raw buffer being iterated. */ - uint32_t len; /* The length of raw. */ - uint32_t off; /* The offset within the buffer. */ - uint32_t type; /* The offset of the type byte. */ - uint32_t key; /* The offset of the key byte. */ - uint32_t d1; /* The offset of the first data byte. */ - uint32_t d2; /* The offset of the second data byte. */ - uint32_t d3; /* The offset of the third data byte. */ - uint32_t d4; /* The offset of the fourth data byte. */ - uint32_t next_off; /* The offset of the next field. */ - uint32_t err_off; /* The offset of the error. */ - bson_value_t value; /* Internal value for various state. */ -} bson_iter_t BSON_ALIGNED_END (128); - - -/** - * bson_reader_t: - * - * This structure is used to iterate over a sequence of BSON documents. It - * allows for them to be iterated with the possibility of no additional - * memory allocations under certain circumstances such as reading from an - * incoming mongo packet. - */ - -BSON_ALIGNED_BEGIN (BSON_ALIGN_OF_PTR) -typedef struct { - uint32_t type; - /*< private >*/ -} bson_reader_t BSON_ALIGNED_END (BSON_ALIGN_OF_PTR); - - -/** - * bson_visitor_t: - * - * This structure contains a series of pointers that can be executed for - * each field of a BSON document based on the field type. - * - * For example, if an int32 field is found, visit_int32 will be called. - * - * When visiting each field using bson_iter_visit_all(), you may provide a - * data pointer that will be provided with each callback. This might be useful - * if you are marshaling to another language. - * - * You may pre-maturely stop the visitation of fields by returning true in your - * visitor. Returning false will continue visitation to further fields. - */ -BSON_ALIGNED_BEGIN (8) -typedef struct { - /* run before / after descending into a document */ - bool (*visit_before) (const bson_iter_t *iter, const char *key, void *data); - bool (*visit_after) (const bson_iter_t *iter, const char *key, void *data); - /* corrupt BSON, or unsupported type and visit_unsupported_type not set */ - void (*visit_corrupt) (const bson_iter_t *iter, void *data); - /* normal bson field callbacks */ - bool (*visit_double) (const bson_iter_t *iter, const char *key, double v_double, void *data); - bool (*visit_utf8) (const bson_iter_t *iter, const char *key, size_t v_utf8_len, const char *v_utf8, void *data); - bool (*visit_document) (const bson_iter_t *iter, const char *key, const bson_t *v_document, void *data); - bool (*visit_array) (const bson_iter_t *iter, const char *key, const bson_t *v_array, void *data); - bool (*visit_binary) (const bson_iter_t *iter, - const char *key, - bson_subtype_t v_subtype, - size_t v_binary_len, - const uint8_t *v_binary, - void *data); - /* normal field with deprecated "Undefined" BSON type */ - bool (*visit_undefined) (const bson_iter_t *iter, const char *key, void *data); - bool (*visit_oid) (const bson_iter_t *iter, const char *key, const bson_oid_t *v_oid, void *data); - bool (*visit_bool) (const bson_iter_t *iter, const char *key, bool v_bool, void *data); - bool (*visit_date_time) (const bson_iter_t *iter, const char *key, int64_t msec_since_epoch, void *data); - bool (*visit_null) (const bson_iter_t *iter, const char *key, void *data); - bool (*visit_regex) ( - const bson_iter_t *iter, const char *key, const char *v_regex, const char *v_options, void *data); - bool (*visit_dbpointer) (const bson_iter_t *iter, - const char *key, - size_t v_collection_len, - const char *v_collection, - const bson_oid_t *v_oid, - void *data); - bool (*visit_code) (const bson_iter_t *iter, const char *key, size_t v_code_len, const char *v_code, void *data); - bool (*visit_symbol) ( - const bson_iter_t *iter, const char *key, size_t v_symbol_len, const char *v_symbol, void *data); - bool (*visit_codewscope) (const bson_iter_t *iter, - const char *key, - size_t v_code_len, - const char *v_code, - const bson_t *v_scope, - void *data); - bool (*visit_int32) (const bson_iter_t *iter, const char *key, int32_t v_int32, void *data); - bool (*visit_timestamp) ( - const bson_iter_t *iter, const char *key, uint32_t v_timestamp, uint32_t v_increment, void *data); - bool (*visit_int64) (const bson_iter_t *iter, const char *key, int64_t v_int64, void *data); - bool (*visit_maxkey) (const bson_iter_t *iter, const char *key, void *data); - bool (*visit_minkey) (const bson_iter_t *iter, const char *key, void *data); - /* if set, called instead of visit_corrupt when an apparently valid BSON - * includes an unrecognized field type (reading future version of BSON) */ - void (*visit_unsupported_type) (const bson_iter_t *iter, const char *key, uint32_t type_code, void *data); - bool (*visit_decimal128) (const bson_iter_t *iter, - const char *key, - const bson_decimal128_t *v_decimal128, - void *data); - - void *padding[7]; -} bson_visitor_t BSON_ALIGNED_END (8); - -#define BSON_ERROR_BUFFER_SIZE 504 - -BSON_ALIGNED_BEGIN (8) -typedef struct _bson_error_t { - uint32_t domain; - uint32_t code; - char message[BSON_ERROR_BUFFER_SIZE]; -} bson_error_t BSON_ALIGNED_END (8); - - -BSON_STATIC_ASSERT2 (error_t, sizeof (bson_error_t) == 512); - - -/** - * bson_next_power_of_two: - * @v: A 32-bit unsigned integer of required bytes. - * - * Determines the next larger power of two for the value of @v - * in a constant number of operations. - * - * It is up to the caller to guarantee this will not overflow. - * - * Returns: The next power of 2 from @v. - */ -static BSON_INLINE size_t -bson_next_power_of_two (size_t v) -{ - v--; - v |= v >> 1; - v |= v >> 2; - v |= v >> 4; - v |= v >> 8; - v |= v >> 16; -#if BSON_WORD_SIZE == 64 - v |= v >> 32; -#endif - v++; - - return v; -} - - -static BSON_INLINE bool -bson_is_power_of_two (uint32_t v) -{ - return ((v != 0) && ((v & (v - 1)) == 0)); -} - - -BSON_END_DECLS - - -#endif /* BSON_TYPES_H */ diff --git a/bsonjs/bson/bson-utf8.c b/bsonjs/bson/bson-utf8.c deleted file mode 100644 index 61fa985..0000000 --- a/bsonjs/bson/bson-utf8.c +++ /dev/null @@ -1,457 +0,0 @@ -/* - * Copyright 2013 MongoDB, Inc. - * - * 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. - */ - - -#include - -#include -#include -#include - - -/* - *-------------------------------------------------------------------------- - * - * _bson_utf8_get_sequence -- - * - * Determine the sequence length of the first UTF-8 character in - * @utf8. The sequence length is stored in @seq_length and the mask - * for the first character is stored in @first_mask. - * - * Returns: - * None. - * - * Side effects: - * @seq_length is set. - * @first_mask is set. - * - *-------------------------------------------------------------------------- - */ - -static BSON_INLINE void -_bson_utf8_get_sequence (const char *utf8, /* IN */ - uint8_t *seq_length, /* OUT */ - uint8_t *first_mask) /* OUT */ -{ - unsigned char c = *(const unsigned char *) utf8; - uint8_t m; - uint8_t n; - - /* - * See the following[1] for a description of what the given multi-byte - * sequences will be based on the bits set of the first byte. We also need - * to mask the first byte based on that. All subsequent bytes are masked - * against 0x3F. - * - * [1] http://www.joelonsoftware.com/articles/Unicode.html - */ - - if ((c & 0x80) == 0) { - n = 1; - m = 0x7F; - } else if ((c & 0xE0) == 0xC0) { - n = 2; - m = 0x1F; - } else if ((c & 0xF0) == 0xE0) { - n = 3; - m = 0x0F; - } else if ((c & 0xF8) == 0xF0) { - n = 4; - m = 0x07; - } else { - n = 0; - m = 0; - } - - *seq_length = n; - *first_mask = m; -} - - -/* - *-------------------------------------------------------------------------- - * - * bson_utf8_validate -- - * - * Validates that @utf8 is a valid UTF-8 string. Note that we only - * support UTF-8 characters which have sequence length less than or equal - * to 4 bytes (RFC 3629). - * - * If @allow_null is true, then \0 is allowed within @utf8_len bytes - * of @utf8. Generally, this is bad practice since the main point of - * UTF-8 strings is that they can be used with strlen() and friends. - * However, some languages such as Python can send UTF-8 encoded - * strings with NUL's in them. - * - * Parameters: - * @utf8: A UTF-8 encoded string. - * @utf8_len: The length of @utf8 in bytes. - * @allow_null: If \0 is allowed within @utf8, excluding trailing \0. - * - * Returns: - * true if @utf8 is valid UTF-8. otherwise false. - * - * Side effects: - * None. - * - *-------------------------------------------------------------------------- - */ - -bool -bson_utf8_validate (const char *utf8, /* IN */ - size_t utf8_len, /* IN */ - bool allow_null) /* IN */ -{ - bson_unichar_t c; - uint8_t first_mask; - uint8_t seq_length; - size_t i; - size_t j; - - BSON_ASSERT (utf8); - - for (i = 0; i < utf8_len; i += seq_length) { - _bson_utf8_get_sequence (&utf8[i], &seq_length, &first_mask); - - /* - * Ensure we have a valid multi-byte sequence length. - */ - if (!seq_length) { - return false; - } - - /* - * Ensure we have enough bytes left. - */ - if ((utf8_len - i) < seq_length) { - return false; - } - - /* - * Also calculate the next char as a unichar so we can - * check code ranges for non-shortest form. - */ - c = utf8[i] & first_mask; - - /* - * Check the high-bits for each additional sequence byte. - */ - for (j = i + 1; j < (i + seq_length); j++) { - c = (c << 6) | (utf8[j] & 0x3F); - if ((utf8[j] & 0xC0) != 0x80) { - return false; - } - } - - /* - * Check for NULL bytes afterwards. - * - * Hint: if you want to optimize this function, starting here to do - * this in the same pass as the data above would probably be a good - * idea. You would add a branch into the inner loop, but save possibly - * on cache-line bouncing on larger strings. Just a thought. - */ - if (!allow_null) { - for (j = 0; j < seq_length; j++) { - if (((i + j) > utf8_len) || !utf8[i + j]) { - return false; - } - } - } - - /* - * Code point won't fit in utf-16, not allowed. - */ - if (c > 0x0010FFFF) { - return false; - } - - /* - * Byte is in reserved range for UTF-16 high-marks - * for surrogate pairs. - */ - if ((c & 0xFFFFF800) == 0xD800) { - return false; - } - - /* - * Check non-shortest form unicode. - */ - switch (seq_length) { - case 1: - if (c <= 0x007F) { - continue; - } - return false; - - case 2: - if ((c >= 0x0080) && (c <= 0x07FF)) { - continue; - } else if (c == 0) { - /* Two-byte representation for NULL. */ - if (!allow_null) { - return false; - } - continue; - } - return false; - - case 3: - if (((c >= 0x0800) && (c <= 0x0FFF)) || ((c >= 0x1000) && (c <= 0xFFFF))) { - continue; - } - return false; - - case 4: - if (((c >= 0x10000) && (c <= 0x3FFFF)) || ((c >= 0x40000) && (c <= 0xFFFFF)) || - ((c >= 0x100000) && (c <= 0x10FFFF))) { - continue; - } - return false; - - default: - return false; - } - } - - return true; -} - - -/* - *-------------------------------------------------------------------------- - * - * bson_utf8_escape_for_json -- - * - * Allocates a new string matching @utf8 except that special - * characters in JSON will be escaped. The resulting string is also - * UTF-8 encoded. - * - * Both " and \ characters will be escaped. Additionally, if a NUL - * byte is found before @utf8_len bytes, it will be converted to the - * two byte UTF-8 sequence. - * - * Parameters: - * @utf8: A UTF-8 encoded string. - * @utf8_len: The length of @utf8 in bytes or -1 if NUL terminated. - * - * Returns: - * A newly allocated string that should be freed with bson_free(). - * - * Side effects: - * None. - * - *-------------------------------------------------------------------------- - */ - -char * -bson_utf8_escape_for_json (const char *utf8, /* IN */ - ssize_t utf8_len) /* IN */ -{ - bson_unichar_t c; - bson_string_t *str; - bool length_provided = true; - const char *end; - - BSON_ASSERT (utf8); - - str = bson_string_new (NULL); - - if (utf8_len < 0) { - length_provided = false; - utf8_len = strlen (utf8); - } - - end = utf8 + utf8_len; - - while (utf8 < end) { - c = bson_utf8_get_char (utf8); - - switch (c) { - case '\\': - case '"': - bson_string_append_c (str, '\\'); - bson_string_append_unichar (str, c); - break; - case '\b': - bson_string_append (str, "\\b"); - break; - case '\f': - bson_string_append (str, "\\f"); - break; - case '\n': - bson_string_append (str, "\\n"); - break; - case '\r': - bson_string_append (str, "\\r"); - break; - case '\t': - bson_string_append (str, "\\t"); - break; - default: - if (c < ' ') { - bson_string_append_printf (str, "\\u%04x", (unsigned) c); - } else { - bson_string_append_unichar (str, c); - } - break; - } - - if (c) { - utf8 = bson_utf8_next_char (utf8); - } else { - if (length_provided && !*utf8) { - /* we escaped nil as '\u0000', now advance past it */ - utf8++; - } else { - /* invalid UTF-8 */ - bson_string_free (str, true); - return NULL; - } - } - } - - return bson_string_free (str, false); -} - - -/* - *-------------------------------------------------------------------------- - * - * bson_utf8_get_char -- - * - * Fetches the next UTF-8 character from the UTF-8 sequence. - * - * Parameters: - * @utf8: A string containing validated UTF-8. - * - * Returns: - * A 32-bit bson_unichar_t reprsenting the multi-byte sequence. - * - * Side effects: - * None. - * - *-------------------------------------------------------------------------- - */ - -bson_unichar_t -bson_utf8_get_char (const char *utf8) /* IN */ -{ - bson_unichar_t c; - uint8_t mask; - uint8_t num; - int i; - - BSON_ASSERT (utf8); - - _bson_utf8_get_sequence (utf8, &num, &mask); - c = (*utf8) & mask; - - for (i = 1; i < num; i++) { - c = (c << 6) | (utf8[i] & 0x3F); - } - - return c; -} - - -/* - *-------------------------------------------------------------------------- - * - * bson_utf8_next_char -- - * - * Returns an incremented pointer to the beginning of the next - * multi-byte sequence in @utf8. - * - * Parameters: - * @utf8: A string containing validated UTF-8. - * - * Returns: - * An incremented pointer in @utf8. - * - * Side effects: - * None. - * - *-------------------------------------------------------------------------- - */ - -const char * -bson_utf8_next_char (const char *utf8) /* IN */ -{ - uint8_t mask; - uint8_t num; - - BSON_ASSERT (utf8); - - _bson_utf8_get_sequence (utf8, &num, &mask); - - return utf8 + num; -} - - -/* - *-------------------------------------------------------------------------- - * - * bson_utf8_from_unichar -- - * - * Converts the unichar to a sequence of utf8 bytes and stores those - * in @utf8. The number of bytes in the sequence are stored in @len. - * - * Parameters: - * @unichar: A bson_unichar_t. - * @utf8: A location for the multi-byte sequence. - * @len: A location for number of bytes stored in @utf8. - * - * Returns: - * None. - * - * Side effects: - * @utf8 is set. - * @len is set. - * - *-------------------------------------------------------------------------- - */ - -void -bson_utf8_from_unichar (bson_unichar_t unichar, /* IN */ - char utf8[BSON_ENSURE_ARRAY_PARAM_SIZE (6)], /* OUT */ - uint32_t *len) /* OUT */ -{ - BSON_ASSERT (utf8); - BSON_ASSERT (len); - - if (unichar <= 0x7F) { - utf8[0] = unichar; - *len = 1; - } else if (unichar <= 0x7FF) { - *len = 2; - utf8[0] = 0xC0 | ((unichar >> 6) & 0x3F); - utf8[1] = 0x80 | ((unichar) & 0x3F); - } else if (unichar <= 0xFFFF) { - *len = 3; - utf8[0] = 0xE0 | ((unichar >> 12) & 0xF); - utf8[1] = 0x80 | ((unichar >> 6) & 0x3F); - utf8[2] = 0x80 | ((unichar) & 0x3F); - } else if (unichar <= 0x1FFFFF) { - *len = 4; - utf8[0] = 0xF0 | ((unichar >> 18) & 0x7); - utf8[1] = 0x80 | ((unichar >> 12) & 0x3F); - utf8[2] = 0x80 | ((unichar >> 6) & 0x3F); - utf8[3] = 0x80 | ((unichar) & 0x3F); - } else { - *len = 0; - } -} diff --git a/bsonjs/bson/bson-utf8.h b/bsonjs/bson/bson-utf8.h deleted file mode 100644 index af08596..0000000 --- a/bsonjs/bson/bson-utf8.h +++ /dev/null @@ -1,46 +0,0 @@ -/* - * Copyright 2013 MongoDB, Inc. - * - * 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. - */ - -#include - - -#ifndef BSON_UTF8_H -#define BSON_UTF8_H - - -#include -#include - - -BSON_BEGIN_DECLS - - -BSON_EXPORT (bool) -bson_utf8_validate (const char *utf8, size_t utf8_len, bool allow_null); -BSON_EXPORT (char *) -bson_utf8_escape_for_json (const char *utf8, ssize_t utf8_len); -BSON_EXPORT (bson_unichar_t) -bson_utf8_get_char (const char *utf8); -BSON_EXPORT (const char *) -bson_utf8_next_char (const char *utf8); -BSON_EXPORT (void) -bson_utf8_from_unichar (bson_unichar_t unichar, char utf8[6], uint32_t *len); - - -BSON_END_DECLS - - -#endif /* BSON_UTF8_H */ diff --git a/bsonjs/bson/bson-value.c b/bsonjs/bson/bson-value.c deleted file mode 100644 index 3e3c468..0000000 --- a/bsonjs/bson/bson-value.c +++ /dev/null @@ -1,177 +0,0 @@ -/* - * Copyright 2014 MongoDB, Inc. - * - * 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. - */ - - -#include -#include -#include -#include - - -void -bson_value_copy (const bson_value_t *src, /* IN */ - bson_value_t *dst) /* OUT */ -{ - BSON_ASSERT (src); - BSON_ASSERT (dst); - - dst->value_type = src->value_type; - - switch (src->value_type) { - case BSON_TYPE_DOUBLE: - dst->value.v_double = src->value.v_double; - break; - case BSON_TYPE_UTF8: - dst->value.v_utf8.len = src->value.v_utf8.len; - dst->value.v_utf8.str = bson_malloc (src->value.v_utf8.len + 1); - memcpy (dst->value.v_utf8.str, src->value.v_utf8.str, dst->value.v_utf8.len); - dst->value.v_utf8.str[dst->value.v_utf8.len] = '\0'; - break; - case BSON_TYPE_DOCUMENT: - case BSON_TYPE_ARRAY: - dst->value.v_doc.data_len = src->value.v_doc.data_len; - dst->value.v_doc.data = bson_malloc (src->value.v_doc.data_len); - memcpy (dst->value.v_doc.data, src->value.v_doc.data, dst->value.v_doc.data_len); - break; - case BSON_TYPE_BINARY: - dst->value.v_binary.subtype = src->value.v_binary.subtype; - dst->value.v_binary.data_len = src->value.v_binary.data_len; - dst->value.v_binary.data = bson_malloc (src->value.v_binary.data_len); - if (dst->value.v_binary.data_len) { - memcpy (dst->value.v_binary.data, src->value.v_binary.data, dst->value.v_binary.data_len); - } - break; - case BSON_TYPE_OID: - bson_oid_copy (&src->value.v_oid, &dst->value.v_oid); - break; - case BSON_TYPE_BOOL: - dst->value.v_bool = src->value.v_bool; - break; - case BSON_TYPE_DATE_TIME: - dst->value.v_datetime = src->value.v_datetime; - break; - case BSON_TYPE_REGEX: - dst->value.v_regex.regex = bson_strdup (src->value.v_regex.regex); - dst->value.v_regex.options = bson_strdup (src->value.v_regex.options); - break; - case BSON_TYPE_DBPOINTER: - dst->value.v_dbpointer.collection_len = src->value.v_dbpointer.collection_len; - dst->value.v_dbpointer.collection = bson_malloc (src->value.v_dbpointer.collection_len + 1); - memcpy ( - dst->value.v_dbpointer.collection, src->value.v_dbpointer.collection, dst->value.v_dbpointer.collection_len); - dst->value.v_dbpointer.collection[dst->value.v_dbpointer.collection_len] = '\0'; - bson_oid_copy (&src->value.v_dbpointer.oid, &dst->value.v_dbpointer.oid); - break; - case BSON_TYPE_CODE: - dst->value.v_code.code_len = src->value.v_code.code_len; - dst->value.v_code.code = bson_malloc (src->value.v_code.code_len + 1); - memcpy (dst->value.v_code.code, src->value.v_code.code, dst->value.v_code.code_len); - dst->value.v_code.code[dst->value.v_code.code_len] = '\0'; - break; - case BSON_TYPE_SYMBOL: - dst->value.v_symbol.len = src->value.v_symbol.len; - dst->value.v_symbol.symbol = bson_malloc (src->value.v_symbol.len + 1); - memcpy (dst->value.v_symbol.symbol, src->value.v_symbol.symbol, dst->value.v_symbol.len); - dst->value.v_symbol.symbol[dst->value.v_symbol.len] = '\0'; - break; - case BSON_TYPE_CODEWSCOPE: - dst->value.v_codewscope.code_len = src->value.v_codewscope.code_len; - dst->value.v_codewscope.code = bson_malloc (src->value.v_codewscope.code_len + 1); - memcpy (dst->value.v_codewscope.code, src->value.v_codewscope.code, dst->value.v_codewscope.code_len); - dst->value.v_codewscope.code[dst->value.v_codewscope.code_len] = '\0'; - dst->value.v_codewscope.scope_len = src->value.v_codewscope.scope_len; - dst->value.v_codewscope.scope_data = bson_malloc (src->value.v_codewscope.scope_len); - memcpy ( - dst->value.v_codewscope.scope_data, src->value.v_codewscope.scope_data, dst->value.v_codewscope.scope_len); - break; - case BSON_TYPE_INT32: - dst->value.v_int32 = src->value.v_int32; - break; - case BSON_TYPE_TIMESTAMP: - dst->value.v_timestamp.timestamp = src->value.v_timestamp.timestamp; - dst->value.v_timestamp.increment = src->value.v_timestamp.increment; - break; - case BSON_TYPE_INT64: - dst->value.v_int64 = src->value.v_int64; - break; - case BSON_TYPE_DECIMAL128: - dst->value.v_decimal128 = src->value.v_decimal128; - break; - case BSON_TYPE_UNDEFINED: - case BSON_TYPE_NULL: - case BSON_TYPE_MAXKEY: - case BSON_TYPE_MINKEY: - break; - case BSON_TYPE_EOD: - default: - BSON_ASSERT (false); - return; - } -} - - -void -bson_value_destroy (bson_value_t *value) /* IN */ -{ - if (!value) { - return; - } - - switch (value->value_type) { - case BSON_TYPE_UTF8: - bson_free (value->value.v_utf8.str); - break; - case BSON_TYPE_DOCUMENT: - case BSON_TYPE_ARRAY: - bson_free (value->value.v_doc.data); - break; - case BSON_TYPE_BINARY: - bson_free (value->value.v_binary.data); - break; - case BSON_TYPE_REGEX: - bson_free (value->value.v_regex.regex); - bson_free (value->value.v_regex.options); - break; - case BSON_TYPE_DBPOINTER: - bson_free (value->value.v_dbpointer.collection); - break; - case BSON_TYPE_CODE: - bson_free (value->value.v_code.code); - break; - case BSON_TYPE_SYMBOL: - bson_free (value->value.v_symbol.symbol); - break; - case BSON_TYPE_CODEWSCOPE: - bson_free (value->value.v_codewscope.code); - bson_free (value->value.v_codewscope.scope_data); - break; - case BSON_TYPE_DOUBLE: - case BSON_TYPE_UNDEFINED: - case BSON_TYPE_OID: - case BSON_TYPE_BOOL: - case BSON_TYPE_DATE_TIME: - case BSON_TYPE_NULL: - case BSON_TYPE_INT32: - case BSON_TYPE_TIMESTAMP: - case BSON_TYPE_INT64: - case BSON_TYPE_DECIMAL128: - case BSON_TYPE_MAXKEY: - case BSON_TYPE_MINKEY: - case BSON_TYPE_EOD: - default: - break; - } -} diff --git a/bsonjs/bson/bson-value.h b/bsonjs/bson/bson-value.h deleted file mode 100644 index 4175690..0000000 --- a/bsonjs/bson/bson-value.h +++ /dev/null @@ -1,40 +0,0 @@ -/* - * Copyright 2014 MongoDB, Inc. - * - * 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. - */ - -#include - - -#ifndef BSON_VALUE_H -#define BSON_VALUE_H - - -#include -#include - - -BSON_BEGIN_DECLS - - -BSON_EXPORT (void) -bson_value_copy (const bson_value_t *src, bson_value_t *dst); -BSON_EXPORT (void) -bson_value_destroy (bson_value_t *value); - - -BSON_END_DECLS - - -#endif /* BSON_VALUE_H */ diff --git a/bsonjs/bson/bson-version-functions.c b/bsonjs/bson/bson-version-functions.c deleted file mode 100644 index 90406ed..0000000 --- a/bsonjs/bson/bson-version-functions.c +++ /dev/null @@ -1,77 +0,0 @@ -/* - * Copyright 2015 MongoDB, Inc. - * - * 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. - */ - - -#include -#include - - -/** - * bson_get_major_version: - * - * Helper function to return the runtime major version of the library. - */ -int -bson_get_major_version (void) -{ - return BSON_MAJOR_VERSION; -} - - -/** - * bson_get_minor_version: - * - * Helper function to return the runtime minor version of the library. - */ -int -bson_get_minor_version (void) -{ - return BSON_MINOR_VERSION; -} - -/** - * bson_get_micro_version: - * - * Helper function to return the runtime micro version of the library. - */ -int -bson_get_micro_version (void) -{ - return BSON_MICRO_VERSION; -} - -/** - * bson_get_version: - * - * Helper function to return the runtime string version of the library. - */ -const char * -bson_get_version (void) -{ - return BSON_VERSION_S; -} - -/** - * bson_check_version: - * - * True if libmongoc's version is greater than or equal to the required - * version. - */ -bool -bson_check_version (int required_major, int required_minor, int required_micro) -{ - return BSON_CHECK_VERSION (required_major, required_minor, required_micro); -} diff --git a/bsonjs/bson/bson-version-functions.h b/bsonjs/bson/bson-version-functions.h deleted file mode 100644 index 923dcf0..0000000 --- a/bsonjs/bson/bson-version-functions.h +++ /dev/null @@ -1,41 +0,0 @@ -/* - * Copyright 2015 MongoDB, Inc. - * - * 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. - */ - - -#include - - -#ifndef BSON_VERSION_FUNCTIONS_H -#define BSON_VERSION_FUNCTIONS_H - -#include - -BSON_BEGIN_DECLS - -BSON_EXPORT (int) -bson_get_major_version (void); -BSON_EXPORT (int) -bson_get_minor_version (void); -BSON_EXPORT (int) -bson_get_micro_version (void); -BSON_EXPORT (const char *) -bson_get_version (void); -BSON_EXPORT (bool) -bson_check_version (int required_major, int required_minor, int required_micro); - -BSON_END_DECLS - -#endif /* BSON_VERSION_FUNCTIONS_H */ diff --git a/bsonjs/bson/bson-version.h b/bsonjs/bson/bson-version.h deleted file mode 100644 index 1283924..0000000 --- a/bsonjs/bson/bson-version.h +++ /dev/null @@ -1,102 +0,0 @@ -/* - * Copyright 2013 MongoDB, Inc. - * - * 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 !defined(BSON_INSIDE) && !defined(BSON_COMPILATION) -#error "Only can be included directly." -#endif - -// clang-format off - -#ifndef BSON_VERSION_H -#define BSON_VERSION_H - - -/** - * BSON_MAJOR_VERSION: - * - * BSON major version component (e.g. 1 if %BSON_VERSION is 1.2.3) - */ -#define BSON_MAJOR_VERSION (1) - - -/** - * BSON_MINOR_VERSION: - * - * BSON minor version component (e.g. 2 if %BSON_VERSION is 1.2.3) - */ -#define BSON_MINOR_VERSION (27) - - -/** - * BSON_MICRO_VERSION: - * - * BSON micro version component (e.g. 3 if %BSON_VERSION is 1.2.3) - */ -#define BSON_MICRO_VERSION (2) - - -/** - * BSON_PRERELEASE_VERSION: - * - * BSON prerelease version component (e.g. pre if %BSON_VERSION is 1.2.3-pre) - */ -#define BSON_PRERELEASE_VERSION () - -/** - * BSON_VERSION: - * - * BSON version. - */ -#define BSON_VERSION (1.27.2) - - -/** - * BSON_VERSION_S: - * - * BSON version, encoded as a string, useful for printing and - * concatenation. - */ -#define BSON_VERSION_S "1.27.2" - - -/** - * BSON_VERSION_HEX: - * - * BSON version, encoded as an hexadecimal number, useful for - * integer comparisons. - */ -#define BSON_VERSION_HEX (BSON_MAJOR_VERSION << 24 | \ - BSON_MINOR_VERSION << 16 | \ - BSON_MICRO_VERSION << 8) - - -/** - * BSON_CHECK_VERSION: - * @major: required major version - * @minor: required minor version - * @micro: required micro version - * - * Compile-time version checking. Evaluates to %TRUE if the version - * of BSON is greater than or equal to the required one. - */ -#define BSON_CHECK_VERSION(major,minor,micro) \ - (BSON_MAJOR_VERSION > (major) || \ - (BSON_MAJOR_VERSION == (major) && BSON_MINOR_VERSION > (minor)) || \ - (BSON_MAJOR_VERSION == (major) && BSON_MINOR_VERSION == (minor) && \ - BSON_MICRO_VERSION >= (micro))) - -#endif /* BSON_VERSION_H */ diff --git a/bsonjs/bson/bson-writer.c b/bsonjs/bson/bson-writer.c deleted file mode 100644 index d547698..0000000 --- a/bsonjs/bson/bson-writer.c +++ /dev/null @@ -1,270 +0,0 @@ -/* - * Copyright 2013 MongoDB, Inc. - * - * 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. - */ - - -#include -#include - - -struct _bson_writer_t { - bool ready; - uint8_t **buf; - size_t *buflen; - size_t offset; - bson_realloc_func realloc_func; - void *realloc_func_ctx; - bson_t b; -}; - - -/* - *-------------------------------------------------------------------------- - * - * bson_writer_new -- - * - * Creates a new instance of bson_writer_t using the buffer, length, - * offset, and realloc() function supplied. - * - * The caller is expected to clean up the structure when finished - * using bson_writer_destroy(). - * - * Parameters: - * @buf: (inout): A pointer to a target buffer. - * @buflen: (inout): A pointer to the buffer length. - * @offset: The offset in the target buffer to start from. - * @realloc_func: A realloc() style function or NULL. - * - * Returns: - * A newly allocated bson_writer_t that should be freed with - * bson_writer_destroy(). - * - * Side effects: - * None. - * - *-------------------------------------------------------------------------- - */ - -bson_writer_t * -bson_writer_new (uint8_t **buf, /* IN */ - size_t *buflen, /* IN */ - size_t offset, /* IN */ - bson_realloc_func realloc_func, /* IN */ - void *realloc_func_ctx) /* IN */ -{ - bson_writer_t *writer; - - writer = BSON_ALIGNED_ALLOC0 (bson_writer_t); - writer->buf = buf; - writer->buflen = buflen; - writer->offset = offset; - writer->realloc_func = realloc_func; - writer->realloc_func_ctx = realloc_func_ctx; - writer->ready = true; - - return writer; -} - - -/* - *-------------------------------------------------------------------------- - * - * bson_writer_destroy -- - * - * Cleanup after @writer and release any allocated memory. Note that - * the buffer supplied to bson_writer_new() is NOT freed from this - * method. The caller is responsible for that. - * - * Returns: - * None. - * - * Side effects: - * None. - * - *-------------------------------------------------------------------------- - */ - -void -bson_writer_destroy (bson_writer_t *writer) /* IN */ -{ - bson_free (writer); -} - - -/* - *-------------------------------------------------------------------------- - * - * bson_writer_get_length -- - * - * Fetches the current length of the content written by the buffer - * (including the initial offset). This includes a partly written - * document currently being written. - * - * This is useful if you want to check to see if you've passed a given - * memory boundary that cannot be sent in a packet. See - * bson_writer_rollback() to abort the current document being written. - * - * Returns: - * The number of bytes written plus initial offset. - * - * Side effects: - * None. - * - *-------------------------------------------------------------------------- - */ - -size_t -bson_writer_get_length (bson_writer_t *writer) /* IN */ -{ - return writer->offset + writer->b.len; -} - - -/* - *-------------------------------------------------------------------------- - * - * bson_writer_begin -- - * - * Begins writing a new document. The caller may use the bson - * structure to write out a new BSON document. When completed, the - * caller must call either bson_writer_end() or - * bson_writer_rollback(). - * - * Parameters: - * @writer: A bson_writer_t. - * @bson: (out): A location for a bson_t*. - * - * Returns: - * true if the underlying realloc was successful; otherwise false. - * - * Side effects: - * @bson is initialized if true is returned. - * - *-------------------------------------------------------------------------- - */ - -bool -bson_writer_begin (bson_writer_t *writer, /* IN */ - bson_t **bson) /* OUT */ -{ - bson_impl_alloc_t *b; - bool grown = false; - - BSON_ASSERT (writer); - BSON_ASSERT (writer->ready); - BSON_ASSERT (bson); - - writer->ready = false; - - memset (&writer->b, 0, sizeof (bson_t)); - - b = (bson_impl_alloc_t *) &writer->b; - b->flags = BSON_FLAG_STATIC | BSON_FLAG_NO_FREE; - b->len = 5; - b->parent = NULL; - b->buf = writer->buf; - b->buflen = writer->buflen; - b->offset = writer->offset; - b->alloc = NULL; - b->alloclen = 0; - b->realloc = writer->realloc_func; - b->realloc_func_ctx = writer->realloc_func_ctx; - - while ((writer->offset + writer->b.len) > *writer->buflen) { - if (!writer->realloc_func) { - memset (&writer->b, 0, sizeof (bson_t)); - writer->ready = true; - return false; - } - grown = true; - - if (!*writer->buflen) { - *writer->buflen = 64; - } else { - (*writer->buflen) *= 2; - } - } - - if (grown) { - *writer->buf = writer->realloc_func (*writer->buf, *writer->buflen, writer->realloc_func_ctx); - } - - memset ((*writer->buf) + writer->offset + 1, 0, 5); - (*writer->buf)[writer->offset] = 5; - - *bson = &writer->b; - - return true; -} - - -/* - *-------------------------------------------------------------------------- - * - * bson_writer_end -- - * - * Complete writing of a bson_writer_t to the buffer supplied. - * - * Returns: - * None. - * - * Side effects: - * None. - * - *-------------------------------------------------------------------------- - */ - -void -bson_writer_end (bson_writer_t *writer) /* IN */ -{ - BSON_ASSERT (writer); - BSON_ASSERT (!writer->ready); - - writer->offset += writer->b.len; - memset (&writer->b, 0, sizeof (bson_t)); - writer->ready = true; -} - - -/* - *-------------------------------------------------------------------------- - * - * bson_writer_rollback -- - * - * Abort the appending of the current bson_t to the memory region - * managed by @writer. This is useful if you detected that you went - * past a particular memory limit. For example, MongoDB has 48MB - * message limits. - * - * Returns: - * None. - * - * Side effects: - * None. - * - *-------------------------------------------------------------------------- - */ - -void -bson_writer_rollback (bson_writer_t *writer) /* IN */ -{ - BSON_ASSERT (writer); - - if (writer->b.len) { - memset (&writer->b, 0, sizeof (bson_t)); - } - - writer->ready = true; -} diff --git a/bsonjs/bson/bson-writer.h b/bsonjs/bson/bson-writer.h deleted file mode 100644 index dd7d898..0000000 --- a/bsonjs/bson/bson-writer.h +++ /dev/null @@ -1,61 +0,0 @@ -/* - * Copyright 2013 MongoDB, Inc. - * - * 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. - */ - -#include - - -#ifndef BSON_WRITER_H -#define BSON_WRITER_H - - -#include "bson.h" - - -BSON_BEGIN_DECLS - - -/** - * bson_writer_t: - * - * The bson_writer_t structure is a helper for writing a series of BSON - * documents to a single malloc() buffer. You can provide a realloc() style - * function to grow the buffer as you go. - * - * This is useful if you want to build a series of BSON documents right into - * the target buffer for an outgoing packet. The offset parameter allows you to - * start at an offset of the target buffer. - */ -typedef struct _bson_writer_t bson_writer_t; - - -BSON_EXPORT (bson_writer_t *) -bson_writer_new (uint8_t **buf, size_t *buflen, size_t offset, bson_realloc_func realloc_func, void *realloc_func_ctx); -BSON_EXPORT (void) -bson_writer_destroy (bson_writer_t *writer); -BSON_EXPORT (size_t) -bson_writer_get_length (bson_writer_t *writer); -BSON_EXPORT (bool) -bson_writer_begin (bson_writer_t *writer, bson_t **bson); -BSON_EXPORT (void) -bson_writer_end (bson_writer_t *writer); -BSON_EXPORT (void) -bson_writer_rollback (bson_writer_t *writer); - - -BSON_END_DECLS - - -#endif /* BSON_WRITER_H */ diff --git a/bsonjs/bson/bson.c b/bsonjs/bson/bson.c deleted file mode 100644 index adc5ee2..0000000 --- a/bsonjs/bson/bson.c +++ /dev/null @@ -1,3644 +0,0 @@ -/* - * Copyright 2013 MongoDB, Inc. - * - * 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. - */ - - -#include "bson.h" -#include -#include -#include -#include -#include - -#include "common-b64-private.h" - -#include -#include - - -#ifndef BSON_MAX_RECURSION -#define BSON_MAX_RECURSION 200 -#endif - - -typedef enum { - BSON_VALIDATE_PHASE_START, - BSON_VALIDATE_PHASE_TOP, - BSON_VALIDATE_PHASE_LF_REF_KEY, - BSON_VALIDATE_PHASE_LF_REF_UTF8, - BSON_VALIDATE_PHASE_LF_ID_KEY, - BSON_VALIDATE_PHASE_LF_DB_KEY, - BSON_VALIDATE_PHASE_LF_DB_UTF8, - BSON_VALIDATE_PHASE_NOT_DBREF, -} bson_validate_phase_t; - - -/* - * Structures. - */ -typedef struct { - bson_validate_flags_t flags; - ssize_t err_offset; - bson_validate_phase_t phase; - bson_error_t error; -} bson_validate_state_t; - - -typedef struct { - uint32_t count; - bool keys; - ssize_t *err_offset; - uint32_t depth; - bson_string_t *str; - bson_json_mode_t mode; - int32_t max_len; - bool max_len_reached; -} bson_json_state_t; - - -/* - * Forward declarations. - */ -static bool -_bson_as_json_visit_array (const bson_iter_t *iter, const char *key, const bson_t *v_array, void *data); -static bool -_bson_as_json_visit_document (const bson_iter_t *iter, const char *key, const bson_t *v_document, void *data); -static char * -_bson_as_json_visit_all ( - const bson_t *bson, size_t *length, bson_json_mode_t mode, int32_t max_len, bool is_outermost_array); - -/* - * Globals. - */ -static const uint8_t gZero; - -/* - *-------------------------------------------------------------------------- - * - * _bson_impl_inline_grow -- - * - * Document growth implementation for documents that currently - * contain stack based buffers. The document may be switched to - * a malloc based buffer. - * - * Returns: - * true if successful; otherwise false indicating BSON_MAX_SIZE overflow. - * - * Side effects: - * None. - * - *-------------------------------------------------------------------------- - */ - -static bool -_bson_impl_inline_grow (bson_impl_inline_t *impl, /* IN */ - size_t size) /* IN */ -{ - bson_impl_alloc_t *alloc = (bson_impl_alloc_t *) impl; - uint8_t *data; - size_t req; - - if (((size_t) impl->len + size) <= sizeof impl->data) { - return true; - } - - req = bson_next_power_of_two (impl->len + size); - - if (req <= BSON_MAX_SIZE) { - data = bson_malloc (req); - - memcpy (data, impl->data, impl->len); -#ifdef BSON_MEMCHECK - bson_free (impl->canary); -#endif - alloc->flags &= ~BSON_FLAG_INLINE; - alloc->parent = NULL; - alloc->depth = 0; - alloc->buf = &alloc->alloc; - alloc->buflen = &alloc->alloclen; - alloc->offset = 0; - alloc->alloc = data; - alloc->alloclen = req; - alloc->realloc = bson_realloc_ctx; - alloc->realloc_func_ctx = NULL; - - return true; - } - - return false; -} - - -/* - *-------------------------------------------------------------------------- - * - * _bson_impl_alloc_grow -- - * - * Document growth implementation for documents containing malloc - * based buffers. - * - * Returns: - * true if successful; otherwise false indicating BSON_MAX_SIZE overflow. - * - * Side effects: - * None. - * - *-------------------------------------------------------------------------- - */ - -static bool -_bson_impl_alloc_grow (bson_impl_alloc_t *impl, /* IN */ - size_t size) /* IN */ -{ - size_t req; - - /* - * Determine how many bytes we need for this document in the buffer - * including necessary trailing bytes for parent documents. - */ - req = (impl->offset + impl->len + size + impl->depth); - - if (req <= *impl->buflen) { - return true; - } - - req = bson_next_power_of_two (req); - - if ((req <= BSON_MAX_SIZE) && impl->realloc) { - *impl->buf = impl->realloc (*impl->buf, req, impl->realloc_func_ctx); - *impl->buflen = req; - return true; - } - - return false; -} - - -/* - *-------------------------------------------------------------------------- - * - * _bson_grow -- - * - * Grows the bson_t structure to be large enough to contain @size - * bytes. - * - * Returns: - * true if successful, false if the size would overflow. - * - * Side effects: - * None. - * - *-------------------------------------------------------------------------- - */ - -static bool -_bson_grow (bson_t *bson, /* IN */ - uint32_t size) /* IN */ -{ - if ((bson->flags & BSON_FLAG_INLINE)) { - return _bson_impl_inline_grow ((bson_impl_inline_t *) bson, size); - } - - return _bson_impl_alloc_grow ((bson_impl_alloc_t *) bson, size); -} - - -/* - *-------------------------------------------------------------------------- - * - * _bson_data -- - * - * A helper function to return the contents of the bson document - * taking into account the polymorphic nature of bson_t. - * - * Returns: - * A buffer which should not be modified or freed. - * - * Side effects: - * None. - * - *-------------------------------------------------------------------------- - */ - -static BSON_INLINE uint8_t * -_bson_data (const bson_t *bson) /* IN */ -{ - if ((bson->flags & BSON_FLAG_INLINE)) { - return ((bson_impl_inline_t *) bson)->data; - } else { - bson_impl_alloc_t *impl = (bson_impl_alloc_t *) bson; - return (*impl->buf) + impl->offset; - } -} - - -/* - *-------------------------------------------------------------------------- - * - * _bson_encode_length -- - * - * Helper to encode the length of the bson_t in the first 4 bytes - * of the bson document. Little endian format is used as specified - * by bsonspec. - * - * Returns: - * None. - * - * Side effects: - * None. - * - *-------------------------------------------------------------------------- - */ - -static BSON_INLINE void -_bson_encode_length (bson_t *bson) /* IN */ -{ -#if BSON_BYTE_ORDER == BSON_LITTLE_ENDIAN - memcpy (_bson_data (bson), &bson->len, sizeof (bson->len)); -#else - uint32_t length_le = BSON_UINT32_TO_LE (bson->len); - memcpy (_bson_data (bson), &length_le, sizeof (length_le)); -#endif -} - - -/* - *-------------------------------------------------------------------------- - * - * _bson_append_va -- - * - * Appends the length,buffer pairs to the bson_t. @n_bytes is an - * optimization to perform one array growth rather than many small - * growths. - * - * @bson: A bson_t - * @n_bytes: The number of bytes to append to the document. - * @n_pairs: The number of length,buffer pairs. - * @first_len: Length of first buffer. - * @first_data: First buffer. - * @args: va_list of additional tuples. - * - * Returns: - * true if the bytes were appended successfully. - * false if it bson would overflow BSON_MAX_SIZE. - * - * Side effects: - * None. - * - *-------------------------------------------------------------------------- - */ - -static BSON_INLINE bool -_bson_append_va (bson_t *bson, /* IN */ - uint32_t n_bytes, /* IN */ - uint32_t n_pairs, /* IN */ - uint32_t first_len, /* IN */ - const uint8_t *first_data, /* IN */ - va_list args) /* IN */ -{ - const uint8_t *data; - uint32_t data_len; - uint8_t *buf; - - BSON_ASSERT (!(bson->flags & BSON_FLAG_IN_CHILD)); - BSON_ASSERT (!(bson->flags & BSON_FLAG_RDONLY)); - - if (BSON_UNLIKELY (!_bson_grow (bson, n_bytes))) { - return false; - } - - data = first_data; - data_len = first_len; - - buf = _bson_data (bson) + bson->len - 1; - - do { - n_pairs--; - /* data may be NULL if data_len is 0. memcpy is not safe to call with - * NULL. */ - if (BSON_LIKELY (data_len != 0 && data != NULL)) { - memcpy (buf, data, data_len); - bson->len += data_len; - buf += data_len; - } else if (BSON_UNLIKELY (data_len != 0 && data == NULL)) { - /* error, user appending NULL with non-zero length. */ - return false; - } - - if (n_pairs) { - data_len = va_arg (args, uint32_t); - data = va_arg (args, const uint8_t *); - } - } while (n_pairs); - - _bson_encode_length (bson); - - *buf = '\0'; - - return true; -} - - -/* - *-------------------------------------------------------------------------- - * - * _bson_append -- - * - * Variadic function to append length,buffer pairs to a bson_t. If the - * append would cause the bson_t to overflow a 32-bit length, it will - * return false and no append will have occurred. - * - * Parameters: - * @bson: A bson_t. - * @n_pairs: Number of length,buffer pairs. - * @n_bytes: the total number of bytes being appended. - * @first_len: Length of first buffer. - * @first_data: First buffer. - * - * Returns: - * true if successful; otherwise false indicating BSON_MAX_SIZE overflow. - * - * Side effects: - * None. - * - *-------------------------------------------------------------------------- - */ - -static bool -_bson_append (bson_t *bson, /* IN */ - uint32_t n_pairs, /* IN */ - uint32_t n_bytes, /* IN */ - uint32_t first_len, /* IN */ - const uint8_t *first_data, /* IN */ - ...) -{ - va_list args; - bool ok; - - BSON_ASSERT (n_pairs); - BSON_ASSERT (first_len); - BSON_ASSERT (first_data); - - /* - * Check to see if this append would overflow 32-bit signed integer. I know - * what you're thinking. BSON uses a signed 32-bit length field? Yeah. It - * does. - */ - if (BSON_UNLIKELY (n_bytes > (BSON_MAX_SIZE - bson->len))) { - return false; - } - - va_start (args, first_data); - ok = _bson_append_va (bson, n_bytes, n_pairs, first_len, first_data, args); - va_end (args); - - return ok; -} - -static BSON_INLINE bool -_string_contains_null (const char *str, size_t len) -{ - for (; len; ++str, --len) { - if (*str == 0) { - return true; - } - } - return false; -} - -#define HANDLE_KEY_LENGTH(key, key_length) \ - do { \ - if (key_length < 0) { \ - key_length = (int) strlen (key); \ - } else { \ - /* Necessary to validate embedded NULL is not present in key. */ \ - if (_string_contains_null (key, key_length)) { \ - return false; \ - } \ - } \ - } while (0) - -/* - *-------------------------------------------------------------------------- - * - * _bson_append_bson_begin -- - * - * Begin appending a subdocument or subarray to the document using - * the key provided by @key. - * - * If @key_length is < 0, then strlen() will be called on @key - * to determine the length. - * - * @key_type MUST be either BSON_TYPE_DOCUMENT or BSON_TYPE_ARRAY. - * - * Returns: - * true if successful; otherwise false indicating BSON_MAX_SIZE overflow. - * - * Side effects: - * @child is initialized if true is returned. - * - *-------------------------------------------------------------------------- - */ - -static bool -_bson_append_bson_begin (bson_t *bson, /* IN */ - const char *key, /* IN */ - int key_length, /* IN */ - bson_type_t child_type, /* IN */ - bson_t *child) /* OUT */ -{ - const uint8_t type = child_type; - const uint8_t empty[5] = {5}; - bson_impl_alloc_t *aparent = (bson_impl_alloc_t *) bson; - bson_impl_alloc_t *achild = (bson_impl_alloc_t *) child; - - BSON_ASSERT (!(bson->flags & BSON_FLAG_RDONLY)); - BSON_ASSERT (!(bson->flags & BSON_FLAG_IN_CHILD)); - BSON_ASSERT (key); - BSON_ASSERT ((child_type == BSON_TYPE_DOCUMENT) || (child_type == BSON_TYPE_ARRAY)); - BSON_ASSERT (child); - - HANDLE_KEY_LENGTH (key, key_length); - - /* - * If the parent is an inline bson_t, then we need to convert - * it to a heap allocated buffer. This makes extending buffers - * of child bson documents much simpler logic, as they can just - * realloc the *buf pointer. - */ - if ((bson->flags & BSON_FLAG_INLINE)) { - BSON_ASSERT (bson->len <= 120); - if (!_bson_grow (bson, 128 - bson->len)) { - return false; - } - BSON_ASSERT (!(bson->flags & BSON_FLAG_INLINE)); - } - - /* - * Append the type and key for the field. - */ - if (!_bson_append (bson, 4, (1 + key_length + 1 + 5), 1, &type, key_length, key, 1, &gZero, 5, empty)) { - return false; - } - - /* - * Mark the document as working on a child document so that no - * further modifications can happen until the caller has called - * bson_append_{document,array}_end(). - */ - bson->flags |= BSON_FLAG_IN_CHILD; - - /* - * Initialize the child bson_t structure and point it at the parents - * buffers. This allows us to realloc directly from the child without - * walking up to the parent bson_t. - */ - achild->flags = (BSON_FLAG_CHILD | BSON_FLAG_NO_FREE | BSON_FLAG_STATIC); - - if ((bson->flags & BSON_FLAG_CHILD)) { - achild->depth = ((bson_impl_alloc_t *) bson)->depth + 1; - } else { - achild->depth = 1; - } - - achild->parent = bson; - achild->buf = aparent->buf; - achild->buflen = aparent->buflen; - achild->offset = aparent->offset + aparent->len - 1 - 5; - achild->len = 5; - achild->alloc = NULL; - achild->alloclen = 0; - achild->realloc = aparent->realloc; - achild->realloc_func_ctx = aparent->realloc_func_ctx; - - return true; -} - - -/* - *-------------------------------------------------------------------------- - * - * _bson_append_bson_end -- - * - * Complete a call to _bson_append_bson_begin. - * - * Returns: - * true if successful. - * - * Side effects: - * @child is destroyed and no longer valid after calling this - * function. - * - *-------------------------------------------------------------------------- - */ - -static bool -_bson_append_bson_end (bson_t *bson, /* IN */ - bson_t *child) /* IN */ -{ - BSON_ASSERT (bson); - BSON_ASSERT ((bson->flags & BSON_FLAG_IN_CHILD)); - BSON_ASSERT (!(child->flags & BSON_FLAG_IN_CHILD)); - - /* - * Unmark the IN_CHILD flag. - */ - bson->flags &= ~BSON_FLAG_IN_CHILD; - - /* - * Now that we are done building the sub-document, add the size to the - * parent, not including the default 5 byte empty document already added. - */ - bson->len = (bson->len + child->len - 5); - - /* - * Ensure we have a \0 byte at the end and proper length encoded at - * the beginning of the document. - */ - _bson_data (bson)[bson->len - 1] = '\0'; - _bson_encode_length (bson); - - return true; -} - - -/* - *-------------------------------------------------------------------------- - * - * bson_append_array_begin -- - * - * Start appending a new array. - * - * Use @child to append to the data area for the given field. - * - * It is a programming error to call any other bson function on - * @bson until bson_append_array_end() has been called. It is - * valid to call bson_append*() functions on @child. - * - * This function is useful to allow building nested documents using - * a single buffer owned by the top-level bson document. - * - * Returns: - * true if successful; otherwise false and @child is invalid. - * - * Side effects: - * @child is initialized if true is returned. - * - *-------------------------------------------------------------------------- - */ - -bool -bson_append_array_begin (bson_t *bson, /* IN */ - const char *key, /* IN */ - int key_length, /* IN */ - bson_t *child) /* IN */ -{ - BSON_ASSERT (bson); - BSON_ASSERT (key); - BSON_ASSERT (child); - - return _bson_append_bson_begin (bson, key, key_length, BSON_TYPE_ARRAY, child); -} - - -/* - *-------------------------------------------------------------------------- - * - * bson_append_array_end -- - * - * Complete a call to bson_append_array_begin(). - * - * It is safe to append other fields to @bson after calling this - * function. - * - * Returns: - * true if successful. - * - * Side effects: - * @child is invalid after calling this function. - * - *-------------------------------------------------------------------------- - */ - -bool -bson_append_array_end (bson_t *bson, /* IN */ - bson_t *child) /* IN */ -{ - BSON_ASSERT (bson); - BSON_ASSERT (child); - - return _bson_append_bson_end (bson, child); -} - - -/* - *-------------------------------------------------------------------------- - * - * bson_append_document_begin -- - * - * Start appending a new document. - * - * Use @child to append to the data area for the given field. - * - * It is a programming error to call any other bson function on - * @bson until bson_append_document_end() has been called. It is - * valid to call bson_append*() functions on @child. - * - * This function is useful to allow building nested documents using - * a single buffer owned by the top-level bson document. - * - * Returns: - * true if successful; otherwise false and @child is invalid. - * - * Side effects: - * @child is initialized if true is returned. - * - *-------------------------------------------------------------------------- - */ -bool -bson_append_document_begin (bson_t *bson, /* IN */ - const char *key, /* IN */ - int key_length, /* IN */ - bson_t *child) /* IN */ -{ - BSON_ASSERT (bson); - BSON_ASSERT (key); - BSON_ASSERT (child); - - return _bson_append_bson_begin (bson, key, key_length, BSON_TYPE_DOCUMENT, child); -} - - -/* - *-------------------------------------------------------------------------- - * - * bson_append_document_end -- - * - * Complete a call to bson_append_document_begin(). - * - * It is safe to append new fields to @bson after calling this - * function, if true is returned. - * - * Returns: - * true if successful; otherwise false indicating BSON_MAX_SIZE overflow. - * - * Side effects: - * @child is destroyed and invalid after calling this function. - * - *-------------------------------------------------------------------------- - */ - -bool -bson_append_document_end (bson_t *bson, /* IN */ - bson_t *child) /* IN */ -{ - BSON_ASSERT (bson); - BSON_ASSERT (child); - - return _bson_append_bson_end (bson, child); -} - - -/* - *-------------------------------------------------------------------------- - * - * bson_append_array -- - * - * Append an array to @bson. - * - * Generally, bson_append_array_begin() will result in faster code - * since few buffers need to be malloced. - * - * Returns: - * true if successful; otherwise false indicating BSON_MAX_SIZE overflow. - * - * Side effects: - * None. - * - *-------------------------------------------------------------------------- - */ - -bool -bson_append_array (bson_t *bson, /* IN */ - const char *key, /* IN */ - int key_length, /* IN */ - const bson_t *array) /* IN */ -{ - static const uint8_t type = BSON_TYPE_ARRAY; - - BSON_ASSERT (bson); - BSON_ASSERT (key); - BSON_ASSERT (array); - - HANDLE_KEY_LENGTH (key, key_length); - - /* - * Let's be a bit pedantic and ensure the array has properly formatted key - * names. We will verify this simply by checking the first element for "0" - * if the array is non-empty. - */ - if (array && !bson_empty (array)) { - bson_iter_t iter; - - if (bson_iter_init (&iter, array) && bson_iter_next (&iter)) { - if (0 != strcmp ("0", bson_iter_key (&iter))) { - fprintf (stderr, - "%s(): invalid array detected. first element of array " - "parameter is not \"0\".\n", - BSON_FUNC); - } - } - } - - return _bson_append ( - bson, 4, (1 + key_length + 1 + array->len), 1, &type, key_length, key, 1, &gZero, array->len, _bson_data (array)); -} - - -/* - *-------------------------------------------------------------------------- - * - * bson_append_binary -- - * - * Append binary data to @bson. The field will have the - * BSON_TYPE_BINARY type. - * - * Parameters: - * @subtype: the BSON Binary Subtype. See bsonspec.org for more - * information. - * @binary: a pointer to the raw binary data. - * @length: the size of @binary in bytes. - * - * Returns: - * true if successful; otherwise false. - * - * Side effects: - * None. - * - *-------------------------------------------------------------------------- - */ - -bool -bson_append_binary (bson_t *bson, /* IN */ - const char *key, /* IN */ - int key_length, /* IN */ - bson_subtype_t subtype, /* IN */ - const uint8_t *binary, /* IN */ - uint32_t length) /* IN */ -{ - static const uint8_t type = BSON_TYPE_BINARY; - uint32_t length_le; - uint32_t deprecated_length_le; - uint8_t subtype8 = 0; - - BSON_ASSERT (bson); - BSON_ASSERT (key); - - HANDLE_KEY_LENGTH (key, key_length); - - subtype8 = subtype; - - if (subtype == BSON_SUBTYPE_BINARY_DEPRECATED) { - length_le = BSON_UINT32_TO_LE (length + 4); - deprecated_length_le = BSON_UINT32_TO_LE (length); - - return _bson_append (bson, - 7, - (1 + key_length + 1 + 4 + 1 + 4 + length), - 1, - &type, - key_length, - key, - 1, - &gZero, - 4, - &length_le, - 1, - &subtype8, - 4, - &deprecated_length_le, - length, - binary); - } else { - length_le = BSON_UINT32_TO_LE (length); - - return _bson_append (bson, - 6, - (1 + key_length + 1 + 4 + 1 + length), - 1, - &type, - key_length, - key, - 1, - &gZero, - 4, - &length_le, - 1, - &subtype8, - length, - binary); - } -} - - -/* - *-------------------------------------------------------------------------- - * - * bson_append_bool -- - * - * Append a new field to @bson with the name @key. The value is - * a boolean indicated by @value. - * - * Returns: - * true if successful; otherwise false. - * - * Side effects: - * None. - * - *-------------------------------------------------------------------------- - */ - -bool -bson_append_bool (bson_t *bson, /* IN */ - const char *key, /* IN */ - int key_length, /* IN */ - bool value) /* IN */ -{ - static const uint8_t type = BSON_TYPE_BOOL; - uint8_t abyte = !!value; - - BSON_ASSERT (bson); - BSON_ASSERT (key); - - HANDLE_KEY_LENGTH (key, key_length); - - return _bson_append (bson, 4, (1 + key_length + 1 + 1), 1, &type, key_length, key, 1, &gZero, 1, &abyte); -} - - -/* - *-------------------------------------------------------------------------- - * - * bson_append_code -- - * - * Append a new field to @bson containing javascript code. - * - * @javascript MUST be a zero terminated UTF-8 string. It MUST NOT - * containing embedded \0 characters. - * - * Returns: - * true if successful; otherwise false. - * - * Side effects: - * None. - * - * See also: - * bson_append_code_with_scope(). - * - *-------------------------------------------------------------------------- - */ - -bool -bson_append_code (bson_t *bson, /* IN */ - const char *key, /* IN */ - int key_length, /* IN */ - const char *javascript) /* IN */ -{ - static const uint8_t type = BSON_TYPE_CODE; - uint32_t length; - uint32_t length_le; - - BSON_ASSERT (bson); - BSON_ASSERT (key); - BSON_ASSERT (javascript); - - HANDLE_KEY_LENGTH (key, key_length); - - length = (int) strlen (javascript) + 1; - length_le = BSON_UINT32_TO_LE (length); - - return _bson_append (bson, - 5, - (1 + key_length + 1 + 4 + length), - 1, - &type, - key_length, - key, - 1, - &gZero, - 4, - &length_le, - length, - javascript); -} - - -/* - *-------------------------------------------------------------------------- - * - * bson_append_code_with_scope -- - * - * Append a new field to @bson containing javascript code with - * supplied scope. - * - * Returns: - * true if successful; otherwise false. - * - * Side effects: - * None. - * - *-------------------------------------------------------------------------- - */ - -bool -bson_append_code_with_scope (bson_t *bson, /* IN */ - const char *key, /* IN */ - int key_length, /* IN */ - const char *javascript, /* IN */ - const bson_t *scope) /* IN */ -{ - static const uint8_t type = BSON_TYPE_CODEWSCOPE; - uint32_t codews_length_le; - uint32_t codews_length; - uint32_t js_length_le; - uint32_t js_length; - - BSON_ASSERT (bson); - BSON_ASSERT (key); - BSON_ASSERT (javascript); - - if (scope == NULL) { - return bson_append_code (bson, key, key_length, javascript); - } - - HANDLE_KEY_LENGTH (key, key_length); - - js_length = (int) strlen (javascript) + 1; - js_length_le = BSON_UINT32_TO_LE (js_length); - - codews_length = 4 + 4 + js_length + scope->len; - codews_length_le = BSON_UINT32_TO_LE (codews_length); - - return _bson_append (bson, - 7, - (1 + key_length + 1 + 4 + 4 + js_length + scope->len), - 1, - &type, - key_length, - key, - 1, - &gZero, - 4, - &codews_length_le, - 4, - &js_length_le, - js_length, - javascript, - scope->len, - _bson_data (scope)); -} - - -/* - *-------------------------------------------------------------------------- - * - * bson_append_dbpointer -- - * - * This BSON data type is DEPRECATED. - * - * Append a BSON dbpointer field to @bson. - * - * Returns: - * true if successful; otherwise false. - * - * Side effects: - * None. - * - *-------------------------------------------------------------------------- - */ - -bool -bson_append_dbpointer (bson_t *bson, /* IN */ - const char *key, /* IN */ - int key_length, /* IN */ - const char *collection, /* IN */ - const bson_oid_t *oid) -{ - static const uint8_t type = BSON_TYPE_DBPOINTER; - uint32_t length; - uint32_t length_le; - - BSON_ASSERT (bson); - BSON_ASSERT (key); - BSON_ASSERT (collection); - BSON_ASSERT (oid); - - HANDLE_KEY_LENGTH (key, key_length); - - length = (int) strlen (collection) + 1; - length_le = BSON_UINT32_TO_LE (length); - - return _bson_append (bson, - 6, - (1 + key_length + 1 + 4 + length + 12), - 1, - &type, - key_length, - key, - 1, - &gZero, - 4, - &length_le, - length, - collection, - 12, - oid); -} - - -/* - *-------------------------------------------------------------------------- - * - * bson_append_document -- - * - * Append a new field to @bson containing a BSON document. - * - * In general, using bson_append_document_begin() results in faster - * code and less memory fragmentation. - * - * Returns: - * true if successful; otherwise false. - * - * Side effects: - * None. - * - * See also: - * bson_append_document_begin(). - * - *-------------------------------------------------------------------------- - */ - -bool -bson_append_document (bson_t *bson, /* IN */ - const char *key, /* IN */ - int key_length, /* IN */ - const bson_t *value) /* IN */ -{ - static const uint8_t type = BSON_TYPE_DOCUMENT; - - BSON_ASSERT (bson); - BSON_ASSERT (key); - BSON_ASSERT (value); - - HANDLE_KEY_LENGTH (key, key_length); - - return _bson_append ( - bson, 4, (1 + key_length + 1 + value->len), 1, &type, key_length, key, 1, &gZero, value->len, _bson_data (value)); -} - - -bool -bson_append_double (bson_t *bson, const char *key, int key_length, double value) -{ - static const uint8_t type = BSON_TYPE_DOUBLE; - - BSON_ASSERT (bson); - BSON_ASSERT (key); - - HANDLE_KEY_LENGTH (key, key_length); - -#if BSON_BYTE_ORDER == BSON_BIG_ENDIAN - value = BSON_DOUBLE_TO_LE (value); -#endif - - return _bson_append (bson, 4, (1 + key_length + 1 + 8), 1, &type, key_length, key, 1, &gZero, 8, &value); -} - - -bool -bson_append_int32 (bson_t *bson, const char *key, int key_length, int32_t value) -{ - static const uint8_t type = BSON_TYPE_INT32; - uint32_t value_le; - - BSON_ASSERT (bson); - BSON_ASSERT (key); - - HANDLE_KEY_LENGTH (key, key_length); - - value_le = BSON_UINT32_TO_LE (value); - - return _bson_append (bson, 4, (1 + key_length + 1 + 4), 1, &type, key_length, key, 1, &gZero, 4, &value_le); -} - - -bool -bson_append_int64 (bson_t *bson, const char *key, int key_length, int64_t value) -{ - static const uint8_t type = BSON_TYPE_INT64; - uint64_t value_le; - - BSON_ASSERT (bson); - BSON_ASSERT (key); - - HANDLE_KEY_LENGTH (key, key_length); - - value_le = BSON_UINT64_TO_LE (value); - - return _bson_append (bson, 4, (1 + key_length + 1 + 8), 1, &type, key_length, key, 1, &gZero, 8, &value_le); -} - - -bool -bson_append_decimal128 (bson_t *bson, const char *key, int key_length, const bson_decimal128_t *value) -{ - static const uint8_t type = BSON_TYPE_DECIMAL128; - uint64_t value_le[2]; - - BSON_ASSERT (bson); - BSON_ASSERT (key); - BSON_ASSERT (value); - - HANDLE_KEY_LENGTH (key, key_length); - - value_le[0] = BSON_UINT64_TO_LE (value->low); - value_le[1] = BSON_UINT64_TO_LE (value->high); - - return _bson_append (bson, 4, (1 + key_length + 1 + 16), 1, &type, key_length, key, 1, &gZero, 16, value_le); -} - - -bool -bson_append_iter (bson_t *bson, const char *key, int key_length, const bson_iter_t *iter) -{ - bool ret = false; - - BSON_ASSERT (bson); - BSON_ASSERT (iter); - - if (!key) { - key = bson_iter_key (iter); - key_length = -1; - } - - switch (bson_iter_type_unsafe (iter)) { - case BSON_TYPE_EOD: - return false; - case BSON_TYPE_DOUBLE: - ret = bson_append_double (bson, key, key_length, bson_iter_double (iter)); - break; - case BSON_TYPE_UTF8: { - uint32_t len = 0; - const char *str; - - str = bson_iter_utf8 (iter, &len); - ret = bson_append_utf8 (bson, key, key_length, str, len); - } break; - case BSON_TYPE_DOCUMENT: { - const uint8_t *buf = NULL; - uint32_t len = 0; - bson_t doc; - - bson_iter_document (iter, &len, &buf); - - if (bson_init_static (&doc, buf, len)) { - ret = bson_append_document (bson, key, key_length, &doc); - bson_destroy (&doc); - } - } break; - case BSON_TYPE_ARRAY: { - const uint8_t *buf = NULL; - uint32_t len = 0; - bson_t doc; - - bson_iter_array (iter, &len, &buf); - - if (bson_init_static (&doc, buf, len)) { - ret = bson_append_array (bson, key, key_length, &doc); - bson_destroy (&doc); - } - } break; - case BSON_TYPE_BINARY: { - const uint8_t *binary = NULL; - bson_subtype_t subtype = BSON_SUBTYPE_BINARY; - uint32_t len = 0; - - bson_iter_binary (iter, &subtype, &len, &binary); - ret = bson_append_binary (bson, key, key_length, subtype, binary, len); - } break; - case BSON_TYPE_UNDEFINED: - ret = bson_append_undefined (bson, key, key_length); - break; - case BSON_TYPE_OID: - ret = bson_append_oid (bson, key, key_length, bson_iter_oid (iter)); - break; - case BSON_TYPE_BOOL: - ret = bson_append_bool (bson, key, key_length, bson_iter_bool (iter)); - break; - case BSON_TYPE_DATE_TIME: - ret = bson_append_date_time (bson, key, key_length, bson_iter_date_time (iter)); - break; - case BSON_TYPE_NULL: - ret = bson_append_null (bson, key, key_length); - break; - case BSON_TYPE_REGEX: { - const char *regex; - const char *options; - - regex = bson_iter_regex (iter, &options); - ret = bson_append_regex (bson, key, key_length, regex, options); - } break; - case BSON_TYPE_DBPOINTER: { - const bson_oid_t *oid; - uint32_t len; - const char *collection; - - bson_iter_dbpointer (iter, &len, &collection, &oid); - ret = bson_append_dbpointer (bson, key, key_length, collection, oid); - } break; - case BSON_TYPE_CODE: { - uint32_t len; - const char *code; - - code = bson_iter_code (iter, &len); - ret = bson_append_code (bson, key, key_length, code); - } break; - case BSON_TYPE_SYMBOL: { - uint32_t len; - const char *symbol; - - symbol = bson_iter_symbol (iter, &len); - ret = bson_append_symbol (bson, key, key_length, symbol, len); - } break; - case BSON_TYPE_CODEWSCOPE: { - const uint8_t *scope = NULL; - uint32_t scope_len = 0; - uint32_t len = 0; - const char *javascript = NULL; - bson_t doc; - - javascript = bson_iter_codewscope (iter, &len, &scope_len, &scope); - - if (bson_init_static (&doc, scope, scope_len)) { - ret = bson_append_code_with_scope (bson, key, key_length, javascript, &doc); - bson_destroy (&doc); - } - } break; - case BSON_TYPE_INT32: - ret = bson_append_int32 (bson, key, key_length, bson_iter_int32 (iter)); - break; - case BSON_TYPE_TIMESTAMP: { - uint32_t ts; - uint32_t inc; - - bson_iter_timestamp (iter, &ts, &inc); - ret = bson_append_timestamp (bson, key, key_length, ts, inc); - } break; - case BSON_TYPE_INT64: - ret = bson_append_int64 (bson, key, key_length, bson_iter_int64 (iter)); - break; - case BSON_TYPE_DECIMAL128: { - bson_decimal128_t dec; - - if (!bson_iter_decimal128 (iter, &dec)) { - return false; - } - - ret = bson_append_decimal128 (bson, key, key_length, &dec); - } break; - case BSON_TYPE_MAXKEY: - ret = bson_append_maxkey (bson, key, key_length); - break; - case BSON_TYPE_MINKEY: - ret = bson_append_minkey (bson, key, key_length); - break; - default: - break; - } - - return ret; -} - - -bool -bson_append_maxkey (bson_t *bson, const char *key, int key_length) -{ - static const uint8_t type = BSON_TYPE_MAXKEY; - - BSON_ASSERT (bson); - BSON_ASSERT (key); - - HANDLE_KEY_LENGTH (key, key_length); - - return _bson_append (bson, 3, (1 + key_length + 1), 1, &type, key_length, key, 1, &gZero); -} - - -bool -bson_append_minkey (bson_t *bson, const char *key, int key_length) -{ - static const uint8_t type = BSON_TYPE_MINKEY; - - BSON_ASSERT (bson); - BSON_ASSERT (key); - - HANDLE_KEY_LENGTH (key, key_length); - - return _bson_append (bson, 3, (1 + key_length + 1), 1, &type, key_length, key, 1, &gZero); -} - - -bool -bson_append_null (bson_t *bson, const char *key, int key_length) -{ - static const uint8_t type = BSON_TYPE_NULL; - - BSON_ASSERT (bson); - BSON_ASSERT (key); - - HANDLE_KEY_LENGTH (key, key_length); - - return _bson_append (bson, 3, (1 + key_length + 1), 1, &type, key_length, key, 1, &gZero); -} - - -bool -bson_append_oid (bson_t *bson, const char *key, int key_length, const bson_oid_t *value) -{ - static const uint8_t type = BSON_TYPE_OID; - - BSON_ASSERT (bson); - BSON_ASSERT (key); - BSON_ASSERT (value); - - HANDLE_KEY_LENGTH (key, key_length); - - return _bson_append (bson, 4, (1 + key_length + 1 + 12), 1, &type, key_length, key, 1, &gZero, 12, value); -} - - -/* - *-------------------------------------------------------------------------- - * - * _bson_append_regex_options_sorted -- - * - * Helper to append regex options to a buffer in a sorted order. - * Any duplicate or unsupported options will be ignored. - * - * Parameters: - * @buffer: Buffer to which sorted options will be appended - * @options: Regex options - * - * Returns: - * None. - * - * Side effects: - * None. - * - *-------------------------------------------------------------------------- - */ - -static BSON_INLINE void -_bson_append_regex_options_sorted (bson_string_t *buffer, /* IN */ - const char *options) /* IN */ -{ - const char *c; - - for (c = BSON_REGEX_OPTIONS_SORTED; *c; c++) { - if (strchr (options, *c)) { - bson_string_append_c (buffer, *c); - } - } -} - - -bool -bson_append_regex (bson_t *bson, const char *key, int key_length, const char *regex, const char *options) -{ - return bson_append_regex_w_len (bson, key, key_length, regex, -1, options); -} - - -bool -bson_append_regex_w_len ( - bson_t *bson, const char *key, int key_length, const char *regex, int regex_length, const char *options) -{ - static const uint8_t type = BSON_TYPE_REGEX; - bson_string_t *options_sorted; - bool r; - - BSON_ASSERT (bson); - BSON_ASSERT (key); - - HANDLE_KEY_LENGTH (key, key_length); - - if (regex_length < 0) { - regex_length = (int) strlen (regex); - } else { - /* Necessary to validate embedded NULL is not present in key. */ - if (_string_contains_null (regex, regex_length)) { - return false; - } - } - - if (!regex) { - regex = ""; - } - - if (!options) { - options = ""; - } - - options_sorted = bson_string_new (NULL); - - _bson_append_regex_options_sorted (options_sorted, options); - - r = _bson_append (bson, - 6, - (1 + key_length + 1 + regex_length + 1 + options_sorted->len + 1), - 1, - &type, - key_length, - key, - 1, - &gZero, - regex_length, - regex, - 1, - &gZero, - options_sorted->len + 1, - options_sorted->str); - - bson_string_free (options_sorted, true); - - return r; -} - - -bool -bson_append_utf8 (bson_t *bson, const char *key, int key_length, const char *value, int length) -{ - static const uint8_t type = BSON_TYPE_UTF8; - uint32_t length_le; - - BSON_ASSERT (bson); - BSON_ASSERT (key); - - if (BSON_UNLIKELY (!value)) { - return bson_append_null (bson, key, key_length); - } - - HANDLE_KEY_LENGTH (key, key_length); - - if (BSON_UNLIKELY (length < 0)) { - length = (int) strlen (value); - } - - length_le = BSON_UINT32_TO_LE (length + 1); - - return _bson_append (bson, - 6, - (1 + key_length + 1 + 4 + length + 1), - 1, - &type, - key_length, - key, - 1, - &gZero, - 4, - &length_le, - length, - value, - 1, - &gZero); -} - - -bool -bson_append_symbol (bson_t *bson, const char *key, int key_length, const char *value, int length) -{ - static const uint8_t type = BSON_TYPE_SYMBOL; - uint32_t length_le; - - BSON_ASSERT (bson); - BSON_ASSERT (key); - - if (!value) { - return bson_append_null (bson, key, key_length); - } - - HANDLE_KEY_LENGTH (key, key_length); - - if (length < 0) { - length = (int) strlen (value); - } - - length_le = BSON_UINT32_TO_LE (length + 1); - - return _bson_append (bson, - 6, - (1 + key_length + 1 + 4 + length + 1), - 1, - &type, - key_length, - key, - 1, - &gZero, - 4, - &length_le, - length, - value, - 1, - &gZero); -} - - -bool -bson_append_time_t (bson_t *bson, const char *key, int key_length, time_t value) -{ -#ifdef BSON_OS_WIN32 - struct timeval tv = {(long) value, 0}; -#else - struct timeval tv = {value, 0}; -#endif - - BSON_ASSERT (bson); - BSON_ASSERT (key); - - return bson_append_timeval (bson, key, key_length, &tv); -} - - -bool -bson_append_timestamp (bson_t *bson, const char *key, int key_length, uint32_t timestamp, uint32_t increment) -{ - static const uint8_t type = BSON_TYPE_TIMESTAMP; - uint64_t value; - - BSON_ASSERT (bson); - BSON_ASSERT (key); - - HANDLE_KEY_LENGTH (key, key_length); - - value = ((((uint64_t) timestamp) << 32) | ((uint64_t) increment)); - value = BSON_UINT64_TO_LE (value); - - return _bson_append (bson, 4, (1 + key_length + 1 + 8), 1, &type, key_length, key, 1, &gZero, 8, &value); -} - - -bool -bson_append_now_utc (bson_t *bson, const char *key, int key_length) -{ - BSON_ASSERT (bson); - BSON_ASSERT (key); - BSON_ASSERT (key_length >= -1); - - return bson_append_time_t (bson, key, key_length, time (NULL)); -} - - -bool -bson_append_date_time (bson_t *bson, const char *key, int key_length, int64_t value) -{ - static const uint8_t type = BSON_TYPE_DATE_TIME; - uint64_t value_le; - - BSON_ASSERT (bson); - BSON_ASSERT (key); - - HANDLE_KEY_LENGTH (key, key_length); - - value_le = BSON_UINT64_TO_LE (value); - - return _bson_append (bson, 4, (1 + key_length + 1 + 8), 1, &type, key_length, key, 1, &gZero, 8, &value_le); -} - - -bool -bson_append_timeval (bson_t *bson, const char *key, int key_length, struct timeval *value) -{ - uint64_t unix_msec; - - BSON_ASSERT (bson); - BSON_ASSERT (key); - BSON_ASSERT (value); - - unix_msec = (((uint64_t) value->tv_sec) * 1000UL) + (value->tv_usec / 1000UL); - return bson_append_date_time (bson, key, key_length, unix_msec); -} - - -bool -bson_append_undefined (bson_t *bson, const char *key, int key_length) -{ - static const uint8_t type = BSON_TYPE_UNDEFINED; - - BSON_ASSERT (bson); - BSON_ASSERT (key); - - HANDLE_KEY_LENGTH (key, key_length); - - return _bson_append (bson, 3, (1 + key_length + 1), 1, &type, key_length, key, 1, &gZero); -} - - -bool -bson_append_value (bson_t *bson, const char *key, int key_length, const bson_value_t *value) -{ - bson_t local; - bool ret = false; - - BSON_ASSERT (bson); - BSON_ASSERT (key); - BSON_ASSERT (value); - - switch (value->value_type) { - case BSON_TYPE_DOUBLE: - ret = bson_append_double (bson, key, key_length, value->value.v_double); - break; - case BSON_TYPE_UTF8: - ret = bson_append_utf8 (bson, key, key_length, value->value.v_utf8.str, value->value.v_utf8.len); - break; - case BSON_TYPE_DOCUMENT: - if (bson_init_static (&local, value->value.v_doc.data, value->value.v_doc.data_len)) { - ret = bson_append_document (bson, key, key_length, &local); - bson_destroy (&local); - } - break; - case BSON_TYPE_ARRAY: - if (bson_init_static (&local, value->value.v_doc.data, value->value.v_doc.data_len)) { - ret = bson_append_array (bson, key, key_length, &local); - bson_destroy (&local); - } - break; - case BSON_TYPE_BINARY: - ret = bson_append_binary (bson, - key, - key_length, - value->value.v_binary.subtype, - value->value.v_binary.data, - value->value.v_binary.data_len); - break; - case BSON_TYPE_UNDEFINED: - ret = bson_append_undefined (bson, key, key_length); - break; - case BSON_TYPE_OID: - ret = bson_append_oid (bson, key, key_length, &value->value.v_oid); - break; - case BSON_TYPE_BOOL: - ret = bson_append_bool (bson, key, key_length, value->value.v_bool); - break; - case BSON_TYPE_DATE_TIME: - ret = bson_append_date_time (bson, key, key_length, value->value.v_datetime); - break; - case BSON_TYPE_NULL: - ret = bson_append_null (bson, key, key_length); - break; - case BSON_TYPE_REGEX: - ret = bson_append_regex (bson, key, key_length, value->value.v_regex.regex, value->value.v_regex.options); - break; - case BSON_TYPE_DBPOINTER: - ret = bson_append_dbpointer ( - bson, key, key_length, value->value.v_dbpointer.collection, &value->value.v_dbpointer.oid); - break; - case BSON_TYPE_CODE: - ret = bson_append_code (bson, key, key_length, value->value.v_code.code); - break; - case BSON_TYPE_SYMBOL: - ret = bson_append_symbol (bson, key, key_length, value->value.v_symbol.symbol, value->value.v_symbol.len); - break; - case BSON_TYPE_CODEWSCOPE: - if (bson_init_static (&local, value->value.v_codewscope.scope_data, value->value.v_codewscope.scope_len)) { - ret = bson_append_code_with_scope (bson, key, key_length, value->value.v_codewscope.code, &local); - bson_destroy (&local); - } - break; - case BSON_TYPE_INT32: - ret = bson_append_int32 (bson, key, key_length, value->value.v_int32); - break; - case BSON_TYPE_TIMESTAMP: - ret = bson_append_timestamp ( - bson, key, key_length, value->value.v_timestamp.timestamp, value->value.v_timestamp.increment); - break; - case BSON_TYPE_INT64: - ret = bson_append_int64 (bson, key, key_length, value->value.v_int64); - break; - case BSON_TYPE_DECIMAL128: - ret = bson_append_decimal128 (bson, key, key_length, &(value->value.v_decimal128)); - break; - case BSON_TYPE_MAXKEY: - ret = bson_append_maxkey (bson, key, key_length); - break; - case BSON_TYPE_MINKEY: - ret = bson_append_minkey (bson, key, key_length); - break; - case BSON_TYPE_EOD: - default: - break; - } - - return ret; -} - - -void -bson_init (bson_t *bson) -{ - bson_impl_inline_t *impl = (bson_impl_inline_t *) bson; - - BSON_ASSERT (bson); - -#ifdef BSON_MEMCHECK - impl->canary = bson_malloc (1); -#endif - impl->flags = BSON_FLAG_INLINE | BSON_FLAG_STATIC; - impl->len = 5; - impl->data[0] = 5; - impl->data[1] = 0; - impl->data[2] = 0; - impl->data[3] = 0; - impl->data[4] = 0; -} - - -void -bson_reinit (bson_t *bson) -{ - uint8_t *data; - - BSON_ASSERT (bson); - - data = _bson_data (bson); - - bson->len = 5; - - data[0] = 5; - data[1] = 0; - data[2] = 0; - data[3] = 0; - data[4] = 0; -} - - -bool -bson_init_static (bson_t *bson, const uint8_t *data, size_t length) -{ - bson_impl_alloc_t *impl = (bson_impl_alloc_t *) bson; - uint32_t len_le; - - BSON_ASSERT (bson); - BSON_ASSERT (data); - - if ((length < 5) || (length > BSON_MAX_SIZE)) { - return false; - } - - memcpy (&len_le, data, sizeof (len_le)); - - if ((size_t) BSON_UINT32_FROM_LE (len_le) != length) { - return false; - } - - if (data[length - 1]) { - return false; - } - - impl->flags = BSON_FLAG_STATIC | BSON_FLAG_RDONLY; - impl->len = (uint32_t) length; - impl->parent = NULL; - impl->depth = 0; - impl->buf = &impl->alloc; - impl->buflen = &impl->alloclen; - impl->offset = 0; - impl->alloc = (uint8_t *) data; - impl->alloclen = length; - impl->realloc = NULL; - impl->realloc_func_ctx = NULL; - - return true; -} - - -bson_t * -bson_new (void) -{ - bson_impl_inline_t *impl; - bson_t *bson; - - bson = BSON_ALIGNED_ALLOC (bson_t); - - impl = (bson_impl_inline_t *) bson; - impl->flags = BSON_FLAG_INLINE; - impl->len = 5; -#ifdef BSON_MEMCHECK - impl->canary = bson_malloc (1); -#endif - impl->data[0] = 5; - impl->data[1] = 0; - impl->data[2] = 0; - impl->data[3] = 0; - impl->data[4] = 0; - - return bson; -} - - -bson_t * -bson_sized_new (size_t size) -{ - bson_impl_alloc_t *impl_a; - bson_t *b; - - BSON_ASSERT (size <= BSON_MAX_SIZE); - - { - b = BSON_ALIGNED_ALLOC (bson_t); - impl_a = (bson_impl_alloc_t *) b; - } - - if (size <= BSON_INLINE_DATA_SIZE) { - bson_init (b); - b->flags &= ~BSON_FLAG_STATIC; - } else { - impl_a->flags = BSON_FLAG_NONE; - impl_a->len = 5; - impl_a->parent = NULL; - impl_a->depth = 0; - impl_a->buf = &impl_a->alloc; - impl_a->buflen = &impl_a->alloclen; - impl_a->offset = 0; - impl_a->alloclen = BSON_MAX (5, size); - impl_a->alloc = bson_malloc (impl_a->alloclen); - impl_a->alloc[0] = 5; - impl_a->alloc[1] = 0; - impl_a->alloc[2] = 0; - impl_a->alloc[3] = 0; - impl_a->alloc[4] = 0; - impl_a->realloc = bson_realloc_ctx; - impl_a->realloc_func_ctx = NULL; - } - - return b; -} - - -bson_t * -bson_new_from_data (const uint8_t *data, size_t length) -{ - uint32_t len_le; - bson_t *bson; - - BSON_ASSERT (data); - - if ((length < 5) || (length > BSON_MAX_SIZE) || data[length - 1]) { - return NULL; - } - - memcpy (&len_le, data, sizeof (len_le)); - - if (length != (size_t) BSON_UINT32_FROM_LE (len_le)) { - return NULL; - } - - bson = bson_sized_new (length); - memcpy (_bson_data (bson), data, length); - bson->len = (uint32_t) length; - - return bson; -} - - -bson_t * -bson_new_from_buffer (uint8_t **buf, size_t *buf_len, bson_realloc_func realloc_func, void *realloc_func_ctx) -{ - bson_impl_alloc_t *impl; - uint32_t len_le; - uint32_t length; - bson_t *bson; - - BSON_ASSERT (buf); - BSON_ASSERT (buf_len); - - if (!realloc_func) { - realloc_func = bson_realloc_ctx; - } - - bson = BSON_ALIGNED_ALLOC0 (bson_t); - impl = (bson_impl_alloc_t *) bson; - - if (!*buf) { - length = 5; - len_le = BSON_UINT32_TO_LE (length); - *buf_len = 5; - *buf = realloc_func (*buf, *buf_len, realloc_func_ctx); - memcpy (*buf, &len_le, sizeof (len_le)); - (*buf)[4] = '\0'; - } else { - if ((*buf_len < 5) || (*buf_len > BSON_MAX_SIZE)) { - bson_free (bson); - return NULL; - } - - memcpy (&len_le, *buf, sizeof (len_le)); - length = BSON_UINT32_FROM_LE (len_le); - } - - if ((*buf)[length - 1]) { - bson_free (bson); - return NULL; - } - - impl->flags = BSON_FLAG_NO_FREE; - impl->len = length; - impl->buf = buf; - impl->buflen = buf_len; - impl->realloc = realloc_func; - impl->realloc_func_ctx = realloc_func_ctx; - - return bson; -} - - -bson_t * -bson_copy (const bson_t *bson) -{ - const uint8_t *data; - - BSON_ASSERT (bson); - - data = _bson_data (bson); - return bson_new_from_data (data, bson->len); -} - - -void -bson_copy_to (const bson_t *src, bson_t *dst) -{ - const uint8_t *data; - bson_impl_alloc_t *adst; - size_t len; - - BSON_ASSERT (src); - BSON_ASSERT (dst); - - if ((src->flags & BSON_FLAG_INLINE)) { -#ifdef BSON_MEMCHECK - dst->len = src->len; - dst->canary = bson_malloc (1); - memcpy (dst->padding, src->padding, sizeof dst->padding); -#else - memcpy (dst, src, sizeof *dst); -#endif - dst->flags = (BSON_FLAG_STATIC | BSON_FLAG_INLINE); - return; - } - - data = _bson_data (src); - len = bson_next_power_of_two ((size_t) src->len); - - adst = (bson_impl_alloc_t *) dst; - adst->flags = BSON_FLAG_STATIC; - adst->len = src->len; - adst->parent = NULL; - adst->depth = 0; - adst->buf = &adst->alloc; - adst->buflen = &adst->alloclen; - adst->offset = 0; - adst->alloc = bson_malloc (len); - adst->alloclen = len; - adst->realloc = bson_realloc_ctx; - adst->realloc_func_ctx = NULL; - memcpy (adst->alloc, data, src->len); -} - - -static bool -should_ignore (const char *first_exclude, va_list args, const char *name) -{ - bool ret = false; - const char *exclude = first_exclude; - va_list args_copy; - - va_copy (args_copy, args); - - do { - if (!strcmp (name, exclude)) { - ret = true; - break; - } - } while ((exclude = va_arg (args_copy, const char *))); - - va_end (args_copy); - - return ret; -} - - -void -bson_copy_to_excluding_noinit_va (const bson_t *src, bson_t *dst, const char *first_exclude, va_list args) -{ - bson_iter_t iter; - - if (bson_iter_init (&iter, src)) { - while (bson_iter_next (&iter)) { - if (!should_ignore (first_exclude, args, bson_iter_key (&iter))) { - if (!bson_append_iter (dst, NULL, 0, &iter)) { - /* - * This should not be able to happen since we are copying - * from within a valid bson_t. - */ - BSON_ASSERT (false); - return; - } - } - } - } -} - - -void -bson_copy_to_excluding (const bson_t *src, bson_t *dst, const char *first_exclude, ...) -{ - va_list args; - - BSON_ASSERT (src); - BSON_ASSERT (dst); - BSON_ASSERT (first_exclude); - - bson_init (dst); - - va_start (args, first_exclude); - bson_copy_to_excluding_noinit_va (src, dst, first_exclude, args); - va_end (args); -} - -void -bson_copy_to_excluding_noinit (const bson_t *src, bson_t *dst, const char *first_exclude, ...) -{ - va_list args; - - BSON_ASSERT (src); - BSON_ASSERT (dst); - BSON_ASSERT (first_exclude); - - va_start (args, first_exclude); - bson_copy_to_excluding_noinit_va (src, dst, first_exclude, args); - va_end (args); -} - -void -bson_destroy (bson_t *bson) -{ - if (!bson) { - return; - } - - if (!(bson->flags & (BSON_FLAG_RDONLY | BSON_FLAG_INLINE | BSON_FLAG_NO_FREE))) { - bson_free (*((bson_impl_alloc_t *) bson)->buf); - } - -#ifdef BSON_MEMCHECK - if (bson->flags & BSON_FLAG_INLINE) { - bson_free (bson->canary); - } -#endif - - if (!(bson->flags & BSON_FLAG_STATIC)) { - bson_free (bson); - } -} - - -uint8_t * -bson_reserve_buffer (bson_t *bson, uint32_t size) -{ - if (bson->flags & (BSON_FLAG_CHILD | BSON_FLAG_IN_CHILD | BSON_FLAG_RDONLY)) { - return NULL; - } - - if (!_bson_grow (bson, size)) { - return NULL; - } - - if (bson->flags & BSON_FLAG_INLINE) { - /* bson_grow didn't spill over */ - ((bson_impl_inline_t *) bson)->len = size; - } else { - ((bson_impl_alloc_t *) bson)->len = size; - } - - return _bson_data (bson); -} - - -bool -bson_steal (bson_t *dst, bson_t *src) -{ - bson_impl_inline_t *src_inline; - bson_impl_inline_t *dst_inline; - bson_impl_alloc_t *alloc; - - BSON_ASSERT (dst); - BSON_ASSERT (src); - - bson_init (dst); - - if (src->flags & (BSON_FLAG_CHILD | BSON_FLAG_IN_CHILD | BSON_FLAG_RDONLY)) { - return false; - } - - if (src->flags & BSON_FLAG_INLINE) { - src_inline = (bson_impl_inline_t *) src; - dst_inline = (bson_impl_inline_t *) dst; - dst_inline->len = src_inline->len; - memcpy (dst_inline->data, src_inline->data, sizeof src_inline->data); - - /* for consistency, src is always invalid after steal, even if inline */ - src->len = 0; -#ifdef BSON_MEMCHECK - bson_free (src->canary); -#endif - } else { -#ifdef BSON_MEMCHECK - bson_free (dst->canary); -#endif - memcpy (dst, src, sizeof (bson_t)); - alloc = (bson_impl_alloc_t *) dst; - alloc->flags |= BSON_FLAG_STATIC; - alloc->buf = &alloc->alloc; - alloc->buflen = &alloc->alloclen; - } - - if (!(src->flags & BSON_FLAG_STATIC)) { - bson_free (src); - } else { - /* src is invalid after steal */ - src->len = 0; - } - - return true; -} - - -uint8_t * -bson_destroy_with_steal (bson_t *bson, bool steal, uint32_t *length) -{ - uint8_t *ret = NULL; - - BSON_ASSERT (bson); - - if (length) { - *length = bson->len; - } - - if (!steal) { - bson_destroy (bson); - return NULL; - } - - if ((bson->flags & (BSON_FLAG_CHILD | BSON_FLAG_IN_CHILD | BSON_FLAG_RDONLY))) { - /* Do nothing */ - } else if ((bson->flags & BSON_FLAG_INLINE)) { - bson_impl_inline_t *inl; - - inl = (bson_impl_inline_t *) bson; - ret = bson_malloc (bson->len); - memcpy (ret, inl->data, bson->len); - } else { - bson_impl_alloc_t *alloc; - - alloc = (bson_impl_alloc_t *) bson; - ret = *alloc->buf; - *alloc->buf = NULL; - } - - bson_destroy (bson); - - return ret; -} - - -const uint8_t * -bson_get_data (const bson_t *bson) -{ - BSON_ASSERT (bson); - - return _bson_data (bson); -} - - -uint32_t -bson_count_keys (const bson_t *bson) -{ - uint32_t count = 0; - bson_iter_t iter; - - BSON_ASSERT (bson); - - if (bson_iter_init (&iter, bson)) { - while (bson_iter_next (&iter)) { - count++; - } - } - - return count; -} - - -bool -bson_has_field (const bson_t *bson, const char *key) -{ - bson_iter_t iter; - bson_iter_t child; - - BSON_ASSERT (bson); - BSON_ASSERT (key); - - if (NULL != strchr (key, '.')) { - return (bson_iter_init (&iter, bson) && bson_iter_find_descendant (&iter, key, &child)); - } - - return bson_iter_init_find (&iter, bson, key); -} - - -int -bson_compare (const bson_t *bson, const bson_t *other) -{ - const uint8_t *data1; - const uint8_t *data2; - size_t len1; - size_t len2; - int64_t ret; - - data1 = _bson_data (bson) + 4; - len1 = bson->len - 4; - - data2 = _bson_data (other) + 4; - len2 = other->len - 4; - - if (len1 == len2) { - return memcmp (data1, data2, len1); - } - - ret = memcmp (data1, data2, BSON_MIN (len1, len2)); - - if (ret == 0) { - ret = (int64_t) len1 - (int64_t) len2; - } - - return (ret < 0) ? -1 : (ret > 0); -} - - -bool -bson_equal (const bson_t *bson, const bson_t *other) -{ - return !bson_compare (bson, other); -} - - -static bool -_bson_as_json_visit_utf8 (const bson_iter_t *iter, const char *key, size_t v_utf8_len, const char *v_utf8, void *data) -{ - bson_json_state_t *state = data; - char *escaped; - - BSON_UNUSED (iter); - BSON_UNUSED (key); - - escaped = bson_utf8_escape_for_json (v_utf8, v_utf8_len); - - if (escaped) { - bson_string_append (state->str, "\""); - bson_string_append (state->str, escaped); - bson_string_append (state->str, "\""); - bson_free (escaped); - return false; - } - - return true; -} - - -static bool -_bson_as_json_visit_int32 (const bson_iter_t *iter, const char *key, int32_t v_int32, void *data) -{ - bson_json_state_t *state = data; - - BSON_UNUSED (iter); - BSON_UNUSED (key); - - if (state->mode == BSON_JSON_MODE_CANONICAL) { - bson_string_append_printf (state->str, "{ \"$numberInt\" : \"%" PRId32 "\" }", v_int32); - } else { - bson_string_append_printf (state->str, "%" PRId32, v_int32); - } - - return false; -} - - -static bool -_bson_as_json_visit_int64 (const bson_iter_t *iter, const char *key, int64_t v_int64, void *data) -{ - bson_json_state_t *state = data; - - BSON_UNUSED (iter); - BSON_UNUSED (key); - - if (state->mode == BSON_JSON_MODE_CANONICAL) { - bson_string_append_printf (state->str, "{ \"$numberLong\" : \"%" PRId64 "\" }", v_int64); - } else { - bson_string_append_printf (state->str, "%" PRId64, v_int64); - } - - return false; -} - - -static bool -_bson_as_json_visit_decimal128 (const bson_iter_t *iter, const char *key, const bson_decimal128_t *value, void *data) -{ - bson_json_state_t *state = data; - char decimal128_string[BSON_DECIMAL128_STRING]; - - BSON_UNUSED (iter); - BSON_UNUSED (key); - - bson_decimal128_to_string (value, decimal128_string); - - bson_string_append (state->str, "{ \"$numberDecimal\" : \""); - bson_string_append (state->str, decimal128_string); - bson_string_append (state->str, "\" }"); - - return false; -} - - -static bool -_bson_as_json_visit_double (const bson_iter_t *iter, const char *key, double v_double, void *data) -{ - bson_json_state_t *state = data; - bson_string_t *str = state->str; - uint32_t start_len; - bool legacy; - - BSON_UNUSED (iter); - BSON_UNUSED (key); - - /* Determine if legacy (i.e. unwrapped) output should be used. Relaxed mode - * will use this for nan and inf values, which we check manually since old - * platforms may not have isinf or isnan. */ - legacy = state->mode == BSON_JSON_MODE_LEGACY || - (state->mode == BSON_JSON_MODE_RELAXED && !(v_double != v_double || v_double * 0 != 0)); - - if (!legacy) { - bson_string_append (state->str, "{ \"$numberDouble\" : \""); - } - - if (!legacy && v_double != v_double) { - bson_string_append (str, "NaN"); - } else if (!legacy && v_double * 0 != 0) { - if (v_double > 0) { - bson_string_append (str, "Infinity"); - } else { - bson_string_append (str, "-Infinity"); - } - } else { - start_len = str->len; - bson_string_append_printf (str, "%.20g", v_double); - - /* ensure trailing ".0" to distinguish "3" from "3.0" */ - if (strspn (&str->str[start_len], "0123456789-") == str->len - start_len) { - bson_string_append (str, ".0"); - } - } - - if (!legacy) { - bson_string_append (state->str, "\" }"); - } - - return false; -} - - -static bool -_bson_as_json_visit_undefined (const bson_iter_t *iter, const char *key, void *data) -{ - bson_json_state_t *state = data; - - BSON_UNUSED (iter); - BSON_UNUSED (key); - - bson_string_append (state->str, "{ \"$undefined\" : true }"); - - return false; -} - - -static bool -_bson_as_json_visit_null (const bson_iter_t *iter, const char *key, void *data) -{ - bson_json_state_t *state = data; - - BSON_UNUSED (iter); - BSON_UNUSED (key); - - bson_string_append (state->str, "null"); - - return false; -} - - -static bool -_bson_as_json_visit_oid (const bson_iter_t *iter, const char *key, const bson_oid_t *oid, void *data) -{ - bson_json_state_t *state = data; - char str[25]; - - BSON_UNUSED (iter); - BSON_UNUSED (key); - - bson_oid_to_string (oid, str); - bson_string_append (state->str, "{ \"$oid\" : \""); - bson_string_append (state->str, str); - bson_string_append (state->str, "\" }"); - - return false; -} - - -static bool -_bson_as_json_visit_binary (const bson_iter_t *iter, - const char *key, - bson_subtype_t v_subtype, - size_t v_binary_len, - const uint8_t *v_binary, - void *data) -{ - bson_json_state_t *state = data; - size_t b64_len; - char *b64; - - BSON_UNUSED (iter); - BSON_UNUSED (key); - - b64_len = mcommon_b64_ntop_calculate_target_size (v_binary_len); - b64 = bson_malloc0 (b64_len); - BSON_ASSERT (mcommon_b64_ntop (v_binary, v_binary_len, b64, b64_len) != -1); - - if (state->mode == BSON_JSON_MODE_CANONICAL || state->mode == BSON_JSON_MODE_RELAXED) { - bson_string_append (state->str, "{ \"$binary\" : { \"base64\" : \""); - bson_string_append (state->str, b64); - bson_string_append (state->str, "\", \"subType\" : \""); - bson_string_append_printf (state->str, "%02x", v_subtype); - bson_string_append (state->str, "\" } }"); - } else { - bson_string_append (state->str, "{ \"$binary\" : \""); - bson_string_append (state->str, b64); - bson_string_append (state->str, "\", \"$type\" : \""); - bson_string_append_printf (state->str, "%02x", v_subtype); - bson_string_append (state->str, "\" }"); - } - - bson_free (b64); - - return false; -} - - -static bool -_bson_as_json_visit_bool (const bson_iter_t *iter, const char *key, bool v_bool, void *data) -{ - bson_json_state_t *state = data; - - BSON_UNUSED (iter); - BSON_UNUSED (key); - - bson_string_append (state->str, v_bool ? "true" : "false"); - - return false; -} - - -static bool -_bson_as_json_visit_date_time (const bson_iter_t *iter, const char *key, int64_t msec_since_epoch, void *data) -{ - bson_json_state_t *state = data; - - BSON_UNUSED (iter); - BSON_UNUSED (key); - - if (state->mode == BSON_JSON_MODE_CANONICAL || (state->mode == BSON_JSON_MODE_RELAXED && msec_since_epoch < 0)) { - bson_string_append (state->str, "{ \"$date\" : { \"$numberLong\" : \""); - bson_string_append_printf (state->str, "%" PRId64, msec_since_epoch); - bson_string_append (state->str, "\" } }"); - } else if (state->mode == BSON_JSON_MODE_RELAXED) { - bson_string_append (state->str, "{ \"$date\" : \""); - _bson_iso8601_date_format (msec_since_epoch, state->str); - bson_string_append (state->str, "\" }"); - } else { - bson_string_append (state->str, "{ \"$date\" : "); - bson_string_append_printf (state->str, "%" PRId64, msec_since_epoch); - bson_string_append (state->str, " }"); - } - - return false; -} - - -static bool -_bson_as_json_visit_regex ( - const bson_iter_t *iter, const char *key, const char *v_regex, const char *v_options, void *data) -{ - bson_json_state_t *state = data; - char *escaped; - - BSON_UNUSED (iter); - BSON_UNUSED (key); - - escaped = bson_utf8_escape_for_json (v_regex, -1); - if (!escaped) { - return true; - } - - if (state->mode == BSON_JSON_MODE_CANONICAL || state->mode == BSON_JSON_MODE_RELAXED) { - bson_string_append (state->str, "{ \"$regularExpression\" : { \"pattern\" : \""); - bson_string_append (state->str, escaped); - bson_string_append (state->str, "\", \"options\" : \""); - _bson_append_regex_options_sorted (state->str, v_options); - bson_string_append (state->str, "\" } }"); - } else { - bson_string_append (state->str, "{ \"$regex\" : \""); - bson_string_append (state->str, escaped); - bson_string_append (state->str, "\", \"$options\" : \""); - _bson_append_regex_options_sorted (state->str, v_options); - bson_string_append (state->str, "\" }"); - } - - bson_free (escaped); - - return false; -} - - -static bool -_bson_as_json_visit_timestamp ( - const bson_iter_t *iter, const char *key, uint32_t v_timestamp, uint32_t v_increment, void *data) -{ - bson_json_state_t *state = data; - - BSON_UNUSED (iter); - BSON_UNUSED (key); - - bson_string_append (state->str, "{ \"$timestamp\" : { \"t\" : "); - bson_string_append_printf (state->str, "%u", v_timestamp); - bson_string_append (state->str, ", \"i\" : "); - bson_string_append_printf (state->str, "%u", v_increment); - bson_string_append (state->str, " } }"); - - return false; -} - - -static bool -_bson_as_json_visit_dbpointer (const bson_iter_t *iter, - const char *key, - size_t v_collection_len, - const char *v_collection, - const bson_oid_t *v_oid, - void *data) -{ - bson_json_state_t *state = data; - char *escaped; - char str[25]; - - BSON_UNUSED (iter); - BSON_UNUSED (key); - BSON_UNUSED (v_collection_len); - - escaped = bson_utf8_escape_for_json (v_collection, -1); - if (!escaped) { - return true; - } - - if (state->mode == BSON_JSON_MODE_CANONICAL || state->mode == BSON_JSON_MODE_RELAXED) { - bson_string_append (state->str, "{ \"$dbPointer\" : { \"$ref\" : \""); - bson_string_append (state->str, escaped); - bson_string_append (state->str, "\""); - - if (v_oid) { - bson_oid_to_string (v_oid, str); - bson_string_append (state->str, ", \"$id\" : { \"$oid\" : \""); - bson_string_append (state->str, str); - bson_string_append (state->str, "\" }"); - } - - bson_string_append (state->str, " } }"); - } else { - bson_string_append (state->str, "{ \"$ref\" : \""); - bson_string_append (state->str, escaped); - bson_string_append (state->str, "\""); - - if (v_oid) { - bson_oid_to_string (v_oid, str); - bson_string_append (state->str, ", \"$id\" : \""); - bson_string_append (state->str, str); - bson_string_append (state->str, "\""); - } - - bson_string_append (state->str, " }"); - } - - bson_free (escaped); - - return false; -} - - -static bool -_bson_as_json_visit_minkey (const bson_iter_t *iter, const char *key, void *data) -{ - bson_json_state_t *state = data; - - BSON_UNUSED (iter); - BSON_UNUSED (key); - - bson_string_append (state->str, "{ \"$minKey\" : 1 }"); - - return false; -} - - -static bool -_bson_as_json_visit_maxkey (const bson_iter_t *iter, const char *key, void *data) -{ - bson_json_state_t *state = data; - - BSON_UNUSED (iter); - BSON_UNUSED (key); - - bson_string_append (state->str, "{ \"$maxKey\" : 1 }"); - - return false; -} - - -static bool -_bson_as_json_visit_before (const bson_iter_t *iter, const char *key, void *data) -{ - bson_json_state_t *state = data; - char *escaped; - - BSON_UNUSED (iter); - - if (state->max_len_reached) { - return true; - } - - if (state->count) { - bson_string_append (state->str, ", "); - } - - if (state->keys) { - escaped = bson_utf8_escape_for_json (key, -1); - if (escaped) { - bson_string_append (state->str, "\""); - bson_string_append (state->str, escaped); - bson_string_append (state->str, "\" : "); - bson_free (escaped); - } else { - return true; - } - } - - state->count++; - - return false; -} - - -static bool -_bson_as_json_visit_after (const bson_iter_t *iter, const char *key, void *data) -{ - bson_json_state_t *state = data; - - BSON_UNUSED (iter); - BSON_UNUSED (key); - - if (state->max_len == BSON_MAX_LEN_UNLIMITED) { - return false; - } - - if (bson_cmp_greater_equal_us (state->str->len, state->max_len)) { - state->max_len_reached = true; - - if (bson_cmp_greater_us (state->str->len, state->max_len)) { - BSON_ASSERT (bson_in_range_signed (uint32_t, state->max_len)); - /* Truncate string to maximum length */ - bson_string_truncate (state->str, (uint32_t) state->max_len); - } - - return true; - } - - return false; -} - - -static void -_bson_as_json_visit_corrupt (const bson_iter_t *iter, void *data) -{ - *(((bson_json_state_t *) data)->err_offset) = iter->off; -} - - -static bool -_bson_as_json_visit_code (const bson_iter_t *iter, const char *key, size_t v_code_len, const char *v_code, void *data) -{ - bson_json_state_t *state = data; - char *escaped; - - BSON_UNUSED (iter); - BSON_UNUSED (key); - - escaped = bson_utf8_escape_for_json (v_code, v_code_len); - if (!escaped) { - return true; - } - - bson_string_append (state->str, "{ \"$code\" : \""); - bson_string_append (state->str, escaped); - bson_string_append (state->str, "\" }"); - bson_free (escaped); - - return false; -} - - -static bool -_bson_as_json_visit_symbol ( - const bson_iter_t *iter, const char *key, size_t v_symbol_len, const char *v_symbol, void *data) -{ - bson_json_state_t *state = data; - char *escaped; - - BSON_UNUSED (iter); - BSON_UNUSED (key); - - escaped = bson_utf8_escape_for_json (v_symbol, v_symbol_len); - if (!escaped) { - return true; - } - - if (state->mode == BSON_JSON_MODE_CANONICAL || state->mode == BSON_JSON_MODE_RELAXED) { - bson_string_append (state->str, "{ \"$symbol\" : \""); - bson_string_append (state->str, escaped); - bson_string_append (state->str, "\" }"); - } else { - bson_string_append (state->str, "\""); - bson_string_append (state->str, escaped); - bson_string_append (state->str, "\""); - } - - bson_free (escaped); - - return false; -} - - -static bool -_bson_as_json_visit_codewscope ( - const bson_iter_t *iter, const char *key, size_t v_code_len, const char *v_code, const bson_t *v_scope, void *data) -{ - bson_json_state_t *state = data; - char *code_escaped; - char *scope; - int32_t max_scope_len = BSON_MAX_LEN_UNLIMITED; - - BSON_UNUSED (iter); - BSON_UNUSED (key); - - code_escaped = bson_utf8_escape_for_json (v_code, v_code_len); - if (!code_escaped) { - return true; - } - - bson_string_append (state->str, "{ \"$code\" : \""); - bson_string_append (state->str, code_escaped); - bson_string_append (state->str, "\", \"$scope\" : "); - - bson_free (code_escaped); - - /* Encode scope with the same mode */ - if (state->max_len != BSON_MAX_LEN_UNLIMITED) { - BSON_ASSERT (bson_in_range_unsigned (int32_t, state->str->len)); - max_scope_len = BSON_MAX (0, state->max_len - (int32_t) state->str->len); - } - - scope = _bson_as_json_visit_all (v_scope, NULL, state->mode, max_scope_len, false); - - if (!scope) { - return true; - } - - bson_string_append (state->str, scope); - bson_string_append (state->str, " }"); - - bson_free (scope); - - return false; -} - - -static const bson_visitor_t bson_as_json_visitors = { - _bson_as_json_visit_before, _bson_as_json_visit_after, _bson_as_json_visit_corrupt, - _bson_as_json_visit_double, _bson_as_json_visit_utf8, _bson_as_json_visit_document, - _bson_as_json_visit_array, _bson_as_json_visit_binary, _bson_as_json_visit_undefined, - _bson_as_json_visit_oid, _bson_as_json_visit_bool, _bson_as_json_visit_date_time, - _bson_as_json_visit_null, _bson_as_json_visit_regex, _bson_as_json_visit_dbpointer, - _bson_as_json_visit_code, _bson_as_json_visit_symbol, _bson_as_json_visit_codewscope, - _bson_as_json_visit_int32, _bson_as_json_visit_timestamp, _bson_as_json_visit_int64, - _bson_as_json_visit_maxkey, _bson_as_json_visit_minkey, NULL, /* visit_unsupported_type */ - _bson_as_json_visit_decimal128, -}; - - -static bool -_bson_as_json_visit_document (const bson_iter_t *iter, const char *key, const bson_t *v_document, void *data) -{ - bson_json_state_t *state = data; - bson_json_state_t child_state = {0, true, state->err_offset}; - bson_iter_t child; - - BSON_UNUSED (iter); - BSON_UNUSED (key); - - if (state->depth >= BSON_MAX_RECURSION) { - bson_string_append (state->str, "{ ... }"); - return false; - } - - if (bson_iter_init (&child, v_document)) { - child_state.str = bson_string_new ("{ "); - child_state.depth = state->depth + 1; - child_state.mode = state->mode; - child_state.max_len = BSON_MAX_LEN_UNLIMITED; - if (state->max_len != BSON_MAX_LEN_UNLIMITED) { - BSON_ASSERT (bson_in_range_unsigned (int32_t, state->str->len)); - child_state.max_len = BSON_MAX (0, state->max_len - (int32_t) state->str->len); - } - - child_state.max_len_reached = child_state.max_len == 0; - - if (bson_iter_visit_all (&child, &bson_as_json_visitors, &child_state)) { - if (child_state.max_len_reached) { - bson_string_append (state->str, child_state.str->str); - } - - bson_string_free (child_state.str, true); - - /* If max_len was reached, we return a success state to ensure that - * VISIT_AFTER is still called - */ - return !child_state.max_len_reached; - } - - bson_string_append (child_state.str, " }"); - bson_string_append (state->str, child_state.str->str); - bson_string_free (child_state.str, true); - } - - return false; -} - - -static bool -_bson_as_json_visit_array (const bson_iter_t *iter, const char *key, const bson_t *v_array, void *data) -{ - bson_json_state_t *state = data; - bson_json_state_t child_state = {0, false, state->err_offset}; - bson_iter_t child; - - BSON_UNUSED (iter); - BSON_UNUSED (key); - - if (state->depth >= BSON_MAX_RECURSION) { - bson_string_append (state->str, "{ ... }"); - return false; - } - - if (bson_iter_init (&child, v_array)) { - child_state.str = bson_string_new ("[ "); - child_state.depth = state->depth + 1; - child_state.mode = state->mode; - child_state.max_len = BSON_MAX_LEN_UNLIMITED; - if (state->max_len != BSON_MAX_LEN_UNLIMITED) { - BSON_ASSERT (bson_in_range_unsigned (int32_t, state->str->len)); - child_state.max_len = BSON_MAX (0, state->max_len - (int32_t) state->str->len); - } - - child_state.max_len_reached = child_state.max_len == 0; - - if (bson_iter_visit_all (&child, &bson_as_json_visitors, &child_state)) { - if (child_state.max_len_reached) { - bson_string_append (state->str, child_state.str->str); - } - - bson_string_free (child_state.str, true); - - /* If max_len was reached, we return a success state to ensure that - * VISIT_AFTER is still called - */ - return !child_state.max_len_reached; - } - - bson_string_append (child_state.str, " ]"); - bson_string_append (state->str, child_state.str->str); - bson_string_free (child_state.str, true); - } - - return false; -} - - -static char * -_bson_as_json_visit_all ( - const bson_t *bson, size_t *length, bson_json_mode_t mode, int32_t max_len, bool is_outermost_array) -{ - bson_json_state_t state; - bson_iter_t iter; - ssize_t err_offset = -1; - int32_t remaining; - - BSON_ASSERT (bson); - - if (length) { - *length = 0; - } - - if (bson_empty0 (bson)) { - if (length) { - *length = 3; - } - - return bson_strdup (is_outermost_array ? "[ ]" : "{ }"); - } - - if (!bson_iter_init (&iter, bson)) { - return NULL; - } - - state.count = 0; - state.keys = !is_outermost_array; - state.str = bson_string_new (is_outermost_array ? "[ " : "{ "); - state.depth = 0; - state.err_offset = &err_offset; - state.mode = mode; - state.max_len = max_len; - state.max_len_reached = false; - - if ((bson_iter_visit_all (&iter, &bson_as_json_visitors, &state) || err_offset != -1) && !state.max_len_reached) { - /* - * We were prematurely exited due to corruption or failed visitor. - */ - bson_string_free (state.str, true); - if (length) { - *length = 0; - } - return NULL; - } - - /* Append closing space and } separately, in case we hit the max in between. - */ - remaining = state.max_len - state.str->len; - if (state.max_len == BSON_MAX_LEN_UNLIMITED || remaining > 1) { - bson_string_append (state.str, is_outermost_array ? " ]" : " }"); - } else if (remaining == 1) { - bson_string_append (state.str, " "); - } - - if (length) { - *length = state.str->len; - } - - return bson_string_free (state.str, false); -} - - -char * -bson_as_json_with_opts (const bson_t *bson, size_t *length, const bson_json_opts_t *opts) -{ - return _bson_as_json_visit_all (bson, length, opts->mode, opts->max_len, opts->is_outermost_array); -} - - -char * -bson_as_canonical_extended_json (const bson_t *bson, size_t *length) -{ - const bson_json_opts_t opts = {BSON_JSON_MODE_CANONICAL, BSON_MAX_LEN_UNLIMITED, false}; - return bson_as_json_with_opts (bson, length, &opts); -} - - -char * -bson_as_json (const bson_t *bson, size_t *length) -{ - const bson_json_opts_t opts = {BSON_JSON_MODE_LEGACY, BSON_MAX_LEN_UNLIMITED, false}; - return bson_as_json_with_opts (bson, length, &opts); -} - - -char * -bson_as_relaxed_extended_json (const bson_t *bson, size_t *length) -{ - const bson_json_opts_t opts = {BSON_JSON_MODE_RELAXED, BSON_MAX_LEN_UNLIMITED, false}; - return bson_as_json_with_opts (bson, length, &opts); -} - - -char * -bson_array_as_json (const bson_t *bson, size_t *length) -{ - const bson_json_opts_t opts = {BSON_JSON_MODE_LEGACY, BSON_MAX_LEN_UNLIMITED, true}; - return bson_as_json_with_opts (bson, length, &opts); -} - - -char * -bson_array_as_relaxed_extended_json (const bson_t *bson, size_t *length) -{ - const bson_json_opts_t opts = {BSON_JSON_MODE_RELAXED, BSON_MAX_LEN_UNLIMITED, true}; - return bson_as_json_with_opts (bson, length, &opts); -} - - -char * -bson_array_as_canonical_extended_json (const bson_t *bson, size_t *length) -{ - const bson_json_opts_t opts = {BSON_JSON_MODE_CANONICAL, BSON_MAX_LEN_UNLIMITED, true}; - return bson_as_json_with_opts (bson, length, &opts); -} - - -#define VALIDATION_ERR(_flag, _msg, ...) bson_set_error (&state->error, BSON_ERROR_INVALID, _flag, _msg, __VA_ARGS__) - -static bool -_bson_iter_validate_utf8 (const bson_iter_t *iter, const char *key, size_t v_utf8_len, const char *v_utf8, void *data) -{ - bson_validate_state_t *state = data; - bool allow_null; - - if ((state->flags & BSON_VALIDATE_UTF8)) { - allow_null = !!(state->flags & BSON_VALIDATE_UTF8_ALLOW_NULL); - - if (!bson_utf8_validate (v_utf8, v_utf8_len, allow_null)) { - state->err_offset = iter->off; - VALIDATION_ERR (BSON_VALIDATE_UTF8, "invalid utf8 string for key \"%s\"", key); - return true; - } - } - - if ((state->flags & BSON_VALIDATE_DOLLAR_KEYS)) { - if (state->phase == BSON_VALIDATE_PHASE_LF_REF_UTF8) { - state->phase = BSON_VALIDATE_PHASE_LF_ID_KEY; - } else if (state->phase == BSON_VALIDATE_PHASE_LF_DB_UTF8) { - state->phase = BSON_VALIDATE_PHASE_NOT_DBREF; - } - } - - return false; -} - - -static void -_bson_iter_validate_corrupt (const bson_iter_t *iter, void *data) -{ - bson_validate_state_t *state = data; - - state->err_offset = iter->err_off; - VALIDATION_ERR (BSON_VALIDATE_NONE, "%s", "corrupt BSON"); -} - - -static bool -_bson_iter_validate_before (const bson_iter_t *iter, const char *key, void *data) -{ - bson_validate_state_t *state = data; - - if ((state->flags & BSON_VALIDATE_EMPTY_KEYS)) { - if (key[0] == '\0') { - state->err_offset = iter->off; - VALIDATION_ERR (BSON_VALIDATE_EMPTY_KEYS, "%s", "empty key"); - return true; - } - } - - if ((state->flags & BSON_VALIDATE_DOLLAR_KEYS)) { - if (key[0] == '$') { - if (state->phase == BSON_VALIDATE_PHASE_LF_REF_KEY && strcmp (key, "$ref") == 0) { - state->phase = BSON_VALIDATE_PHASE_LF_REF_UTF8; - } else if (state->phase == BSON_VALIDATE_PHASE_LF_ID_KEY && strcmp (key, "$id") == 0) { - state->phase = BSON_VALIDATE_PHASE_LF_DB_KEY; - } else if (state->phase == BSON_VALIDATE_PHASE_LF_DB_KEY && strcmp (key, "$db") == 0) { - state->phase = BSON_VALIDATE_PHASE_LF_DB_UTF8; - } else { - state->err_offset = iter->off; - VALIDATION_ERR (BSON_VALIDATE_DOLLAR_KEYS, "keys cannot begin with \"$\": \"%s\"", key); - return true; - } - } else if (state->phase == BSON_VALIDATE_PHASE_LF_ID_KEY || state->phase == BSON_VALIDATE_PHASE_LF_REF_UTF8 || - state->phase == BSON_VALIDATE_PHASE_LF_DB_UTF8) { - state->err_offset = iter->off; - VALIDATION_ERR (BSON_VALIDATE_DOLLAR_KEYS, "invalid key within DBRef subdocument: \"%s\"", key); - return true; - } else { - state->phase = BSON_VALIDATE_PHASE_NOT_DBREF; - } - } - - if ((state->flags & BSON_VALIDATE_DOT_KEYS)) { - if (strstr (key, ".")) { - state->err_offset = iter->off; - VALIDATION_ERR (BSON_VALIDATE_DOT_KEYS, "keys cannot contain \".\": \"%s\"", key); - return true; - } - } - - return false; -} - - -static bool -_bson_iter_validate_codewscope ( - const bson_iter_t *iter, const char *key, size_t v_code_len, const char *v_code, const bson_t *v_scope, void *data) -{ - bson_validate_state_t *state = data; - size_t offset = 0; - - BSON_UNUSED (key); - BSON_UNUSED (v_code_len); - BSON_UNUSED (v_code); - - if (!bson_validate (v_scope, state->flags, &offset)) { - state->err_offset = iter->off + offset; - VALIDATION_ERR (BSON_VALIDATE_NONE, "%s", "corrupt code-with-scope"); - return false; - } - - return true; -} - - -static bool -_bson_iter_validate_document (const bson_iter_t *iter, const char *key, const bson_t *v_document, void *data); - - -static const bson_visitor_t bson_validate_funcs = { - _bson_iter_validate_before, - NULL, /* visit_after */ - _bson_iter_validate_corrupt, - NULL, /* visit_double */ - _bson_iter_validate_utf8, - _bson_iter_validate_document, - _bson_iter_validate_document, /* visit_array */ - NULL, /* visit_binary */ - NULL, /* visit_undefined */ - NULL, /* visit_oid */ - NULL, /* visit_bool */ - NULL, /* visit_date_time */ - NULL, /* visit_null */ - NULL, /* visit_regex */ - NULL, /* visit_dbpoint */ - NULL, /* visit_code */ - NULL, /* visit_symbol */ - _bson_iter_validate_codewscope, -}; - - -static bool -_bson_iter_validate_document (const bson_iter_t *iter, const char *key, const bson_t *v_document, void *data) -{ - bson_validate_state_t *state = data; - bson_iter_t child; - bson_validate_phase_t phase = state->phase; - - BSON_UNUSED (key); - - if (!bson_iter_init (&child, v_document)) { - state->err_offset = iter->off; - return true; - } - - if (state->phase == BSON_VALIDATE_PHASE_START) { - state->phase = BSON_VALIDATE_PHASE_TOP; - } else { - state->phase = BSON_VALIDATE_PHASE_LF_REF_KEY; - } - - (void) bson_iter_visit_all (&child, &bson_validate_funcs, state); - - if (state->phase == BSON_VALIDATE_PHASE_LF_ID_KEY || state->phase == BSON_VALIDATE_PHASE_LF_REF_UTF8 || - state->phase == BSON_VALIDATE_PHASE_LF_DB_UTF8) { - if (state->err_offset <= 0) { - state->err_offset = iter->off; - } - - return true; - } - - state->phase = phase; - - return false; -} - - -static void -_bson_validate_internal (const bson_t *bson, bson_validate_state_t *state) -{ - bson_iter_t iter; - - state->err_offset = -1; - state->phase = BSON_VALIDATE_PHASE_START; - memset (&state->error, 0, sizeof state->error); - - if (!bson_iter_init (&iter, bson)) { - state->err_offset = 0; - VALIDATION_ERR (BSON_VALIDATE_NONE, "%s", "corrupt BSON"); - } else { - _bson_iter_validate_document (&iter, NULL, bson, state); - } -} - - -bool -bson_validate (const bson_t *bson, bson_validate_flags_t flags, size_t *offset) -{ - bson_validate_state_t state; - - state.flags = flags; - _bson_validate_internal (bson, &state); - - if (state.err_offset > 0 && offset) { - *offset = (size_t) state.err_offset; - } - - return state.err_offset < 0; -} - - -bool -bson_validate_with_error (const bson_t *bson, bson_validate_flags_t flags, bson_error_t *error) -{ - bson_validate_state_t state; - - state.flags = flags; - _bson_validate_internal (bson, &state); - - if (state.err_offset > 0 && error) { - memcpy (error, &state.error, sizeof *error); - } - - return state.err_offset < 0; -} - - -bool -bson_concat (bson_t *dst, const bson_t *src) -{ - BSON_ASSERT (dst); - BSON_ASSERT (src); - - if (!bson_empty (src)) { - return _bson_append (dst, 1, src->len - 5, src->len - 5, _bson_data (src) + 4); - } - - return true; -} - -struct _bson_array_builder_t { - uint32_t index; - bson_t bson; -}; - -bson_array_builder_t * -bson_array_builder_new (void) -{ - bson_array_builder_t *bab = BSON_ALIGNED_ALLOC0 (bson_array_builder_t); - bson_init (&bab->bson); - return bab; -} - -// `bson_array_builder_append_impl` generates the next key index, calls -// `append_fn`, and may update the tracked next index. -#define bson_array_builder_append_impl(append_fn, ...) \ - if (1) { \ - BSON_ASSERT_PARAM (bab); \ - const char *key; \ - char buf[16]; \ - size_t key_length = bson_uint32_to_string (bab->index, &key, buf, sizeof buf); \ - /* Expect enough room in `buf` for key string. UINT32_MAX is 10 digits. \ - * With the NULL terminator, 11 is expected maximum number of \ - * characters. */ \ - BSON_ASSERT (key_length < sizeof buf); \ - bool ok = append_fn (&bab->bson, key, (int) key_length, __VA_ARGS__); \ - if (ok) { \ - bab->index += 1; \ - } \ - return ok; \ - } else \ - (void) 0 - -#define bson_array_builder_append_impl_noargs(append_fn) \ - if (1) { \ - BSON_ASSERT_PARAM (bab); \ - const char *key; \ - char buf[16]; \ - size_t key_length = bson_uint32_to_string (bab->index, &key, buf, sizeof buf); \ - /* Expect enough room in `buf` for key string. UINT32_MAX is 10 digits. \ - * With the NULL terminator, 11 is expected maximum number of \ - * characters. */ \ - BSON_ASSERT (key_length < sizeof buf); \ - bool ok = append_fn (&bab->bson, key, (int) key_length); \ - if (ok) { \ - bab->index += 1; \ - } \ - return ok; \ - } else \ - (void) 0 - -bool -bson_array_builder_append_value (bson_array_builder_t *bab, const bson_value_t *value) -{ - bson_array_builder_append_impl (bson_append_value, value); -} - -bool -bson_array_builder_append_array (bson_array_builder_t *bab, const bson_t *array) -{ - bson_array_builder_append_impl (bson_append_array, array); -} - - -bool -bson_array_builder_append_binary (bson_array_builder_t *bab, - bson_subtype_t subtype, - const uint8_t *binary, - uint32_t length) -{ - bson_array_builder_append_impl (bson_append_binary, subtype, binary, length); -} - - -bool -bson_array_builder_append_bool (bson_array_builder_t *bab, bool value) -{ - bson_array_builder_append_impl (bson_append_bool, value); -} - - -bool -bson_array_builder_append_code (bson_array_builder_t *bab, const char *javascript) -{ - bson_array_builder_append_impl (bson_append_code, javascript); -} - - -bool -bson_array_builder_append_code_with_scope (bson_array_builder_t *bab, const char *javascript, const bson_t *scope) -{ - bson_array_builder_append_impl (bson_append_code_with_scope, javascript, scope); -} - - -bool -bson_array_builder_append_dbpointer (bson_array_builder_t *bab, const char *collection, const bson_oid_t *oid) -{ - bson_array_builder_append_impl (bson_append_dbpointer, collection, oid); -} - - -bool -bson_array_builder_append_double (bson_array_builder_t *bab, double value) -{ - bson_array_builder_append_impl (bson_append_double, value); -} - - -bool -bson_array_builder_append_document (bson_array_builder_t *bab, const bson_t *value) -{ - bson_array_builder_append_impl (bson_append_document, value); -} - - -bool -bson_array_builder_append_document_begin (bson_array_builder_t *bab, bson_t *child) -{ - bson_array_builder_append_impl (bson_append_document_begin, child); -} - - -bool -bson_array_builder_append_document_end (bson_array_builder_t *bab, bson_t *child) -{ - return bson_append_document_end (&bab->bson, child); -} - - -bool -bson_array_builder_append_int32 (bson_array_builder_t *bab, int32_t value) -{ - bson_array_builder_append_impl (bson_append_int32, value); -} - - -bool -bson_array_builder_append_int64 (bson_array_builder_t *bab, int64_t value) -{ - bson_array_builder_append_impl (bson_append_int64, value); -} - - -bool -bson_array_builder_append_decimal128 (bson_array_builder_t *bab, const bson_decimal128_t *value) -{ - bson_array_builder_append_impl (bson_append_decimal128, value); -} - - -bool -bson_array_builder_append_iter (bson_array_builder_t *bab, const bson_iter_t *iter) -{ - bson_array_builder_append_impl (bson_append_iter, iter); -} - - -bool -bson_array_builder_append_minkey (bson_array_builder_t *bab) -{ - bson_array_builder_append_impl_noargs (bson_append_minkey); -} - - -bool -bson_array_builder_append_maxkey (bson_array_builder_t *bab) -{ - bson_array_builder_append_impl_noargs (bson_append_maxkey); -} - - -bool -bson_array_builder_append_null (bson_array_builder_t *bab) -{ - bson_array_builder_append_impl_noargs (bson_append_null); -} - - -bool -bson_array_builder_append_oid (bson_array_builder_t *bab, const bson_oid_t *oid) -{ - bson_array_builder_append_impl (bson_append_oid, oid); -} - - -bool -bson_array_builder_append_regex (bson_array_builder_t *bab, const char *regex, const char *options) -{ - bson_array_builder_append_impl (bson_append_regex, regex, options); -} - - -bool -bson_array_builder_append_regex_w_len (bson_array_builder_t *bab, - const char *regex, - int regex_length, - const char *options) -{ - bson_array_builder_append_impl (bson_append_regex_w_len, regex, regex_length, options); -} - - -bool -bson_array_builder_append_utf8 (bson_array_builder_t *bab, const char *value, int length) -{ - bson_array_builder_append_impl (bson_append_utf8, value, length); -} - - -bool -bson_array_builder_append_symbol (bson_array_builder_t *bab, const char *value, int length) -{ - bson_array_builder_append_impl (bson_append_symbol, value, length); -} - - -bool -bson_array_builder_append_time_t (bson_array_builder_t *bab, time_t value) -{ - bson_array_builder_append_impl (bson_append_time_t, value); -} - - -bool -bson_array_builder_append_timeval (bson_array_builder_t *bab, struct timeval *value) -{ - bson_array_builder_append_impl (bson_append_timeval, value); -} - - -bool -bson_array_builder_append_date_time (bson_array_builder_t *bab, int64_t value) -{ - bson_array_builder_append_impl (bson_append_date_time, value); -} - - -bool -bson_array_builder_append_now_utc (bson_array_builder_t *bab) -{ - bson_array_builder_append_impl_noargs (bson_append_now_utc); -} - - -bool -bson_array_builder_append_timestamp (bson_array_builder_t *bab, uint32_t timestamp, uint32_t increment) -{ - bson_array_builder_append_impl (bson_append_timestamp, timestamp, increment); -} - - -bool -bson_array_builder_append_undefined (bson_array_builder_t *bab) -{ - bson_array_builder_append_impl_noargs (bson_append_undefined); -} - - -bool -bson_array_builder_append_array_builder_begin (bson_array_builder_t *bab, bson_array_builder_t **child) -{ - bson_array_builder_append_impl (bson_append_array_builder_begin, child); -} - -bool -bson_array_builder_append_array_builder_end (bson_array_builder_t *bab, bson_array_builder_t *child) -{ - return bson_append_array_builder_end (&bab->bson, child); -} - - -bool -bson_array_builder_build (bson_array_builder_t *bab, bson_t *out) -{ - BSON_ASSERT_PARAM (bab); - BSON_ASSERT_PARAM (out); - if (!bson_steal (out, &bab->bson)) { - return false; - } - bson_init (&bab->bson); - bab->index = 0; - return true; -} - -void -bson_array_builder_destroy (bson_array_builder_t *bab) -{ - if (!bab) { - return; - } - bson_destroy (&bab->bson); - bson_free (bab); -} - -bool -bson_append_array_builder_begin (bson_t *bson, const char *key, int key_length, bson_array_builder_t **child) -{ - BSON_ASSERT_PARAM (bson); - BSON_ASSERT_PARAM (key); - BSON_ASSERT_PARAM (child); - *child = bson_array_builder_new (); - return bson_append_array_begin (bson, key, key_length, &(*child)->bson); -} - -bool -bson_append_array_builder_end (bson_t *bson, bson_array_builder_t *child) -{ - bool ok = bson_append_array_end (bson, &child->bson); - bson_array_builder_destroy (child); - return ok; -} diff --git a/bsonjs/bson/bson.h b/bsonjs/bson/bson.h deleted file mode 100644 index f86967b..0000000 --- a/bsonjs/bson/bson.h +++ /dev/null @@ -1,1222 +0,0 @@ -/* - * Copyright 2013 MongoDB, Inc. - * - * 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. - */ - - -#ifndef BSON_H -#define BSON_H - -#define BSON_INSIDE - -#include - -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#undef BSON_INSIDE - - -BSON_BEGIN_DECLS - - -/** - * bson_empty: - * @b: a bson_t. - * - * Checks to see if @b is an empty BSON document. An empty BSON document is - * a 5 byte document which contains the length (4 bytes) and a single NUL - * byte indicating end of fields. - */ -#define bson_empty(b) (((b)->len == 5) || !bson_get_data ((b))[4]) - - -/** - * bson_empty0: - * - * Like bson_empty() but treats NULL the same as an empty bson_t document. - */ -#define bson_empty0(b) (!(b) || bson_empty (b)) - - -/** - * bson_clear: - * - * Easily free a bson document and set it to NULL. Use like: - * - * bson_t *doc = bson_new(); - * bson_clear (&doc); - * BSON_ASSERT (doc == NULL); - */ -#define bson_clear(bptr) \ - do { \ - if (*(bptr)) { \ - bson_destroy (*(bptr)); \ - *(bptr) = NULL; \ - } \ - } while (0) - - -/** - * BSON_MAX_SIZE: - * - * The maximum size in bytes of a BSON document. - */ -#define BSON_MAX_SIZE ((size_t) ((1U << 31) - 1)) - - -#define BSON_APPEND_ARRAY(b, key, val) bson_append_array (b, key, (int) strlen (key), val) - -#define BSON_APPEND_ARRAY_BEGIN(b, key, child) bson_append_array_begin (b, key, (int) strlen (key), child) - -#define BSON_APPEND_BINARY(b, key, subtype, val, len) bson_append_binary (b, key, (int) strlen (key), subtype, val, len) - -#define BSON_APPEND_BOOL(b, key, val) bson_append_bool (b, key, (int) strlen (key), val) - -#define BSON_APPEND_CODE(b, key, val) bson_append_code (b, key, (int) strlen (key), val) - -#define BSON_APPEND_CODE_WITH_SCOPE(b, key, val, scope) \ - bson_append_code_with_scope (b, key, (int) strlen (key), val, scope) - -#define BSON_APPEND_DBPOINTER(b, key, coll, oid) bson_append_dbpointer (b, key, (int) strlen (key), coll, oid) - -#define BSON_APPEND_DOCUMENT_BEGIN(b, key, child) bson_append_document_begin (b, key, (int) strlen (key), child) - -#define BSON_APPEND_DOUBLE(b, key, val) bson_append_double (b, key, (int) strlen (key), val) - -#define BSON_APPEND_DOCUMENT(b, key, val) bson_append_document (b, key, (int) strlen (key), val) - -#define BSON_APPEND_INT32(b, key, val) bson_append_int32 (b, key, (int) strlen (key), val) - -#define BSON_APPEND_INT64(b, key, val) bson_append_int64 (b, key, (int) strlen (key), val) - -#define BSON_APPEND_MINKEY(b, key) bson_append_minkey (b, key, (int) strlen (key)) - -#define BSON_APPEND_DECIMAL128(b, key, val) bson_append_decimal128 (b, key, (int) strlen (key), val) - -#define BSON_APPEND_MAXKEY(b, key) bson_append_maxkey (b, key, (int) strlen (key)) - -#define BSON_APPEND_NULL(b, key) bson_append_null (b, key, (int) strlen (key)) - -#define BSON_APPEND_OID(b, key, val) bson_append_oid (b, key, (int) strlen (key), val) - -#define BSON_APPEND_REGEX(b, key, val, opt) bson_append_regex (b, key, (int) strlen (key), val, opt) - -#define BSON_APPEND_UTF8(b, key, val) bson_append_utf8 (b, key, (int) strlen (key), val, (int) strlen (val)) - -#define BSON_APPEND_SYMBOL(b, key, val) bson_append_symbol (b, key, (int) strlen (key), val, (int) strlen (val)) - -#define BSON_APPEND_TIME_T(b, key, val) bson_append_time_t (b, key, (int) strlen (key), val) - -#define BSON_APPEND_TIMEVAL(b, key, val) bson_append_timeval (b, key, (int) strlen (key), val) - -#define BSON_APPEND_DATE_TIME(b, key, val) bson_append_date_time (b, key, (int) strlen (key), val) - -#define BSON_APPEND_TIMESTAMP(b, key, val, inc) bson_append_timestamp (b, key, (int) strlen (key), val, inc) - -#define BSON_APPEND_UNDEFINED(b, key) bson_append_undefined (b, key, (int) strlen (key)) - -#define BSON_APPEND_VALUE(b, key, val) bson_append_value (b, key, (int) strlen (key), (val)) - - -/** - * bson_new: - * - * Allocates a new bson_t structure. Call the various bson_append_*() - * functions to add fields to the bson. You can iterate the bson_t at any - * time using a bson_iter_t and bson_iter_init(). - * - * Returns: A newly allocated bson_t that should be freed with bson_destroy(). - */ -BSON_EXPORT (bson_t *) -bson_new (void); - - -BSON_EXPORT (bson_t *) -bson_new_from_json (const uint8_t *data, ssize_t len, bson_error_t *error); - - -BSON_EXPORT (bool) -bson_init_from_json (bson_t *bson, const char *data, ssize_t len, bson_error_t *error); - - -/** - * bson_init_static: - * @b: A pointer to a bson_t. - * @data: The data buffer to use. - * @length: The length of @data. - * - * Initializes a bson_t using @data and @length. This is ideal if you would - * like to use a stack allocation for your bson and do not need to grow the - * buffer. @data must be valid for the life of @b. - * - * Returns: true if initialized successfully; otherwise false. - */ -BSON_EXPORT (bool) -bson_init_static (bson_t *b, const uint8_t *data, size_t length); - - -/** - * bson_init: - * @b: A pointer to a bson_t. - * - * Initializes a bson_t for use. This function is useful to those that want a - * stack allocated bson_t. The usefulness of a stack allocated bson_t is - * marginal as the target buffer for content will still require heap - * allocations. It can help reduce heap fragmentation on allocators that do - * not employ SLAB/magazine semantics. - * - * You must call bson_destroy() with @b to release resources when you are done - * using @b. - */ -BSON_EXPORT (void) -bson_init (bson_t *b); - - -/** - * bson_reinit: - * @b: (inout): A bson_t. - * - * This is equivalent to calling bson_destroy() and bson_init() on a #bson_t. - * However, it will try to persist the existing malloc'd buffer if one exists. - * This is useful in cases where you want to reduce malloc overhead while - * building many documents. - */ -BSON_EXPORT (void) -bson_reinit (bson_t *b); - - -/** - * bson_new_from_data: - * @data: A buffer containing a serialized bson document. - * @length: The length of the document in bytes. - * - * Creates a new bson_t structure using the data provided. @data should contain - * at least @length bytes that can be copied into the new bson_t structure. - * - * Returns: A newly allocated bson_t that should be freed with bson_destroy(). - * If the first four bytes (little-endian) of data do not match @length, - * then NULL will be returned. - */ -BSON_EXPORT (bson_t *) -bson_new_from_data (const uint8_t *data, size_t length); - - -/** - * bson_new_from_buffer: - * @buf: A pointer to a buffer containing a serialized bson document. - * @buf_len: The length of the buffer in bytes. - * @realloc_fun: a realloc like function - * @realloc_fun_ctx: a context for the realloc function - * - * Creates a new bson_t structure using the data provided. @buf should contain - * a bson document, or null pointer should be passed for new allocations. - * - * Returns: A newly allocated bson_t that should be freed with bson_destroy(). - * The underlying buffer will be used and not be freed in destroy. - */ -BSON_EXPORT (bson_t *) -bson_new_from_buffer (uint8_t **buf, size_t *buf_len, bson_realloc_func realloc_func, void *realloc_func_ctx); - - -/** - * bson_sized_new: - * @size: A size_t containing the number of bytes to allocate. - * - * This will allocate a new bson_t with enough bytes to hold a buffer - * sized @size. @size must be smaller than INT_MAX bytes. - * - * Returns: A newly allocated bson_t that should be freed with bson_destroy(). - */ -BSON_EXPORT (bson_t *) -bson_sized_new (size_t size); - - -/** - * bson_copy: - * @bson: A bson_t. - * - * Copies @bson into a newly allocated bson_t. You must call bson_destroy() - * when you are done with the resulting value to free its resources. - * - * Returns: A newly allocated bson_t that should be free'd with bson_destroy() - */ -BSON_EXPORT (bson_t *) -bson_copy (const bson_t *bson); - - -/** - * bson_copy_to: - * @src: The source bson_t. - * @dst: The destination bson_t. - * - * Initializes @dst and copies the content from @src into @dst. - */ -BSON_EXPORT (void) -bson_copy_to (const bson_t *src, bson_t *dst); - - -/** - * bson_copy_to_excluding: - * @src: A bson_t. - * @dst: A bson_t to initialize and copy into. - * @first_exclude: First field name to exclude. - * - * Copies @src into @dst excluding any field that is provided. - * This is handy for situations when you need to remove one or - * more fields in a bson_t. Note that bson_init() will be called - * on dst. - */ -BSON_EXPORT (void) -bson_copy_to_excluding (const bson_t *src, bson_t *dst, const char *first_exclude, ...) BSON_GNUC_NULL_TERMINATED - BSON_GNUC_DEPRECATED_FOR (bson_copy_to_excluding_noinit); - -/** - * bson_copy_to_excluding_noinit: - * @src: A bson_t. - * @dst: A bson_t to initialize and copy into. - * @first_exclude: First field name to exclude. - * - * The same as bson_copy_to_excluding, but does not call bson_init() - * on the dst. This version should be preferred in new code, but the - * old function is left for backwards compatibility. - */ -BSON_EXPORT (void) -bson_copy_to_excluding_noinit (const bson_t *src, bson_t *dst, const char *first_exclude, ...) - BSON_GNUC_NULL_TERMINATED; - -BSON_EXPORT (void) -bson_copy_to_excluding_noinit_va (const bson_t *src, bson_t *dst, const char *first_exclude, va_list args); - - -/** - * bson_destroy: - * @bson: A bson_t. - * - * Frees the resources associated with @bson. - */ -BSON_EXPORT (void) -bson_destroy (bson_t *bson); - -BSON_EXPORT (uint8_t *) -bson_reserve_buffer (bson_t *bson, uint32_t size); - -BSON_EXPORT (bool) -bson_steal (bson_t *dst, bson_t *src); - - -/** - * bson_destroy_with_steal: - * @bson: A #bson_t. - * @steal: If ownership of the data buffer should be transferred to caller. - * @length: (out): location for the length of the buffer. - * - * Destroys @bson similar to calling bson_destroy() except that the underlying - * buffer will be returned and ownership transferred to the caller if @steal - * is non-zero. - * - * If length is non-NULL, the length of @bson will be stored in @length. - * - * It is a programming error to call this function with any bson that has - * been initialized static, or is being used to create a subdocument with - * functions such as bson_append_document_begin() or bson_append_array_begin(). - * - * Returns: a buffer owned by the caller if @steal is true. Otherwise NULL. - * If there was an error, NULL is returned. - */ -BSON_EXPORT (uint8_t *) -bson_destroy_with_steal (bson_t *bson, bool steal, uint32_t *length); - - -/** - * bson_get_data: - * @bson: A bson_t. - * - * Fetched the data buffer for @bson of @bson->len bytes in length. - * - * Returns: A buffer that should not be modified or freed. - */ -BSON_EXPORT (const uint8_t *) -bson_get_data (const bson_t *bson); - - -/** - * bson_count_keys: - * @bson: A bson_t. - * - * Counts the number of elements found in @bson. - */ -BSON_EXPORT (uint32_t) -bson_count_keys (const bson_t *bson); - - -/** - * bson_has_field: - * @bson: A bson_t. - * @key: The key to lookup. - * - * Checks to see if @bson contains a field named @key. - * - * This function is case-sensitive. - * - * Returns: true if @key exists in @bson; otherwise false. - */ -BSON_EXPORT (bool) -bson_has_field (const bson_t *bson, const char *key); - - -/** - * bson_compare: - * @bson: A bson_t. - * @other: A bson_t. - * - * Compares @bson to @other in a qsort() style comparison. - * See qsort() for information on how this function works. - * - * Returns: Less than zero, zero, or greater than zero. - */ -BSON_EXPORT (int) -bson_compare (const bson_t *bson, const bson_t *other); - -/* - * bson_equal: - * @bson: A bson_t. - * @other: A bson_t. - * - * Checks to see if @bson and @other are equal. - * - * Returns: true if equal; otherwise false. - */ -BSON_EXPORT (bool) -bson_equal (const bson_t *bson, const bson_t *other); - - -/** - * bson_validate: - * @bson: A bson_t. - * @offset: A location for the error offset. - * - * Validates a BSON document by walking through the document and inspecting - * the fields for valid content. - * - * Returns: true if @bson is valid; otherwise false and @offset is set. - */ -BSON_EXPORT (bool) -bson_validate (const bson_t *bson, bson_validate_flags_t flags, size_t *offset); - - -/** - * bson_validate_with_error: - * @bson: A bson_t. - * @error: A location for the error info. - * - * Validates a BSON document by walking through the document and inspecting - * the fields for valid content. - * - * Returns: true if @bson is valid; otherwise false and @error is filled out. - */ -BSON_EXPORT (bool) -bson_validate_with_error (const bson_t *bson, bson_validate_flags_t flags, bson_error_t *error); - - -/** - * bson_as_json_with_opts: - * @bson: A bson_t. - * @length: A location for the string length, or NULL. - * @opts: A bson_t_json_opts_t defining options for the conversion - * - * Creates a new string containing @bson in the selected JSON format, - * conforming to the MongoDB Extended JSON Spec: - * - * github.com/mongodb/specifications/blob/master/source/extended-json.rst - * - * The caller is responsible for freeing the resulting string. If @length is - * non-NULL, then the length of the resulting string will be placed in @length. - * - * See https://www.mongodb.com/docs/manual/reference/mongodb-extended-json/ for - * more information on extended JSON. - * - * Returns: A newly allocated string that should be freed with bson_free(). - */ -BSON_EXPORT (char *) -bson_as_json_with_opts (const bson_t *bson, size_t *length, const bson_json_opts_t *opts); - - -/** - * bson_as_canonical_extended_json: - * @bson: A bson_t. - * @length: A location for the string length, or NULL. - * - * Creates a new string containing @bson in canonical extended JSON format, - * conforming to the MongoDB Extended JSON Spec: - * - * github.com/mongodb/specifications/blob/master/source/extended-json.rst - * - * The caller is responsible for freeing the resulting string. If @length is - * non-NULL, then the length of the resulting string will be placed in @length. - * - * See https://www.mongodb.com/docs/manual/reference/mongodb-extended-json/ for - * more information on extended JSON. - * - * Returns: A newly allocated string that should be freed with bson_free(). - */ -BSON_EXPORT (char *) -bson_as_canonical_extended_json (const bson_t *bson, size_t *length); - - -/** - * bson_as_json: - * @bson: A bson_t. - * @length: A location for the string length, or NULL. - * - * Creates a new string containing @bson in libbson's legacy JSON format. - * Superseded by bson_as_canonical_extended_json and - * bson_as_relaxed_extended_json. The caller is - * responsible for freeing the resulting string. If @length is non-NULL, then - * the length of the resulting string will be placed in @length. - * - * Returns: A newly allocated string that should be freed with bson_free(). - */ -BSON_EXPORT (char *) -bson_as_json (const bson_t *bson, size_t *length); - - -/** - * bson_as_relaxed_extended_json: - * @bson: A bson_t. - * @length: A location for the string length, or NULL. - * - * Creates a new string containing @bson in relaxed extended JSON format, - * conforming to the MongoDB Extended JSON Spec: - * - * github.com/mongodb/specifications/blob/master/source/extended-json.rst - * - * The caller is responsible for freeing the resulting string. If @length is - * non-NULL, then the length of the resulting string will be placed in @length. - * - * See https://www.mongodb.com/docs/manual/reference/mongodb-extended-json/ for - * more information on extended JSON. - * - * Returns: A newly allocated string that should be freed with bson_free(). - */ -BSON_EXPORT (char *) -bson_as_relaxed_extended_json (const bson_t *bson, size_t *length); - - -/* like bson_as_json() but for outermost arrays. */ -BSON_EXPORT (char *) bson_array_as_json (const bson_t *bson, size_t *length); - - -/* like bson_as_relaxed_extended_json() but for outermost arrays. */ -BSON_EXPORT (char *) -bson_array_as_relaxed_extended_json (const bson_t *bson, size_t *length); - - -/* like bson_as_canonical_extended_json() but for outermost arrays. */ -BSON_EXPORT (char *) -bson_array_as_canonical_extended_json (const bson_t *bson, size_t *length); - -// bson_array_builder_t defines an API for building arrays. -// BSON arrays require sequential numeric keys "0", "1", "2", ... -typedef struct _bson_array_builder_t bson_array_builder_t; - -// bson_array_builder_new may be used to build a top-level BSON array. Example: -// `[1,2,3]`. -// To append an array field to a document (Example: `{ "field": [1,2,3] }`), use -// `bson_append_array_builder_begin`. -BSON_EXPORT (bson_array_builder_t *) bson_array_builder_new (void); - -// bson_array_builder_build initializes and moves BSON data to `out`. -// `bab` may be reused and will start appending a new array at index "0". -BSON_EXPORT (bool) -bson_array_builder_build (bson_array_builder_t *bab, bson_t *out); - -BSON_EXPORT (void) -bson_array_builder_destroy (bson_array_builder_t *bab); - -BSON_EXPORT (bool) -bson_append_value (bson_t *bson, const char *key, int key_length, const bson_value_t *value); - -#define BSON_APPEND_VALUE(b, key, val) bson_append_value (b, key, (int) strlen (key), (val)) - -BSON_EXPORT (bool) -bson_array_builder_append_value (bson_array_builder_t *bab, const bson_value_t *value); - -/** - * bson_append_array: - * @bson: A bson_t. - * @key: The key for the field. - * @array: A bson_t containing the array. - * - * Appends a BSON array to @bson. BSON arrays are like documents where the - * key is the string version of the index. For example, the first item of the - * array would have the key "0". The second item would have the index "1". - * - * Returns: true if successful; false if append would overflow max size. - */ -BSON_EXPORT (bool) -bson_append_array (bson_t *bson, const char *key, int key_length, const bson_t *array); - -#define BSON_APPEND_ARRAY(b, key, val) bson_append_array (b, key, (int) strlen (key), val) - -BSON_EXPORT (bool) -bson_array_builder_append_array (bson_array_builder_t *bab, const bson_t *array); - -/** - * bson_append_binary: - * @bson: A bson_t to append. - * @key: The key for the field. - * @subtype: The bson_subtype_t of the binary. - * @binary: The binary buffer to append. - * @length: The length of @binary. - * - * Appends a binary buffer to the BSON document. - * - * Returns: true if successful; false if append would overflow max size. - */ -BSON_EXPORT (bool) -bson_append_binary ( - bson_t *bson, const char *key, int key_length, bson_subtype_t subtype, const uint8_t *binary, uint32_t length); - -#define BSON_APPEND_BINARY(b, key, subtype, val, len) bson_append_binary (b, key, (int) strlen (key), subtype, val, len) - -BSON_EXPORT (bool) -bson_array_builder_append_binary (bson_array_builder_t *bab, - bson_subtype_t subtype, - const uint8_t *binary, - uint32_t length); - -/** - * bson_append_bool: - * @bson: A bson_t. - * @key: The key for the field. - * @value: The boolean value. - * - * Appends a new field to @bson of type BSON_TYPE_BOOL. - * - * Returns: true if successful; false if append would overflow max size. - */ -BSON_EXPORT (bool) -bson_append_bool (bson_t *bson, const char *key, int key_length, bool value); - -#define BSON_APPEND_BOOL(b, key, val) bson_append_bool (b, key, (int) strlen (key), val) - -BSON_EXPORT (bool) -bson_array_builder_append_bool (bson_array_builder_t *bab, bool value); - -/** - * bson_append_code: - * @bson: A bson_t. - * @key: The key for the document. - * @javascript: JavaScript code to be executed. - * - * Appends a field of type BSON_TYPE_CODE to the BSON document. @javascript - * should contain a script in javascript to be executed. - * - * Returns: true if successful; false if append would overflow max size. - */ -BSON_EXPORT (bool) -bson_append_code (bson_t *bson, const char *key, int key_length, const char *javascript); - -#define BSON_APPEND_CODE(b, key, val) bson_append_code (b, key, (int) strlen (key), val) - -BSON_EXPORT (bool) -bson_array_builder_append_code (bson_array_builder_t *bab, const char *javascript); - -/** - * bson_append_code_with_scope: - * @bson: A bson_t. - * @key: The key for the document. - * @javascript: JavaScript code to be executed. - * @scope: A bson_t containing the scope for @javascript. - * - * Appends a field of type BSON_TYPE_CODEWSCOPE to the BSON document. - * @javascript should contain a script in javascript to be executed. - * - * Returns: true if successful; false if append would overflow max size. - */ -BSON_EXPORT (bool) -bson_append_code_with_scope ( - bson_t *bson, const char *key, int key_length, const char *javascript, const bson_t *scope); - -#define BSON_APPEND_CODE_WITH_SCOPE(b, key, val, scope) \ - bson_append_code_with_scope (b, key, (int) strlen (key), val, scope) - -BSON_EXPORT (bool) -bson_array_builder_append_code_with_scope (bson_array_builder_t *bab, const char *javascript, const bson_t *scope); - -/** - * bson_append_dbpointer: - * @bson: A bson_t. - * @key: The key for the field. - * @collection: The collection name. - * @oid: The oid to the reference. - * - * Appends a new field of type BSON_TYPE_DBPOINTER. This datum type is - * deprecated in the BSON spec and should not be used in new code. - * - * Returns: true if successful; false if append would overflow max size. - */ -BSON_EXPORT (bool) -bson_append_dbpointer (bson_t *bson, const char *key, int key_length, const char *collection, const bson_oid_t *oid); - -#define BSON_APPEND_DBPOINTER(b, key, coll, oid) bson_append_dbpointer (b, key, (int) strlen (key), coll, oid) - -BSON_EXPORT (bool) -bson_array_builder_append_dbpointer (bson_array_builder_t *bab, const char *collection, const bson_oid_t *oid); - -/** - * bson_append_double: - * @bson: A bson_t. - * @key: The key for the field. - * - * Appends a new field to @bson of the type BSON_TYPE_DOUBLE. - * - * Returns: true if successful; false if append would overflow max size. - */ -BSON_EXPORT (bool) -bson_append_double (bson_t *bson, const char *key, int key_length, double value); - -#define BSON_APPEND_DOUBLE(b, key, val) bson_append_double (b, key, (int) strlen (key), val) - -BSON_EXPORT (bool) -bson_array_builder_append_double (bson_array_builder_t *bab, double value); - -/** - * bson_append_document: - * @bson: A bson_t. - * @key: The key for the field. - * @value: A bson_t containing the subdocument. - * - * Appends a new field to @bson of the type BSON_TYPE_DOCUMENT. - * The documents contents will be copied into @bson. - * - * Returns: true if successful; false if append would overflow max size. - */ -BSON_EXPORT (bool) -bson_append_document (bson_t *bson, const char *key, int key_length, const bson_t *value); - -#define BSON_APPEND_DOCUMENT(b, key, val) bson_append_document (b, key, (int) strlen (key), val) - -BSON_EXPORT (bool) -bson_array_builder_append_document (bson_array_builder_t *bab, const bson_t *value); - -/** - * bson_append_document_begin: - * @bson: A bson_t. - * @key: The key for the field. - * @key_length: The length of @key in bytes not including NUL or -1 - * if @key_length is NUL terminated. - * @child: A location to an uninitialized bson_t. - * - * Appends a new field named @key to @bson. The field is, however, - * incomplete. @child will be initialized so that you may add fields to the - * child document. Child will use a memory buffer owned by @bson and - * therefore grow the parent buffer as additional space is used. This allows - * a single malloc'd buffer to be used when building documents which can help - * reduce memory fragmentation. - * - * Returns: true if successful; false if append would overflow max size. - */ -BSON_EXPORT (bool) -bson_append_document_begin (bson_t *bson, const char *key, int key_length, bson_t *child); - -#define BSON_APPEND_DOCUMENT_BEGIN(b, key, child) bson_append_document_begin (b, key, (int) strlen (key), child) - -BSON_EXPORT (bool) -bson_array_builder_append_document_begin (bson_array_builder_t *bab, bson_t *child); - -/** - * bson_append_document_end: - * @bson: A bson_t. - * @child: A bson_t supplied to bson_append_document_begin(). - * - * Finishes the appending of a document to a @bson. @child is considered - * disposed after this call and should not be used any further. - * - * Returns: true if successful; false if append would overflow max size. - */ -BSON_EXPORT (bool) -bson_append_document_end (bson_t *bson, bson_t *child); - -BSON_EXPORT (bool) -bson_array_builder_append_document_end (bson_array_builder_t *bab, bson_t *child); - - -/** - * bson_append_array_begin: - * @bson: A bson_t. - * @key: The key for the field. - * @key_length: The length of @key in bytes not including NUL or -1 - * if @key_length is NUL terminated. - * @child: A location to an uninitialized bson_t. - * - * Appends a new field named @key to @bson. The field is, however, - * incomplete. @child will be initialized so that you may add fields to the - * child array. Child will use a memory buffer owned by @bson and - * therefore grow the parent buffer as additional space is used. This allows - * a single malloc'd buffer to be used when building arrays which can help - * reduce memory fragmentation. - * - * The type of @child will be BSON_TYPE_ARRAY and therefore the keys inside - * of it MUST be "0", "1", etc. - * - * Returns: true if successful; false if append would overflow max size. - */ -BSON_EXPORT (bool) -bson_append_array_begin (bson_t *bson, const char *key, int key_length, bson_t *child); - -#define BSON_APPEND_ARRAY_BEGIN(b, key, child) bson_append_array_begin (b, key, (int) strlen (key), child) - -/** - * bson_append_array_end: - * @bson: A bson_t. - * @child: A bson_t supplied to bson_append_array_begin(). - * - * Finishes the appending of a array to a @bson. @child is considered - * disposed after this call and should not be used any further. - * - * Returns: true if successful; false if append would overflow max size. - */ -BSON_EXPORT (bool) -bson_append_array_end (bson_t *bson, bson_t *child); - - -/** - * bson_append_int32: - * @bson: A bson_t. - * @key: The key for the field. - * @value: The int32_t 32-bit integer value. - * - * Appends a new field of type BSON_TYPE_INT32 to @bson. - * - * Returns: true if successful; false if append would overflow max size. - */ -BSON_EXPORT (bool) -bson_append_int32 (bson_t *bson, const char *key, int key_length, int32_t value); - -#define BSON_APPEND_INT32(b, key, val) bson_append_int32 (b, key, (int) strlen (key), val) - -BSON_EXPORT (bool) -bson_array_builder_append_int32 (bson_array_builder_t *bab, int32_t value); - -/** - * bson_append_int64: - * @bson: A bson_t. - * @key: The key for the field. - * @value: The int64_t 64-bit integer value. - * - * Appends a new field of type BSON_TYPE_INT64 to @bson. - * - * Returns: true if successful; false if append would overflow max size. - */ -BSON_EXPORT (bool) -bson_append_int64 (bson_t *bson, const char *key, int key_length, int64_t value); - -#define BSON_APPEND_INT64(b, key, val) bson_append_int64 (b, key, (int) strlen (key), val) - -BSON_EXPORT (bool) -bson_array_builder_append_int64 (bson_array_builder_t *bab, int64_t value); - -/** - * bson_append_decimal128: - * @bson: A bson_t. - * @key: The key for the field. - * @value: The bson_decimal128_t decimal128 value. - * - * Appends a new field of type BSON_TYPE_DECIMAL128 to @bson. - * - * Returns: true if successful; false if append would overflow max size. - */ -BSON_EXPORT (bool) -bson_append_decimal128 (bson_t *bson, const char *key, int key_length, const bson_decimal128_t *value); - -#define BSON_APPEND_DECIMAL128(b, key, val) bson_append_decimal128 (b, key, (int) strlen (key), val) - -BSON_EXPORT (bool) -bson_array_builder_append_decimal128 (bson_array_builder_t *bab, const bson_decimal128_t *value); - -/** - * bson_append_iter: - * @bson: A bson_t to append to. - * @key: The key name or %NULL to take current key from @iter. - * @key_length: The key length or -1 to use strlen(). - * @iter: The iter located on the position of the element to append. - * - * Appends a new field to @bson that is equivalent to the field currently - * pointed to by @iter. - * - * Returns: true if successful; false if append would overflow max size. - */ -BSON_EXPORT (bool) -bson_append_iter (bson_t *bson, const char *key, int key_length, const bson_iter_t *iter); - -#define BSON_APPEND_ITER(b, key, val) bson_append_iter (b, key, (int) strlen (key), val) - -BSON_EXPORT (bool) -bson_array_builder_append_iter (bson_array_builder_t *bab, const bson_iter_t *iter); - -/** - * bson_append_minkey: - * @bson: A bson_t. - * @key: The key for the field. - * - * Appends a new field of type BSON_TYPE_MINKEY to @bson. This is a special - * type that compares lower than all other possible BSON element values. - * - * See http://bsonspec.org for more information on this type. - * - * Returns: true if successful; false if append would overflow max size. - */ -BSON_EXPORT (bool) -bson_append_minkey (bson_t *bson, const char *key, int key_length); - -#define BSON_APPEND_MINKEY(b, key) bson_append_minkey (b, key, (int) strlen (key)) - -BSON_EXPORT (bool) -bson_array_builder_append_minkey (bson_array_builder_t *bab); - -/** - * bson_append_maxkey: - * @bson: A bson_t. - * @key: The key for the field. - * - * Appends a new field of type BSON_TYPE_MAXKEY to @bson. This is a special - * type that compares higher than all other possible BSON element values. - * - * See http://bsonspec.org for more information on this type. - * - * Returns: true if successful; false if append would overflow max size. - */ -BSON_EXPORT (bool) -bson_append_maxkey (bson_t *bson, const char *key, int key_length); - -#define BSON_APPEND_MAXKEY(b, key) bson_append_maxkey (b, key, (int) strlen (key)) - -BSON_EXPORT (bool) -bson_array_builder_append_maxkey (bson_array_builder_t *bab); - -/** - * bson_append_null: - * @bson: A bson_t. - * @key: The key for the field. - * - * Appends a new field to @bson with NULL for the value. - * - * Returns: true if successful; false if append would overflow max size. - */ -BSON_EXPORT (bool) -bson_append_null (bson_t *bson, const char *key, int key_length); - -#define BSON_APPEND_NULL(b, key) bson_append_null (b, key, (int) strlen (key)) - -BSON_EXPORT (bool) -bson_array_builder_append_null (bson_array_builder_t *bab); - -/** - * bson_append_oid: - * @bson: A bson_t. - * @key: The key for the field. - * @oid: bson_oid_t. - * - * Appends a new field to the @bson of type BSON_TYPE_OID using the contents of - * @oid. - * - * Returns: true if successful; false if append would overflow max size. - */ -BSON_EXPORT (bool) -bson_append_oid (bson_t *bson, const char *key, int key_length, const bson_oid_t *oid); - -#define BSON_APPEND_OID(b, key, val) bson_append_oid (b, key, (int) strlen (key), val) - -BSON_EXPORT (bool) -bson_array_builder_append_oid (bson_array_builder_t *bab, const bson_oid_t *oid); - -/** - * bson_append_regex: - * @bson: A bson_t. - * @key: The key of the field. - * @regex: The regex to append to the bson. - * @options: Options for @regex. - * - * Appends a new field to @bson of type BSON_TYPE_REGEX. @regex should - * be the regex string. @options should contain the options for the regex. - * - * Valid options for @options are: - * - * 'i' for case-insensitive. - * 'm' for multiple matching. - * 'x' for verbose mode. - * 'l' to make \w and \W locale dependent. - * 's' for dotall mode ('.' matches everything) - * 'u' to make \w and \W match unicode. - * - * For more detailed information about BSON regex elements, see bsonspec.org. - * - * Returns: true if successful; false if append would overflow max size. - */ -BSON_EXPORT (bool) -bson_append_regex (bson_t *bson, const char *key, int key_length, const char *regex, const char *options); - -#define BSON_APPEND_REGEX(b, key, val, opt) bson_append_regex (b, key, (int) strlen (key), val, opt) - -BSON_EXPORT (bool) -bson_array_builder_append_regex (bson_array_builder_t *bab, const char *regex, const char *options); - -/** - * bson_append_regex: - * @bson: A bson_t. - * @key: The key of the field. - * @key_length: The length of the key string. - * @regex: The regex to append to the bson. - * @regex_length: The length of the regex string. - * @options: Options for @regex. - * - * Appends a new field to @bson of type BSON_TYPE_REGEX. @regex should - * be the regex string. @options should contain the options for the regex. - * - * Valid options for @options are: - * - * 'i' for case-insensitive. - * 'm' for multiple matching. - * 'x' for verbose mode. - * 'l' to make \w and \W locale dependent. - * 's' for dotall mode ('.' matches everything) - * 'u' to make \w and \W match unicode. - * - * For more detailed information about BSON regex elements, see bsonspec.org. - * - * Returns: true if successful; false if append would overflow max size. - */ -BSON_EXPORT (bool) -bson_append_regex_w_len ( - bson_t *bson, const char *key, int key_length, const char *regex, int regex_length, const char *options); - -BSON_EXPORT (bool) -bson_array_builder_append_regex_w_len (bson_array_builder_t *bab, - const char *regex, - int regex_length, - const char *options); - -/** - * bson_append_utf8: - * @bson: A bson_t. - * @key: The key for the field. - * @value: A UTF-8 encoded string. - * @length: The length of @value or -1 if it is NUL terminated. - * - * Appends a new field to @bson using @key as the key and @value as the UTF-8 - * encoded value. - * - * It is the callers responsibility to ensure @value is valid UTF-8. You can - * use bson_utf8_validate() to perform this check. - * - * Returns: true if successful; false if append would overflow max size. - */ -BSON_EXPORT (bool) -bson_append_utf8 (bson_t *bson, const char *key, int key_length, const char *value, int length); - -#define BSON_APPEND_UTF8(b, key, val) bson_append_utf8 (b, key, (int) strlen (key), val, (int) strlen (val)) - -BSON_EXPORT (bool) -bson_array_builder_append_utf8 (bson_array_builder_t *bab, const char *value, int length); - -/** - * bson_append_symbol: - * @bson: A bson_t. - * @key: The key for the field. - * @value: The symbol as a string. - * @length: The length of @value or -1 if NUL-terminated. - * - * Appends a new field to @bson of type BSON_TYPE_SYMBOL. This BSON type is - * deprecated and should not be used in new code. - * - * See http://bsonspec.org for more information on this type. - * - * Returns: true if successful; false if append would overflow max size. - */ -BSON_EXPORT (bool) -bson_append_symbol (bson_t *bson, const char *key, int key_length, const char *value, int length); - -#define BSON_APPEND_SYMBOL(b, key, val) bson_append_symbol (b, key, (int) strlen (key), val, (int) strlen (val)) - -BSON_EXPORT (bool) -bson_array_builder_append_symbol (bson_array_builder_t *bab, const char *value, int length); - -/** - * bson_append_time_t: - * @bson: A bson_t. - * @key: The key for the field. - * @value: A time_t. - * - * Appends a BSON_TYPE_DATE_TIME field to @bson using the time_t @value for the - * number of seconds since UNIX epoch in UTC. - * - * Returns: true if successful; false if append would overflow max size. - */ -BSON_EXPORT (bool) -bson_append_time_t (bson_t *bson, const char *key, int key_length, time_t value); - -#define BSON_APPEND_TIME_T(b, key, val) bson_append_time_t (b, key, (int) strlen (key), val) - -BSON_EXPORT (bool) -bson_array_builder_append_time_t (bson_array_builder_t *bab, time_t value); - -/** - * bson_append_timeval: - * @bson: A bson_t. - * @key: The key for the field. - * @value: A struct timeval containing the date and time. - * - * Appends a BSON_TYPE_DATE_TIME field to @bson using the struct timeval - * provided. The time is persisted in milliseconds since the UNIX epoch in UTC. - * - * Returns: true if successful; false if append would overflow max size. - */ -BSON_EXPORT (bool) -bson_append_timeval (bson_t *bson, const char *key, int key_length, struct timeval *value); - -#define BSON_APPEND_TIMEVAL(b, key, val) bson_append_timeval (b, key, (int) strlen (key), val) - -BSON_EXPORT (bool) -bson_array_builder_append_timeval (bson_array_builder_t *bab, struct timeval *value); - -/** - * bson_append_date_time: - * @bson: A bson_t. - * @key: The key for the field. - * @key_length: The length of @key in bytes or -1 if \0 terminated. - * @value: The number of milliseconds elapsed since UNIX epoch. - * - * Appends a new field to @bson of type BSON_TYPE_DATE_TIME. - * - * Returns: true if successful; otherwise false. - */ -BSON_EXPORT (bool) -bson_append_date_time (bson_t *bson, const char *key, int key_length, int64_t value); - -#define BSON_APPEND_DATE_TIME(b, key, val) bson_append_date_time (b, key, (int) strlen (key), val) - -BSON_EXPORT (bool) -bson_array_builder_append_date_time (bson_array_builder_t *bab, int64_t value); - -/** - * bson_append_now_utc: - * @bson: A bson_t. - * @key: The key for the field. - * @key_length: The length of @key or -1 if it is NULL terminated. - * - * Appends a BSON_TYPE_DATE_TIME field to @bson using the current time in UTC - * as the field value. - * - * Returns: true if successful; false if append would overflow max size. - */ -BSON_EXPORT (bool) -bson_append_now_utc (bson_t *bson, const char *key, int key_length); - -#define BSON_APPEND_NOW_UTC(b, key) bson_append_now_utc (b, key, (int) strlen (key)) - -BSON_EXPORT (bool) -bson_array_builder_append_now_utc (bson_array_builder_t *bab); - -/** - * bson_append_timestamp: - * @bson: A bson_t. - * @key: The key for the field. - * @timestamp: 4 byte timestamp. - * @increment: 4 byte increment for timestamp. - * - * Appends a field of type BSON_TYPE_TIMESTAMP to @bson. This is a special type - * used by MongoDB replication and sharding. If you need generic time and date - * fields use bson_append_time_t() or bson_append_timeval(). - * - * Setting @increment and @timestamp to zero has special semantics. See - * http://bsonspec.org for more information on this field type. - * - * Returns: true if successful; false if append would overflow max size. - */ -BSON_EXPORT (bool) -bson_append_timestamp (bson_t *bson, const char *key, int key_length, uint32_t timestamp, uint32_t increment); - -#define BSON_APPEND_TIMESTAMP(b, key, val, inc) bson_append_timestamp (b, key, (int) strlen (key), val, inc) - -BSON_EXPORT (bool) -bson_array_builder_append_timestamp (bson_array_builder_t *bab, uint32_t timestamp, uint32_t increment); - -/** - * bson_append_undefined: - * @bson: A bson_t. - * @key: The key for the field. - * - * Appends a field of type BSON_TYPE_UNDEFINED. This type is deprecated in the - * spec and should not be used for new code. However, it is provided for those - * needing to interact with legacy systems. - * - * Returns: true if successful; false if append would overflow max size. - */ -BSON_EXPORT (bool) -bson_append_undefined (bson_t *bson, const char *key, int key_length); - -#define BSON_APPEND_UNDEFINED(b, key) bson_append_undefined (b, key, (int) strlen (key)) - -BSON_EXPORT (bool) -bson_array_builder_append_undefined (bson_array_builder_t *bab); - -BSON_EXPORT (bool) -bson_concat (bson_t *dst, const bson_t *src); - -BSON_EXPORT (bool) -bson_append_array_builder_begin (bson_t *bson, const char *key, int key_length, bson_array_builder_t **child); - -#define BSON_APPEND_ARRAY_BUILDER_BEGIN(b, key, child) \ - bson_append_array_builder_begin (b, key, (int) strlen (key), child) - -BSON_EXPORT (bool) -bson_array_builder_append_array_builder_begin (bson_array_builder_t *bab, bson_array_builder_t **child); - -BSON_EXPORT (bool) -bson_append_array_builder_end (bson_t *bson, bson_array_builder_t *child); - -BSON_EXPORT (bool) -bson_array_builder_append_array_builder_end (bson_array_builder_t *bab, bson_array_builder_t *child); - - -BSON_END_DECLS - - -#endif /* BSON_H */ diff --git a/bsonjs/bsonjs.c b/bsonjs/bsonjs.c index cd22ad4..8d54fef 100644 --- a/bsonjs/bsonjs.c +++ b/bsonjs/bsonjs.c @@ -45,7 +45,7 @@ int mode) } else if (mode == 2) { json = bson_as_canonical_extended_json(b, json_len); } else if (mode == 0) { - json = bson_as_json(b, json_len); + json = bson_as_legacy_extended_json(b, json_len); } else { PyErr_SetString(PyExc_ValueError, "The value of mode must be one of: " "bsonjs.RELAXED, bsonjs.LEGACY, " diff --git a/bsonjs/common/bson-dsl.h b/bsonjs/common/bson-dsl.h deleted file mode 100644 index 58a14e2..0000000 --- a/bsonjs/common/bson-dsl.h +++ /dev/null @@ -1,1284 +0,0 @@ -#include "common-prelude.h" - -#ifndef BSON_BSON_DSL_H_INCLUDED -#define BSON_BSON_DSL_H_INCLUDED - -/** - * @file bson-dsl.h - * @brief Define a C-preprocessor DSL for working with BSON objects - * - * This file defines an embedded DSL for working with BSON objects consisely and - * correctly. - * - * For more information about using this DSL, refer to `bson-dsl.md`. - */ - -#include "bson/bson.h" - -enum { - /// Toggle this value to enable/disable debug output for all bsonDSL - /// operations (printed to stderr). You can also set a constant - /// BSON_DSL_DEBUG within the scope of a DSL command to selectively debug - /// only the commands within that scope. - BSON_DSL_DEBUG = 0 -}; - -#define _bson_thread_local BSON_IF_GNU_LIKE (__thread) BSON_IF_MSVC (__declspec (thread)) - -#define _bson_comdat \ - BSON_IF_WINDOWS (__declspec (selectany)) \ - BSON_IF_POSIX (__attribute__ ((weak))) - -#ifdef __GNUC__ -// GCC has a bug handling pragma statements that disable warnings within complex -// nested macro expansions. If we're GCC, just disable -Wshadow outright: -BSON_IF_GNU_LIKE (_Pragma ("GCC diagnostic ignored \"-Wshadow\"")) -#endif - -#define _bsonDSL_disableWarnings() \ - if (1) { \ - BSON_IF_GNU_LIKE (_Pragma ("GCC diagnostic push");) \ - BSON_IF_GNU_LIKE (_Pragma ("GCC diagnostic ignored \"-Wshadow\"");) \ - } else \ - ((void) 0) - -#define _bsonDSL_restoreWarnings() \ - if (1) { \ - BSON_IF_GNU_LIKE (_Pragma ("GCC diagnostic pop");) \ - } else \ - ((void) 0) - -/** - * @brief Parse the given BSON document. - * - * @param doc A bson_t object to walk. (Not a pointer) - */ -#define bsonParse(Document, ...) \ - _bsonDSL_begin ("bsonParse(%s)", _bsonDSL_str (Document)); \ - _bsonDSL_disableWarnings (); \ - bsonParseError = NULL; \ - BSON_MAYBE_UNUSED bool _bvHalt = false; \ - BSON_MAYBE_UNUSED const bool _bvContinue = false; \ - BSON_MAYBE_UNUSED const bool _bvBreak = false; \ - _bsonDSL_eval (_bsonParse ((Document), __VA_ARGS__)); \ - _bsonDSL_restoreWarnings (); \ - _bsonDSL_end - -/** - * @brief Visit each element of a BSON document - */ -#define bsonVisitEach(Document, ...) \ - _bsonDSL_begin ("bsonVisitEach(%s)", _bsonDSL_str (Document)); \ - _bsonDSL_disableWarnings (); \ - BSON_MAYBE_UNUSED bool _bvHalt = false; \ - _bsonDSL_eval (_bsonVisitEach ((Document), __VA_ARGS__)); \ - _bsonDSL_restoreWarnings (); \ - _bsonDSL_end - -#define bsonBuildContext (*_bsonBuildContextThreadLocalPtr) -#define bsonVisitContext (*_bsonVisitContextThreadLocalPtr) -#define bsonVisitIter (bsonVisitContext.iter) - -/// Begin any function-like macro by opening a new scope and writing a debug -/// message. -#define _bsonDSL_begin(Str, ...) \ - if (true) { \ - _bsonDSLDebug (Str, __VA_ARGS__); \ - ++_bson_dsl_indent - -/// End a function-like macro scope. -#define _bsonDSL_end \ - --_bson_dsl_indent; \ - } \ - else ((void) 0) - -/** - * @brief Expands to a call to bson_append_{Kind}, with the three first - * arguments filled in by the DSL context variables. - */ -#define _bsonBuildAppendArgs bsonBuildContext.doc, bsonBuildContext.key, bsonBuildContext.key_len - -/** - * The _bsonDocOperation_XYZ macros handle the top-level bsonBuild() - * items, and any nested doc() items, with XYZ being the doc-building - * subcommand. - */ -#define _bsonDocOperation(Command, _ignore, _count) \ - if (!bsonBuildError) { \ - _bsonDocOperation_##Command; \ - if (bsonBuildError) { \ - _bsonDSLDebug ("Stopping doc() due to bsonBuildError: [%s]", bsonBuildError); \ - } \ - } - -#define _bsonValueOperation(P) _bsonValueOperation_##P - -/// key-value pair with explicit key length -#define _bsonDocOperation_kvl(String, Len, Element) \ - _bsonDSL_begin ("\"%s\" => [%s]", String, _bsonDSL_strElide (30, Element)); \ - const char *_bbString = (String); \ - const uint64_t length = (Len); \ - if (bson_in_range_unsigned (int, length)) { \ - _bbCtx.key = _bbString; \ - _bbCtx.key_len = (int) length; \ - _bsonValueOperation (Element); \ - } else { \ - bsonBuildError = "Out-of-range key string length value"; \ - } \ - _bsonDSL_end - -/// Key-value pair with a C-string -#define _bsonDocOperation_kv(String, Element) _bsonDocOperation_kvl ((String), strlen ((String)), Element) - -/// Execute arbitrary code -#define _bsonDocOperation_do(...) \ - _bsonDSL_begin ("do(%s)", _bsonDSL_strElide (30, __VA_ARGS__)); \ - do { \ - __VA_ARGS__; \ - } while (0); \ - if (bsonBuildError) { \ - _bsonDSLDebug ("do() set bsonBuildError: [%s]", bsonBuildError); \ - } \ - _bsonDSL_end - -/// We must defer expansion of the nested doc() to allow "recursive" evaluation -#define _bsonValueOperation_doc _bsonValueOperationDeferred_doc _bsonDSL_nothing () -#define _bsonArrayOperation_doc(...) _bsonArrayAppendValue (doc (__VA_ARGS__)) - -#define _bsonValueOperationDeferred_doc(...) \ - _bsonDSL_begin ("doc(%s)", _bsonDSL_strElide (30, __VA_ARGS__)); \ - /* Write to this variable as the child: */ \ - bson_t _bbChildDoc = BSON_INITIALIZER; \ - if (!bson_append_document_begin (_bsonBuildAppendArgs, &_bbChildDoc)) { \ - bsonBuildError = "Error while initializing child document: " _bsonDSL_str (__VA_ARGS__); \ - } else { \ - _bsonBuildAppend (_bbChildDoc, __VA_ARGS__); \ - if (!bsonBuildError) { \ - if (!bson_append_document_end (bsonBuildContext.doc, &_bbChildDoc)) { \ - bsonBuildError = "Error while finalizing document: " _bsonDSL_str (__VA_ARGS__); \ - } \ - } \ - } \ - _bsonDSL_end - -/// We must defer expansion of the nested array() to allow "recursive" -/// evaluation -#define _bsonValueOperation_array _bsonValueOperationDeferred_array _bsonDSL_nothing () -#define _bsonArrayOperation_array(...) _bsonArrayAppendValue (array (__VA_ARGS__)) - -#define _bsonValueOperationDeferred_array(...) \ - _bsonDSL_begin ("array(%s)", _bsonDSL_strElide (30, __VA_ARGS__)); \ - /* Write to this variable as the child array: */ \ - bson_t _bbArray = BSON_INITIALIZER; \ - if (!bson_append_array_begin (_bsonBuildAppendArgs, &_bbArray)) { \ - bsonBuildError = "Error while initializing child array: " _bsonDSL_str (__VA_ARGS__); \ - } else { \ - _bsonBuildArray (_bbArray, __VA_ARGS__); \ - if (!bsonBuildError) { \ - if (!bson_append_array_end (bsonBuildContext.doc, &_bbArray)) { \ - bsonBuildError = "Error while finalizing child array: " _bsonDSL_str (__VA_ARGS__); \ - } \ - } else { \ - _bsonDSLDebug ("Got bsonBuildError: [%s]", bsonBuildError); \ - } \ - } \ - _bsonDSL_end - -/// Append a UTF-8 string with an explicit length -#define _bsonValueOperation_utf8_w_len(String, Len) \ - if (!bson_append_utf8 (_bsonBuildAppendArgs, (String), (int) (Len))) { \ - bsonBuildError = "Error while appending utf8 string: " _bsonDSL_str (String); \ - } else \ - ((void) 0) -#define _bsonArrayOperation_utf8_w_len(X) _bsonArrayAppendValue (utf8_w_len (X)) - -/// Append a "cstr" as UTF-8 -#define _bsonValueOperation_cstr(String) _bsonValueOperation_utf8_w_len ((String), strlen (String)) -#define _bsonArrayOperation_cstr(X) _bsonArrayAppendValue (cstr (X)) - -/// Append an int32 -#define _bsonValueOperation_int32(Integer) \ - if (!bson_append_int32 (_bsonBuildAppendArgs, (Integer))) { \ - bsonBuildError = "Error while appending int32(" _bsonDSL_str (Integer) ")"; \ - } else \ - ((void) 0) -#define _bsonArrayOperation_int32(X) _bsonArrayAppendValue (int32 (X)) - -/// Append an int64 -#define _bsonValueOperation_int64(Integer) \ - if (!bson_append_int64 (_bsonBuildAppendArgs, (Integer))) { \ - bsonBuildError = "Error while appending int64(" _bsonDSL_str (Integer) ")"; \ - } else \ - ((void) 0) -#define _bsonArrayOperation_int64(X) _bsonArrayAppendValue (int64 (X)) - -/// Append the value referenced by a given iterator -#define _bsonValueOperation_iterValue(Iter) \ - if (!bson_append_iter (_bsonBuildAppendArgs, &(Iter))) { \ - bsonBuildError = "Error while appending iterValue(" _bsonDSL_str (Iter) ")"; \ - } else \ - ((void) 0) -#define _bsonArrayOperation_iterValue(X) _bsonArrayAppendValue (iterValue (X)) - -/// Append the BSON document referenced by the given pointer -#define _bsonValueOperation_bson(Doc) \ - if (!bson_append_document (_bsonBuildAppendArgs, &(Doc))) { \ - bsonBuildError = "Error while appending subdocument: bson(" _bsonDSL_str (Doc) ")"; \ - } else \ - ((void) 0) -#define _bsonArrayOperation_bson(X) _bsonArrayAppendValue (bson (X)) - -/// Append the BSON document referenced by the given pointer as an array -#define _bsonValueOperation_bsonArray(Arr) \ - if (!bson_append_array (_bsonBuildAppendArgs, &(Arr))) { \ - bsonBuildError = "Error while appending subdocument array: " \ - "bsonArray(" _bsonDSL_str (Arr) ")"; \ - } else \ - ((void) 0) -#define _bsonArrayOperation_bsonArray(X) _bsonArrayAppendValue (bsonArray (X)) - -#define _bsonValueOperation_bool(b) \ - if (!bson_append_bool (_bsonBuildAppendArgs, (b))) { \ - bsonBuildError = "Error while appending bool(" _bsonDSL_str (b) ")"; \ - } else \ - ((void) 0) -#define _bsonArrayOperation_bool(X) _bsonArrayAppendValue (bool (X)) -#define _bsonValueOperation__Bool(b) _bsonValueOperation_bool (b) -#define _bsonArrayOperation__Bool(X) _bsonArrayAppendValue (_Bool (X)) - -#define _bsonValueOperation_null \ - if (!bson_append_null (_bsonBuildAppendArgs)) { \ - bsonBuildError = "Error while appending a null"; \ - } else \ - ((void) 0) -#define _bsonArrayOperation_null _bsonValueOperation (null) - -#define _bsonArrayOperation_value(X) _bsonArrayAppendValue (value (X)) - -#define _bsonValueOperation_value(Value) \ - _bsonDSL_begin ("value(%s)", _bsonDSL_str (Value)); \ - if (!bson_append_value (_bsonBuildAppendArgs, &(Value))) { \ - bsonBuildError = "Error while appending value(" _bsonDSL_str (Value) ")"; \ - } \ - _bsonDSL_end - -/// Insert the given BSON document into the parent document in-place -#define _bsonDocOperation_insert(OtherBSON, Pred) \ - _bsonDSL_begin ("Insert other document: [%s]", _bsonDSL_str (OtherBSON)); \ - const bool _bvHalt = false; /* Required for _bsonVisitEach() */ \ - _bsonVisitEach (OtherBSON, if (Pred, then (do (_bsonDocOperation_iterElement (bsonVisitIter))))); \ - _bsonDSL_end - -#define _bsonDocOperation_insertFromIter(Iter, Pred) \ - _bsonDSL_begin ("Insert document from iterator: [%s]", _bsonDSL_str (Iter)); \ - bson_t _bbDocFromIter = _bson_dsl_iter_as_doc (&(Iter)); \ - if (_bbDocFromIter.len == 0) { \ - _bsonDSLDebug ("NOTE: Skipping insert of non-document value from iterator"); \ - } else { \ - _bsonDocOperation_insert (_bbDocFromIter, Pred); \ - } \ - _bsonDSL_end - -#define _bsonDocOperation_iterElement(Iter) \ - _bsonDSL_begin ("Insert element from bson_iter_t [%s]", _bsonDSL_str (Iter)); \ - bson_iter_t _bbIter = (Iter); \ - _bsonDocOperation_kvl (bson_iter_key (&_bbIter), bson_iter_key_len (&_bbIter), iterValue (_bbIter)); \ - _bsonDSL_end - -/// Insert the given BSON document into the parent array. Keys of the given -/// document are discarded and it is treated as an array of values. -#define _bsonArrayOperation_insert(OtherArr, Pred) \ - _bsonDSL_begin ("Insert other array: [%s]", _bsonDSL_str (OtherArr)); \ - _bsonVisitEach (OtherArr, if (Pred, then (do (_bsonArrayOperation_iterValue (bsonVisitIter))))); \ - _bsonDSL_end - -#define _bsonArrayAppendValue(ValueOperation) \ - _bsonDSL_begin ("[%d] => [%s]", (int) bsonBuildContext.index, _bsonDSL_strElide (30, ValueOperation)); \ - /* Set the doc key to the array index as a string: */ \ - _bsonBuild_setKeyToArrayIndex (bsonBuildContext.index); \ - /* Append a value: */ \ - _bsonValueOperation_##ValueOperation; \ - /* Increment the array index: */ \ - ++_bbCtx.index; \ - _bsonDSL_end - - -#define _bsonDocOperationIfThen_then _bsonBuildAppendWithCurrentContext -#define _bsonDocOperationIfElse_else _bsonBuildAppendWithCurrentContext - -#define _bsonDocOperationIfThenElse(Condition, Then, Else) \ - if ((Condition)) { \ - _bsonDSLDebug ("Taking TRUE branch: [%s]", _bsonDSL_str (Then)); \ - _bsonDocOperationIfThen_##Then; \ - } else { \ - _bsonDSLDebug ("Taking FALSE branch: [%s]", _bsonDSL_str (Else)); \ - _bsonDocOperationIfElse_##Else; \ - } - -#define _bsonDocOperationIfThen(Condition, Then) \ - if ((Condition)) { \ - _bsonDSLDebug ("Taking TRUE branch: [%s]", _bsonDSL_str (Then)); \ - _bsonDocOperationIfThen_##Then; \ - } - -#define _bsonDocOperation_if(Condition, ...) \ - _bsonDSL_begin ("Conditional append on [%s]", _bsonDSL_str (Condition)); \ - /* Pick a sub-macro depending on if there are one or two args */ \ - _bsonDSL_ifElse (_bsonDSL_hasComma (__VA_ARGS__), _bsonDocOperationIfThenElse, _bsonDocOperationIfThen) ( \ - Condition, __VA_ARGS__); \ - _bsonDSL_end - -#define _bsonArrayOperationIfThen_then _bsonBuildArrayWithCurrentContext -#define _bsonArrayOperationIfElse_else _bsonBuildArrayWithCurrentContext - -#define _bsonArrayOperationIfThenElse(Condition, Then, Else) \ - if ((Condition)) { \ - _bsonDSLDebug ("Taking TRUE branch: [%s]", _bsonDSL_str (Then)); \ - _bsonArrayOperationIfThen_##Then; \ - } else { \ - _bsonDSLDebug ("Taking FALSE branch: [%s]", _bsonDSL_str (Else)); \ - _bsonArrayOperationIfElse_##Else; \ - } - -#define _bsonArrayOperationIfThen(Condition, Then) \ - if ((Condition)) { \ - _bsonDSLDebug ("Taking TRUE branch: [%s]", _bsonDSL_str (Then)); \ - _bsonArrayOperationIfThen_##Then; \ - } - -#define _bsonArrayOperation_if(Condition, ...) \ - _bsonDSL_begin ("Conditional value on [%s]", _bsonDSL_str (Condition)); \ - /* Pick a sub-macro depending on if there are one or two args */ \ - _bsonDSL_ifElse (_bsonDSL_hasComma (__VA_ARGS__), _bsonArrayOperationIfThenElse, _bsonArrayOperationIfThen) ( \ - Condition, __VA_ARGS__); \ - _bsonDSL_end - -#define _bsonValueOperationIf_then(X) _bsonValueOperation_##X -#define _bsonValueOperationIf_else(X) _bsonValueOperation_##X - -#define _bsonValueOperation_if(Condition, Then, Else) \ - if ((Condition)) { \ - _bsonDSLDebug ("Taking TRUE branch: [%s]", _bsonDSL_str (Then)); \ - _bsonValueOperationIf_##Then; \ - } else { \ - _bsonDSLDebug ("Taking FALSE branch: [%s]", _bsonDSL_str (Else)); \ - _bsonValueOperationIf_##Else; \ - } - -#define _bsonBuild_setKeyToArrayIndex(Idx) \ - _bbCtx.key_len = bson_snprintf (_bbCtx.index_key_str, sizeof _bbCtx.index_key_str, "%d", (int) _bbCtx.index); \ - _bbCtx.key = _bbCtx.index_key_str - -/// Handle an element of array() -#define _bsonArrayOperation(Element, _nil, _count) \ - if (!bsonBuildError) { \ - _bsonArrayOperation_##Element; \ - } - -#define _bsonBuildAppendWithCurrentContext(...) _bsonDSL_mapMacro (_bsonDocOperation, ~, __VA_ARGS__) - -#define _bsonBuildArrayWithCurrentContext(...) _bsonDSL_mapMacro (_bsonArrayOperation, ~, __VA_ARGS__) - -#define _bsonDSL_Type_double BSON_TYPE_DOUBLE -#define _bsonDSL_Type_utf8 BSON_TYPE_UTF8 -#define _bsonDSL_Type_doc BSON_TYPE_DOCUMENT -#define _bsonDSL_Type_array BSON_TYPE_ARRAY -#define _bsonDSL_Type_binary BSON_TYPE_BINARY -#define _bsonDSL_Type_undefined BSON_TYPE_UNDEFINED -#define _bsonDSL_Type_oid BSON_TYPE_OID -#define _bsonDSL_Type_bool BSON_TYPE_BOOL -// ("bool" may be spelled _Bool due to macro expansion:) -#define _bsonDSL_Type__Bool BSON_TYPE_BOOL -#define _bsonDSL_Type_date_time BSON_TYPE_DATE_TIME -#define _bsonDSL_Type_null BSON_TYPE_NULL -#define _bsonDSL_Type_regex BSON_TYPE_REGEX -#define _bsonDSL_Type_dbpointer BSON_TYPE_DBPOINTER -#define _bsonDSL_Type_code BSON_TYPE_CODE -#define _bsonDSL_Type_codewscope BSON_TYPE_CODEWSCOPE -#define _bsonDSL_Type_int32 BSON_TYPE_INT32 -#define _bsonDSL_Type_timestamp BSON_TYPE_TIMESTAMP -#define _bsonDSL_Type_int64 BSON_TYPE_INT64 -#define _bsonDSL_Type_decimal128 BSON_TYPE_DECIMAL128 - -#define _bsonDSL_Type_string __NOTE__No_type_named__string__did_you_mean__utf8 - -#define _bsonVisitOperation_halt _bvHalt = true - -#define _bsonVisitOperation_if(Predicate, ...) \ - _bsonDSL_begin ("if(%s)", _bsonDSL_str (Predicate)); \ - _bsonDSL_ifElse (_bsonDSL_hasComma (__VA_ARGS__), _bsonVisit_ifThenElse, _bsonVisit_ifThen) (Predicate, \ - __VA_ARGS__); \ - _bsonDSL_end - -#define _bsonVisit_ifThenElse(Predicate, Then, Else) \ - if (bsonPredicate (Predicate)) { \ - _bsonDSLDebug ("then:"); \ - _bsonVisit_ifThen_##Then; \ - } else { \ - _bsonDSLDebug ("else:"); \ - _bsonVisit_ifElse_##Else; \ - } - -#define _bsonVisit_ifThen(Predicate, Then) \ - if (bsonPredicate (Predicate)) { \ - _bsonDSLDebug ("then:"); \ - _bsonVisit_ifThen_##Then; \ - } else { \ - _bsonDSLDebug ("[else nothing]"); \ - } - -#define _bsonVisit_ifThen_then _bsonVisit_applyOps -#define _bsonVisit_ifElse_else _bsonVisit_applyOps - -#define _bsonVisitOperation_storeBool(Dest) \ - _bsonDSL_begin ("storeBool(%s)", _bsonDSL_str (Dest)); \ - (Dest) = bson_iter_as_bool (&bsonVisitIter); \ - _bsonDSL_end - -#define _bsonVisitOperation_storeStrRef(Dest) \ - _bsonDSL_begin ("storeStrRef(%s)", _bsonDSL_str (Dest)); \ - (Dest) = bson_iter_utf8 (&bsonVisitIter, NULL); \ - _bsonDSL_end - -#define _bsonVisitOperation_storeStrDup(Dest) \ - _bsonDSL_begin ("storeStrDup(%s)", _bsonDSL_str (Dest)); \ - (Dest) = bson_iter_dup_utf8 (&bsonVisitIter, NULL); \ - _bsonDSL_end - -#define _bsonVisitOperation_storeDocDup(Dest) \ - _bsonDSL_begin ("storeDocDup(%s)", _bsonDSL_str (Dest)); \ - bson_t _bvDoc = BSON_INITIALIZER; \ - _bson_dsl_iter_as_doc (&_bvDoc, &bsonVisitIter); \ - if (_bvDoc.len) { \ - bson_copy_to (&_bvDoc, &(Dest)); \ - } \ - _bsonDSL_end - -#define _bsonVisitOperation_storeDocRef(Dest) \ - _bsonDSL_begin ("storeDocRef(%s)", _bsonDSL_str (Dest)); \ - _bson_dsl_iter_as_doc (&(Dest), &bsonVisitIter); \ - _bsonDSL_end - -#define _bsonVisitOperation_storeDocDupPtr(Dest) \ - _bsonDSL_begin ("storeDocDupPtr(%s)", _bsonDSL_str (Dest)); \ - bson_t _bvDoc = BSON_INITIALIZER; \ - _bson_dsl_iter_as_doc (&_bvDoc, &bsonVisitIter); \ - if (_bvDoc.len) { \ - (Dest) = bson_copy (&_bvDoc); \ - } \ - _bsonDSL_end - -#define _bsonVisitOperation_storeInt32(Dest) \ - _bsonDSL_begin ("storeInt32(%s)", _bsonDSL_str (Dest)); \ - (Dest) = bson_iter_int32 (&bsonVisitIter); \ - _bsonDSL_end - -#define _bsonVisitOperation_do(...) \ - _bsonDSL_begin ("do: %s", _bsonDSL_strElide (30, __VA_ARGS__)); \ - do { \ - __VA_ARGS__; \ - } while (0); \ - _bsonDSL_end - -#define _bsonVisitOperation_appendTo(BSON) \ - _bsonDSL_begin ("appendTo(%s)", _bsonDSL_str (BSON)); \ - if (!bson_append_iter ( \ - &(BSON), bson_iter_key (&bsonVisitIter), (int) bson_iter_key_len (&bsonVisitIter), &bsonVisitIter)) { \ - bsonParseError = "Error in appendTo(" _bsonDSL_str (BSON) ")"; \ - } \ - _bsonDSL_end - -#define _bsonVisitCase_when(Pred, ...) \ - _bsonDSL_begin ("when: [%s]", _bsonDSL_str (Pred)); \ - _bvCaseMatched = _bsonPredicate (Pred); \ - if (_bvCaseMatched) { \ - _bsonVisit_applyOps (__VA_ARGS__); \ - } \ - _bsonDSL_end - -#define _bsonVisitCase_else(...) \ - _bsonDSL_begin ("else:%s", ""); \ - _bvCaseMatched = true; \ - _bsonVisit_applyOps (__VA_ARGS__); \ - _bsonDSL_end - -#define _bsonVisitCase(Pair, _nil, _count) \ - if (!_bvCaseMatched) { \ - _bsonVisitCase_##Pair; \ - } else \ - ((void) 0); - -#define _bsonVisitOperation_case(...) \ - _bsonDSL_begin ("case:%s", ""); \ - BSON_MAYBE_UNUSED bool _bvCaseMatched = false; \ - _bsonDSL_mapMacro (_bsonVisitCase, ~, __VA_ARGS__); \ - _bsonDSL_end - -#define _bsonVisitOperation_append _bsonVisitOneApplyDeferred_append _bsonDSL_nothing () -#define _bsonVisitOneApplyDeferred_append(Doc, ...) \ - _bsonDSL_begin ("append to [%s] : %s", _bsonDSL_str (Doc), _bsonDSL_strElide (30, __VA_ARGS__)); \ - _bsonBuildAppend (Doc, __VA_ARGS__); \ - if (bsonBuildError) { \ - bsonParseError = bsonBuildError; \ - } \ - _bsonDSL_end - -#define _bsonVisitEach(Doc, ...) \ - _bsonDSL_begin ("visitEach(%s)", _bsonDSL_str (Doc)); \ - do { \ - /* Reset the context */ \ - struct _bsonVisitContext_t _bvCtx = { \ - .doc = &(Doc), \ - .parent = _bsonVisitContextThreadLocalPtr, \ - .index = 0, \ - }; \ - _bsonVisitContextThreadLocalPtr = &_bvCtx; \ - bsonParseError = NULL; \ - /* Iterate over each element of the document */ \ - if (!bson_iter_init (&_bvCtx.iter, &(Doc))) { \ - bsonParseError = "Invalid BSON data [a]"; \ - } \ - BSON_MAYBE_UNUSED bool _bvBreak = false; \ - BSON_MAYBE_UNUSED bool _bvContinue = false; \ - while (bson_iter_next (&_bvCtx.iter) && !_bvHalt && !bsonParseError && !_bvBreak) { \ - _bvContinue = false; \ - _bsonVisit_applyOps (__VA_ARGS__); \ - ++_bvCtx.index; \ - } \ - if (bsonVisitIter.err_off) { \ - bsonParseError = "Invalid BSON data [b]"; \ - } \ - /* Restore the dsl context */ \ - _bsonVisitContextThreadLocalPtr = _bvCtx.parent; \ - } while (0); \ - _bsonDSL_end - -#define _bsonVisitOperation_visitEach _bsonVisitOperation_visitEachDeferred _bsonDSL_nothing () -#define _bsonVisitOperation_visitEachDeferred(...) \ - _bsonDSL_begin ("visitEach:%s", ""); \ - do { \ - const uint8_t *data; \ - uint32_t len; \ - bson_type_t typ = bson_iter_type_unsafe (&bsonVisitIter); \ - if (typ == BSON_TYPE_ARRAY) \ - bson_iter_array (&bsonVisitIter, &len, &data); \ - else if (typ == BSON_TYPE_DOCUMENT) \ - bson_iter_document (&bsonVisitIter, &len, &data); \ - else { \ - _bsonDSLDebug ("(Skipping visitEach() of non-array/document value)"); \ - break; \ - } \ - bson_t inner; \ - BSON_ASSERT (bson_init_static (&inner, data, len)); \ - _bsonVisitEach (inner, __VA_ARGS__); \ - } while (0); \ - _bsonDSL_end - -#define _bsonVisitOperation_nop _bsonDSLDebug ("[nop]") -#define _bsonVisitOperation_parse(...) \ - do { \ - const uint8_t *data; \ - uint32_t len; \ - bson_type_t typ = bson_iter_type (&bsonVisitIter); \ - if (typ == BSON_TYPE_ARRAY) \ - bson_iter_array (&bsonVisitIter, &len, &data); \ - else if (typ == BSON_TYPE_DOCUMENT) \ - bson_iter_document (&bsonVisitIter, &len, &data); \ - else { \ - _bsonDSLDebug ("Ignoring parse() for non-document/array value"); \ - break; \ - } \ - bson_t inner; \ - BSON_ASSERT (bson_init_static (&inner, data, len)); \ - _bsonParse (inner, __VA_ARGS__); \ - } while (0); - -#define _bsonVisitOperation_continue _bvContinue = true -#define _bsonVisitOperation_break _bvBreak = _bvContinue = true -#define _bsonVisitOperation_require(Predicate) \ - _bsonDSL_begin ("require(%s)", _bsonDSL_str (Predicate)); \ - if (!bsonPredicate (Predicate)) { \ - bsonParseError = "Element requirement failed: " _bsonDSL_str (Predicate); \ - } \ - _bsonDSL_end - -#define _bsonVisitOperation_error(S) bsonParseError = (S) -#define _bsonVisitOperation_errorf(S, ...) (bsonParseError = _bson_dsl_errorf (&(S), __VA_ARGS__)) -#define _bsonVisitOperation_dupPath(S) \ - _bsonDSL_begin ("dupPath(%s)", _bsonDSL_str (S)); \ - _bson_dsl_dupPath (&(S)); \ - _bsonDSL_end - -#define _bsonVisit_applyOp(P, _const, _count) \ - do { \ - if (!_bvContinue && !_bvHalt && !bsonParseError) { \ - _bsonVisitOperation_##P; \ - } \ - } while (0); - -#define _bsonParse(Doc, ...) \ - do { \ - BSON_MAYBE_UNUSED const bson_t *_bpDoc = &(Doc); \ - /* Keep track of which elements have been visited based on their index*/ \ - uint64_t _bpVisitBits_static[4] = {0}; \ - BSON_MAYBE_UNUSED uint64_t *_bpVisitBits = _bpVisitBits_static; \ - BSON_MAYBE_UNUSED size_t _bpNumVisitBitInts = sizeof _bpVisitBits_static / sizeof (uint64_t); \ - BSON_MAYBE_UNUSED bool _bpFoundElement = false; \ - _bsonParse_applyOps (__VA_ARGS__); \ - /* We may have allocated for visit bits */ \ - if (_bpVisitBits != _bpVisitBits_static) { \ - bson_free (_bpVisitBits); \ - } \ - } while (0) - -#define _bsonParse_applyOps(...) _bsonDSL_mapMacro (_bsonParse_applyOp, ~, __VA_ARGS__) - -/// Parse one entry referrenced by the context iterator -#define _bsonParse_applyOp(P, _nil, Counter) \ - do { \ - if (!_bvHalt && !bsonParseError) { \ - _bsonParseOperation_##P; \ - } \ - } while (0); - -#define _bsonParseMarkVisited(Index) \ - if (1) { \ - const size_t nth_int = Index / 64u; \ - const size_t nth_bit = Index % 64u; \ - while (nth_int >= _bpNumVisitBitInts) { \ - /* Say that five times, fast: */ \ - size_t new_num_visit_bit_ints = _bpNumVisitBitInts * 2u; \ - uint64_t *new_visit_bit_ints = bson_malloc0 (sizeof (uint64_t) * new_num_visit_bit_ints); \ - memcpy (new_visit_bit_ints, _bpVisitBits, sizeof (uint64_t) * _bpNumVisitBitInts); \ - if (_bpVisitBits != _bpVisitBits_static) { \ - bson_free (_bpVisitBits); \ - } \ - _bpVisitBits = new_visit_bit_ints; \ - _bpNumVisitBitInts = new_num_visit_bit_ints; \ - } \ - \ - _bpVisitBits[nth_int] |= (UINT64_C (1) << nth_bit); \ - } else \ - ((void) 0) - -#define _bsonParseDidVisitNth(Index) _bsonParseDidVisitNth_1 (Index / 64u, Index % 64u) -#define _bsonParseDidVisitNth_1(NthInt, NthBit) \ - (NthInt < _bpNumVisitBitInts && (_bpVisitBits[NthInt] & (UINT64_C (1) << NthBit))) - -#define _bsonParseOperation_find(Predicate, ...) \ - _bsonDSL_begin ("find(%s)", _bsonDSL_str (Predicate)); \ - _bpFoundElement = false; \ - _bsonVisitEach ( \ - *_bpDoc, \ - if (Predicate, \ - then (do (_bsonParseMarkVisited (bsonVisitContext.index); _bpFoundElement = true), __VA_ARGS__, break))); \ - if (!_bpFoundElement && !bsonParseError) { \ - _bsonDSLDebug ("[not found]"); \ - } \ - _bsonDSL_end - -#define _bsonParseOperation_require(Predicate, ...) \ - _bsonDSL_begin ("require(%s)", _bsonDSL_str (Predicate)); \ - _bpFoundElement = false; \ - _bsonVisitEach ( \ - *_bpDoc, \ - if (Predicate, \ - then (do (_bsonParseMarkVisited (bsonVisitContext.index); _bpFoundElement = true), __VA_ARGS__, break))); \ - if (!_bpFoundElement && !bsonParseError) { \ - bsonParseError = "Failed to find a required element: " _bsonDSL_str (Predicate); \ - } \ - _bsonDSL_end - -#define _bsonParseOperation_visitOthers(...) \ - _bsonDSL_begin ("visitOthers(%s)", _bsonDSL_strElide (30, __VA_ARGS__)); \ - _bsonVisitEach (*_bpDoc, if (not(eval (_bsonParseDidVisitNth (bsonVisitContext.index))), then (__VA_ARGS__))); \ - _bsonDSL_end - -#define bsonPredicate(P) _bsonPredicate _bsonDSL_nothing () (P) -#define _bsonPredicate(P) _bsonPredicate_Condition_##P - -#define _bsonPredicate_Condition_ __NOTE__Missing_name_for_a_predicate_expression - -#define _bsonPredicate_Condition_allOf(...) (1 _bsonDSL_mapMacro (_bsonPredicateAnd, ~, __VA_ARGS__)) -#define _bsonPredicate_Condition_anyOf(...) (0 _bsonDSL_mapMacro (_bsonPredicateOr, ~, __VA_ARGS__)) -#define _bsonPredicate_Condition_not(...) (!(0 _bsonDSL_mapMacro (_bsonPredicateOr, ~, __VA_ARGS__))) -#define _bsonPredicateAnd(Pred, _ignore, _ignore1) &&_bsonPredicate _bsonDSL_nothing () (Pred) -#define _bsonPredicateOr(Pred, _ignore, _ignore2) || _bsonPredicate _bsonDSL_nothing () (Pred) - -#define _bsonPredicate_Condition_eval(X) (X) - -#define _bsonPredicate_Condition_key(...) \ - (_bson_dsl_key_is_anyof (bson_iter_key (&bsonVisitIter), \ - bson_iter_key_len (&bsonVisitIter), \ - true /* case senstive */, \ - __VA_ARGS__, \ - NULL)) - -#define _bsonPredicate_Condition_iKey(...) \ - (_bson_dsl_key_is_anyof (bson_iter_key (&bsonVisitIter), \ - bson_iter_key_len (&bsonVisitIter), \ - false /* case insenstive */, \ - __VA_ARGS__, \ - NULL)) - -#define _bsonPredicate_Condition_type(Type) (bson_iter_type (&bsonVisitIter) == _bsonDSL_Type_##Type) - -#define _bsonPredicate_Condition_keyWithType(Key, Type) \ - (_bsonPredicate_Condition_allOf _bsonDSL_nothing () (key (Key), type (Type))) - -#define _bsonPredicate_Condition_iKeyWithType(Key, Type) \ - (_bsonPredicate_Condition_allOf _bsonDSL_nothing () (iKey (Key), type (Type))) - -#define _bsonPredicate_Condition_lastElement (_bson_dsl_iter_is_last_element (&bsonVisitIter)) - -#define _bsonPredicate_Condition_isNumeric BSON_ITER_HOLDS_NUMBER (&bsonVisitIter) - -#define _bsonPredicate_Condition_1 1 -#define _bsonPredicate_Condition_0 0 -#define _bsonPredicate_Condition_true true -#define _bsonPredicate_Condition_false false - -#define _bsonPredicate_Condition_isTrue (bson_iter_as_bool (&bsonVisitIter)) -#define _bsonPredicate_Condition_isFalse (!bson_iter_as_bool (&bsonVisitIter)) -#define _bsonPredicate_Condition_empty (_bson_dsl_is_empty_bson (&bsonVisitIter)) - -#define _bsonPredicate_Condition_strEqual(S) (_bson_dsl_test_strequal (S, true)) -#define _bsonPredicate_Condition_iStrEqual(S) (_bson_dsl_test_strequal (S, false)) - -#define _bsonPredicate_Condition_eq(Type, Value) (_bsonPredicate_Condition_type (Type) && bsonAs (Type) == Value) - -#define _bsonParseOperation_else _bsonParse_deferredElse _bsonDSL_nothing () -#define _bsonParse_deferredElse(...) \ - if (!_bpFoundElement) { \ - _bsonDSL_begin ("else:%s", ""); \ - _bsonParse_applyOps (__VA_ARGS__); \ - _bsonDSL_end; \ - } else \ - ((void) 0) - -#define _bsonParseOperation_do(...) \ - _bsonDSL_begin ("do: %s", _bsonDSL_strElide (30, __VA_ARGS__)); \ - do { \ - __VA_ARGS__; \ - } while (0); \ - _bsonDSL_end - -#define _bsonParseOperation_halt _bvHalt = true - -#define _bsonParseOperation_error(S) bsonParseError = (S) -#define _bsonParseOperation_errorf(S, ...) (bsonParseError = _bson_dsl_errorf (&(S), __VA_ARGS__)) - -/// Perform conditional parsing -#define _bsonParseOperation_if(Condition, ...) \ - _bsonDSL_begin ("if(%s)", _bsonDSL_str (Condition)); \ - /* Pick a sub-macro depending on if there are one or two args */ \ - _bsonDSL_ifElse (_bsonDSL_hasComma (__VA_ARGS__), _bsonParse_ifThenElse, _bsonParse_ifThen) (Condition, \ - __VA_ARGS__); \ - _bsonDSL_end - -#define _bsonParse_ifThen_then _bsonParse_applyOps -#define _bsonParse_ifElse_else _bsonParse_applyOps - -#define _bsonParse_ifThenElse(Condition, Then, Else) \ - if ((Condition)) { \ - _bsonDSLDebug ("then:"); \ - _bsonParse_ifThen_##Then; \ - } else { \ - _bsonDSLDebug ("else:"); \ - _bsonParse_ifElse_##Else; \ - } - -#define _bsonParse_ifThen(Condition, Then) \ - if ((Condition)) { \ - _bsonDSLDebug ("%s", _bsonDSL_str (Then)); \ - _bsonParse_ifThen_##Then; \ - } else { \ - _bsonDSLDebug ("[else nothing]"); \ - } - -#define _bsonParseOperation_append _bsonParseOperationDeferred_append _bsonDSL_nothing () -#define _bsonParseOperationDeferred_append(Doc, ...) \ - _bsonDSL_begin ("append to [%s] : %s", _bsonDSL_str (Doc), _bsonDSL_strElide (30, __VA_ARGS__)); \ - _bsonBuildAppend (Doc, __VA_ARGS__); \ - if (bsonBuildError) { \ - bsonParseError = bsonBuildError; \ - } \ - _bsonDSL_end - -#define _bsonVisit_applyOps _bsonVisit_applyOpsDeferred _bsonDSL_nothing () -#define _bsonVisit_applyOpsDeferred(...) \ - do { \ - _bsonDSL_mapMacro (_bsonVisit_applyOp, ~, __VA_ARGS__); \ - } while (0); - -#define bsonBuildArray(BSON, ...) \ - _bsonDSL_begin ("bsonBuildArray(%s, %s)", _bsonDSL_str (BSON), _bsonDSL_strElide (30, __VA_ARGS__)); \ - _bsonDSL_eval (_bsonBuildArray (BSON, __VA_ARGS__)); \ - _bsonDSL_end - -#define _bsonBuildArray(BSON, ...) \ - do { \ - _bsonDSL_disableWarnings (); \ - struct _bsonBuildContext_t _bbCtx = { \ - .doc = &(BSON), \ - .parent = _bsonBuildContextThreadLocalPtr, \ - .index = 0, \ - }; \ - _bsonBuildContextThreadLocalPtr = &_bbCtx; \ - _bsonBuildArrayWithCurrentContext (__VA_ARGS__); \ - _bsonBuildContextThreadLocalPtr = _bbCtx.parent; \ - _bsonDSL_restoreWarnings (); \ - } while (0) - -/** - * @brief Build a BSON document by appending to an existing bson_t document - * - * @param Pointer The document upon which to append - * @param ... The Document elements to append to the document - */ -#define bsonBuildAppend(BSON, ...) _bsonDSL_eval (_bsonBuildAppend (BSON, __VA_ARGS__)) -#define _bsonBuildAppend(BSON, ...) \ - _bsonDSL_begin ("Appending to document '%s'", _bsonDSL_str (BSON)); \ - _bsonDSL_disableWarnings (); \ - /* Save the dsl context */ \ - struct _bsonBuildContext_t _bbCtx = { \ - .doc = &(BSON), \ - .parent = _bsonBuildContextThreadLocalPtr, \ - }; \ - /* Reset the context */ \ - _bsonBuildContextThreadLocalPtr = &_bbCtx; \ - bsonBuildError = NULL; \ - _bsonBuildAppendWithCurrentContext (__VA_ARGS__); \ - /* Restore the dsl context */ \ - _bsonBuildContextThreadLocalPtr = _bbCtx.parent; \ - _bsonDSL_restoreWarnings (); \ - _bsonDSL_end - -/** - * @brief Build a new BSON document and assign the value into the given - * pointer. - */ -#define bsonBuild(BSON, ...) \ - _bsonDSL_begin ("Build a new document for '%s'", _bsonDSL_str (BSON)); \ - bson_t *_bbDest = &(BSON); \ - bson_init (_bbDest); \ - bsonBuildAppend (*_bbDest, __VA_ARGS__); \ - _bsonDSL_end - -/** - * @brief Declare a variable and build it with the BSON DSL @see bsonBuild - */ -#define bsonBuildDecl(Variable, ...) \ - bson_t Variable = BSON_INITIALIZER; \ - bsonBuild (Variable, __VA_ARGS__) - - -struct _bsonBuildContext_t { - /// The document that is being built - bson_t *doc; - /// The key that is pending an append - const char *key; - /// The length of the string given in 'key' - int key_len; - /// The index of the array being built (if applicable) - size_t index; - /// A buffer for formatting key strings - char index_key_str[16]; - /// The parent context (if building a sub-document) - struct _bsonBuildContext_t *parent; -}; - -/// A pointer to the current thread's bsonBuild context -_bson_thread_local _bson_comdat struct _bsonBuildContext_t *_bsonBuildContextThreadLocalPtr = NULL; - -struct _bsonVisitContext_t { - const bson_t *doc; - bson_iter_t iter; - const struct _bsonVisitContext_t *parent; - size_t index; -}; - -/// A pointer to the current thread's bsonVisit/bsonParse context -_bson_thread_local _bson_comdat struct _bsonVisitContext_t const *_bsonVisitContextThreadLocalPtr = NULL; - -/** - * @brief The most recent error from a bsonBuild() DSL command. - * - * If NULL, no error occurred. Users can assign a value to this string to - * indicate failure. - */ -_bson_thread_local _bson_comdat const char *bsonBuildError = NULL; - -/** - * @brief The most recent error from a buildVisit() or bsonParse() DSL command. - * - * If NULL, no error occurred. Users can assign a value to this string to - * indicate an error. - * - * If this string becomes non-NULL, the current bsonVisit()/bsonParse() will - * halt and return. - * - * Upon entering a new bsonVisit()/bsonParse(), this will be reset to NULL. - */ -_bson_thread_local _bson_comdat const char *bsonParseError = NULL; - -#define _bsonDSLDebug(...) _bson_dsl_debug (BSON_DSL_DEBUG, __FILE__, __LINE__, BSON_FUNC, __VA_ARGS__) - - -static BSON_INLINE bool -_bson_dsl_test_strequal (const char *string, bool case_sensitive) -{ - bson_iter_t it = bsonVisitIter; - if (bson_iter_type (&it) == BSON_TYPE_UTF8) { - uint32_t len; - const char *s = bson_iter_utf8 (&it, &len); - if (len != (uint32_t) strlen (string)) { - return false; - } - if (case_sensitive) { - return memcmp (string, s, len) == 0; - } else { - return bson_strcasecmp (string, s) == 0; - } - } - return false; -} - -static BSON_INLINE bool -_bson_dsl_key_is_anyof (const char *key, const size_t keylen, int case_sensitive, ...) -{ - va_list va; - va_start (va, case_sensitive); - const char *str; - while ((str = va_arg (va, const char *))) { - size_t str_len = strlen (str); - if (str_len != keylen) { - continue; - } - if (case_sensitive) { - if (memcmp (str, key, str_len) == 0) { - va_end (va); - return true; - } - } else { - if (bson_strcasecmp (str, key) == 0) { - va_end (va); - return true; - } - } - } - va_end (va); - return false; -} - -static BSON_INLINE void -_bson_dsl_iter_as_doc (bson_t *into, const bson_iter_t *it) -{ - uint32_t len = 0; - const uint8_t *dataptr = NULL; - if (BSON_ITER_HOLDS_ARRAY (it)) { - bson_iter_array (it, &len, &dataptr); - } else if (BSON_ITER_HOLDS_DOCUMENT (it)) { - bson_iter_document (it, &len, &dataptr); - } - if (dataptr) { - BSON_ASSERT (bson_init_static (into, dataptr, len)); - } -} - -static BSON_INLINE bool -_bson_dsl_is_empty_bson (const bson_iter_t *it) -{ - bson_t d = BSON_INITIALIZER; - _bson_dsl_iter_as_doc (&d, it); - return d.len == 5; // Empty documents/arrays have byte-size of five -} - -static BSON_INLINE bool -_bson_dsl_iter_is_last_element (const bson_iter_t *it) -{ - bson_iter_t dup = *it; - return !bson_iter_next (&dup) && dup.err_off == 0; -} - -_bson_thread_local _bson_comdat int _bson_dsl_indent = 0; - -static BSON_INLINE void BSON_GNUC_PRINTF (5, 6) - _bson_dsl_debug (bool do_debug, const char *file, int line, const char *func, const char *string, ...) -{ - if (do_debug) { - fprintf (stderr, "%s:%d: [%s] bson_dsl: ", file, line, func); - for (int i = 0; i < _bson_dsl_indent; ++i) { - fputs (" ", stderr); - } - va_list va; - va_start (va, string); - vfprintf (stderr, string, va); - va_end (va); - fputc ('\n', stderr); - fflush (stderr); - } -} - -static BSON_INLINE char *BSON_GNUC_PRINTF (2, 3) _bson_dsl_errorf (char **const into, const char *const fmt, ...) -{ - if (*into) { - bson_free (*into); - *into = NULL; - } - va_list args; - va_start (args, fmt); - *into = bson_strdupv_printf (fmt, args); - va_end (args); - return *into; -} - -static BSON_INLINE void -_bson_dsl_dupPath (char **into) -{ - if (*into) { - bson_free (*into); - *into = NULL; - } - char *acc = bson_strdup (""); - for (const struct _bsonVisitContext_t *ctx = &bsonVisitContext; ctx; ctx = ctx->parent) { - char *prev = acc; - if (ctx->parent && BSON_ITER_HOLDS_ARRAY (&ctx->parent->iter)) { - // We're an array element - acc = bson_strdup_printf ("[%d]%s", (int) ctx->index, prev); - } else { - // We're a document element - acc = bson_strdup_printf (".%s%s", bson_iter_key (&ctx->iter), prev); - } - bson_free (prev); - } - *into = bson_strdup_printf ("$%s", acc); - bson_free (acc); -} - -static BSON_INLINE const char * -_bsonVisitIterAs_cstr (void) -{ - return bson_iter_utf8 (&bsonVisitIter, NULL); -} - -static BSON_INLINE int32_t -_bsonVisitIterAs_int32 (void) -{ - return bson_iter_int32 (&bsonVisitIter); -} - -static BSON_INLINE bool -_bsonVisitIterAs_bool (void) -{ - return bson_iter_as_bool (&bsonVisitIter); -} - -static BSON_INLINE bool -_bsonVisitIterAs__Bool (void) -{ - return _bsonVisitIterAs_bool (); -} - -#define bsonAs(Type) _bsonDSL_paste (_bsonVisitIterAs_, Type) () - -/// Convert the given argument into a string without inhibitting macro expansion -#define _bsonDSL_str(...) _bsonDSL_str_1 (__VA_ARGS__) -// Empty quotes "" are to ensure a string appears. Old MSVC has a bug -// where empty #__VA_ARGS__ just vanishes. -#define _bsonDSL_str_1(...) "" #__VA_ARGS__ - -#define _bsonDSL_strElide(MaxLen, ...) \ - (strlen (_bsonDSL_str (__VA_ARGS__)) > (MaxLen) ? "[...]" : _bsonDSL_str (__VA_ARGS__)) - -/// Paste two tokens: -#define _bsonDSL_paste(a, ...) _bsonDSL_paste_impl (a, __VA_ARGS__) -#define _bsonDSL_paste_impl(a, ...) a##__VA_ARGS__ - -/// Paste three tokens: -#define _bsonDSL_paste3(a, b, c) _bsonDSL_paste (a, _bsonDSL_paste (b, c)) -/// Paste four tokens: -#define _bsonDSL_paste4(a, b, c, d) _bsonDSL_paste (a, _bsonDSL_paste3 (b, c, d)) - -// clang-format off - -/// Now we need a MAP() macro. This idiom is common, but fairly opaque. Below is -/// some crazy preprocessor trickery to implement it. Fortunately, once we have -/// MAP(), the remainder of this file is straightforward. This implementation -/// isn't the simplest one possible, but is one that supports the old -/// non-compliant MSVC preprocessor. - -/* Expands to nothing. Used to defer a function-like macro and to ignore arguments */ -#define _bsonDSL_nothing(...) - -/// Expand to the 64th argument. See below for why this is useful. -#define _bsonDSL_pick64th(\ - _0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, \ - _11, _12, _13, _14, _15, _16, _17, _18, _19, _20, \ - _21, _22, _23, _24, _25, _26, _27, _28, _29, _30, \ - _31, _32, _33, _34, _35, _36, _37, _38, _39, _40, \ - _41, _42, _43, _44, _45, _46, _47, _48, _49, _50, \ - _51, _52, _53, _54, _55, _56, _57, _58, _59, _60, \ - _61, _62, _63, ...) \ - _63 - -/** - * @brief Expands to 1 if the given arguments contain any top-level commas, zero otherwise. - * - * There is an expansion of __VA_ARGS__, followed by 62 '1' arguments, followed - * by single '0'. If __VA_ARGS__ contains no commas, pick64th() will return the - * single zero. If __VA_ARGS__ contains any top-level commas, the series of ones - * will shift to the right and pick64th will return one of those ones. (This only - * works __VA_ARGS__ contains fewer than 62 commas, which is a somewhat reasonable - * limit.) The _bsonDSL_nothing() is a workaround for MSVC's bad preprocessor that - * expands __VA_ARGS__ incorrectly. - * - * If we have __VA_OPT__, this can be a lot simpler. - */ -#define _bsonDSL_hasComma(...) \ - _bsonDSL_pick64th \ - _bsonDSL_nothing() (__VA_ARGS__, \ - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, \ - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, \ - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, \ - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, ~) - -/** - * Expands to a single comma if "invoked" as a function-like macro. - * (This will make sense, I promise.) - */ -#define _bsonDSL_commaIfRHSHasParens(...) , - -/** - * @brief Expand to 1 if given no arguments, otherwise 0. - * - * This could be done much more simply using __VA_OPT__, but we need to work on - * older compilers. - */ -#define _bsonDSL_isEmpty(...) \ - _bsonDSL_isEmpty_1(\ - /* Expands to '1' if __VA_ARGS__ contains any top-level commas */ \ - _bsonDSL_hasComma(__VA_ARGS__), \ - /* Expands to '1' if __VA_ARGS__ begins with a parenthesis, because \ - * that will cause an "invocation" of _bsonDSL_commaIfRHSHasParens, \ - * which immediately expands to a single comma. */ \ - _bsonDSL_hasComma(_bsonDSL_commaIfRHSHasParens __VA_ARGS__), \ - /* Expands to '1' if __VA_ARGS__ expands to a function-like macro name \ - * that then expands to anything containing a top-level comma */ \ - _bsonDSL_hasComma(__VA_ARGS__ ()), \ - /* Expands to '1' if __VA_ARGS__ expands to nothing. */ \ - _bsonDSL_hasComma(_bsonDSL_commaIfRHSHasParens __VA_ARGS__ ())) - -/** - * A helper for isEmpty(): If given (0, 0, 0, 1), expands as: - * - first: _bsonDSL_hasComma(_bsonDSL_isEmpty_CASE_0001) - * - then: _bsonDSL_hasComma(,) - * - then: 1 - * Given any other aruments: - * - first: _bsonDSL_hasComma(_bsonDSL_isEmpty_CASE_) - * - then: 0 - */ -#define _bsonDSL_isEmpty_1(_1, _2, _3, _4) \ - _bsonDSL_hasComma(_bsonDSL_paste(_bsonDSL_isEmpty_CASE_, _bsonDSL_paste4(_1, _2, _3, _4))) -#define _bsonDSL_isEmpty_CASE_0001 , - -/** - * @brief Expand to the first argument if `Cond` is 1, the second argument if `Cond` is 0 - */ -#define _bsonDSL_ifElse(Cond, IfTrue, IfFalse) \ - /* Suppress expansion of the two branches by using the '#' operator */ \ - _bsonDSL_nothing(#IfTrue, #IfFalse) \ - /* Concat the cond 1/0 with a prefix macro: */ \ - _bsonDSL_paste(_bsonDSL_ifElse_PICK_, Cond)(IfTrue, IfFalse) - -#define _bsonDSL_ifElse_PICK_1(IfTrue, IfFalse) \ - /* Expand the first operand, throw away the second */ \ - IfTrue _bsonDSL_nothing(#IfFalse) -#define _bsonDSL_ifElse_PICK_0(IfTrue, IfFalse) \ - /* Expand to the second operand, throw away the first */ \ - IfFalse _bsonDSL_nothing(#IfTrue) - -#ifdef _MSC_VER -// MSVC's "traditional" preprocessor requires many more expansion passes, -// but GNU and Clang are very slow when evaluating hugely nested expansions -// and generate massive macro expansion backtraces. -#define _bsonDSL_eval_1(...) __VA_ARGS__ -#define _bsonDSL_eval_2(...) _bsonDSL_eval_1(_bsonDSL_eval_1(_bsonDSL_eval_1(_bsonDSL_eval_1(_bsonDSL_eval_1(__VA_ARGS__))))) -#define _bsonDSL_eval_4(...) _bsonDSL_eval_2(_bsonDSL_eval_2(_bsonDSL_eval_2(_bsonDSL_eval_2(_bsonDSL_eval_2(__VA_ARGS__))))) -#define _bsonDSL_eval_8(...) _bsonDSL_eval_4(_bsonDSL_eval_4(_bsonDSL_eval_4(_bsonDSL_eval_4(_bsonDSL_eval_4(__VA_ARGS__))))) -#define _bsonDSL_eval_16(...) _bsonDSL_eval_8(_bsonDSL_eval_8(_bsonDSL_eval_8(_bsonDSL_eval_8(_bsonDSL_eval_8(__VA_ARGS__))))) -#define _bsonDSL_eval(...) _bsonDSL_eval_16(_bsonDSL_eval_16(_bsonDSL_eval_16(_bsonDSL_eval_16(_bsonDSL_eval_16(__VA_ARGS__))))) -#else -// Each level of "eval" applies double the expansions of the previous level. -#define _bsonDSL_eval_1(...) __VA_ARGS__ -#define _bsonDSL_eval_2(...) _bsonDSL_eval_1(_bsonDSL_eval_1(__VA_ARGS__)) -#define _bsonDSL_eval_4(...) _bsonDSL_eval_2(_bsonDSL_eval_2(__VA_ARGS__)) -#define _bsonDSL_eval_8(...) _bsonDSL_eval_4(_bsonDSL_eval_4(__VA_ARGS__)) -#define _bsonDSL_eval_16(...) _bsonDSL_eval_8(_bsonDSL_eval_8(__VA_ARGS__)) -#define _bsonDSL_eval_32(...) _bsonDSL_eval_16(_bsonDSL_eval_16(__VA_ARGS__)) -#define _bsonDSL_eval(...) _bsonDSL_eval_32(__VA_ARGS__) -#endif - -/** - * Finally, the Map() macro that allows us to do the magic, which we've been - * building up to all along. - * - * The dance with mapMacro_first, mapMacro_final, and _bsonDSL_nothing - * conditional on argument count is to prevent warnings from pre-C99 about - * passing no arguments to the '...' parameters. Yet again, if we had C99 and - * __VA_OPT__ this would be simpler. - */ -#define _bsonDSL_mapMacro(Action, Constant, ...) \ - /* Pick our first action based on the content of '...': */ \ - _bsonDSL_ifElse( \ - /* If given no arguments: */\ - _bsonDSL_isEmpty(__VA_ARGS__), \ - /* expand to _bsonDSL_nothing */ \ - _bsonDSL_nothing, \ - /* Otherwise, expand to mapMacro_first: */ \ - _bsonDSL_mapMacro_first) \ - /* Now "invoke" the chosen macro: */ \ - _bsonDSL_nothing() (Action, Constant, __VA_ARGS__) - -#define _bsonDSL_mapMacro_first(Action, Constant, ...) \ - /* Select our next step based on whether we have one or more arguments: */ \ - _bsonDSL_ifElse( \ - /* If '...' contains more than one argument (has a top-level comma): */ \ - _bsonDSL_hasComma(__VA_ARGS__), \ - /* Begin the mapMacro loop with mapMacro_A: */ \ - _bsonDSL_mapMacro_A, \ - /* Otherwise skip to the final step of the loop: */ \ - _bsonDSL_mapMacro_final) \ - /* Invoke the chosen macro, setting the counter to zero: */ \ - _bsonDSL_nothing() (Action, Constant, 0, __VA_ARGS__) - -/// Handle the last expansion in a mapMacro sequence. -#define _bsonDSL_mapMacro_final(Action, Constant, Counter, FinalElement) \ - Action(FinalElement, Constant, Counter) - -/** - * mapMacro_A and mapMacro_B are identical and just invoke each other. - */ -#define _bsonDSL_mapMacro_A(Action, Constant, Counter, Head, ...) \ - /* First evaluate the action once: */ \ - Action(Head, Constant, Counter) \ - /* Pick our next step: */ \ - _bsonDSL_ifElse( \ - /* If '...' contains more than one argument (has a top-level comma): */ \ - _bsonDSL_hasComma(__VA_ARGS__), \ - /* Jump to the other mapMacro: */ \ - _bsonDSL_mapMacro_B, \ - /* Otherwise go to mapMacro_final */ \ - _bsonDSL_mapMacro_final) \ - /* Invoke the next step of the map: */ \ - _bsonDSL_nothing() (Action, Constant, Counter + 1, __VA_ARGS__) - -#define _bsonDSL_mapMacro_B(Action, Constant, Counter, Head, ...) \ - Action(Head, Constant, Counter) \ - _bsonDSL_ifElse(_bsonDSL_hasComma(__VA_ARGS__), _bsonDSL_mapMacro_A, _bsonDSL_mapMacro_final) \ - _bsonDSL_nothing() (Action, Constant, Counter + 1, __VA_ARGS__) - -// clang-format on - - -#endif // BSON_BSON_DSL_H_INCLUDED diff --git a/bsonjs/common/common-b64-private.h b/bsonjs/common/common-b64-private.h deleted file mode 100644 index 7f5c4e3..0000000 --- a/bsonjs/common/common-b64-private.h +++ /dev/null @@ -1,58 +0,0 @@ -/* - * Copyright 2018-present MongoDB Inc. - * - * 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. - */ - -#include "common-prelude.h" - -#ifndef COMMON_B64_PRIVATE_H -#define COMMON_B64_PRIVATE_H - -#include - -#define mcommon_b64_ntop_calculate_target_size COMMON_NAME (b64_ntop_calculate_target_size) -#define mcommon_b64_pton_calculate_target_size COMMON_NAME (b64_pton_calculate_target_size) -#define mcommon_b64_ntop COMMON_NAME (b64_ntop) -#define mcommon_b64_pton COMMON_NAME (b64_pton) - -/** - * When encoding from "network" (raw data) to "presentation" (base64 encoded). - * Includes the trailing null byte. */ -size_t -mcommon_b64_ntop_calculate_target_size (size_t raw_size); - -/* When encoding from "presentation" (base64 encoded) to "network" (raw data). - * This may be an overestimate if the base64 data includes spaces. For a more - * accurate size, call b64_pton (src, NULL, 0), which will read the src - * data and return an exact size. */ -size_t -mcommon_b64_pton_calculate_target_size (size_t base64_encoded_size); - -/* Returns the number of bytes written (excluding NULL byte) to target on - * success or -1 on error. Adds a trailing NULL byte. - * Encodes from "network" (raw data) to "presentation" (base64 encoded), - * hence the obscure name "ntop". - */ -int -mcommon_b64_ntop (uint8_t const *src, size_t srclength, char *target, size_t targsize); - -/** If target is not NULL, the number of bytes written to target on success or - * -1 on error. If target is NULL, returns the exact number of bytes that would - * be written to target on decoding. Encodes from "presentation" (base64 - * encoded) to "network" (raw data), hence the obscure name "pton". - */ -int -mcommon_b64_pton (char const *src, uint8_t *target, size_t targsize); - -#endif /* COMMON_B64_PRIVATE_H */ diff --git a/bsonjs/common/common-b64.c b/bsonjs/common/common-b64.c deleted file mode 100644 index 051ca64..0000000 --- a/bsonjs/common/common-b64.c +++ /dev/null @@ -1,555 +0,0 @@ -/* - * Copyright (c) 1996, 1998 by Internet Software Consortium. - * - * Permission to use, copy, modify, and distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SOFTWARE CONSORTIUM DISCLAIMS - * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES - * OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL INTERNET SOFTWARE - * CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL - * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR - * PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS - * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS - * SOFTWARE. - */ - -/* - * Portions Copyright (c) 1995 by International Business Machines, Inc. - * - * International Business Machines, Inc. (hereinafter called IBM) grants - * permission under its copyrights to use, copy, modify, and distribute this - * Software with or without fee, provided that the above copyright notice and - * all paragraphs of this notice appear in all copies, and that the name of IBM - * not be used in connection with the marketing of any product incorporating - * the Software or modifications thereof, without specific, written prior - * permission. - * - * To the extent it has a right to do so, IBM grants an immunity from suit - * under its patents, if any, for the use, sale or manufacture of products to - * the extent that such products are used for performing Domain Name System - * dynamic updates in TCP/IP networks by means of the Software. No immunity is - * granted for any product per se or for any other function of any product. - * - * THE SOFTWARE IS PROVIDED "AS IS", AND IBM DISCLAIMS ALL WARRANTIES, - * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A - * PARTICULAR PURPOSE. IN NO EVENT SHALL IBM BE LIABLE FOR ANY SPECIAL, - * DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER ARISING - * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE, EVEN - * IF IBM IS APPRISED OF THE POSSIBILITY OF SUCH DAMAGES. - */ - -#include "bson/bson.h" -#include "common-b64-private.h" - -#define Assert(Cond) \ - if (!(Cond)) \ - abort () - -static const char Base64[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; -static const char Pad64 = '='; - -/* (From RFC1521 and draft-ietf-dnssec-secext-03.txt) - * The following encoding technique is taken from RFC 1521 by Borenstein - * and Freed. It is reproduced here in a slightly edited form for - * convenience. - * - * A 65-character subset of US-ASCII is used, enabling 6 bits to be - * represented per printable character. (The extra 65th character, "=", - * is used to signify a special processing function.) - * - * The encoding process represents 24-bit groups of input bits as output - * strings of 4 encoded characters. Proceeding from left to right, a - * 24-bit input group is formed by concatenating 3 8-bit input groups. - * These 24 bits are then treated as 4 concatenated 6-bit groups, each - * of which is translated into a single digit in the base64 alphabet. - * - * Each 6-bit group is used as an index into an array of 64 printable - * characters. The character referenced by the index is placed in the - * output string. - * - * Table 1: The Base64 Alphabet - * - * Value Encoding Value Encoding Value Encoding Value Encoding - * 0 A 17 R 34 i 51 z - * 1 B 18 S 35 j 52 0 - * 2 C 19 T 36 k 53 1 - * 3 D 20 U 37 l 54 2 - * 4 E 21 V 38 m 55 3 - * 5 F 22 W 39 n 56 4 - * 6 G 23 X 40 o 57 5 - * 7 H 24 Y 41 p 58 6 - * 8 I 25 Z 42 q 59 7 - * 9 J 26 a 43 r 60 8 - * 10 K 27 b 44 s 61 9 - * 11 L 28 c 45 t 62 + - * 12 M 29 d 46 u 63 / - * 13 N 30 e 47 v - * 14 O 31 f 48 w (pad) = - * 15 P 32 g 49 x - * 16 Q 33 h 50 y - * - * Special processing is performed if fewer than 24 bits are available - * at the end of the data being encoded. A full encoding quantum is - * always completed at the end of a quantity. When fewer than 24 input - * bits are available in an input group, zero bits are added (on the - * right) to form an integral number of 6-bit groups. Padding at the - * end of the data is performed using the '=' character. - * - * Since all base64 input is an integral number of octets, only the - * following cases can arise: - * - * (1) the final quantum of encoding input is an integral - * multiple of 24 bits; here, the final unit of encoded - * output will be an integral multiple of 4 characters - * with no "=" padding, - * (2) the final quantum of encoding input is exactly 8 bits; - * here, the final unit of encoded output will be two - * characters followed by two "=" padding characters, or - * (3) the final quantum of encoding input is exactly 16 bits; - * here, the final unit of encoded output will be three - * characters followed by one "=" padding character. - */ - -int -mcommon_b64_ntop (uint8_t const *src, size_t srclength, char *target, size_t targsize) -{ - size_t datalength = 0; - uint8_t input[3]; - uint8_t output[4]; - size_t i; - - if (!target) { - return -1; - } - - while (2 < srclength) { - input[0] = *src++; - input[1] = *src++; - input[2] = *src++; - srclength -= 3; - - output[0] = input[0] >> 2; - output[1] = ((input[0] & 0x03) << 4) + (input[1] >> 4); - output[2] = ((input[1] & 0x0f) << 2) + (input[2] >> 6); - output[3] = input[2] & 0x3f; - Assert (output[0] < 64); - Assert (output[1] < 64); - Assert (output[2] < 64); - Assert (output[3] < 64); - - if (datalength + 4 > targsize) { - return -1; - } - target[datalength++] = Base64[output[0]]; - target[datalength++] = Base64[output[1]]; - target[datalength++] = Base64[output[2]]; - target[datalength++] = Base64[output[3]]; - } - - /* Now we worry about padding. */ - if (0 != srclength) { - /* Get what's left. */ - input[0] = input[1] = input[2] = '\0'; - - for (i = 0; i < srclength; i++) { - input[i] = *src++; - } - output[0] = input[0] >> 2; - output[1] = ((input[0] & 0x03) << 4) + (input[1] >> 4); - output[2] = ((input[1] & 0x0f) << 2) + (input[2] >> 6); - Assert (output[0] < 64); - Assert (output[1] < 64); - Assert (output[2] < 64); - - if (datalength + 4 > targsize) { - return -1; - } - target[datalength++] = Base64[output[0]]; - target[datalength++] = Base64[output[1]]; - - if (srclength == 1) { - target[datalength++] = Pad64; - } else { - target[datalength++] = Base64[output[2]]; - } - target[datalength++] = Pad64; - } - - if (datalength >= targsize) { - return -1; - } - target[datalength] = '\0'; /* Returned value doesn't count \0. */ - return (int) datalength; -} - -/* (From RFC1521 and draft-ietf-dnssec-secext-03.txt) - The following encoding technique is taken from RFC 1521 by Borenstein - and Freed. It is reproduced here in a slightly edited form for - convenience. - - A 65-character subset of US-ASCII is used, enabling 6 bits to be - represented per printable character. (The extra 65th character, "=", - is used to signify a special processing function.) - - The encoding process represents 24-bit groups of input bits as output - strings of 4 encoded characters. Proceeding from left to right, a - 24-bit input group is formed by concatenating 3 8-bit input groups. - These 24 bits are then treated as 4 concatenated 6-bit groups, each - of which is translated into a single digit in the base64 alphabet. - - Each 6-bit group is used as an index into an array of 64 printable - characters. The character referenced by the index is placed in the - output string. - - Table 1: The Base64 Alphabet - - Value Encoding Value Encoding Value Encoding Value Encoding - 0 A 17 R 34 i 51 z - 1 B 18 S 35 j 52 0 - 2 C 19 T 36 k 53 1 - 3 D 20 U 37 l 54 2 - 4 E 21 V 38 m 55 3 - 5 F 22 W 39 n 56 4 - 6 G 23 X 40 o 57 5 - 7 H 24 Y 41 p 58 6 - 8 I 25 Z 42 q 59 7 - 9 J 26 a 43 r 60 8 - 10 K 27 b 44 s 61 9 - 11 L 28 c 45 t 62 + - 12 M 29 d 46 u 63 / - 13 N 30 e 47 v - 14 O 31 f 48 w (pad) = - 15 P 32 g 49 x - 16 Q 33 h 50 y - - Special processing is performed if fewer than 24 bits are available - at the end of the data being encoded. A full encoding quantum is - always completed at the end of a quantity. When fewer than 24 input - bits are available in an input group, zero bits are added (on the - right) to form an integral number of 6-bit groups. Padding at the - end of the data is performed using the '=' character. - - Since all base64 input is an integral number of octets, only the - following cases can arise: - - (1) the final quantum of encoding input is an integral - multiple of 24 bits; here, the final unit of encoded - output will be an integral multiple of 4 characters - with no "=" padding, - (2) the final quantum of encoding input is exactly 8 bits; - here, the final unit of encoded output will be two - characters followed by two "=" padding characters, or - (3) the final quantum of encoding input is exactly 16 bits; - here, the final unit of encoded output will be three - characters followed by one "=" padding character. - */ - -/* skips all whitespace anywhere. - converts characters, four at a time, starting at (or after) - src from base - 64 numbers into three 8 bit bytes in the target area. - it returns the number of data bytes stored at the target, or -1 on error. - */ - -static uint8_t mongoc_b64rmap[256]; - -static const uint8_t mongoc_b64rmap_special = 0xf0; -static const uint8_t mongoc_b64rmap_end = 0xfd; -static const uint8_t mongoc_b64rmap_space = 0xfe; -static const uint8_t mongoc_b64rmap_invalid = 0xff; - -/* initializing the reverse map isn't thread safe, do it in pthread_once */ -#if defined(BSON_OS_UNIX) -#include -#define mongoc_common_once_t pthread_once_t -#define mongoc_common_once pthread_once -#define MONGOC_COMMON_ONCE_FUN(n) void n (void) -#define MONGOC_COMMON_ONCE_RETURN return -#define MONGOC_COMMON_ONCE_INIT PTHREAD_ONCE_INIT -#else -#define mongoc_common_once_t INIT_ONCE -#define MONGOC_COMMON_ONCE_INIT INIT_ONCE_STATIC_INIT -#define mongoc_common_once(o, c) InitOnceExecuteOnce (o, c, NULL, NULL) -#define MONGOC_COMMON_ONCE_FUN(n) BOOL CALLBACK n (PINIT_ONCE _ignored_a, PVOID _ignored_b, PVOID *_ignored_c) -#define MONGOC_COMMON_ONCE_RETURN return true -#endif - -static MONGOC_COMMON_ONCE_FUN (bson_b64_initialize_rmap) -{ - int i; - unsigned char ch; - - /* Null: end of string, stop parsing */ - mongoc_b64rmap[0] = mongoc_b64rmap_end; - - for (i = 1; i < 256; ++i) { - ch = (unsigned char) i; - /* Whitespaces */ - if (bson_isspace (ch)) - mongoc_b64rmap[i] = mongoc_b64rmap_space; - /* Padding: stop parsing */ - else if (ch == Pad64) - mongoc_b64rmap[i] = mongoc_b64rmap_end; - /* Non-base64 char */ - else - mongoc_b64rmap[i] = mongoc_b64rmap_invalid; - } - - /* Fill reverse mapping for base64 chars */ - for (i = 0; Base64[i] != '\0'; ++i) - mongoc_b64rmap[(uint8_t) Base64[i]] = i; - - MONGOC_COMMON_ONCE_RETURN; -} - -static int -mongoc_b64_pton_do (char const *src, uint8_t *target, size_t targsize) -{ - int tarindex, state; - uint8_t ch, ofs; - - state = 0; - tarindex = 0; - - while (1) { - ch = *src++; - ofs = mongoc_b64rmap[ch]; - - if (ofs >= mongoc_b64rmap_special) { - /* Ignore whitespaces */ - if (ofs == mongoc_b64rmap_space) - continue; - /* End of base64 characters */ - if (ofs == mongoc_b64rmap_end) - break; - /* A non-base64 character. */ - return (-1); - } - - switch (state) { - case 0: - if ((size_t) tarindex >= targsize) - return (-1); - target[tarindex] = ofs << 2; - state = 1; - break; - case 1: - if ((size_t) tarindex + 1 >= targsize) - return (-1); - target[tarindex] |= ofs >> 4; - target[tarindex + 1] = (ofs & 0x0f) << 4; - tarindex++; - state = 2; - break; - case 2: - if ((size_t) tarindex + 1 >= targsize) - return (-1); - target[tarindex] |= ofs >> 2; - target[tarindex + 1] = (ofs & 0x03) << 6; - tarindex++; - state = 3; - break; - case 3: - if ((size_t) tarindex >= targsize) - return (-1); - target[tarindex] |= ofs; - tarindex++; - state = 0; - break; - default: - abort (); - } - } - - /* - * We are done decoding Base-64 chars. Let's see if we ended - * on a byte boundary, and/or with erroneous trailing characters. - */ - - if (ch == Pad64) { /* We got a pad char. */ - ch = *src++; /* Skip it, get next. */ - switch (state) { - case 0: /* Invalid = in first position */ - case 1: /* Invalid = in second position */ - return (-1); - - case 2: /* Valid, means one byte of info */ - /* Skip any number of spaces. */ - for ((void) NULL; ch != '\0'; ch = *src++) - if (mongoc_b64rmap[ch] != mongoc_b64rmap_space) - break; - /* Make sure there is another trailing = sign. */ - if (ch != Pad64) - return (-1); - ch = *src++; /* Skip the = */ - /* Fall through to "single trailing =" case. */ - /* FALLTHROUGH */ - - case 3: /* Valid, means two bytes of info */ - /* - * We know this char is an =. Is there anything but - * whitespace after it? - */ - for ((void) NULL; ch != '\0'; ch = *src++) - if (mongoc_b64rmap[ch] != mongoc_b64rmap_space) - return (-1); - - /* - * Now make sure for cases 2 and 3 that the "extra" - * bits that slopped past the last full byte were - * zeros. If we don't check them, they become a - * subliminal channel. - */ - if (target[tarindex] != 0) - return (-1); - default: - break; - } - } else { - /* - * We ended by seeing the end of the string. Make sure we - * have no partial bytes lying around. - */ - if (state != 0) - return (-1); - } - - return (tarindex); -} - - -static int -mongoc_b64_pton_len (char const *src) -{ - int tarindex, state; - uint8_t ch, ofs; - - state = 0; - tarindex = 0; - - while (1) { - ch = *src++; - ofs = mongoc_b64rmap[ch]; - - if (ofs >= mongoc_b64rmap_special) { - /* Ignore whitespaces */ - if (ofs == mongoc_b64rmap_space) - continue; - /* End of base64 characters */ - if (ofs == mongoc_b64rmap_end) - break; - /* A non-base64 character. */ - return (-1); - } - - switch (state) { - case 0: - state = 1; - break; - case 1: - tarindex++; - state = 2; - break; - case 2: - tarindex++; - state = 3; - break; - case 3: - tarindex++; - state = 0; - break; - default: - abort (); - } - } - - /* - * We are done decoding Base-64 chars. Let's see if we ended - * on a byte boundary, and/or with erroneous trailing characters. - */ - - if (ch == Pad64) { /* We got a pad char. */ - ch = *src++; /* Skip it, get next. */ - switch (state) { - case 0: /* Invalid = in first position */ - case 1: /* Invalid = in second position */ - return (-1); - - case 2: /* Valid, means one byte of info */ - /* Skip any number of spaces. */ - for ((void) NULL; ch != '\0'; ch = *src++) - if (mongoc_b64rmap[ch] != mongoc_b64rmap_space) - break; - /* Make sure there is another trailing = sign. */ - if (ch != Pad64) - return (-1); - ch = *src++; /* Skip the = */ - /* Fall through to "single trailing =" case. */ - /* FALLTHROUGH */ - - case 3: /* Valid, means two bytes of info */ - /* - * We know this char is an =. Is there anything but - * whitespace after it? - */ - for ((void) NULL; ch != '\0'; ch = *src++) - if (mongoc_b64rmap[ch] != mongoc_b64rmap_space) - return (-1); - - default: - break; - } - } else { - /* - * We ended by seeing the end of the string. Make sure we - * have no partial bytes lying around. - */ - if (state != 0) - return (-1); - } - - return (tarindex); -} - - -int -mcommon_b64_pton (char const *src, uint8_t *target, size_t targsize) -{ - static mongoc_common_once_t once = MONGOC_COMMON_ONCE_INIT; - - mongoc_common_once (&once, bson_b64_initialize_rmap); - - if (!src) { - return -1; - } - - if (target) - return mongoc_b64_pton_do (src, target, targsize); - else - return mongoc_b64_pton_len (src); -} - -size_t -mcommon_b64_ntop_calculate_target_size (size_t raw_size) -{ - size_t num_bits = raw_size * 8; - /* Calculate how many groups of six bits this contains, adding 5 to round up - * to the nearest group of 6. */ - size_t num_b64_chars = (num_bits + 5) / 6; - /* Round to nearest set of four. */ - size_t num_b64_chars_with_padding = 4 * ((num_b64_chars + 3) / 4); - /* Add one for NULL byte. */ - return num_b64_chars_with_padding + 1; -} - -size_t -mcommon_b64_pton_calculate_target_size (size_t base64_encoded_size) -{ - /* Without inspecting the data, we don't know how many padding characters - * there are. Assuming none, that means each character represents 6 bits of - * data. */ - size_t num_bits = base64_encoded_size * 6; - /* Round down to the nearest group of eight. */ - return num_bits / 8; -} diff --git a/bsonjs/common/common-config.h b/bsonjs/common/common-config.h deleted file mode 100644 index a40df73..0000000 --- a/bsonjs/common/common-config.h +++ /dev/null @@ -1,10 +0,0 @@ -#ifndef COMMON_CONFIG_H -#define COMMON_CONFIG_H - -#define MONGOC_ENABLE_DEBUG_ASSERTIONS 0 - -#if MONGOC_ENABLE_DEBUG_ASSERTIONS != 1 -# undef MONGOC_ENABLE_DEBUG_ASSERTIONS -#endif - -#endif diff --git a/bsonjs/common/common-macros-private.h b/bsonjs/common/common-macros-private.h deleted file mode 100644 index 360a0f5..0000000 --- a/bsonjs/common/common-macros-private.h +++ /dev/null @@ -1,15 +0,0 @@ - -#include "common-prelude.h" - -#ifndef MONGO_C_DRIVER_COMMON_MACROS_H -#define MONGO_C_DRIVER_COMMON_MACROS_H - -/* Test only assert. Is a noop unless -DENABLE_DEBUG_ASSERTIONS=ON is set - * during configuration */ -#if defined(MONGOC_ENABLE_DEBUG_ASSERTIONS) && defined(BSON_OS_UNIX) -#define MONGOC_DEBUG_ASSERT(statement) BSON_ASSERT (statement) -#else -#define MONGOC_DEBUG_ASSERT(statement) ((void) 0) -#endif - -#endif diff --git a/bsonjs/common/common-md5-private.h b/bsonjs/common/common-md5-private.h deleted file mode 100644 index 4feadb9..0000000 --- a/bsonjs/common/common-md5-private.h +++ /dev/null @@ -1,39 +0,0 @@ -/* - * Copyright 2018-present MongoDB, Inc. - * - * 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. - */ - -#include "common-prelude.h" - -#ifndef COMMON_MD5_PRIVATE_H -#define COMMON_MD5_PRIVATE_H - -#include "bson/bson.h" - -BSON_BEGIN_DECLS - -#define mcommon_md5_init COMMON_NAME (md5_init) -#define mcommon_md5_append COMMON_NAME (md5_append) -#define mcommon_md5_finish COMMON_NAME (md5_finish) - -void -mcommon_md5_init (bson_md5_t *pms); -void -mcommon_md5_append (bson_md5_t *pms, const uint8_t *data, uint32_t nbytes); -void -mcommon_md5_finish (bson_md5_t *pms, uint8_t digest[16]); - -BSON_END_DECLS - -#endif /* COMMON_MD5_PRIVATE_H */ diff --git a/bsonjs/common/common-md5.c b/bsonjs/common/common-md5.c deleted file mode 100644 index 71fa989..0000000 --- a/bsonjs/common/common-md5.c +++ /dev/null @@ -1,394 +0,0 @@ -/* - Copyright (C) 1999, 2000, 2002 Aladdin Enterprises. All rights reserved. - - This software is provided 'as-is', without any express or implied - warranty. In no event will the authors be held liable for any damages - arising from the use of this software. - - Permission is granted to anyone to use this software for any purpose, - including commercial applications, and to alter it and redistribute it - freely, subject to the following restrictions: - - 1. The origin of this software must not be misrepresented; you must not - claim that you wrote the original software. If you use this software - in a product, an acknowledgement in the product documentation would be - appreciated but is not required. - 2. Altered source versions must be plainly marked as such, and must not be - misrepresented as being the original software. - 3. This notice may not be removed or altered from any source distribution. - - L. Peter Deutsch - ghost@aladdin.com - - */ -/* $Id: md5.c,v 1.6 2002/04/13 19:20:28 lpd Exp $ */ -/* - Independent implementation of MD5 (RFC 1321). - - This code implements the MD5 Algorithm defined in RFC 1321, whose - text is available at - http://www.ietf.org/rfc/rfc1321.txt - The code is derived from the text of the RFC, including the test suite - (section A.5) but excluding the rest of Appendix A. It does not include - any code or documentation that is identified in the RFC as being - copyrighted. - - The original and principal author of md5.c is L. Peter Deutsch - . Other authors are noted in the change history - that follows (in reverse chronological order): - - 2002-04-13 lpd Clarified derivation from RFC 1321; now handles byte order - either statically or dynamically; added missing #include - in library. - 2002-03-11 lpd Corrected argument list for main(), and added int return - type, in test program and T value program. - 2002-02-21 lpd Added missing #include in test program. - 2000-07-03 lpd Patched to eliminate warnings about "constant is - unsigned in ANSI C, signed in traditional"; made test program - self-checking. - 1999-11-04 lpd Edited comments slightly for automatic TOC extraction. - 1999-10-18 lpd Fixed typo in header comment (ansi2knr rather than md5). - 1999-05-03 lpd Original version. - */ - -/* - * The following MD5 implementation has been modified to use types as - * specified in libbson. - */ - -#include - -#include "common-md5-private.h" - -#undef BYTE_ORDER /* 1 = big-endian, -1 = little-endian, 0 = unknown */ -#if BSON_BYTE_ORDER == BSON_BIG_ENDIAN -#define BYTE_ORDER 1 -#else -#define BYTE_ORDER -1 -#endif - -#define T_MASK ((uint32_t) ~0) -#define T1 /* 0xd76aa478 */ (T_MASK ^ 0x28955b87) -#define T2 /* 0xe8c7b756 */ (T_MASK ^ 0x173848a9) -#define T3 0x242070db -#define T4 /* 0xc1bdceee */ (T_MASK ^ 0x3e423111) -#define T5 /* 0xf57c0faf */ (T_MASK ^ 0x0a83f050) -#define T6 0x4787c62a -#define T7 /* 0xa8304613 */ (T_MASK ^ 0x57cfb9ec) -#define T8 /* 0xfd469501 */ (T_MASK ^ 0x02b96afe) -#define T9 0x698098d8 -#define T10 /* 0x8b44f7af */ (T_MASK ^ 0x74bb0850) -#define T11 /* 0xffff5bb1 */ (T_MASK ^ 0x0000a44e) -#define T12 /* 0x895cd7be */ (T_MASK ^ 0x76a32841) -#define T13 0x6b901122 -#define T14 /* 0xfd987193 */ (T_MASK ^ 0x02678e6c) -#define T15 /* 0xa679438e */ (T_MASK ^ 0x5986bc71) -#define T16 0x49b40821 -#define T17 /* 0xf61e2562 */ (T_MASK ^ 0x09e1da9d) -#define T18 /* 0xc040b340 */ (T_MASK ^ 0x3fbf4cbf) -#define T19 0x265e5a51 -#define T20 /* 0xe9b6c7aa */ (T_MASK ^ 0x16493855) -#define T21 /* 0xd62f105d */ (T_MASK ^ 0x29d0efa2) -#define T22 0x02441453 -#define T23 /* 0xd8a1e681 */ (T_MASK ^ 0x275e197e) -#define T24 /* 0xe7d3fbc8 */ (T_MASK ^ 0x182c0437) -#define T25 0x21e1cde6 -#define T26 /* 0xc33707d6 */ (T_MASK ^ 0x3cc8f829) -#define T27 /* 0xf4d50d87 */ (T_MASK ^ 0x0b2af278) -#define T28 0x455a14ed -#define T29 /* 0xa9e3e905 */ (T_MASK ^ 0x561c16fa) -#define T30 /* 0xfcefa3f8 */ (T_MASK ^ 0x03105c07) -#define T31 0x676f02d9 -#define T32 /* 0x8d2a4c8a */ (T_MASK ^ 0x72d5b375) -#define T33 /* 0xfffa3942 */ (T_MASK ^ 0x0005c6bd) -#define T34 /* 0x8771f681 */ (T_MASK ^ 0x788e097e) -#define T35 0x6d9d6122 -#define T36 /* 0xfde5380c */ (T_MASK ^ 0x021ac7f3) -#define T37 /* 0xa4beea44 */ (T_MASK ^ 0x5b4115bb) -#define T38 0x4bdecfa9 -#define T39 /* 0xf6bb4b60 */ (T_MASK ^ 0x0944b49f) -#define T40 /* 0xbebfbc70 */ (T_MASK ^ 0x4140438f) -#define T41 0x289b7ec6 -#define T42 /* 0xeaa127fa */ (T_MASK ^ 0x155ed805) -#define T43 /* 0xd4ef3085 */ (T_MASK ^ 0x2b10cf7a) -#define T44 0x04881d05 -#define T45 /* 0xd9d4d039 */ (T_MASK ^ 0x262b2fc6) -#define T46 /* 0xe6db99e5 */ (T_MASK ^ 0x1924661a) -#define T47 0x1fa27cf8 -#define T48 /* 0xc4ac5665 */ (T_MASK ^ 0x3b53a99a) -#define T49 /* 0xf4292244 */ (T_MASK ^ 0x0bd6ddbb) -#define T50 0x432aff97 -#define T51 /* 0xab9423a7 */ (T_MASK ^ 0x546bdc58) -#define T52 /* 0xfc93a039 */ (T_MASK ^ 0x036c5fc6) -#define T53 0x655b59c3 -#define T54 /* 0x8f0ccc92 */ (T_MASK ^ 0x70f3336d) -#define T55 /* 0xffeff47d */ (T_MASK ^ 0x00100b82) -#define T56 /* 0x85845dd1 */ (T_MASK ^ 0x7a7ba22e) -#define T57 0x6fa87e4f -#define T58 /* 0xfe2ce6e0 */ (T_MASK ^ 0x01d3191f) -#define T59 /* 0xa3014314 */ (T_MASK ^ 0x5cfebceb) -#define T60 0x4e0811a1 -#define T61 /* 0xf7537e82 */ (T_MASK ^ 0x08ac817d) -#define T62 /* 0xbd3af235 */ (T_MASK ^ 0x42c50dca) -#define T63 0x2ad7d2bb -#define T64 /* 0xeb86d391 */ (T_MASK ^ 0x14792c6e) - - -static void -bson_md5_process (bson_md5_t *md5, const uint8_t *data) -{ - uint32_t a = md5->abcd[0]; - uint32_t b = md5->abcd[1]; - uint32_t c = md5->abcd[2]; - uint32_t d = md5->abcd[3]; - uint32_t t; - -#if BYTE_ORDER > 0 - /* Define storage only for big-endian CPUs. */ - uint32_t X[16]; -#else - /* Define storage for little-endian or both types of CPUs. */ - uint32_t xbuf[16]; - const uint32_t *X; -#endif - - { -#if BYTE_ORDER == 0 - /* - * Determine dynamically whether this is a big-endian or - * little-endian machine, since we can use a more efficient - * algorithm on the latter. - */ - static const int w = 1; - - if (*((const uint8_t *) &w)) /* dynamic little-endian */ -#endif -#if BYTE_ORDER <= 0 /* little-endian */ - { - /* - * On little-endian machines, we can process properly aligned - * data without copying it. - */ - if (!(((uintptr_t) data) & 3u)) { -/* data are properly aligned */ -#ifdef __clang__ -#pragma clang diagnostic push -#pragma clang diagnostic ignored "-Wcast-align" -#endif - X = (const uint32_t *) data; -#ifdef __clang__ -#pragma clang diagnostic pop -#endif - } else { - /* not aligned */ - memcpy (xbuf, data, sizeof (xbuf)); - X = xbuf; - } - } -#endif -#if BYTE_ORDER == 0 - else /* dynamic big-endian */ -#endif -#if BYTE_ORDER >= 0 /* big-endian */ - { - /* - * On big-endian machines, we must arrange the bytes in the - * right order. - */ - const uint8_t *xp = data; - int i; - -#if BYTE_ORDER == 0 - X = xbuf; /* (dynamic only) */ -#else -#define xbuf X /* (static only) */ -#endif - for (i = 0; i < 16; ++i, xp += 4) - xbuf[i] = xp[0] + (xp[1] << 8) + (xp[2] << 16) + (xp[3] << 24); - } -#endif - } - -#define ROTATE_LEFT(x, n) (((x) << (n)) | ((x) >> (32 - (n)))) - -/* Round 1. */ -/* Let [abcd k s i] denote the operation - a = b + ((a + F(b,c,d) + X[k] + T[i]) <<< s). */ -#define F(x, y, z) (((x) & (y)) | (~(x) & (z))) -#define SET(a, b, c, d, k, s, Ti) \ - t = a + F (b, c, d) + X[k] + Ti; \ - a = ROTATE_LEFT (t, s) + b - /* Do the following 16 operations. */ - SET (a, b, c, d, 0, 7, T1); - SET (d, a, b, c, 1, 12, T2); - SET (c, d, a, b, 2, 17, T3); - SET (b, c, d, a, 3, 22, T4); - SET (a, b, c, d, 4, 7, T5); - SET (d, a, b, c, 5, 12, T6); - SET (c, d, a, b, 6, 17, T7); - SET (b, c, d, a, 7, 22, T8); - SET (a, b, c, d, 8, 7, T9); - SET (d, a, b, c, 9, 12, T10); - SET (c, d, a, b, 10, 17, T11); - SET (b, c, d, a, 11, 22, T12); - SET (a, b, c, d, 12, 7, T13); - SET (d, a, b, c, 13, 12, T14); - SET (c, d, a, b, 14, 17, T15); - SET (b, c, d, a, 15, 22, T16); -#undef SET - -/* Round 2. */ -/* Let [abcd k s i] denote the operation - a = b + ((a + G(b,c,d) + X[k] + T[i]) <<< s). */ -#define G(x, y, z) (((x) & (z)) | ((y) & ~(z))) -#define SET(a, b, c, d, k, s, Ti) \ - t = a + G (b, c, d) + X[k] + Ti; \ - a = ROTATE_LEFT (t, s) + b - /* Do the following 16 operations. */ - SET (a, b, c, d, 1, 5, T17); - SET (d, a, b, c, 6, 9, T18); - SET (c, d, a, b, 11, 14, T19); - SET (b, c, d, a, 0, 20, T20); - SET (a, b, c, d, 5, 5, T21); - SET (d, a, b, c, 10, 9, T22); - SET (c, d, a, b, 15, 14, T23); - SET (b, c, d, a, 4, 20, T24); - SET (a, b, c, d, 9, 5, T25); - SET (d, a, b, c, 14, 9, T26); - SET (c, d, a, b, 3, 14, T27); - SET (b, c, d, a, 8, 20, T28); - SET (a, b, c, d, 13, 5, T29); - SET (d, a, b, c, 2, 9, T30); - SET (c, d, a, b, 7, 14, T31); - SET (b, c, d, a, 12, 20, T32); -#undef SET - -/* Round 3. */ -/* Let [abcd k s t] denote the operation - a = b + ((a + H(b,c,d) + X[k] + T[i]) <<< s). */ -#define H(x, y, z) ((x) ^ (y) ^ (z)) -#define SET(a, b, c, d, k, s, Ti) \ - t = a + H (b, c, d) + X[k] + Ti; \ - a = ROTATE_LEFT (t, s) + b - /* Do the following 16 operations. */ - SET (a, b, c, d, 5, 4, T33); - SET (d, a, b, c, 8, 11, T34); - SET (c, d, a, b, 11, 16, T35); - SET (b, c, d, a, 14, 23, T36); - SET (a, b, c, d, 1, 4, T37); - SET (d, a, b, c, 4, 11, T38); - SET (c, d, a, b, 7, 16, T39); - SET (b, c, d, a, 10, 23, T40); - SET (a, b, c, d, 13, 4, T41); - SET (d, a, b, c, 0, 11, T42); - SET (c, d, a, b, 3, 16, T43); - SET (b, c, d, a, 6, 23, T44); - SET (a, b, c, d, 9, 4, T45); - SET (d, a, b, c, 12, 11, T46); - SET (c, d, a, b, 15, 16, T47); - SET (b, c, d, a, 2, 23, T48); -#undef SET - -/* Round 4. */ -/* Let [abcd k s t] denote the operation - a = b + ((a + I(b,c,d) + X[k] + T[i]) <<< s). */ -#define I(x, y, z) ((y) ^ ((x) | ~(z))) -#define SET(a, b, c, d, k, s, Ti) \ - t = a + I (b, c, d) + X[k] + Ti; \ - a = ROTATE_LEFT (t, s) + b - /* Do the following 16 operations. */ - SET (a, b, c, d, 0, 6, T49); - SET (d, a, b, c, 7, 10, T50); - SET (c, d, a, b, 14, 15, T51); - SET (b, c, d, a, 5, 21, T52); - SET (a, b, c, d, 12, 6, T53); - SET (d, a, b, c, 3, 10, T54); - SET (c, d, a, b, 10, 15, T55); - SET (b, c, d, a, 1, 21, T56); - SET (a, b, c, d, 8, 6, T57); - SET (d, a, b, c, 15, 10, T58); - SET (c, d, a, b, 6, 15, T59); - SET (b, c, d, a, 13, 21, T60); - SET (a, b, c, d, 4, 6, T61); - SET (d, a, b, c, 11, 10, T62); - SET (c, d, a, b, 2, 15, T63); - SET (b, c, d, a, 9, 21, T64); -#undef SET - - /* Then perform the following additions. (That is increment each - of the four registers by the value it had before this block - was started.) */ - md5->abcd[0] += a; - md5->abcd[1] += b; - md5->abcd[2] += c; - md5->abcd[3] += d; -} - -void -mcommon_md5_init (bson_md5_t *pms) -{ - pms->count[0] = pms->count[1] = 0; - pms->abcd[0] = 0x67452301; - pms->abcd[1] = /*0xefcdab89*/ T_MASK ^ 0x10325476; - pms->abcd[2] = /*0x98badcfe*/ T_MASK ^ 0x67452301; - pms->abcd[3] = 0x10325476; -} - -void -mcommon_md5_append (bson_md5_t *pms, const uint8_t *data, uint32_t nbytes) -{ - const uint8_t *p = data; - int left = nbytes; - int offset = (pms->count[0] >> 3) & 63; - uint32_t nbits = (uint32_t) (nbytes << 3); - - if (nbytes <= 0) - return; - - /* Update the message length. */ - pms->count[1] += nbytes >> 29; - pms->count[0] += nbits; - if (pms->count[0] < nbits) - pms->count[1]++; - - /* Process an initial partial block. */ - if (offset) { - int copy = (offset + nbytes > 64 ? 64 - offset : nbytes); - - memcpy (pms->buf + offset, p, copy); - if (offset + copy < 64) - return; - p += copy; - left -= copy; - bson_md5_process (pms, pms->buf); - } - - /* Process full blocks. */ - for (; left >= 64; p += 64, left -= 64) - bson_md5_process (pms, p); - - /* Process a final partial block. */ - if (left) - memcpy (pms->buf, p, left); -} - - -void -mcommon_md5_finish (bson_md5_t *pms, uint8_t digest[16]) -{ - static const uint8_t pad[64] = {0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; - uint8_t data[8]; - int i; - - /* Save the length before padding. */ - for (i = 0; i < 8; ++i) - data[i] = (uint8_t) (pms->count[i >> 2] >> ((i & 3) << 3)); - /* Pad to 56 bytes mod 64. */ - mcommon_md5_append (pms, pad, ((55 - (pms->count[0] >> 3)) & 63) + 1); - /* Append the length. */ - mcommon_md5_append (pms, data, sizeof (data)); - for (i = 0; i < 16; ++i) - digest[i] = (uint8_t) (pms->abcd[i >> 2] >> ((i & 3) << 3)); -} diff --git a/bsonjs/common/common-prelude.h b/bsonjs/common/common-prelude.h deleted file mode 100644 index 4f3a5fd..0000000 --- a/bsonjs/common/common-prelude.h +++ /dev/null @@ -1,28 +0,0 @@ -/* - * Copyright 2018-present MongoDB, Inc. - * - * 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 !defined(MONGOC_INSIDE) && !defined(MONGOC_COMPILATION) && !defined(BSON_COMPILATION) && !defined(BSON_INSIDE) -#error "Only or can be included directly." -#endif - -#define COMMON_NAME_1(a, b) COMMON_NAME_2 (a, b) -#define COMMON_NAME_2(a, b) a##_##b - -#if defined(MCOMMON_NAME_PREFIX) && !defined(__INTELLISENSE__) -#define COMMON_NAME(Name) COMMON_NAME_1 (MCOMMON_NAME_PREFIX, Name) -#else -#define COMMON_NAME(Name) COMMON_NAME_1 (mcommon, Name) -#endif diff --git a/bsonjs/common/common-thread-private.h b/bsonjs/common/common-thread-private.h deleted file mode 100644 index 291af21..0000000 --- a/bsonjs/common/common-thread-private.h +++ /dev/null @@ -1,209 +0,0 @@ -/* - * Copyright 2013-present MongoDB, Inc. - * - * 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. - */ - -#include "common-prelude.h" -#include "common-config.h" -#include "common-macros-private.h" - -#ifndef COMMON_THREAD_PRIVATE_H -#define COMMON_THREAD_PRIVATE_H - -#define BSON_INSIDE -#include "bson/bson-compat.h" -#include "bson/bson-config.h" -#include "bson/bson-macros.h" -#undef BSON_INSIDE - -BSON_BEGIN_DECLS - -#define mcommon_thread_create COMMON_NAME (thread_create) -#define mcommon_thread_join COMMON_NAME (thread_join) - -#if defined(BSON_OS_UNIX) -#include - -#define BSON_ONCE_FUN(n) void n (void) -#define BSON_ONCE_RETURN return -#define BSON_ONCE_INIT PTHREAD_ONCE_INIT -#define bson_once(o, c) \ - do { \ - BSON_ASSERT (pthread_once ((o), (c)) == 0); \ - } while (0) -#define bson_once_t pthread_once_t -#define bson_thread_t pthread_t -#define BSON_THREAD_FUN(_function_name, _arg_name) void *(_function_name) (void *(_arg_name)) -#define BSON_THREAD_FUN_TYPE(_function_name) void *(*(_function_name)) (void *) -#define BSON_THREAD_RETURN return NULL - -/* this macro can be defined as a as a build configuration option - * with -DENABLE_DEBUG_ASSERTIONS=ON. its purpose is to allow for functions - * that require a mutex to be locked on entry to assert that the mutex - * is actually locked. - * this can prevent bugs where a caller forgets to lock the mutex. */ - -#ifndef MONGOC_ENABLE_DEBUG_ASSERTIONS - -#define bson_mutex_destroy(m) \ - do { \ - BSON_ASSERT (pthread_mutex_destroy ((m)) == 0); \ - } while (0) - -#define bson_mutex_init(_n) \ - do { \ - BSON_ASSERT (pthread_mutex_init ((_n), NULL) == 0); \ - } while (0) - -#define bson_mutex_lock(m) \ - do { \ - BSON_ASSERT (pthread_mutex_lock ((m)) == 0); \ - } while (0) - -#define bson_mutex_t pthread_mutex_t - -#define bson_mutex_unlock(m) \ - do { \ - BSON_ASSERT (pthread_mutex_unlock ((m)) == 0); \ - } while (0) - -#else -typedef struct { - pthread_t lock_owner; - pthread_mutex_t wrapped_mutex; - bool valid_tid; -} bson_mutex_t; - -#define bson_mutex_destroy(mutex) \ - do { \ - BSON_ASSERT (pthread_mutex_destroy (&(mutex)->wrapped_mutex) == 0); \ - } while (0); - -#define bson_mutex_init(mutex) \ - do { \ - BSON_ASSERT (pthread_mutex_init (&(mutex)->wrapped_mutex, NULL) == 0); \ - (mutex)->valid_tid = false; \ - } while (0); - -#define bson_mutex_lock(mutex) \ - do { \ - BSON_ASSERT (pthread_mutex_lock (&(mutex)->wrapped_mutex) == 0); \ - (mutex)->lock_owner = pthread_self (); \ - (mutex)->valid_tid = true; \ - } while (0); - -#define bson_mutex_unlock(mutex) \ - do { \ - (mutex)->valid_tid = false; \ - BSON_ASSERT (pthread_mutex_unlock (&(mutex)->wrapped_mutex) == 0); \ - } while (0); - -#endif - -#else -#include -#define BSON_ONCE_FUN(n) BOOL CALLBACK n (PINIT_ONCE _ignored_a, PVOID _ignored_b, PVOID *_ignored_c) -#define BSON_ONCE_INIT INIT_ONCE_STATIC_INIT -#define BSON_ONCE_RETURN return true -#define bson_mutex_destroy DeleteCriticalSection -#define bson_mutex_init InitializeCriticalSection -#define bson_mutex_lock EnterCriticalSection -#define bson_mutex_t CRITICAL_SECTION -#define bson_mutex_unlock LeaveCriticalSection -#define bson_once(o, c) \ - do { \ - BSON_ASSERT (InitOnceExecuteOnce ((o), (c), NULL, NULL)); \ - } while (0) -#define bson_once_t INIT_ONCE -#define bson_thread_t HANDLE -#define BSON_THREAD_FUN(_function_name, _arg_name) unsigned (__stdcall _function_name) (void *(_arg_name)) -#define BSON_THREAD_FUN_TYPE(_function_name) unsigned (__stdcall * _function_name) (void *) -#define BSON_THREAD_RETURN return 0 -#endif - -/* Functions that require definitions get the common prefix (_mongoc for - * libmongoc or _bson for libbson) to avoid duplicate symbols when linking both - * libbson and libmongoc statically. */ -int -mcommon_thread_join (bson_thread_t thread); -// mcommon_thread_create returns 0 on success. Returns a non-zero error code on -// error. Callers may use `bson_strerror_r` to get an error message from the -// returned error code. -int -mcommon_thread_create (bson_thread_t *thread, BSON_THREAD_FUN_TYPE (func), void *arg); - -#if defined(MONGOC_ENABLE_DEBUG_ASSERTIONS) && defined(BSON_OS_UNIX) -#define mcommon_mutex_is_locked COMMON_NAME (mutex_is_locked) -bool -mcommon_mutex_is_locked (bson_mutex_t *mutex); -#endif - -/** - * @brief A shared mutex (a read-write lock) - * - * A shared mutex can be locked in 'shared' mode or 'exclusive' mode. Only one - * thread may hold exclusive mode at a time. Any number of threads may hold - * the lock in shared mode simultaneously. No thread can hold in exclusive mode - * while another thread holds in shared mode, and vice-versa. - */ -typedef struct bson_shared_mutex_t { - BSON_IF_WINDOWS (SRWLOCK native;) - BSON_IF_POSIX (pthread_rwlock_t native;) -} bson_shared_mutex_t; - -static BSON_INLINE void -bson_shared_mutex_init (bson_shared_mutex_t *mtx) -{ - BSON_IF_WINDOWS (InitializeSRWLock (&mtx->native)); - BSON_IF_POSIX (BSON_ASSERT (pthread_rwlock_init (&mtx->native, NULL) == 0);) -} - -static BSON_INLINE void -bson_shared_mutex_destroy (bson_shared_mutex_t *mtx) -{ - BSON_IF_WINDOWS ((void) mtx;) - BSON_IF_POSIX (BSON_ASSERT (pthread_rwlock_destroy (&mtx->native) == 0);) -} - -static BSON_INLINE void -bson_shared_mutex_lock_shared (bson_shared_mutex_t *mtx) -{ - BSON_IF_WINDOWS (AcquireSRWLockShared (&mtx->native);) - BSON_IF_POSIX (BSON_ASSERT (pthread_rwlock_rdlock (&mtx->native) == 0);) -} - -static BSON_INLINE void -bson_shared_mutex_lock (bson_shared_mutex_t *mtx) -{ - BSON_IF_WINDOWS (AcquireSRWLockExclusive (&mtx->native);) - BSON_IF_POSIX (BSON_ASSERT (pthread_rwlock_wrlock (&mtx->native) == 0);) -} - -static BSON_INLINE void -bson_shared_mutex_unlock (bson_shared_mutex_t *mtx) -{ - BSON_IF_WINDOWS (ReleaseSRWLockExclusive (&mtx->native);) - BSON_IF_POSIX (BSON_ASSERT (pthread_rwlock_unlock (&mtx->native) == 0);) -} - -static BSON_INLINE void -bson_shared_mutex_unlock_shared (bson_shared_mutex_t *mtx) -{ - BSON_IF_WINDOWS (ReleaseSRWLockShared (&mtx->native);) - BSON_IF_POSIX (BSON_ASSERT (pthread_rwlock_unlock (&mtx->native) == 0);) -} - -BSON_END_DECLS - -#endif /* COMMON_THREAD_PRIVATE_H */ diff --git a/bsonjs/common/common-thread.c b/bsonjs/common/common-thread.c deleted file mode 100644 index 9b26f6e..0000000 --- a/bsonjs/common/common-thread.c +++ /dev/null @@ -1,75 +0,0 @@ -/* - * Copyright 2020-present MongoDB, Inc. - * - * 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. - */ - -#include "common-thread-private.h" - -#include - -#if defined(BSON_OS_UNIX) -int -mcommon_thread_create (bson_thread_t *thread, BSON_THREAD_FUN_TYPE (func), void *arg) -{ - BSON_ASSERT_PARAM (thread); - BSON_ASSERT_PARAM (func); - BSON_ASSERT (arg || true); // optional. - return pthread_create (thread, NULL, func, arg); -} -int -mcommon_thread_join (bson_thread_t thread) -{ - return pthread_join (thread, NULL); -} - -#if defined(MONGOC_ENABLE_DEBUG_ASSERTIONS) && defined(BSON_OS_UNIX) -bool -mcommon_mutex_is_locked (bson_mutex_t *mutex) -{ - return mutex->valid_tid && pthread_equal (pthread_self (), mutex->lock_owner); -} -#endif - -#else -int -mcommon_thread_create (bson_thread_t *thread, BSON_THREAD_FUN_TYPE (func), void *arg) -{ - BSON_ASSERT_PARAM (thread); - BSON_ASSERT_PARAM (func); - BSON_ASSERT (arg || true); // optional. - - *thread = (HANDLE) _beginthreadex (NULL, 0, func, arg, 0, NULL); - if (0 == *thread) { - return errno; - } - return 0; -} -int -mcommon_thread_join (bson_thread_t thread) -{ - int ret; - - /* zero indicates success for WaitForSingleObject. */ - ret = WaitForSingleObject (thread, INFINITE); - if (WAIT_OBJECT_0 != ret) { - return ret; - } - /* zero indicates failure for CloseHandle. */ - ret = CloseHandle (thread); - if (0 == ret) { - return 1; - } - return 0; -} -#endif diff --git a/bsonjs/jsonsl/LICENSE b/bsonjs/jsonsl/LICENSE deleted file mode 100644 index e021f06..0000000 --- a/bsonjs/jsonsl/LICENSE +++ /dev/null @@ -1,20 +0,0 @@ -Copyright (c) 2012-2015 M. Nunberg, mnunberg@haskalah.org - -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/bsonjs/jsonsl/jsonsl.c b/bsonjs/jsonsl/jsonsl.c deleted file mode 100644 index a7bb8f4..0000000 --- a/bsonjs/jsonsl/jsonsl.c +++ /dev/null @@ -1,1680 +0,0 @@ -/* Copyright (C) 2012-2015 Mark Nunberg. - * - * See included LICENSE file for license details. - */ - -#include "jsonsl.h" -#include "bson/bson-memory.h" - -#include -#include - -#ifdef JSONSL_USE_METRICS -#define XMETRICS \ - X(STRINGY_INSIGNIFICANT) \ - X(STRINGY_SLOWPATH) \ - X(ALLOWED_WHITESPACE) \ - X(QUOTE_FASTPATH) \ - X(SPECIAL_FASTPATH) \ - X(SPECIAL_WSPOP) \ - X(SPECIAL_SLOWPATH) \ - X(GENERIC) \ - X(STRUCTURAL_TOKEN) \ - X(SPECIAL_SWITCHFIRST) \ - X(STRINGY_CATCH) \ - X(NUMBER_FASTPATH) \ - X(ESCAPES) \ - X(TOTAL) \ - -struct jsonsl_metrics_st { -#define X(m) \ - unsigned long metric_##m; - XMETRICS -#undef X -}; - -static struct jsonsl_metrics_st GlobalMetrics = { 0 }; -static unsigned long GenericCounter[0x100] = { 0 }; -static unsigned long StringyCatchCounter[0x100] = { 0 }; - -#define INCR_METRIC(m) \ - GlobalMetrics.metric_##m++; - -#define INCR_GENERIC(c) \ - INCR_METRIC(GENERIC); \ - GenericCounter[c]++; \ - -#define INCR_STRINGY_CATCH(c) \ - INCR_METRIC(STRINGY_CATCH); \ - StringyCatchCounter[c]++; - -JSONSL_API -void jsonsl_dump_global_metrics(void) -{ - int ii; - printf("JSONSL Metrics:\n"); -#define X(m) \ - printf("\t%-30s %20lu (%0.2f%%)\n", #m, GlobalMetrics.metric_##m, \ - (float)((float)(GlobalMetrics.metric_##m/(float)GlobalMetrics.metric_TOTAL)) * 100); - XMETRICS -#undef X - printf("Generic Characters:\n"); - for (ii = 0; ii < 0xff; ii++) { - if (GenericCounter[ii]) { - printf("\t[ %c ] %lu\n", ii, GenericCounter[ii]); - } - } - printf("Weird string loop\n"); - for (ii = 0; ii < 0xff; ii++) { - if (StringyCatchCounter[ii]) { - printf("\t[ %c ] %lu\n", ii, StringyCatchCounter[ii]); - } - } -} - -#else -#define INCR_METRIC(m) -#define INCR_GENERIC(c) -#define INCR_STRINGY_CATCH(c) -JSONSL_API -void jsonsl_dump_global_metrics(void) { } -#endif /* JSONSL_USE_METRICS */ - -#define CASE_DIGITS \ -case '1': \ -case '2': \ -case '3': \ -case '4': \ -case '5': \ -case '6': \ -case '7': \ -case '8': \ -case '9': \ -case '0': - -static unsigned extract_special(unsigned); -static int is_special_end(unsigned); -static int is_allowed_whitespace(unsigned); -static int is_allowed_escape(unsigned); -static int is_simple_char(unsigned); -static char get_escape_equiv(unsigned); - -JSONSL_API -jsonsl_t jsonsl_new(int nlevels) -{ - unsigned int ii; - struct jsonsl_st * jsn; - - if (nlevels < 2) { - return NULL; - } - - jsn = (struct jsonsl_st *) - bson_malloc0(sizeof (*jsn) + - ( (nlevels-1) * sizeof (struct jsonsl_state_st) ) - ); - - jsn->levels_max = (unsigned int) nlevels; - jsn->max_callback_level = UINT_MAX; - jsonsl_reset(jsn); - for (ii = 0; ii < jsn->levels_max; ii++) { - jsn->stack[ii].level = ii; - } - return jsn; -} - -JSONSL_API -void jsonsl_reset(jsonsl_t jsn) -{ - jsn->tok_last = 0; - jsn->can_insert = 1; - jsn->pos = 0; - jsn->level = 0; - jsn->stopfl = 0; - jsn->in_escape = 0; - jsn->expecting = 0; -} - -JSONSL_API -void jsonsl_destroy(jsonsl_t jsn) -{ - if (jsn) { - bson_free(jsn); - } -} - - -#define FASTPARSE_EXHAUSTED 1 -#define FASTPARSE_BREAK 0 - -/* - * This function is meant to accelerate string parsing, reducing the main loop's - * check if we are indeed a string. - * - * @param jsn the parser - * @param[in,out] bytes_p A pointer to the current buffer (i.e. current position) - * @param[in,out] nbytes_p A pointer to the current size of the buffer - * @return true if all bytes have been exhausted (and thus the main loop can - * return), false if a special character was examined which requires greater - * examination. - */ -static int -jsonsl__str_fastparse(jsonsl_t jsn, - const jsonsl_uchar_t **bytes_p, size_t *nbytes_p) -{ - const jsonsl_uchar_t *bytes = *bytes_p; - const jsonsl_uchar_t *end; - for (end = bytes + *nbytes_p; bytes != end; bytes++) { - if ( -#ifdef JSONSL_USE_WCHAR - *bytes >= 0x100 || -#endif /* JSONSL_USE_WCHAR */ - (is_simple_char(*bytes))) { - INCR_METRIC(TOTAL); - INCR_METRIC(STRINGY_INSIGNIFICANT); - } else { - /* Once we're done here, re-calculate the position variables */ - jsn->pos += (bytes - *bytes_p); - *nbytes_p -= (bytes - *bytes_p); - *bytes_p = bytes; - return FASTPARSE_BREAK; - } - } - - /* Once we're done here, re-calculate the position variables */ - jsn->pos += (bytes - *bytes_p); - return FASTPARSE_EXHAUSTED; -} - -/* Functions exactly like str_fastparse, except it also accepts a 'state' - * argument, since the number's value is updated in the state. */ -static int -jsonsl__num_fastparse(jsonsl_t jsn, - const jsonsl_uchar_t **bytes_p, size_t *nbytes_p, - struct jsonsl_state_st *state) -{ - int exhausted = 1; - size_t nbytes = *nbytes_p; - const jsonsl_uchar_t *bytes = *bytes_p; - - for (; nbytes; nbytes--, bytes++) { - jsonsl_uchar_t c = *bytes; - if (isdigit(c)) { - INCR_METRIC(TOTAL); - INCR_METRIC(NUMBER_FASTPATH); - state->nelem = (state->nelem * 10) + (c - 0x30); - } else { - exhausted = 0; - break; - } - } - jsn->pos += (*nbytes_p - nbytes); - if (exhausted) { - return FASTPARSE_EXHAUSTED; - } - *nbytes_p = nbytes; - *bytes_p = bytes; - return FASTPARSE_BREAK; -} - -JSONSL_API -void -jsonsl_feed(jsonsl_t jsn, const jsonsl_char_t *bytes, size_t nbytes) -{ - -#define INVOKE_ERROR(eb) \ - if (jsn->error_callback(jsn, JSONSL_ERROR_##eb, state, (char*)c)) { \ - goto GT_AGAIN; \ - } \ - return; - -#define STACK_PUSH \ - if (jsn->level >= (levels_max-1)) { \ - jsn->error_callback(jsn, JSONSL_ERROR_LEVELS_EXCEEDED, state, (char*)c); \ - return; \ - } \ - state = jsn->stack + (++jsn->level); \ - state->ignore_callback = jsn->stack[jsn->level-1].ignore_callback; \ - state->pos_begin = jsn->pos; - -#define STACK_POP_NOPOS \ - state->pos_cur = jsn->pos; \ - state = jsn->stack + (--jsn->level); - - -#define STACK_POP \ - STACK_POP_NOPOS; \ - state->pos_cur = jsn->pos; - -#define CALLBACK_AND_POP_NOPOS(T) \ - state->pos_cur = jsn->pos; \ - DO_CALLBACK(T, POP); \ - state->nescapes = 0; \ - state = jsn->stack + (--jsn->level); - -#define CALLBACK_AND_POP(T) \ - CALLBACK_AND_POP_NOPOS(T); \ - state->pos_cur = jsn->pos; - -#define SPECIAL_POP \ - CALLBACK_AND_POP(SPECIAL); \ - jsn->expecting = 0; \ - jsn->tok_last = 0; \ - -#define CUR_CHAR (*(jsonsl_uchar_t*)c) - -#define DO_CALLBACK(T, action) \ - if (jsn->call_##T && \ - jsn->max_callback_level > state->level && \ - state->ignore_callback == 0) { \ - \ - if (jsn->action_callback_##action) { \ - jsn->action_callback_##action(jsn, JSONSL_ACTION_##action, state, (jsonsl_char_t*)c); \ - } else if (jsn->action_callback) { \ - jsn->action_callback(jsn, JSONSL_ACTION_##action, state, (jsonsl_char_t*)c); \ - } \ - if (jsn->stopfl) { return; } \ - } - - /** - * Verifies that we are able to insert the (non-string) item into a hash. - */ -#define ENSURE_HVAL \ - if (state->nelem % 2 == 0 && state->type == JSONSL_T_OBJECT) { \ - INVOKE_ERROR(HKEY_EXPECTED); \ - } - -#define VERIFY_SPECIAL(lit, lit_len) \ - if ((jsn->pos - state->pos_begin) > lit_len \ - || CUR_CHAR != (lit)[jsn->pos - state->pos_begin]) { \ - INVOKE_ERROR(SPECIAL_EXPECTED); \ - } - -#define VERIFY_SPECIAL_CI(lit, lit_len) \ - if ((jsn->pos - state->pos_begin) > lit_len \ - || tolower(CUR_CHAR) != (lit)[jsn->pos - state->pos_begin]) { \ - INVOKE_ERROR(SPECIAL_EXPECTED); \ - } - -#define STATE_SPECIAL_LENGTH \ - (state)->nescapes - -#define IS_NORMAL_NUMBER \ - ((state)->special_flags == JSONSL_SPECIALf_UNSIGNED || \ - (state)->special_flags == JSONSL_SPECIALf_SIGNED) - -#define STATE_NUM_LAST jsn->tok_last - -#define CONTINUE_NEXT_CHAR() continue - - const jsonsl_uchar_t *c = (jsonsl_uchar_t*)bytes; - size_t levels_max = jsn->levels_max; - struct jsonsl_state_st *state = jsn->stack + jsn->level; - jsn->base = bytes; - - for (; nbytes; nbytes--, jsn->pos++, c++) { - unsigned state_type; - INCR_METRIC(TOTAL); - - GT_AGAIN: - state_type = state->type; - /* Most common type is typically a string: */ - if (state_type & JSONSL_Tf_STRINGY) { - /* Special escape handling for some stuff */ - if (jsn->in_escape) { - jsn->in_escape = 0; - if (!is_allowed_escape(CUR_CHAR)) { - INVOKE_ERROR(ESCAPE_INVALID); - } else if (CUR_CHAR == 'u') { - DO_CALLBACK(UESCAPE, UESCAPE); - if (jsn->return_UESCAPE) { - return; - } - } - CONTINUE_NEXT_CHAR(); - } - - if (jsonsl__str_fastparse(jsn, &c, &nbytes) == - FASTPARSE_EXHAUSTED) { - /* No need to readjust variables as we've exhausted the iterator */ - return; - } else { - if (CUR_CHAR == '"') { - goto GT_QUOTE; - } else if (CUR_CHAR == '\\') { - goto GT_ESCAPE; - } else { - INVOKE_ERROR(WEIRD_WHITESPACE); - } - } - INCR_METRIC(STRINGY_SLOWPATH); - - } else if (state_type == JSONSL_T_SPECIAL) { - /* Fast track for signed/unsigned */ - if (IS_NORMAL_NUMBER) { - if (jsonsl__num_fastparse(jsn, &c, &nbytes, state) == - FASTPARSE_EXHAUSTED) { - return; - } else { - goto GT_SPECIAL_NUMERIC; - } - } else if (state->special_flags == JSONSL_SPECIALf_DASH) { -#ifdef JSONSL_PARSE_NAN - if (CUR_CHAR == 'I' || CUR_CHAR == 'i') { - /* parsing -Infinity? */ - state->special_flags = JSONSL_SPECIALf_NEG_INF; - CONTINUE_NEXT_CHAR(); - } -#endif - - if (!isdigit(CUR_CHAR)) { - INVOKE_ERROR(INVALID_NUMBER); - } - - if (CUR_CHAR == '0') { - state->special_flags = JSONSL_SPECIALf_ZERO|JSONSL_SPECIALf_SIGNED; - } else if (isdigit(CUR_CHAR)) { - state->special_flags = JSONSL_SPECIALf_SIGNED; - state->nelem = CUR_CHAR - 0x30; - } else { - INVOKE_ERROR(INVALID_NUMBER); - } - CONTINUE_NEXT_CHAR(); - - } else if (state->special_flags == JSONSL_SPECIALf_ZERO) { - if (isdigit(CUR_CHAR)) { - /* Following a zero! */ - INVOKE_ERROR(INVALID_NUMBER); - } - /* Unset the 'zero' flag: */ - if (state->special_flags & JSONSL_SPECIALf_SIGNED) { - state->special_flags = JSONSL_SPECIALf_SIGNED; - } else { - state->special_flags = JSONSL_SPECIALf_UNSIGNED; - } - goto GT_SPECIAL_NUMERIC; - } - - if ((state->special_flags & JSONSL_SPECIALf_NUMERIC) && - !(state->special_flags & JSONSL_SPECIALf_INF)) { - GT_SPECIAL_NUMERIC: - switch (CUR_CHAR) { - CASE_DIGITS - STATE_NUM_LAST = '1'; - CONTINUE_NEXT_CHAR(); - - case '.': - if (state->special_flags & JSONSL_SPECIALf_FLOAT) { - INVOKE_ERROR(INVALID_NUMBER); - } - state->special_flags |= JSONSL_SPECIALf_FLOAT; - STATE_NUM_LAST = '.'; - CONTINUE_NEXT_CHAR(); - - case 'e': - case 'E': - if (state->special_flags & JSONSL_SPECIALf_EXPONENT) { - INVOKE_ERROR(INVALID_NUMBER); - } - state->special_flags |= JSONSL_SPECIALf_EXPONENT; - STATE_NUM_LAST = 'e'; - CONTINUE_NEXT_CHAR(); - - case '-': - case '+': - if (STATE_NUM_LAST != 'e') { - INVOKE_ERROR(INVALID_NUMBER); - } - STATE_NUM_LAST = '-'; - CONTINUE_NEXT_CHAR(); - - default: - if (is_special_end(CUR_CHAR)) { - goto GT_SPECIAL_POP; - } - INVOKE_ERROR(INVALID_NUMBER); - break; - } - } - /* else if (!NUMERIC) */ - if (!is_special_end(CUR_CHAR)) { - STATE_SPECIAL_LENGTH++; - - /* Verify TRUE, FALSE, NULL */ - if (state->special_flags == JSONSL_SPECIALf_TRUE) { - VERIFY_SPECIAL("true", 4 /* strlen("true") */); - } else if (state->special_flags == JSONSL_SPECIALf_FALSE) { - VERIFY_SPECIAL("false", 5 /* strlen("false") */); - } else if (state->special_flags == JSONSL_SPECIALf_NULL) { - VERIFY_SPECIAL("null", 4 /* strlen("null") */); -#ifdef JSONSL_PARSE_NAN - } else if (state->special_flags == JSONSL_SPECIALf_POS_INF) { - VERIFY_SPECIAL_CI("infinity", 8 /* strlen("infinity") */); - } else if (state->special_flags == JSONSL_SPECIALf_NEG_INF) { - VERIFY_SPECIAL_CI("-infinity", 9 /* strlen("-infinity") */); - } else if (state->special_flags == JSONSL_SPECIALf_NAN) { - VERIFY_SPECIAL_CI("nan", 3 /* strlen("nan") */); - } else if (state->special_flags & JSONSL_SPECIALf_NULL || - state->special_flags & JSONSL_SPECIALf_NAN) { - /* previous char was "n", are we parsing null or nan? */ - const bool not_u = CUR_CHAR != 'u'; - const bool not_a = tolower (CUR_CHAR) != 'a'; - if (not_u) { - state->special_flags &= ~JSONSL_SPECIALf_NULL; - } - if (not_a) { - state->special_flags &= ~JSONSL_SPECIALf_NAN; - } - if (not_u && not_a) { - /* This verify will always fail, as we have an 'n' - * followed by a character that is neither 'a' nor 'u' - * (and hence cannot be "null"). The purpose of this - * VERIFY_SPECIAL is to generate an error in tokenization - * that stops if a bare 'n' cannot possibly be a "nan" or - * a "null". */ - VERIFY_SPECIAL ("null", 4); - } -#endif - } - INCR_METRIC(SPECIAL_FASTPATH); - CONTINUE_NEXT_CHAR(); - } - - GT_SPECIAL_POP: - jsn->can_insert = 0; - if (IS_NORMAL_NUMBER) { - /* Nothing */ - } else if (state->special_flags == JSONSL_SPECIALf_ZERO || - state->special_flags == (JSONSL_SPECIALf_ZERO|JSONSL_SPECIALf_SIGNED)) { - /* 0 is unsigned! */ - state->special_flags = JSONSL_SPECIALf_UNSIGNED; - } else if (state->special_flags == JSONSL_SPECIALf_DASH) { - /* Still in dash! */ - INVOKE_ERROR(INVALID_NUMBER); - } else if (state->special_flags & JSONSL_SPECIALf_INF) { - if (STATE_SPECIAL_LENGTH != 8) { - INVOKE_ERROR(SPECIAL_INCOMPLETE); - } - state->nelem = 1; - } else if (state->special_flags & JSONSL_SPECIALf_NUMERIC) { - /* Check that we're not at the end of a token */ - if (STATE_NUM_LAST != '1') { - INVOKE_ERROR(INVALID_NUMBER); - } - } else if (state->special_flags == JSONSL_SPECIALf_TRUE) { - if (STATE_SPECIAL_LENGTH != 4) { - INVOKE_ERROR(SPECIAL_INCOMPLETE); - } - state->nelem = 1; - } else if (state->special_flags == JSONSL_SPECIALf_FALSE) { - if (STATE_SPECIAL_LENGTH != 5) { - INVOKE_ERROR(SPECIAL_INCOMPLETE); - } - } else if (state->special_flags == JSONSL_SPECIALf_NULL) { - if (STATE_SPECIAL_LENGTH != 4) { - INVOKE_ERROR(SPECIAL_INCOMPLETE); - } - } - SPECIAL_POP; - jsn->expecting = ','; - if (is_allowed_whitespace(CUR_CHAR)) { - CONTINUE_NEXT_CHAR(); - } - /** - * This works because we have a non-whitespace token - * which is not a special token. If this is a structural - * character then it will be gracefully handled by the - * switch statement. Otherwise it will default to the 'special' - * state again, - */ - goto GT_STRUCTURAL_TOKEN; - } else if (is_allowed_whitespace(CUR_CHAR)) { - INCR_METRIC(ALLOWED_WHITESPACE); - /* So we're not special. Harmless insignificant whitespace - * passthrough - */ - CONTINUE_NEXT_CHAR(); - } else if (extract_special(CUR_CHAR)) { - /* not a string, whitespace, or structural token. must be special */ - goto GT_SPECIAL_BEGIN; - } - - INCR_GENERIC(CUR_CHAR); - - if (CUR_CHAR == '"') { - GT_QUOTE: - jsn->can_insert = 0; - switch (state_type) { - - /* the end of a string or hash key */ - case JSONSL_T_STRING: - CALLBACK_AND_POP(STRING); - CONTINUE_NEXT_CHAR(); - case JSONSL_T_HKEY: - CALLBACK_AND_POP(HKEY); - CONTINUE_NEXT_CHAR(); - - case JSONSL_T_OBJECT: - state->nelem++; - if ( (state->nelem-1) % 2 ) { - /* Odd, this must be a hash value */ - if (jsn->tok_last != ':') { - INVOKE_ERROR(MISSING_TOKEN); - } - jsn->expecting = ','; /* Can't figure out what to expect next */ - jsn->tok_last = 0; - - STACK_PUSH; - state->type = JSONSL_T_STRING; - DO_CALLBACK(STRING, PUSH); - - } else { - /* hash key */ - if (jsn->expecting != '"') { - INVOKE_ERROR(STRAY_TOKEN); - } - jsn->tok_last = 0; - jsn->expecting = ':'; - - STACK_PUSH; - state->type = JSONSL_T_HKEY; - DO_CALLBACK(HKEY, PUSH); - } - CONTINUE_NEXT_CHAR(); - - case JSONSL_T_LIST: - state->nelem++; - STACK_PUSH; - state->type = JSONSL_T_STRING; - jsn->expecting = ','; - jsn->tok_last = 0; - DO_CALLBACK(STRING, PUSH); - CONTINUE_NEXT_CHAR(); - - case JSONSL_T_SPECIAL: - INVOKE_ERROR(STRAY_TOKEN); - break; - - default: - INVOKE_ERROR(STRING_OUTSIDE_CONTAINER); - break; - } /* switch(state->type) */ - } else if (CUR_CHAR == '\\') { - GT_ESCAPE: - INCR_METRIC(ESCAPES); - /* Escape */ - if ( (state->type & JSONSL_Tf_STRINGY) == 0 ) { - INVOKE_ERROR(ESCAPE_OUTSIDE_STRING); - } - state->nescapes++; - jsn->in_escape = 1; - CONTINUE_NEXT_CHAR(); - } /* " or \ */ - - GT_STRUCTURAL_TOKEN: - switch (CUR_CHAR) { - case ':': - INCR_METRIC(STRUCTURAL_TOKEN); - if (jsn->expecting != CUR_CHAR) { - INVOKE_ERROR(STRAY_TOKEN); - } - jsn->tok_last = ':'; - jsn->can_insert = 1; - jsn->expecting = '"'; - CONTINUE_NEXT_CHAR(); - - case ',': - INCR_METRIC(STRUCTURAL_TOKEN); - /** - * The comma is one of the more generic tokens. - * In the context of an OBJECT, the can_insert flag - * should never be set, and no other action is - * necessary. - */ - if (jsn->expecting != CUR_CHAR) { - /* make this branch execute only when we haven't manually - * just placed the ',' in the expecting register. - */ - INVOKE_ERROR(STRAY_TOKEN); - } - - if (state->type == JSONSL_T_OBJECT) { - /* end of hash value, expect a string as a hash key */ - jsn->expecting = '"'; - } else { - jsn->can_insert = 1; - } - - jsn->tok_last = ','; - jsn->expecting = '"'; - CONTINUE_NEXT_CHAR(); - - /* new list or object */ - /* hashes are more common */ - case '{': - case '[': - INCR_METRIC(STRUCTURAL_TOKEN); - if (!jsn->can_insert) { - INVOKE_ERROR(CANT_INSERT); - } - - ENSURE_HVAL; - state->nelem++; - - STACK_PUSH; - /* because the constants match the opening delimiters, we can do this: */ - state->type = CUR_CHAR; - state->nelem = 0; - jsn->can_insert = 1; - if (CUR_CHAR == '{') { - /* If we're a hash, we expect a key first, which is quouted */ - jsn->expecting = '"'; - } - if (CUR_CHAR == JSONSL_T_OBJECT) { - DO_CALLBACK(OBJECT, PUSH); - } else { - DO_CALLBACK(LIST, PUSH); - } - jsn->tok_last = 0; - CONTINUE_NEXT_CHAR(); - - /* closing of list or object */ - case '}': - case ']': - INCR_METRIC(STRUCTURAL_TOKEN); - if (jsn->tok_last == ',' && jsn->options.allow_trailing_comma == 0) { - INVOKE_ERROR(TRAILING_COMMA); - } - - jsn->can_insert = 0; - jsn->level--; - jsn->expecting = ','; - jsn->tok_last = 0; - if (CUR_CHAR == ']') { - if (state->type != '[') { - INVOKE_ERROR(BRACKET_MISMATCH); - } - DO_CALLBACK(LIST, POP); - } else { - if (state->type != '{') { - INVOKE_ERROR(BRACKET_MISMATCH); - } else if (state->nelem && state->nelem % 2 != 0) { - INVOKE_ERROR(VALUE_EXPECTED); - } - DO_CALLBACK(OBJECT, POP); - } - state = jsn->stack + jsn->level; - state->pos_cur = jsn->pos; - CONTINUE_NEXT_CHAR(); - - default: - GT_SPECIAL_BEGIN: - /** - * Not a string, not a structural token, and not benign whitespace. - * Technically we should iterate over the character always, but since - * we are not doing full numerical/value decoding anyway (but only hinting), - * we only check upon entry. - */ - if (state->type != JSONSL_T_SPECIAL) { - int special_flags = extract_special(CUR_CHAR); - if (!special_flags) { - /** - * Try to do some heuristics here anyway to figure out what kind of - * error this is. The 'special' case is a fallback scenario anyway. - */ - if (CUR_CHAR == '\0') { - INVOKE_ERROR(FOUND_NULL_BYTE); - } else if (CUR_CHAR < 0x20) { - INVOKE_ERROR(WEIRD_WHITESPACE); - } else { - INVOKE_ERROR(SPECIAL_EXPECTED); - } - } - ENSURE_HVAL; - state->nelem++; - if (!jsn->can_insert) { - INVOKE_ERROR(CANT_INSERT); - } - STACK_PUSH; - state->type = JSONSL_T_SPECIAL; - state->special_flags = special_flags; - STATE_SPECIAL_LENGTH = 1; - - if (special_flags == JSONSL_SPECIALf_UNSIGNED) { - state->nelem = CUR_CHAR - 0x30; - STATE_NUM_LAST = '1'; - } else { - STATE_NUM_LAST = '-'; - state->nelem = 0; - } - DO_CALLBACK(SPECIAL, PUSH); - } - CONTINUE_NEXT_CHAR(); - } - } -} - -JSONSL_API -const char* jsonsl_strerror(jsonsl_error_t err) -{ - if (err == JSONSL_ERROR_SUCCESS) { - return "SUCCESS"; - } -#define X(t) \ - if (err == JSONSL_ERROR_##t) \ - return #t; - JSONSL_XERR; -#undef X - return ""; -} - -JSONSL_API -const char *jsonsl_strtype(jsonsl_type_t type) -{ -#define X(o,c) \ - if (type == JSONSL_T_##o) \ - return #o; - JSONSL_XTYPE -#undef X - return "UNKNOWN TYPE"; - -} - -/* - * - * JPR/JSONPointer functions - * - * - */ -#ifndef JSONSL_NO_JPR -static -jsonsl_jpr_type_t -populate_component(char *in, - struct jsonsl_jpr_component_st *component, - char **next, - jsonsl_error_t *errp) -{ - unsigned long pctval; - char *c = NULL, *outp = NULL, *end = NULL; - size_t input_len; - jsonsl_jpr_type_t ret = JSONSL_PATH_NONE; - - if (*next == NULL || *(*next) == '\0') { - return JSONSL_PATH_NONE; - } - - /* Replace the next / with a NULL */ - *next = strstr(in, "/"); - if (*next != NULL) { - *(*next) = '\0'; /* drop the forward slash */ - input_len = *next - in; - end = *next; - *next += 1; /* next character after the '/' */ - } else { - input_len = strlen(in); - end = in + input_len + 1; - } - - component->pstr = in; - - /* Check for special components of interest */ - if (*in == JSONSL_PATH_WILDCARD_CHAR && input_len == 1) { - /* Lone wildcard */ - ret = JSONSL_PATH_WILDCARD; - goto GT_RET; - } else if (isdigit(*in)) { - /* ASCII Numeric */ - char *endptr; - component->idx = strtoul(in, &endptr, 10); - if (endptr && *endptr == '\0') { - ret = JSONSL_PATH_NUMERIC; - goto GT_RET; - } - } - - /* Default, it's a string */ - ret = JSONSL_PATH_STRING; - for (c = outp = in; c < end; c++, outp++) { - char origc; - if (*c != '%') { - goto GT_ASSIGN; - } - /* - * c = { [+0] = '%', [+1] = 'b', [+2] = 'e', [+3] = '\0' } - */ - - /* Need %XX */ - if (c+2 >= end) { - *errp = JSONSL_ERROR_PERCENT_BADHEX; - return JSONSL_PATH_INVALID; - } - if (! (isxdigit(*(c+1)) && isxdigit(*(c+2))) ) { - *errp = JSONSL_ERROR_PERCENT_BADHEX; - return JSONSL_PATH_INVALID; - } - - /* Temporarily null-terminate the characters */ - origc = *(c+3); - *(c+3) = '\0'; - pctval = strtoul(c+1, NULL, 16); - *(c+3) = origc; - - *outp = (char) pctval; - c += 2; - continue; - - GT_ASSIGN: - *outp = *c; - } - /* Null-terminate the string */ - for (; outp < c; outp++) { - *outp = '\0'; - } - - GT_RET: - component->ptype = ret; - if (ret != JSONSL_PATH_WILDCARD) { - component->len = strlen(component->pstr); - } - return ret; -} - -JSONSL_API -jsonsl_jpr_t -jsonsl_jpr_new(const char *path, jsonsl_error_t *errp) -{ - char *my_copy = NULL; - int count, curidx; - struct jsonsl_jpr_st *ret = NULL; - struct jsonsl_jpr_component_st *components = NULL; - size_t origlen; - jsonsl_error_t errstacked; - -#define JPR_BAIL(err) *errp = err; goto GT_ERROR; - - if (errp == NULL) { - errp = &errstacked; - } - - if (path == NULL || *path != '/') { - JPR_BAIL(JSONSL_ERROR_JPR_NOROOT); - } - - count = 1; - path++; - { - const char *c = path; - for (; *c; c++) { - if (*c == '/') { - count++; - if (*(c+1) == '/') { - JPR_BAIL(JSONSL_ERROR_JPR_DUPSLASH); - } - } - } - } - if(*path) { - count++; - } - - components = (struct jsonsl_jpr_component_st *) - malloc(sizeof(*components) * count); - if (!components) { - JPR_BAIL(JSONSL_ERROR_ENOMEM); - } - - my_copy = (char *)malloc(strlen(path) + 1); - if (!my_copy) { - JPR_BAIL(JSONSL_ERROR_ENOMEM); - } - - strcpy(my_copy, path); - - components[0].ptype = JSONSL_PATH_ROOT; - - if (*my_copy) { - char *cur = my_copy; - int pathret = JSONSL_PATH_STRING; - curidx = 1; - while (curidx < count) { - pathret = populate_component(cur, components + curidx, &cur, errp); - if (pathret > 0) { - curidx++; - } else { - break; - } - } - - if (pathret == JSONSL_PATH_INVALID) { - JPR_BAIL(JSONSL_ERROR_JPR_BADPATH); - } - } else { - curidx = 1; - } - - path--; /*revert path to leading '/' */ - origlen = strlen(path) + 1; - ret = (struct jsonsl_jpr_st *)malloc(sizeof(*ret)); - if (!ret) { - JPR_BAIL(JSONSL_ERROR_ENOMEM); - } - ret->orig = (char *)malloc(origlen); - if (!ret->orig) { - JPR_BAIL(JSONSL_ERROR_ENOMEM); - } - ret->components = components; - ret->ncomponents = curidx; - ret->basestr = my_copy; - ret->norig = origlen-1; - strcpy(ret->orig, path); - - return ret; - - GT_ERROR: - free(my_copy); - free(components); - if (ret) { - free(ret->orig); - } - free(ret); - return NULL; -#undef JPR_BAIL -} - -void jsonsl_jpr_destroy(jsonsl_jpr_t jpr) -{ - free(jpr->components); - free(jpr->basestr); - free(jpr->orig); - free(jpr); -} - -/** - * Call when there is a possibility of a match, either as a final match or - * as a path within a match - * @param jpr The JPR path - * @param component Component corresponding to the current element - * @param prlevel The level of the *parent* - * @param chtype The type of the child - * @return Match status - */ -static jsonsl_jpr_match_t -jsonsl__match_continue(jsonsl_jpr_t jpr, - const struct jsonsl_jpr_component_st *component, - unsigned prlevel, unsigned chtype) -{ - const struct jsonsl_jpr_component_st *next_comp = component + 1; - if (prlevel == jpr->ncomponents - 1) { - /* This is the match. Check the expected type of the match against - * the child */ - if (jpr->match_type == 0 || jpr->match_type == chtype) { - return JSONSL_MATCH_COMPLETE; - } else { - return JSONSL_MATCH_TYPE_MISMATCH; - } - } - if (chtype == JSONSL_T_LIST) { - if (next_comp->ptype == JSONSL_PATH_NUMERIC) { - return JSONSL_MATCH_POSSIBLE; - } else { - return JSONSL_MATCH_TYPE_MISMATCH; - } - } else if (chtype == JSONSL_T_OBJECT) { - if (next_comp->ptype == JSONSL_PATH_NUMERIC) { - return JSONSL_MATCH_TYPE_MISMATCH; - } else { - return JSONSL_MATCH_POSSIBLE; - } - } else { - return JSONSL_MATCH_TYPE_MISMATCH; - } -} - -JSONSL_API -jsonsl_jpr_match_t -jsonsl_path_match(jsonsl_jpr_t jpr, - const struct jsonsl_state_st *parent, - const struct jsonsl_state_st *child, - const char *key, size_t nkey) -{ - const struct jsonsl_jpr_component_st *comp; - if (!parent) { - /* No parent. Return immediately since it's always a match */ - return jsonsl__match_continue(jpr, jpr->components, 0, child->type); - } - - comp = jpr->components + parent->level; - - /* note that we don't need to verify the type of the match, this is - * always done through the previous call to jsonsl__match_continue. - * If we are in a POSSIBLE tree then we can be certain the types (at - * least at this level) are correct */ - if (parent->type == JSONSL_T_OBJECT) { - if (comp->len != nkey || strncmp(key, comp->pstr, nkey) != 0) { - return JSONSL_MATCH_NOMATCH; - } - } else { - if (comp->idx != parent->nelem - 1) { - return JSONSL_MATCH_NOMATCH; - } - } - return jsonsl__match_continue(jpr, comp, parent->level, child->type); -} - -JSONSL_API -jsonsl_jpr_match_t -jsonsl_jpr_match(jsonsl_jpr_t jpr, - unsigned int parent_type, - unsigned int parent_level, - const char *key, - size_t nkey) -{ - /* find our current component. This is the child level */ - int cmpret; - struct jsonsl_jpr_component_st *p_component; - p_component = jpr->components + parent_level; - - if (parent_level >= jpr->ncomponents) { - return JSONSL_MATCH_NOMATCH; - } - - /* Lone query for 'root' element. Always matches */ - if (parent_level == 0) { - if (jpr->ncomponents == 1) { - return JSONSL_MATCH_COMPLETE; - } else { - return JSONSL_MATCH_POSSIBLE; - } - } - - /* Wildcard, always matches */ - if (p_component->ptype == JSONSL_PATH_WILDCARD) { - if (parent_level == jpr->ncomponents-1) { - return JSONSL_MATCH_COMPLETE; - } else { - return JSONSL_MATCH_POSSIBLE; - } - } - - /* Check numeric array index. This gets its special block so we can avoid - * string comparisons */ - if (p_component->ptype == JSONSL_PATH_NUMERIC) { - if (parent_type == JSONSL_T_LIST) { - if (p_component->idx != nkey) { - /* Wrong index */ - return JSONSL_MATCH_NOMATCH; - } else { - if (parent_level == jpr->ncomponents-1) { - /* This is the last element of the path */ - return JSONSL_MATCH_COMPLETE; - } else { - /* Intermediate element */ - return JSONSL_MATCH_POSSIBLE; - } - } - } else if (p_component->is_arridx) { - /* Numeric and an array index (set explicitly by user). But not - * a list for a parent */ - return JSONSL_MATCH_TYPE_MISMATCH; - } - } else if (parent_type == JSONSL_T_LIST) { - return JSONSL_MATCH_TYPE_MISMATCH; - } - - /* Check lengths */ - if (p_component->len != nkey) { - return JSONSL_MATCH_NOMATCH; - } - - /* Check string comparison */ - cmpret = strncmp(p_component->pstr, key, nkey); - if (cmpret == 0) { - if (parent_level == jpr->ncomponents-1) { - return JSONSL_MATCH_COMPLETE; - } else { - return JSONSL_MATCH_POSSIBLE; - } - } - - return JSONSL_MATCH_NOMATCH; -} - -JSONSL_API -void jsonsl_jpr_match_state_init(jsonsl_t jsn, - jsonsl_jpr_t *jprs, - size_t njprs) -{ - size_t ii, *firstjmp; - if (njprs == 0) { - return; - } - jsn->jprs = (jsonsl_jpr_t *)malloc(sizeof(jsonsl_jpr_t) * njprs); - jsn->jpr_count = njprs; - jsn->jpr_root = (size_t*)calloc(1, sizeof(size_t) * njprs * jsn->levels_max); - memcpy(jsn->jprs, jprs, sizeof(jsonsl_jpr_t) * njprs); - /* Set the initial jump table values */ - - firstjmp = jsn->jpr_root; - for (ii = 0; ii < njprs; ii++) { - firstjmp[ii] = ii+1; - } -} - -JSONSL_API -void jsonsl_jpr_match_state_cleanup(jsonsl_t jsn) -{ - if (jsn->jpr_count == 0) { - return; - } - - free(jsn->jpr_root); - free(jsn->jprs); - jsn->jprs = NULL; - jsn->jpr_root = NULL; - jsn->jpr_count = 0; -} - -/** - * This function should be called exactly once on each element... - * This should also be called in recursive order, since we rely - * on the parent having been initialized for a match. - * - * Since the parent is checked for a match as well, we maintain a 'serial' counter. - * Whenever we traverse an element, we expect the serial to be the same as a global - * integer. If they do not match, we re-initialize the context, and set the serial. - * - * This ensures a type of consistency without having a proactive reset by the - * main lexer itself. - * - */ -JSONSL_API -jsonsl_jpr_t jsonsl_jpr_match_state(jsonsl_t jsn, - struct jsonsl_state_st *state, - const char *key, - size_t nkey, - jsonsl_jpr_match_t *out) -{ - struct jsonsl_state_st *parent_state; - jsonsl_jpr_t ret = NULL; - - /* Jump and JPR tables for our own state and the parent state */ - size_t *jmptable, *pjmptable; - size_t jmp_cur, ii, ourjmpidx; - - if (!jsn->jpr_root) { - *out = JSONSL_MATCH_NOMATCH; - return NULL; - } - - pjmptable = jsn->jpr_root + (jsn->jpr_count * (state->level-1)); - jmptable = pjmptable + jsn->jpr_count; - - /* If the parent cannot match, then invalidate it */ - if (*pjmptable == 0) { - *jmptable = 0; - *out = JSONSL_MATCH_NOMATCH; - return NULL; - } - - parent_state = jsn->stack + state->level - 1; - - if (parent_state->type == JSONSL_T_LIST) { - nkey = (size_t) parent_state->nelem; - } - - *jmptable = 0; - ourjmpidx = 0; - memset(jmptable, 0, sizeof(int) * jsn->jpr_count); - - for (ii = 0; ii < jsn->jpr_count; ii++) { - jmp_cur = pjmptable[ii]; - if (jmp_cur) { - jsonsl_jpr_t jpr = jsn->jprs[jmp_cur-1]; - *out = jsonsl_jpr_match(jpr, - parent_state->type, - parent_state->level, - key, nkey); - if (*out == JSONSL_MATCH_COMPLETE) { - ret = jpr; - *jmptable = 0; - return ret; - } else if (*out == JSONSL_MATCH_POSSIBLE) { - jmptable[ourjmpidx] = ii+1; - ourjmpidx++; - } - } else { - break; - } - } - if (!*jmptable) { - *out = JSONSL_MATCH_NOMATCH; - } - return NULL; -} - -JSONSL_API -const char *jsonsl_strmatchtype(jsonsl_jpr_match_t match) -{ -#define X(T,v) \ - if ( match == JSONSL_MATCH_##T ) \ - return #T; - JSONSL_XMATCH -#undef X - return ""; -} - -#endif /* JSONSL_WITH_JPR */ - -static char * -jsonsl__writeutf8(uint32_t pt, char *out) -{ - #define ADD_OUTPUT(c) *out = (char)(c); out++; - - if (pt < 0x80) { - ADD_OUTPUT(pt); - } else if (pt < 0x800) { - ADD_OUTPUT((pt >> 6) | 0xC0); - ADD_OUTPUT((pt & 0x3F) | 0x80); - } else if (pt < 0x10000) { - ADD_OUTPUT((pt >> 12) | 0xE0); - ADD_OUTPUT(((pt >> 6) & 0x3F) | 0x80); - ADD_OUTPUT((pt & 0x3F) | 0x80); - } else { - ADD_OUTPUT((pt >> 18) | 0xF0); - ADD_OUTPUT(((pt >> 12) & 0x3F) | 0x80); - ADD_OUTPUT(((pt >> 6) & 0x3F) | 0x80); - ADD_OUTPUT((pt & 0x3F) | 0x80); - } - return out; - #undef ADD_OUTPUT -} - -/* Thanks snej (https://github.com/mnunberg/jsonsl/issues/9) */ -static int -jsonsl__digit2int(char ch) { - int d = ch - '0'; - if ((unsigned) d < 10) { - return d; - } - d = ch - 'a'; - if ((unsigned) d < 6) { - return d + 10; - } - d = ch - 'A'; - if ((unsigned) d < 6) { - return d + 10; - } - return -1; -} - -/* Assume 's' is at least 4 bytes long */ -static int -jsonsl__get_uescape_16(const char *s) -{ - int ret = 0; - int cur; - - #define GET_DIGIT(off) \ - cur = jsonsl__digit2int(s[off]); \ - if (cur == -1) { return -1; } \ - ret |= (cur << (12 - (off * 4))); - - GET_DIGIT(0); - GET_DIGIT(1); - GET_DIGIT(2); - GET_DIGIT(3); - #undef GET_DIGIT - return ret; -} - -/** - * Utility function to convert escape sequences - */ -JSONSL_API -size_t jsonsl_util_unescape_ex(const char *in, - char *out, - size_t len, - const int toEscape[128], - unsigned *oflags, - jsonsl_error_t *err, - const char **errat) -{ - const unsigned char *c = (const unsigned char*)in; - char *begin_p = out; - unsigned oflags_s; - uint16_t last_codepoint = 0; - - if (!oflags) { - oflags = &oflags_s; - } - *oflags = 0; - - #define UNESCAPE_BAIL(e,offset) \ - *err = JSONSL_ERROR_##e; \ - if (errat) { \ - *errat = (const char*)(c+ (ptrdiff_t)(offset)); \ - } \ - return 0; - - for (; len; len--, c++, out++) { - int uescval; - if (*c != '\\') { - /* Not an escape, so we don't care about this */ - goto GT_ASSIGN; - } - - if (len < 2) { - UNESCAPE_BAIL(ESCAPE_INVALID, 0); - } - if (!is_allowed_escape(c[1])) { - UNESCAPE_BAIL(ESCAPE_INVALID, 1) - } - if ((toEscape && toEscape[(unsigned char)c[1] & 0x7f] == 0 && - c[1] != '\\' && c[1] != '"')) { - /* if we don't want to unescape this string, write the escape sequence to the output */ - *out++ = *c++; - --len; - goto GT_ASSIGN; - } - - if (c[1] != 'u') { - /* simple skip-and-replace using pre-defined maps. - * TODO: should the maps actually reflect the desired - * replacement character in toEscape? - */ - char esctmp = get_escape_equiv(c[1]); - if (esctmp) { - /* Check if there is a corresponding replacement */ - *out = esctmp; - } else { - /* Just gobble up the 'reverse-solidus' */ - *out = c[1]; - } - len--; - c++; - /* do not assign, just continue */ - continue; - } - - /* next == 'u' */ - if (len < 6) { - /* Need at least six characters.. */ - UNESCAPE_BAIL(UESCAPE_TOOSHORT, 2); - } - - uescval = jsonsl__get_uescape_16((const char *)c + 2); - if (uescval == -1) { - UNESCAPE_BAIL(PERCENT_BADHEX, -1); - } - - if (last_codepoint) { - uint16_t w1 = last_codepoint, w2 = (uint16_t)uescval; - uint32_t cp; - - if (uescval < 0xDC00 || uescval > 0xDFFF) { - UNESCAPE_BAIL(INVALID_CODEPOINT, -1); - } - - cp = (w1 & 0x3FF) << 10; - cp |= (w2 & 0x3FF); - cp += 0x10000; - - out = jsonsl__writeutf8(cp, out) - 1; - last_codepoint = 0; - - } else if (uescval < 0xD800 || uescval > 0xDFFF) { - *oflags |= JSONSL_SPECIALf_NONASCII; - out = jsonsl__writeutf8(uescval, out) - 1; - - } else if (uescval < 0xDC00) { - *oflags |= JSONSL_SPECIALf_NONASCII; - last_codepoint = (uint16_t)uescval; - out--; - } else { - UNESCAPE_BAIL(INVALID_CODEPOINT, 2); - } - - /* Post uescape cleanup */ - len -= 5; /* Gobble up 5 chars after 'u' */ - c += 5; - continue; - - /* Only reached by previous branches */ - GT_ASSIGN: - *out = *c; - } - - if (last_codepoint) { - *err = JSONSL_ERROR_INVALID_CODEPOINT; - return 0; - } - - *err = JSONSL_ERROR_SUCCESS; - return out - begin_p; -} - -/** - * Character Table definitions. - * These were all generated via srcutil/genchartables.pl - */ - -/** - * This table contains the beginnings of non-string - * allowable (bareword) values. - */ -static unsigned short Special_Table[0x100] = { - /* 0x00 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 0x1f */ - /* 0x20 */ 0,0,0,0,0,0,0,0,0,0,0,0,0, /* 0x2c */ - /* 0x2d */ JSONSL_SPECIALf_DASH /* <-> */, /* 0x2d */ - /* 0x2e */ 0,0, /* 0x2f */ - /* 0x30 */ JSONSL_SPECIALf_ZERO /* <0> */, /* 0x30 */ - /* 0x31 */ JSONSL_SPECIALf_UNSIGNED /* <1> */, /* 0x31 */ - /* 0x32 */ JSONSL_SPECIALf_UNSIGNED /* <2> */, /* 0x32 */ - /* 0x33 */ JSONSL_SPECIALf_UNSIGNED /* <3> */, /* 0x33 */ - /* 0x34 */ JSONSL_SPECIALf_UNSIGNED /* <4> */, /* 0x34 */ - /* 0x35 */ JSONSL_SPECIALf_UNSIGNED /* <5> */, /* 0x35 */ - /* 0x36 */ JSONSL_SPECIALf_UNSIGNED /* <6> */, /* 0x36 */ - /* 0x37 */ JSONSL_SPECIALf_UNSIGNED /* <7> */, /* 0x37 */ - /* 0x38 */ JSONSL_SPECIALf_UNSIGNED /* <8> */, /* 0x38 */ - /* 0x39 */ JSONSL_SPECIALf_UNSIGNED /* <9> */, /* 0x39 */ - /* 0x3a */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 0x48 */ - /* 0x49 */ JSONSL__INF_PROXY /* */, /* 0x49 */ - /* 0x4a */ 0,0,0,0, /* 0x4d */ - /* 0x4e */ JSONSL__NAN_PROXY /* */, /* 0x4e */ - /* 0x4f */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 0x65 */ - /* 0x66 */ JSONSL_SPECIALf_FALSE /* */, /* 0x66 */ - /* 0x67 */ 0,0, /* 0x68 */ - /* 0x69 */ JSONSL__INF_PROXY /* */, /* 0x69 */ - /* 0x6a */ 0,0,0,0, /* 0x6d */ - /* 0x6e */ JSONSL_SPECIALf_NULL|JSONSL__NAN_PROXY /* */, /* 0x6e */ - /* 0x6f */ 0,0,0,0,0, /* 0x73 */ - /* 0x74 */ JSONSL_SPECIALf_TRUE /* */, /* 0x74 */ - /* 0x75 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 0x94 */ - /* 0x95 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 0xb4 */ - /* 0xb5 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 0xd4 */ - /* 0xd5 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 0xf4 */ - /* 0xf5 */ 0,0,0,0,0,0,0,0,0,0, /* 0xfe */ -}; - -/** - * Contains characters which signal the termination of any of the 'special' bareword - * values. - */ -static int Special_Endings[0x100] = { - /* 0x00 */ 0,0,0,0,0,0,0,0,0, /* 0x08 */ - /* 0x09 */ 1 /* */, /* 0x09 */ - /* 0x0a */ 1 /* */, /* 0x0a */ - /* 0x0b */ 0,0, /* 0x0c */ - /* 0x0d */ 1 /* */, /* 0x0d */ - /* 0x0e */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 0x1f */ - /* 0x20 */ 1 /* */, /* 0x20 */ - /* 0x21 */ 0, /* 0x21 */ - /* 0x22 */ 1 /* " */, /* 0x22 */ - /* 0x23 */ 0,0,0,0,0,0,0,0,0, /* 0x2b */ - /* 0x2c */ 1 /* , */, /* 0x2c */ - /* 0x2d */ 0,0,0,0,0,0,0,0,0,0,0,0,0, /* 0x39 */ - /* 0x3a */ 1 /* : */, /* 0x3a */ - /* 0x3b */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 0x5a */ - /* 0x5b */ 1 /* [ */, /* 0x5b */ - /* 0x5c */ 1 /* \ */, /* 0x5c */ - /* 0x5d */ 1 /* ] */, /* 0x5d */ - /* 0x5e */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 0x7a */ - /* 0x7b */ 1 /* { */, /* 0x7b */ - /* 0x7c */ 0, /* 0x7c */ - /* 0x7d */ 1 /* } */, /* 0x7d */ - /* 0x7e */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 0x9d */ - /* 0x9e */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 0xbd */ - /* 0xbe */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 0xdd */ - /* 0xde */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 0xfd */ - /* 0xfe */ 0 /* 0xfe */ -}; - -/** - * This table contains entries for the allowed whitespace as per RFC 4627 - */ -static int Allowed_Whitespace[0x100] = { - /* 0x00 */ 0,0,0,0,0,0,0,0,0, /* 0x08 */ - /* 0x09 */ 1 /* */, /* 0x09 */ - /* 0x0a */ 1 /* */, /* 0x0a */ - /* 0x0b */ 0,0, /* 0x0c */ - /* 0x0d */ 1 /* */, /* 0x0d */ - /* 0x0e */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 0x1f */ - /* 0x20 */ 1 /* */, /* 0x20 */ - /* 0x21 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 0x40 */ - /* 0x41 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 0x60 */ - /* 0x61 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 0x80 */ - /* 0x81 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 0xa0 */ - /* 0xa1 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 0xc0 */ - /* 0xc1 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 0xe0 */ - /* 0xe1 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 /* 0xfe */ -}; - -static const int String_No_Passthrough[0x100] = { - /* 0x00 */ 1 /* */, /* 0x00 */ - /* 0x01 */ 1 /* */, /* 0x01 */ - /* 0x02 */ 1 /* */, /* 0x02 */ - /* 0x03 */ 1 /* */, /* 0x03 */ - /* 0x04 */ 1 /* */, /* 0x04 */ - /* 0x05 */ 1 /* */, /* 0x05 */ - /* 0x06 */ 1 /* */, /* 0x06 */ - /* 0x07 */ 1 /* */, /* 0x07 */ - /* 0x08 */ 1 /* */, /* 0x08 */ - /* 0x09 */ 1 /* */, /* 0x09 */ - /* 0x0a */ 1 /* */, /* 0x0a */ - /* 0x0b */ 1 /* */, /* 0x0b */ - /* 0x0c */ 1 /* */, /* 0x0c */ - /* 0x0d */ 1 /* */, /* 0x0d */ - /* 0x0e */ 1 /* */, /* 0x0e */ - /* 0x0f */ 1 /* */, /* 0x0f */ - /* 0x10 */ 1 /* */, /* 0x10 */ - /* 0x11 */ 1 /* */, /* 0x11 */ - /* 0x12 */ 1 /* */, /* 0x12 */ - /* 0x13 */ 1 /* */, /* 0x13 */ - /* 0x14 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 0x21 */ - /* 0x22 */ 1 /* <"> */, /* 0x22 */ - /* 0x23 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 0x42 */ - /* 0x43 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 0x5b */ - /* 0x5c */ 1 /* <\> */, /* 0x5c */ - /* 0x5d */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 0x7c */ - /* 0x7d */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 0x9c */ - /* 0x9d */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 0xbc */ - /* 0xbd */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 0xdc */ - /* 0xdd */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 0xfc */ - /* 0xfd */ 0,0, /* 0xfe */ -}; - -/** - * Allowable two-character 'common' escapes: - */ -static int Allowed_Escapes[0x100] = { - /* 0x00 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 0x1f */ - /* 0x20 */ 0,0, /* 0x21 */ - /* 0x22 */ 1 /* <"> */, /* 0x22 */ - /* 0x23 */ 0,0,0,0,0,0,0,0,0,0,0,0, /* 0x2e */ - /* 0x2f */ 1 /* */, /* 0x2f */ - /* 0x30 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 0x4f */ - /* 0x50 */ 0,0,0,0,0,0,0,0,0,0,0,0, /* 0x5b */ - /* 0x5c */ 1 /* <\> */, /* 0x5c */ - /* 0x5d */ 0,0,0,0,0, /* 0x61 */ - /* 0x62 */ 1 /* */, /* 0x62 */ - /* 0x63 */ 0,0,0, /* 0x65 */ - /* 0x66 */ 1 /* */, /* 0x66 */ - /* 0x67 */ 0,0,0,0,0,0,0, /* 0x6d */ - /* 0x6e */ 1 /* */, /* 0x6e */ - /* 0x6f */ 0,0,0, /* 0x71 */ - /* 0x72 */ 1 /* */, /* 0x72 */ - /* 0x73 */ 0, /* 0x73 */ - /* 0x74 */ 1 /* */, /* 0x74 */ - /* 0x75 */ 1 /* */, /* 0x75 */ - /* 0x76 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 0x95 */ - /* 0x96 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 0xb5 */ - /* 0xb6 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 0xd5 */ - /* 0xd6 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 0xf5 */ - /* 0xf6 */ 0,0,0,0,0,0,0,0,0, /* 0xfe */ -}; - -/** - * This table contains the _values_ for a given (single) escaped character. - */ -static unsigned char Escape_Equivs[0x100] = { - /* 0x00 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 0x1f */ - /* 0x20 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 0x3f */ - /* 0x40 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 0x5f */ - /* 0x60 */ 0,0, /* 0x61 */ - /* 0x62 */ 8 /* */, /* 0x62 */ - /* 0x63 */ 0,0,0, /* 0x65 */ - /* 0x66 */ 12 /* */, /* 0x66 */ - /* 0x67 */ 0,0,0,0,0,0,0, /* 0x6d */ - /* 0x6e */ 10 /* */, /* 0x6e */ - /* 0x6f */ 0,0,0, /* 0x71 */ - /* 0x72 */ 13 /* */, /* 0x72 */ - /* 0x73 */ 0, /* 0x73 */ - /* 0x74 */ 9 /* */, /* 0x74 */ - /* 0x75 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 0x94 */ - /* 0x95 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 0xb4 */ - /* 0xb5 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 0xd4 */ - /* 0xd5 */ 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 0xf4 */ - /* 0xf5 */ 0,0,0,0,0,0,0,0,0,0 /* 0xfe */ -}; - -/* Definitions of above-declared static functions */ -static char get_escape_equiv(unsigned c) { - return Escape_Equivs[c & 0xff]; -} -static unsigned extract_special(unsigned c) { - return Special_Table[c & 0xff]; -} -static int is_special_end(unsigned c) { - return Special_Endings[c & 0xff]; -} -static int is_allowed_whitespace(unsigned c) { - return c == ' ' || Allowed_Whitespace[c & 0xff]; -} -static int is_allowed_escape(unsigned c) { - return Allowed_Escapes[c & 0xff]; -} -static int is_simple_char(unsigned c) { - return !String_No_Passthrough[c & 0xff]; -} - -/* Clean up all our macros! */ -#undef INCR_METRIC -#undef INCR_GENERIC -#undef INCR_STRINGY_CATCH -#undef CASE_DIGITS -#undef INVOKE_ERROR -#undef STACK_PUSH -#undef STACK_POP_NOPOS -#undef STACK_POP -#undef CALLBACK_AND_POP_NOPOS -#undef CALLBACK_AND_POP -#undef SPECIAL_POP -#undef CUR_CHAR -#undef DO_CALLBACK -#undef ENSURE_HVAL -#undef VERIFY_SPECIAL -#undef STATE_SPECIAL_LENGTH -#undef IS_NORMAL_NUMBER -#undef STATE_NUM_LAST -#undef FASTPARSE_EXHAUSTED -#undef FASTPARSE_BREAK diff --git a/bsonjs/jsonsl/jsonsl.h b/bsonjs/jsonsl/jsonsl.h deleted file mode 100644 index d4d9832..0000000 --- a/bsonjs/jsonsl/jsonsl.h +++ /dev/null @@ -1,1006 +0,0 @@ -/** - * JSON Simple/Stacked/Stateful Lexer. - * - Does not buffer data - * - Maintains state - * - Callback oriented - * - Lightweight and fast. One source file and one header file - * - * Copyright (C) 2012-2015 Mark Nunberg - * See included LICENSE file for license details. - */ - -#include "../bson/bson-prelude.h" - -#ifndef JSONSL_H_ -#define JSONSL_H_ - -#include -#include -#include -#include -#include -#include - -#ifdef __cplusplus -extern "C" { -#endif /* __cplusplus */ - -#ifdef JSONSL_USE_WCHAR -typedef jsonsl_char_t wchar_t; -typedef jsonsl_uchar_t unsigned wchar_t; -#else -typedef char jsonsl_char_t; -typedef unsigned char jsonsl_uchar_t; -#endif /* JSONSL_USE_WCHAR */ - -#ifdef JSONSL_PARSE_NAN -#define JSONSL__NAN_PROXY JSONSL_SPECIALf_NAN -#define JSONSL__INF_PROXY JSONSL_SPECIALf_INF -#else -#define JSONSL__NAN_PROXY 0 -#define JSONSL__INF_PROXY 0 -#endif - -/* Stolen from http-parser.h, and possibly others */ -#if defined(_WIN32) && !defined(__MINGW32__) && (!defined(_MSC_VER) || _MSC_VER<1600) -typedef __int8 int8_t; -typedef unsigned __int8 uint8_t; -typedef __int16 int16_t; -typedef unsigned __int16 uint16_t; -typedef __int32 int32_t; -typedef unsigned __int32 uint32_t; -typedef __int64 int64_t; -typedef unsigned __int64 uint64_t; -#if !defined(_MSC_VER) || _MSC_VER<1400 -typedef unsigned int size_t; -typedef int ssize_t; -#endif -#else -#include -#endif - - -#if (!defined(JSONSL_STATE_GENERIC)) && (!defined(JSONSL_STATE_USER_FIELDS)) -#define JSONSL_STATE_GENERIC -#endif /* !defined JSONSL_STATE_GENERIC */ - -#ifdef JSONSL_STATE_GENERIC -#define JSONSL_STATE_USER_FIELDS -#endif /* JSONSL_STATE_GENERIC */ - -/* Additional fields for component object */ -#ifndef JSONSL_JPR_COMPONENT_USER_FIELDS -#define JSONSL_JPR_COMPONENT_USER_FIELDS -#endif - -#ifndef JSONSL_API -/** - * We require a /DJSONSL_DLL so that users already using this as a static - * or embedded library don't get confused - */ -#if defined(_WIN32) && defined(JSONSL_DLL) -#define JSONSL_API __declspec(dllexport) -#else -#define JSONSL_API -#endif /* _WIN32 */ - -#endif /* !JSONSL_API */ - -#ifndef JSONSL_INLINE -#if defined(_MSC_VER) - #define JSONSL_INLINE __inline - #elif defined(__GNUC__) - #define JSONSL_INLINE __inline__ - #else - #define JSONSL_INLINE inline - #endif /* _MSC_VER or __GNUC__ */ -#endif /* JSONSL_INLINE */ - -#define JSONSL_MAX_LEVELS 512 - -struct jsonsl_st; -typedef struct jsonsl_st *jsonsl_t; - -typedef struct jsonsl_jpr_st* jsonsl_jpr_t; - -/** - * This flag is true when AND'd against a type whose value - * must be in "quoutes" i.e. T_HKEY and T_STRING - */ -#define JSONSL_Tf_STRINGY 0xffff00 - -/** - * Constant representing the special JSON types. - * The values are special and aid in speed (the OBJECT and LIST - * values are the char literals of their openings). - * - * Their actual value is a character which attempts to resemble - * some mnemonic reference to the actual type. - * - * If new types are added, they must fit into the ASCII printable - * range (so they should be AND'd with 0x7f and yield something - * meaningful) - */ -#define JSONSL_XTYPE \ - X(STRING, '"'|JSONSL_Tf_STRINGY) \ - X(HKEY, '#'|JSONSL_Tf_STRINGY) \ - X(OBJECT, '{') \ - X(LIST, '[') \ - X(SPECIAL, '^') \ - X(UESCAPE, 'u') -typedef enum { -#define X(o, c) \ - JSONSL_T_##o = c, - JSONSL_XTYPE - JSONSL_T_UNKNOWN = '?', - /* Abstract 'root' object */ - JSONSL_T_ROOT = 0 -#undef X -} jsonsl_type_t; - -/** - * Subtypes for T_SPECIAL. We define them as flags - * because more than one type can be applied to a - * given object. - */ - -#define JSONSL_XSPECIAL \ - X(NONE, 0) \ - X(SIGNED, 1<<0) \ - X(UNSIGNED, 1<<1) \ - X(TRUE, 1<<2) \ - X(FALSE, 1<<3) \ - X(NULL, 1<<4) \ - X(FLOAT, 1<<5) \ - X(EXPONENT, 1<<6) \ - X(NONASCII, 1<<7) \ - X(NAN, 1<<8) \ - X(INF, 1<<9) -typedef enum { -#define X(o,b) \ - JSONSL_SPECIALf_##o = b, - JSONSL_XSPECIAL -#undef X - /* Handy flags for checking */ - - JSONSL_SPECIALf_UNKNOWN = 1 << 10, - - /** @private Private */ - JSONSL_SPECIALf_ZERO = 1 << 11 | JSONSL_SPECIALf_UNSIGNED, - /** @private */ - JSONSL_SPECIALf_DASH = 1 << 12, - /** @private */ - JSONSL_SPECIALf_POS_INF = (JSONSL_SPECIALf_INF), - JSONSL_SPECIALf_NEG_INF = (JSONSL_SPECIALf_INF|JSONSL_SPECIALf_SIGNED), - - /** Type is numeric */ - JSONSL_SPECIALf_NUMERIC = (JSONSL_SPECIALf_SIGNED| JSONSL_SPECIALf_UNSIGNED), - - /** Type is a boolean */ - JSONSL_SPECIALf_BOOLEAN = (JSONSL_SPECIALf_TRUE|JSONSL_SPECIALf_FALSE), - - /** Type is an "extended", not integral type (but numeric) */ - JSONSL_SPECIALf_NUMNOINT = - (JSONSL_SPECIALf_FLOAT|JSONSL_SPECIALf_EXPONENT|JSONSL_SPECIALf_NAN - |JSONSL_SPECIALf_INF) -} jsonsl_special_t; - - -/** - * These are the various types of stack (or other) events - * which will trigger a callback. - * Like the type constants, this are also mnemonic - */ -#define JSONSL_XACTION \ - X(PUSH, '+') \ - X(POP, '-') \ - X(UESCAPE, 'U') \ - X(ERROR, '!') -typedef enum { -#define X(a,c) \ - JSONSL_ACTION_##a = c, - JSONSL_XACTION - JSONSL_ACTION_UNKNOWN = '?' -#undef X -} jsonsl_action_t; - - -/** - * Various errors which may be thrown while parsing JSON - */ -#define JSONSL_XERR \ -/* Trailing garbage characters */ \ - X(GARBAGE_TRAILING) \ -/* We were expecting a 'special' (numeric, true, false, null) */ \ - X(SPECIAL_EXPECTED) \ -/* The 'special' value was incomplete */ \ - X(SPECIAL_INCOMPLETE) \ -/* Found a stray token */ \ - X(STRAY_TOKEN) \ -/* We were expecting a token before this one */ \ - X(MISSING_TOKEN) \ -/* Cannot insert because the container is not ready */ \ - X(CANT_INSERT) \ -/* Found a '\' outside a string */ \ - X(ESCAPE_OUTSIDE_STRING) \ -/* Found a ':' outside of a hash */ \ - X(KEY_OUTSIDE_OBJECT) \ -/* found a string outside of a container */ \ - X(STRING_OUTSIDE_CONTAINER) \ -/* Found a null byte in middle of string */ \ - X(FOUND_NULL_BYTE) \ -/* Current level exceeds limit specified in constructor */ \ - X(LEVELS_EXCEEDED) \ -/* Got a } as a result of an opening [ or vice versa */ \ - X(BRACKET_MISMATCH) \ -/* We expected a key, but got something else instead */ \ - X(HKEY_EXPECTED) \ -/* We got an illegal control character (bad whitespace or something) */ \ - X(WEIRD_WHITESPACE) \ -/* Found a \u-escape, but there were less than 4 following hex digits */ \ - X(UESCAPE_TOOSHORT) \ -/* Invalid two-character escape */ \ - X(ESCAPE_INVALID) \ -/* Trailing comma */ \ - X(TRAILING_COMMA) \ -/* An invalid number was passed in a numeric field */ \ - X(INVALID_NUMBER) \ -/* Value is missing for object */ \ - X(VALUE_EXPECTED) \ -/* The following are for JPR Stuff */ \ - \ -/* Found a literal '%' but it was only followed by a single valid hex digit */ \ - X(PERCENT_BADHEX) \ -/* jsonpointer URI is malformed '/' */ \ - X(JPR_BADPATH) \ -/* Duplicate slash */ \ - X(JPR_DUPSLASH) \ -/* No leading root */ \ - X(JPR_NOROOT) \ -/* Allocation failure */ \ - X(ENOMEM) \ -/* Invalid unicode codepoint detected (in case of escapes) */ \ - X(INVALID_CODEPOINT) - -typedef enum { - JSONSL_ERROR_SUCCESS = 0, -#define X(e) \ - JSONSL_ERROR_##e, - JSONSL_XERR -#undef X - JSONSL_ERROR_GENERIC -} jsonsl_error_t; - - -/** - * A state is a single level of the stack. - * Non-private data (i.e. the 'data' field, see the STATE_GENERIC section) - * will remain in tact until the item is popped. - * - * As a result, it means a parent state object may be accessed from a child - * object, (the parents fields will all be valid). This allows a user to create - * an ad-hoc hierarchy on top of the JSON one. - * - */ -struct jsonsl_state_st { - /** - * The JSON object type - */ - unsigned type; - - /** If this element is special, then its extended type is here */ - unsigned special_flags; - - /** - * The position (in terms of number of bytes since the first call to - * jsonsl_feed()) at which the state was first pushed. This includes - * opening tokens, if applicable. - * - * @note For strings (i.e. type & JSONSL_Tf_STRINGY is nonzero) this will - * be the position of the first quote. - * - * @see jsonsl_st::pos which contains the _current_ position and can be - * used during a POP callback to get the length of the element. - */ - size_t pos_begin; - - /**FIXME: This is redundant as the same information can be derived from - * jsonsl_st::pos at pop-time */ - size_t pos_cur; - - /** - * Level of recursion into nesting. This is mainly a convenience - * variable, as this can technically be deduced from the lexer's - * level parameter (though the logic is not that simple) - */ - unsigned int level; - - - /** - * how many elements in the object/list. - * For objects (hashes), an element is either - * a key or a value. Thus for one complete pair, - * nelem will be 2. - * - * For special types, this will hold the sum of the digits. - * This only holds true for values which are simple signed/unsigned - * numbers. Otherwise a special flag is set, and extra handling is not - * performed. - */ - uint64_t nelem; - - - - /*TODO: merge this and special_flags into a union */ - - - /** - * Useful for an opening nest, this will prevent a callback from being - * invoked on this item or any of its children - */ - int ignore_callback; - - /** - * Counter which is incremented each time an escape ('\') is encountered. - * This is used internally for non-string types and should only be - * inspected by the user if the state actually represents a string - * type. - */ - unsigned int nescapes; - - /** - * Put anything you want here. if JSONSL_STATE_USER_FIELDS is here, then - * the macro expansion happens here. - * - * You can use these fields to store hierarchical or 'tagging' information - * for specific objects. - * - * See the documentation above for the lifetime of the state object (i.e. - * if the private data points to allocated memory, it should be freed - * when the object is popped, as the state object will be re-used) - */ -#ifndef JSONSL_STATE_GENERIC - JSONSL_STATE_USER_FIELDS -#else - - /** - * Otherwise, this is a simple void * pointer for anything you want - */ - void *data; -#endif /* JSONSL_STATE_USER_FIELDS */ -}; - -/**Gets the number of elements in the list. - * @param st The state. Must be of type JSONSL_T_LIST - * @return number of elements in the list - */ -#define JSONSL_LIST_SIZE(st) ((st)->nelem) - -/**Gets the number of key-value pairs in an object - * @param st The state. Must be of type JSONSL_T_OBJECT - * @return the number of key-value pairs in the object - */ -#define JSONSL_OBJECT_SIZE(st) ((st)->nelem / 2) - -/**Gets the numeric value. - * @param st The state. Must be of type JSONSL_T_SPECIAL and - * special_flags must have the JSONSL_SPECIALf_NUMERIC flag - * set. - * @return the numeric value of the state. - */ -#define JSONSL_NUMERIC_VALUE(st) ((st)->nelem) - -/* - * So now we need some special structure for keeping the - * JPR info in sync. Preferably all in a single block - * of memory (there's no need for separate allocations. - * So we will define a 'table' with the following layout - * - * Level nPosbl JPR1_last JPR2_last JPR3_last - * - * 0 1 NOMATCH POSSIBLE POSSIBLE - * 1 0 NOMATCH NOMATCH COMPLETE - * [ table ends here because no further path is possible] - * - * Where the JPR..n corresponds to the number of JPRs - * requested, and nPosble is a quick flag to determine - * - * the number of possibilities. In the future this might - * be made into a proper 'jump' table, - * - * Since we always mark JPRs from the higher levels descending - * into the lower ones, a prospective child match would first - * look at the parent table to check the possibilities, and then - * see which ones were possible.. - * - * Thus, the size of this blob would be (and these are all ints here) - * nLevels * nJPR * 2. - * - * the 'Width' of the table would be nJPR*2, and the 'height' would be - * nlevels - */ - -/** - * This is called when a stack change ocurs. - * - * @param jsn The lexer - * @param action The type of action, this can be PUSH or POP - * @param state A pointer to the stack currently affected by the action - * @param at A pointer to the position of the input buffer which triggered - * this action. - */ -typedef void (*jsonsl_stack_callback)( - jsonsl_t jsn, - jsonsl_action_t action, - struct jsonsl_state_st* state, - const jsonsl_char_t *at); - - -/** - * This is called when an error is encountered. - * Sometimes it's possible to 'erase' characters (by replacing them - * with whitespace). If you think you have corrected the error, you - * can return a true value, in which case the parser will backtrack - * and try again. - * - * @param jsn The lexer - * @param error The error which was thrown - * @param state the current state - * @param a pointer to the position of the input buffer which triggered - * the error. Note that this is not const, this is because you have the - * possibility of modifying the character in an attempt to correct the - * error - * - * @return zero to bail, nonzero to try again (this only makes sense if - * the input buffer has been modified by this callback) - */ -typedef int (*jsonsl_error_callback)( - jsonsl_t jsn, - jsonsl_error_t error, - struct jsonsl_state_st* state, - jsonsl_char_t *at); - -struct jsonsl_st { - /** Public, read-only */ - - /** This is the current level of the stack */ - unsigned int level; - - /** Flag set to indicate we should stop processing */ - unsigned int stopfl; - - /** - * This is the current position, relative to the beginning - * of the stream. - */ - size_t pos; - - /** This is the 'bytes' variable passed to feed() */ - const jsonsl_char_t *base; - - /** Callback invoked for PUSH actions */ - jsonsl_stack_callback action_callback_PUSH; - - /** Callback invoked for POP actions */ - jsonsl_stack_callback action_callback_POP; - - /** Default callback for any action, if neither PUSH or POP callbacks are defined */ - jsonsl_stack_callback action_callback; - - /** - * Do not invoke callbacks for objects deeper than this level. - * NOTE: This field establishes the lower bound for ignored callbacks, - * and is thus misnamed. `min_ignore_level` would actually make more - * sense, but we don't want to break API. - */ - unsigned int max_callback_level; - - /** The error callback. Invoked when an error happens. Should not be NULL */ - jsonsl_error_callback error_callback; - - /* these are boolean flags you can modify. You will be called - * about notification for each of these types if the corresponding - * variable is true. - */ - - /** - * @name Callback Booleans. - * These determine whether a callback is to be invoked for certain types of objects - * @{*/ - - /** Boolean flag to enable or disable the invokcation for events on this type*/ - int call_SPECIAL; - int call_OBJECT; - int call_LIST; - int call_STRING; - int call_HKEY; - /*@}*/ - - /** - * @name u-Escape handling - * Special handling for the \\u-f00d type sequences. These are meant - * to be translated back into the corresponding octet(s). - * A special callback (if set) is invoked with *at=='u'. An application - * may wish to temporarily suspend parsing and handle the 'u-' sequence - * internally (or not). - */ - - /*@{*/ - - /** Callback to be invoked for a u-escape */ - jsonsl_stack_callback action_callback_UESCAPE; - - /** Boolean flag, whether to invoke the callback */ - int call_UESCAPE; - - /** Boolean flag, whether we should return after encountering a u-escape: - * the callback is invoked and then we return if this is true - */ - int return_UESCAPE; - /*@}*/ - - struct { - int allow_trailing_comma; - } options; - - /** Put anything here */ - void *data; - - /*@{*/ - /** Private */ - int in_escape; - char expecting; - char tok_last; - int can_insert; - unsigned int levels_max; - -#ifndef JSONSL_NO_JPR - size_t jpr_count; - jsonsl_jpr_t *jprs; - - /* Root pointer for JPR matching information */ - size_t *jpr_root; -#endif /* JSONSL_NO_JPR */ - /*@}*/ - - /** - * This is the stack. Its upper bound is levels_max, or the - * nlevels argument passed to jsonsl_new. If you modify this structure, - * make sure that this member is last. - */ - struct jsonsl_state_st stack[1]; -}; - - -/** - * Creates a new lexer object, with capacity for recursion up to nlevels - * - * @param nlevels maximum recursion depth - */ -JSONSL_API -jsonsl_t jsonsl_new(int nlevels); - -/** - * Feeds data into the lexer. - * - * @param jsn the lexer object - * @param bytes new data to be fed - * @param nbytes size of new data - */ -JSONSL_API -void jsonsl_feed(jsonsl_t jsn, const jsonsl_char_t *bytes, size_t nbytes); - -/** - * Resets the internal parser state. This does not free the parser - * but does clean it internally, so that the next time feed() is called, - * it will be treated as a new stream - * - * @param jsn the lexer - */ -JSONSL_API -void jsonsl_reset(jsonsl_t jsn); - -/** - * Frees the lexer, cleaning any allocated memory taken - * - * @param jsn the lexer - */ -JSONSL_API -void jsonsl_destroy(jsonsl_t jsn); - -/** - * Gets the 'parent' element, given the current one - * - * @param jsn the lexer - * @param cur the current nest, which should be a struct jsonsl_nest_st - */ -static JSONSL_INLINE -struct jsonsl_state_st *jsonsl_last_state(const jsonsl_t jsn, - const struct jsonsl_state_st *state) -{ - /* Don't complain about overriding array bounds */ - if (state->level > 1) { - return jsn->stack + state->level - 1; - } else { - return NULL; - } -} - -/** - * Gets the state of the last fully consumed child of this parent. This is - * only valid in the parent's POP callback. - * - * @param the lexer - * @return A pointer to the child. - */ -static JSONSL_INLINE -struct jsonsl_state_st *jsonsl_last_child(const jsonsl_t jsn, - const struct jsonsl_state_st *parent) -{ - return jsn->stack + (parent->level + 1); -} - -/**Call to instruct the parser to stop parsing and return. This is valid - * only from within a callback */ -static JSONSL_INLINE -void jsonsl_stop(jsonsl_t jsn) -{ - jsn->stopfl = 1; -} - -/** - * This enables receiving callbacks on all events. Doesn't do - * anything special but helps avoid some boilerplate. - * This does not touch the UESCAPE callbacks or flags. - */ -static JSONSL_INLINE -void jsonsl_enable_all_callbacks(jsonsl_t jsn) -{ - jsn->call_HKEY = 1; - jsn->call_STRING = 1; - jsn->call_OBJECT = 1; - jsn->call_SPECIAL = 1; - jsn->call_LIST = 1; -} - -/** - * A macro which returns true if the current state object can - * have children. This means a list type or an object type. - */ -#define JSONSL_STATE_IS_CONTAINER(state) \ - (state->type == JSONSL_T_OBJECT || state->type == JSONSL_T_LIST) - -/** - * These two functions, dump a string representation - * of the error or type, respectively. They will never - * return NULL - */ -JSONSL_API -const char* jsonsl_strerror(jsonsl_error_t err); -JSONSL_API -const char* jsonsl_strtype(jsonsl_type_t jt); - -/** - * Dumps global metrics to the screen. This is a noop unless - * jsonsl was compiled with JSONSL_USE_METRICS - */ -JSONSL_API -void jsonsl_dump_global_metrics(void); - -/* This macro just here for editors to do code folding */ -#ifndef JSONSL_NO_JPR - -/** - * @name JSON Pointer API - * - * JSONPointer API. This isn't really related to the lexer (at least not yet) - * JSONPointer provides an extremely simple specification for providing - * locations within JSON objects. We will extend it a bit and allow for - * providing 'wildcard' characters by which to be able to 'query' the stream. - * - * See http://tools.ietf.org/html/draft-pbryan-zyp-json-pointer-00 - * - * Currently I'm implementing the 'single query' API which can only use a single - * query component. In the future I will integrate my yet-to-be-published - * Boyer-Moore-esque prefix searching implementation, in order to allow - * multiple paths to be merged into one for quick and efficient searching. - * - * - * JPR (as we'll refer to it within the source) can be used by splitting - * the components into multiple sections, and incrementally 'track' each - * component. When JSONSL delivers a 'pop' callback for a string, or a 'push' - * callback for an object, we will check to see whether the index matching - * the component corresponding to the current level contains a match - * for our path. - * - * In order to do this properly, a structure must be maintained within the - * parent indicating whether its children are possible matches. This flag - * will be 'inherited' by call children which may conform to the match - * specification, and discarded by all which do not (thereby eliminating - * their children from inheriting it). - * - * A successful match is a complete one. One can provide multiple paths with - * multiple levels of matches e.g. - * /foo/bar/baz/^/blah - * - * @{ - */ - -/** The wildcard character */ -#ifndef JSONSL_PATH_WILDCARD_CHAR -#define JSONSL_PATH_WILDCARD_CHAR '^' -#endif /* WILDCARD_CHAR */ - -#define JSONSL_XMATCH \ - X(COMPLETE,1) \ - X(POSSIBLE,0) \ - X(NOMATCH,-1) \ - X(TYPE_MISMATCH, -2) - -typedef enum { - -#define X(T,v) \ - JSONSL_MATCH_##T = v, - JSONSL_XMATCH - -#undef X - JSONSL_MATCH_UNKNOWN -} jsonsl_jpr_match_t; - -typedef enum { - JSONSL_PATH_STRING = 1, - JSONSL_PATH_WILDCARD, - JSONSL_PATH_NUMERIC, - JSONSL_PATH_ROOT, - - /* Special */ - JSONSL_PATH_INVALID = -1, - JSONSL_PATH_NONE = 0 -} jsonsl_jpr_type_t; - -struct jsonsl_jpr_component_st { - /** The string the component points to */ - char *pstr; - /** if this is a numeric type, the number is 'cached' here */ - unsigned long idx; - /** The length of the string */ - size_t len; - /** The type of component (NUMERIC or STRING) */ - jsonsl_jpr_type_t ptype; - - /** Set this to true to enforce type checking between dict keys and array - * indices. jsonsl_jpr_match() will return TYPE_MISMATCH if it detects - * that an array index is actually a child of a dictionary. */ - short is_arridx; - - /* Extra fields (for more advanced searches. Default is empty) */ - JSONSL_JPR_COMPONENT_USER_FIELDS -}; - -struct jsonsl_jpr_st { - /** Path components */ - struct jsonsl_jpr_component_st *components; - size_t ncomponents; - - /**Type of the match to be expected. If nonzero, will be compared against - * the actual type */ - unsigned match_type; - - /** Base of allocated string for components */ - char *basestr; - - /** The original match string. Useful for returning to the user */ - char *orig; - size_t norig; -}; - -/** - * Create a new JPR object. - * - * @param path the JSONPointer path specification. - * @param errp a pointer to a jsonsl_error_t. If this function returns NULL, - * then more details will be in this variable. - * - * @return a new jsonsl_jpr_t object, or NULL on error. - */ -JSONSL_API -jsonsl_jpr_t jsonsl_jpr_new(const char *path, jsonsl_error_t *errp); - -/** - * Destroy a JPR object - */ -JSONSL_API -void jsonsl_jpr_destroy(jsonsl_jpr_t jpr); - -/** - * Match a JSON object against a type and specific level - * - * @param jpr the JPR object - * @param parent_type the type of the parent (should be T_LIST or T_OBJECT) - * @param parent_level the level of the parent - * @param key the 'key' of the child. If the parent is an array, this should be - * empty. - * @param nkey - the length of the key. If the parent is an array (T_LIST), then - * this should be the current index. - * - * NOTE: The key of the child means any kind of associative data related to the - * element. Thus: <<< { "foo" : [ >>, - * the opening array's key is "foo". - * - * @return a status constant. This indicates whether a match was excluded, possible, - * or successful. - */ -JSONSL_API -jsonsl_jpr_match_t jsonsl_jpr_match(jsonsl_jpr_t jpr, - unsigned int parent_type, - unsigned int parent_level, - const char *key, size_t nkey); - -/** - * Alternate matching algorithm. This matching algorithm does not use - * JSONPointer but relies on a more structured searching mechanism. It - * assumes that there is a clear distinction between array indices and - * object keys. In this case, the jsonsl_path_component_st::ptype should - * be set to @ref JSONSL_PATH_NUMERIC for an array index (the - * jsonsl_path_comonent_st::is_arridx field will be removed in a future - * version). - * - * @param jpr The path - * @param parent The parent structure. Can be NULL if this is the root object - * @param child The child structure. Should not be NULL - * @param key Object key, if an object - * @param nkey Length of object key - * @return Status constant if successful - * - * @note - * For successful matching, both the key and the path itself should be normalized - * to contain 'proper' utf8 sequences rather than utf16 '\uXXXX' escapes. This - * should currently be done in the application. Another version of this function - * may use a temporary buffer in such circumstances (allocated by the application). - * - * Since this function also checks the state of the child, it should only - * be called on PUSH callbacks, and not POP callbacks - */ -JSONSL_API -jsonsl_jpr_match_t -jsonsl_path_match(jsonsl_jpr_t jpr, - const struct jsonsl_state_st *parent, - const struct jsonsl_state_st *child, - const char *key, size_t nkey); - - -/** - * Associate a set of JPR objects with a lexer instance. - * This should be called before the lexer has been fed any data (and - * behavior is undefined if you don't adhere to this). - * - * After using this function, you may subsequently call match_state() on - * given states (presumably from within the callbacks). - * - * Note that currently the first JPR is the quickest and comes - * pre-allocated with the state structure. Further JPR objects - * are chained. - * - * @param jsn The lexer - * @param jprs An array of jsonsl_jpr_t objects - * @param njprs How many elements in the jprs array. - */ -JSONSL_API -void jsonsl_jpr_match_state_init(jsonsl_t jsn, - jsonsl_jpr_t *jprs, - size_t njprs); - -/** - * This follows the same semantics as the normal match, - * except we infer parent and type information from the relevant state objects. - * The match status (for all possible JPR objects) is set in the *out parameter. - * - * If a match has succeeded, then its JPR object will be returned. In all other - * instances, NULL is returned; - * - * @param jpr The jsonsl_jpr_t handle - * @param state The jsonsl_state_st which is a candidate - * @param key The hash key (if applicable, can be NULL if parent is list) - * @param nkey Length of hash key (if applicable, can be zero if parent is list) - * @param out A pointer to a jsonsl_jpr_match_t. This will be populated with - * the match result - * - * @return If a match was completed in full, then the JPR object containing - * the matching path will be returned. Otherwise, the return is NULL (note, this - * does not mean matching has failed, it can still be part of the match: check - * the out parameter). - */ -JSONSL_API -jsonsl_jpr_t jsonsl_jpr_match_state(jsonsl_t jsn, - struct jsonsl_state_st *state, - const char *key, - size_t nkey, - jsonsl_jpr_match_t *out); - - -/** - * Cleanup any memory allocated and any states set by - * match_state_init() and match_state() - * @param jsn The lexer - */ -JSONSL_API -void jsonsl_jpr_match_state_cleanup(jsonsl_t jsn); - -/** - * Return a string representation of the match result returned by match() - */ -JSONSL_API -const char *jsonsl_strmatchtype(jsonsl_jpr_match_t match); - -/* @}*/ - -/** - * Utility function to convert escape sequences into their original form. - * - * The decoders I've sampled do not seem to specify a standard behavior of what - * to escape/unescape. - * - * RFC 4627 Mandates only that the quoute, backslash, and ASCII control - * characters (0x00-0x1f) be escaped. It is often common for applications - * to escape a '/' - however this may also be desired behavior. the JSON - * spec is not clear on this, and therefore jsonsl leaves it up to you. - * - * Additionally, sometimes you may wish to _normalize_ JSON. This is specifically - * true when dealing with 'u-escapes' which can be expressed perfectly fine - * as utf8. One use case for normalization is JPR string comparison, in which - * case two effectively equivalent strings may not match because one is using - * u-escapes and the other proper utf8. To normalize u-escapes only, pass in - * an empty `toEscape` table, enabling only the `u` index. - * - * @param in The input string. - * @param out An allocated output (should be the same size as in) - * @param len the size of the buffer - * @param toEscape - A sparse array of characters to unescape. Characters - * which are not present in this array, e.g. toEscape['c'] == 0 will be - * ignored and passed to the output in their original form. - * @param oflags If not null, and a \uXXXX escape expands to a non-ascii byte, - * then this variable will have the SPECIALf_NONASCII flag on. - * - * @param err A pointer to an error variable. If an error ocurrs, it will be - * set in this variable - * @param errat If not null and an error occurs, this will be set to point - * to the position within the string at which the offending character was - * encountered. - * - * @return The effective size of the output buffer. - * - * @note - * This function now encodes the UTF8 equivalents of utf16 escapes (i.e. - * 'u-escapes'). Previously this would encode the escapes as utf16 literals, - * which while still correct in some sense was confusing for many (especially - * considering that the inputs were variations of char). - * - * @note - * The output buffer will never be larger than the input buffer, since - * standard escape sequences (i.e. '\t') occupy two bytes in the source - * but only one byte (when unescaped) in the output. Likewise u-escapes - * (i.e. \uXXXX) will occupy six bytes in the source, but at the most - * two bytes when escaped. - */ -JSONSL_API -size_t jsonsl_util_unescape_ex(const char *in, - char *out, - size_t len, - const int toEscape[128], - unsigned *oflags, - jsonsl_error_t *err, - const char **errat); - -/** - * Convenience macro to avoid passing too many parameters - */ -#define jsonsl_util_unescape(in, out, len, toEscape, err) \ - jsonsl_util_unescape_ex(in, out, len, toEscape, NULL, err, NULL) - -#endif /* JSONSL_NO_JPR */ - -#ifdef __cplusplus -} -#endif /* __cplusplus */ - -#endif /* JSONSL_H_ */ diff --git a/build-wheels.sh b/build-wheels.sh deleted file mode 100755 index e5d1e02..0000000 --- a/build-wheels.sh +++ /dev/null @@ -1,52 +0,0 @@ -#!/bin/bash -ex - -if [ "$#" -ne 1 ]; then - echo "$0 requires one argument: " - echo "For example: $0 /user/home/git/python-bsonjs" - exit 1 -fi - -BSONJS_SOURCE_DIRECTORY="$1" -cd "$BSONJS_SOURCE_DIRECTORY" - -ls -la -if [ -z "$PYTHON_BINARY" ]; then - PYTHON_BINARY="python" -fi - -$PYTHON_BINARY --version - -if [ ! "$(uname)" == "Linux" ]; then - $PYTHON_BINARY -m pip install wheel -fi -# Build limited abi3 wheel. -$PYTHON_BINARY setup.py bdist_wheel -# https://github.com/pypa/manylinux/issues/49 -rm -rf build - -# Audit wheels and write multilinux1 tag -# Only if on linux -if [ "$(uname)" == "Linux" ]; then - for whl in dist/*.whl; do - # Skip already built manylinux wheels. - if [[ "$whl" != *"manylinux"* ]]; then - auditwheel repair $whl -w dist - rm $whl - fi - done -fi - -# Install packages and test. -for PYBIN in /opt/python/*/bin; do - if [[ ! "${PYBIN}" =~ (39|310) || "${PYBIN}" =~ (pypy) ]]; then - continue - fi - "${PYBIN}/pip" install python-bsonjs --no-index -f dist - # The tests require PyMongo. - "${PYBIN}/pip" install 'pymongo>=4' - for TEST_FILE in "${BSONJS_SOURCE_DIRECTORY}"/test/test_*.py; do - "${PYBIN}/python" "$TEST_FILE" -v - done -done - -ls -lah dist diff --git a/docker-build.sh b/docker-build.sh deleted file mode 100755 index 2cc3ecc..0000000 --- a/docker-build.sh +++ /dev/null @@ -1,17 +0,0 @@ -#!/bin/bash - -if [ "$#" -ne 0 ]; then - echo "$0 takes no arguments" - exit 1 -fi - -set -e -x - - -DOCKER_IMAGE=quay.io/pypa/manylinux1_x86_64 -docker pull "$DOCKER_IMAGE" -docker run --rm -v `pwd`:/io "$DOCKER_IMAGE" /io/build-wheels.sh /io - -DOCKER_IMAGE=quay.io/pypa/manylinux1_i686 -docker pull "$DOCKER_IMAGE" -docker run --rm -v `pwd`:/io "$DOCKER_IMAGE" linux32 /io/build-wheels.sh /io diff --git a/meson.build b/meson.build new file mode 100644 index 0000000..32246b3 --- /dev/null +++ b/meson.build @@ -0,0 +1,177 @@ +project( + 'bsonjs', + 'c', + version: '0.8.0.dev0', + meson_version: '>=1.3', + default_options: ['c_std=c99', 'warning_level=1'], +) + +py = import('python').find_installation(pure: false) +fs = import('fs') +cc = meson.get_compiler('c') +threads = dependency('threads') + +# libbson's mlib selects its POSIX clock primitives from _POSIX_C_SOURCE or +# _DEFAULT_SOURCE, and error.c uses strerror_l only when _XOPEN_SOURCE >= 700. +# glibc derives both from _GNU_SOURCE; musl derives neither, so define them +# explicitly. Windows has its own code path (guarded on _WIN32), so leave it out +# entirely there. The feature probes below compile with the same macros so they +# test the environment libbson is actually compiled in. +if host_machine.system() == 'darwin' + feature_args = ['-D_POSIX_C_SOURCE=200809L'] +elif host_machine.system() != 'windows' + feature_args = ['-D_GNU_SOURCE', '-D_DEFAULT_SOURCE', '-D_XOPEN_SOURCE=700'] +else + feature_args = [] +endif +if feature_args.length() > 0 + add_project_arguments(feature_args, language: 'c') +endif + +# --- libbson from source ------------------------------------------------ +# Meson has no FetchContent, so the mongo-c-driver release tarball is +# extracted to .mongo-c-driver/: the CI action pre-fetches it, and meson +# fetches it here when absent. We compile only libbson (static), never +# libmongoc, by listing its sources explicitly. +# +# The pinned release, read by scripts/fetch_mongo_c_driver.py. The SHA256 of +# that tarball is updated by scripts/bump_libbson.py alongside the version. +mcd_version = '2.5.3' +mcd_sha256 = '5eb6f2297f5fbfcf0bf79942623b84f883e9223f008f24497ae60937802a6315' + +mcd_src = get_option('mongo-c-driver-dir') +if mcd_src == '' + # Fallback: the CI action pre-fetches and extracts the release tarball here. + fallback = meson.project_source_root() / '.mongo-c-driver' / 'mongo-c-driver-@0@'.format(mcd_version) + if not fs.is_dir(fallback) + # Nothing pre-fetched, so fetch the pinned release now. This lets an + # sdist install build itself without a separate setup step. + fetch = run_command( + py, + meson.project_source_root() / 'scripts' / 'fetch_mongo_c_driver.py', + check: false, + ) + if fetch.returncode() != 0 + error('Failed to fetch mongo-c-driver:\n' + fetch.stdout() + fetch.stderr()) + endif + endif + if fs.is_dir(fallback) + mcd_src = fallback + endif +endif +if mcd_src == '' or not fs.is_dir(mcd_src) + error('mongo-c-driver source dir not found. Set -Dmongo-c-driver-dir or extract the tarball to .mongo-c-driver/mongo-c-driver-@0@.'.format(mcd_version)) +endif + +bson_src_dir = mcd_src / 'src' / 'libbson' / 'src' +common_src_dir = mcd_src / 'src' / 'common' / 'src' + +# Generated headers (config.h, version.h) from the CMake templates. The +# feature probes mirror upstream's src/libbson/CMakeLists.txt, which runs +# CMake's check_include_file/check_symbol_exists/check_struct_has_member on +# every platform; cc.has_header()/cc.has_function()/cc.has_member() are the +# Meson equivalents. +mcd_ver_comps = mcd_version.split('.') +libbson_major = mcd_ver_comps[0].to_int() +libbson_minor = mcd_ver_comps[1].to_int() +libbson_patch = mcd_ver_comps[2].to_int() +conf = configuration_data() +if host_machine.endian() == 'little' + conf.set('BSON_BYTE_ORDER', 1234) +else + conf.set('BSON_BYTE_ORDER', 4321) +endif +conf.set('BSON_OS', host_machine.system() == 'windows' ? 2 : 1) +conf.set('BSON_HAVE_STRINGS_H', cc.has_header('strings.h') ? 1 : 0) +conf.set('BSON_HAVE_STRNLEN', cc.has_function('strnlen', prefix: '#include ', args: feature_args) ? 1 : 0) +conf.set('BSON_HAVE_CLOCK_GETTIME', cc.has_function('clock_gettime', prefix: '#include ', args: feature_args) ? 1 : 0) +conf.set('BSON_HAVE_GMTIME_R', cc.has_function('gmtime_r', prefix: '#include ', args: feature_args) ? 1 : 0) +conf.set('BSON_HAVE_RAND_R', cc.has_function('rand_r', prefix: '#include ', args: feature_args) ? 1 : 0) +conf.set('BSON_HAVE_TIMESPEC', cc.has_member('struct timespec', 'tv_sec', prefix: '#include ', args: feature_args) ? 1 : 0) +conf.set('BSON_HAVE_STRLCPY', cc.has_function('strlcpy', prefix: '#include ', args: feature_args) ? 1 : 0) +conf.set('BSON_HAVE_STDBOOL_H', cc.has_header('stdbool.h') ? 1 : 0) +conf.set('BSON_HAVE_SNPRINTF', cc.has_function('snprintf', prefix: '#include ', args: feature_args) ? 1 : 0) +# aligned_alloc is C11 and is not declared under -std=c99. +conf.set('BSON_HAVE_ALIGNED_ALLOC', 0) +version_conf = configuration_data() +version_conf.set('libbson_VERSION_MAJOR', libbson_major) +version_conf.set('libbson_VERSION_MINOR', libbson_minor) +version_conf.set('libbson_VERSION_PATCH', libbson_patch) +version_conf.set('libbson_VERSION_FULL', mcd_version) +version_conf.set('libbson_VERSION_PRERELEASE', '') +subdir('bson') +# common-config.h is included by the common/ sources; the build dir is on the +# include path (via inc_flags), so this generated header resolves as . +common_conf = configuration_data() +common_conf.set('MONGOC_ENABLE_DEBUG_ASSERTIONS', 0) +configure_file(input: common_src_dir / 'common-config.h.in', + output: 'common-config.h', configuration: common_conf) + +# --- libbson static library -------------------------------------------- +# Meson rejects absolute source-tree paths in include_directories, and the +# libbson tree lives in .mongo-c-driver/ (or an externally supplied dir), so +# pass the include dirs as -I flags in c_args. +bson_incs = [ + bson_src_dir, + bson_src_dir / 'bson', + common_src_dir, + meson.current_build_dir(), +] +inc_flags = [] +foreach d : bson_incs + inc_flags += '-I' + d +endforeach +libbson_src = [ + common_src_dir / 'common-atomic.c', + common_src_dir / 'common-b64.c', + common_src_dir / 'common-json.c', + common_src_dir / 'common-md5.c', + common_src_dir / 'common-oid.c', + common_src_dir / 'common-string.c', + common_src_dir / 'common-thread.c', + bson_src_dir / 'bson' / 'bson.c', + bson_src_dir / 'bson' / 'bson-bcon.c', + bson_src_dir / 'bson' / 'bson-clock.c', + bson_src_dir / 'bson' / 'bson-context.c', + bson_src_dir / 'bson' / 'bson-decimal128.c', + bson_src_dir / 'bson' / 'bson-iso8601.c', + bson_src_dir / 'bson' / 'bson-iter.c', + bson_src_dir / 'bson' / 'bson-json.c', + bson_src_dir / 'bson' / 'bson-keys.c', + bson_src_dir / 'bson' / 'bson-oid.c', + bson_src_dir / 'bson' / 'bson-reader.c', + bson_src_dir / 'bson' / 'bson-string.c', + bson_src_dir / 'bson' / 'bson-timegm.c', + bson_src_dir / 'bson' / 'bson-utf8.c', + bson_src_dir / 'bson' / 'bson-value.c', + bson_src_dir / 'bson' / 'bson-vector.c', + bson_src_dir / 'bson' / 'bson-version-functions.c', + bson_src_dir / 'bson' / 'error.c', + bson_src_dir / 'bson' / 'memory.c', + bson_src_dir / 'bson' / 'validate.c', + bson_src_dir / 'jsonsl' / 'jsonsl.c', +] +libbson = static_library('bson', + libbson_src, + c_args: ['-DBSON_COMPILATION', '-DBSON_STATIC', '-DJSONSL_PARSE_NAN'] + inc_flags, +) + +# --- Python extension module (Limited API / abi3) ------------------------ +# libbson's bson-context.c calls gethostname, which lives in ws2_32.lib on +# Windows; find_library resolves it to the import library (a bare 'ws2_32' +# link arg would be treated as an .obj and fail with LNK1181). +ws2_32 = cc.find_library('ws2_32', required: false) +# bsonjs.__version__ comes from this macro. The project version is also the +# wheel metadata version: pyproject.toml declares the version dynamically and +# meson-python feeds it from here, so meson.build is the single source. +bsonjs_version = meson.project_version() + +py.extension_module( + 'bsonjs', + 'bsonjs/bsonjs.c', + c_args: ['-DBSON_STATIC', '-DBSONJS_VERSION="@0@"'.format(bsonjs_version)] + inc_flags, + link_with: libbson, + dependencies: ws2_32.found() ? [ws2_32] : [], + install: true, + limited_api: '3.11', +) diff --git a/meson_options.txt b/meson_options.txt new file mode 100644 index 0000000..79b6822 --- /dev/null +++ b/meson_options.txt @@ -0,0 +1,2 @@ +option('mongo-c-driver-dir', type: 'string', value: '', + description: 'Path to the extracted mongo-c-driver source tree') diff --git a/pyproject.toml b/pyproject.toml index 5195552..395f9d1 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,17 +1,16 @@ [build-system] -requires = ["setuptools>=65"] -build-backend = "setuptools.build_meta" - -[tool.setuptools] -packages = [] +requires = ["meson-python>=0.17", "meson>=1.3", "ninja"] +build-backend = "mesonpy" [project] name = "python-bsonjs" -version = "0.8.0.dev0" +# The version lives in meson.build (project()); meson-python feeds it here so +# the wheel metadata and the bsonjs.__version__ macro cannot drift apart. +dynamic = ["version"] description = "A library for converting between BSON and JSON." readme = "README.rst" license = { file = "LICENSE" } -requires-python = ">=3.9" +requires-python = ">=3.11" authors = [ { name = "Shane Harvey", email = "shane.harvey@mongodb.com" }, ] @@ -29,9 +28,7 @@ classifiers = [ "Operating System :: POSIX", "Programming Language :: Python :: 3", "Programming Language :: Python :: 3 :: Only", - "Programming Language :: Python :: 3.9", "Programming Language :: Python :: Implementation :: CPython", - "Programming Language :: Python :: 3.10", "Programming Language :: Python :: 3.11", "Programming Language :: Python :: 3.12", "Programming Language :: Python :: 3.13", @@ -44,13 +41,21 @@ Homepage = "https://github.com/mongodb-labs/python-bsonjs" [project.optional-dependencies] test = ["pymongo>=4", "pytest"] +[tool.meson-python] +# Build a single stable-ABI (abi3) wheel: meson-python tags it cp311-abi3 and +# Meson auto-detects MSVC on Windows (no MinGW fallback). +limited-api = true + [tool.cibuildwheel] test-command = "pytest {package}/test" test-extras = ["test"] -skip = ["cp314t-*"] +skip = ["cp314t-*", "cp315t-*"] # Use abi3audit to catch issues with Limited API wheels [tool.cibuildwheel.linux] +# Best-effort: make ccache available in the manylinux container so the +# compiler launcher picks it up. CCACHE_DIR is passed through by cibuildwheel. +before-all = "yum install -y ccache || true" repair-wheel-command = [ "auditwheel repair -w {dest_dir} {wheel}", "pipx run abi3audit --strict --report {wheel}", @@ -61,6 +66,14 @@ repair-wheel-command = [ "pipx run abi3audit --strict --report {wheel}", ] [tool.cibuildwheel.windows] +# Meson picks MinGW gcc by default on GitHub Actions Windows; --vsenv makes it +# set up the Visual Studio (MSVC) environment instead. +config-settings = { "setup-args" = "--vsenv" } +# Build both 64-bit and 32-bit wheels. The 32-bit build must run with the x86 +# MSVC toolset in the environment: meson's --vsenv only ever activates the +# x64 toolset, and it rejects a 32-bit Python against an x64 compiler. The +# dist.yml workflow activates vcvarsall x86 for the x86 cibuildwheel run. +archs = ["AMD64", "x86"] repair-wheel-command = [ "copy {wheel} {dest_dir}", "pipx run abi3audit --strict --report {wheel}", diff --git a/benchmark.py b/scripts/benchmark.py similarity index 100% rename from benchmark.py rename to scripts/benchmark.py diff --git a/scripts/bump-libbson.sh b/scripts/bump-libbson.sh new file mode 100755 index 0000000..88c18f3 --- /dev/null +++ b/scripts/bump-libbson.sh @@ -0,0 +1,49 @@ +#!/usr/bin/env bash +set -eu + +# Usage: bump-libbson.sh [LIBBSON_VERSION] +# With no argument, fetches the latest released mongo-c-driver tag. If the +# repo already pins that version, prints that it is up to date and exits +# without installing or benchmarking. + +SELF_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +REPO_ROOT="$(cd "${SELF_DIR}/.." && pwd)" +BENCHMARK="${SELF_DIR}/benchmark.py" +BUMP_PY="${SELF_DIR}/bump_libbson.py" + +# --- Determine the libbson version to bump to --- +CURRENT_VERSION=$(python3 "${BUMP_PY}" current) +LATEST_VERSION=$(python3 "${BUMP_PY}" latest) + +if [ -z "${1:-}" ]; then + LIBBSON_VERSION="$LATEST_VERSION" + if [ "$LIBBSON_VERSION" == "$CURRENT_VERSION" ]; then + echo "libbson is already up to date (${CURRENT_VERSION})." + exit 0 + fi + echo "Found latest libbson ${LATEST_VERSION}; current is ${CURRENT_VERSION}." +else + LIBBSON_VERSION="$1" +fi + +# 1. Update the libbson version in meson.build, the README About line, +# and the CHANGELOG 0.8.0 entry. +python3 "${BUMP_PY}" update-versions "$LIBBSON_VERSION" +echo "Updated libbson version to: ${LIBBSON_VERSION}" + +# 2. Install the package and the latest stable pymongo. +cd "${REPO_ROOT}" +python3 -m pip install -e ".[test]" +python3 -m pip install --upgrade "pymongo>=4" + +# 3. Run the benchmark, capturing raw output. +BENCHMARK_OUT=$(mktemp) +trap 'rm -f "$BENCHMARK_OUT"' EXIT +python3 "${BENCHMARK}" > "$BENCHMARK_OUT" 2>&1 +echo "Benchmark:" +sed 's/^/ /' "$BENCHMARK_OUT" + +# 4. Update the README Speed section with the results and versions. +PYMONGO_VERSION=$(python3 -c "import pymongo; print(pymongo.version)") +python3 "${BUMP_PY}" update-readme "$LIBBSON_VERSION" "$PYMONGO_VERSION" "$BENCHMARK_OUT" +echo "Updated README.rst (libbson ${LIBBSON_VERSION}, pymongo ${PYMONGO_VERSION})." diff --git a/scripts/bump_libbson.py b/scripts/bump_libbson.py new file mode 100644 index 0000000..0d776ee --- /dev/null +++ b/scripts/bump_libbson.py @@ -0,0 +1,213 @@ +#!/usr/bin/env python3 +"""Version bump helper used by bump-libbson.sh.""" + +import argparse +import hashlib +import json +import re +import urllib.request +from pathlib import Path + +REPO_ROOT = Path(__file__).resolve().parent.parent +README = REPO_ROOT / "README.rst" +CHANGELOG = REPO_ROOT / "CHANGELOG.rst" +MESON_BUILD = REPO_ROOT / "meson.build" + +LATEST_RELEASE_URL = ( + "https://api.github.com/repos/mongodb/mongo-c-driver/releases/latest" +) +RELEASE_URL = ( + "https://github.com/mongodb/mongo-c-driver/releases/download/" + "{version}/mongo-c-driver-{version}.tar.gz" +) + + +def package_version(): + """Return the package release version (X.Y.Z) from meson.build.""" + text = (REPO_ROOT / "meson.build").read_text() + m = re.search(r"(?/ + sub_file( + README, + r"(mongoc\.org/libbson/)[0-9]+\.[0-9]+\.[0-9]+/", + r"\g<1>{}/".format(version), + "README About link", + ) + # CHANGELOG section for the current package release. Scope the edits to + # that section only so historic entries are left alone; the lower bound is + # the next section header (any version), so future bumps stay correct. + changelog = CHANGELOG.read_text() + ver = re.escape(package_version()) + sec = re.search( + r"(?ms)^{ver}\s*\n\s*```+\s*\n.*?(?=^\d+\.\d+\.\d+\s*\n\s*```+)".format( + ver=ver + ), + changelog, + ) + if not sec: + raise SystemExit("Could not find the CHANGELOG {} section".format(ver)) + block = sec.group(0) + patterns = ( + (r"libbson [0-9]+\.[0-9]+\.[0-9]+ from source", + "libbson {} from source".format(version)), + (r"mongo-c-driver/blob/[0-9]+\.[0-9]+\.[0-9]+/NEWS", + "mongo-c-driver/blob/{}/NEWS".format(version)), + (r"mongoc\.org/libbson/[0-9]+\.[0-9]+\.[0-9]+/", + "mongoc.org/libbson/{}/".format(version)), + ) + if not any(re.search(p, block) for p, _ in patterns): + raise SystemExit("Could not update the CHANGELOG {} entry".format(ver)) + for pattern, repl in patterns: + block = re.sub(pattern, repl, block) + CHANGELOG.write_text(changelog[:sec.start()] + block + changelog[sec.end():]) + + +def update_readme(version, pymongo_version, bench_path): + """Rewrite the README Speed section using the measured benchmark output.""" + bench = Path(bench_path).read_text() + + ratios = [float(x) for x in re.findall(r"bsonjs is ([0-9.]+?)x faster", bench)] + if len(ratios) != 2: + raise SystemExit("Expected two benchmark ratios, got: {}".format(ratios)) + lo, hi = min(ratios), max(ratios) + + raw_numbers = re.findall(r"best of 3: ([0-9.e+-]+)", bench) + if len(raw_numbers) != 4: + raise SystemExit( + "Expected four benchmark timings, got: {}".format(raw_numbers) + ) + dumps_bsonjs, dumps_json_util, loads_bsonjs, loads_json_util = raw_numbers + + new_block = """Speed +===== + +bsonjs is roughly {lo:.0f}-{hi:.0f}x faster than PyMongo {pymongo_version}'s +json_util at decoding BSON to JSON and encoding JSON to BSON. Benchmarked +against libbson {libbson_version}. See `scripts/benchmark.py`:: + + $ python scripts/benchmark.py + Timing: bsonjs.dumps(b) + 10000 loops, best of 3: {dumps_bsonjs} + Timing: json_util.dumps(bson.decode(b)) + 10000 loops, best of 3: {dumps_json_util} + bsonjs is {dumps_ratio:.2f}x faster than json_util + + Timing: bsonjs.loads(j) + 10000 loops, best of 3: {loads_bsonjs} + Timing: bson.encode(json_util.loads(j)) + 10000 loops, best of 3: {loads_json_util} + bsonjs is {loads_ratio:.2f}x faster than json_util +""".format( + lo=lo, + hi=hi, + pymongo_version=pymongo_version, + libbson_version=version, + dumps_bsonjs=dumps_bsonjs, + dumps_json_util=dumps_json_util, + dumps_ratio=ratios[0], + loads_bsonjs=loads_bsonjs, + loads_json_util=loads_json_util, + loads_ratio=ratios[1], + ) + + readme = README.read_text() + speedy = re.compile(r"Speed\n=====\n\n.*?(?=\nLimitations)", re.DOTALL) + if not speedy.search(readme): + raise SystemExit("Could not find the Speed section in README.rst") + README.write_text(speedy.sub(new_block, readme, count=1)) + + +def main(): + parser = argparse.ArgumentParser() + sub = parser.add_subparsers(dest="cmd", required=True) + sub.add_parser("current") + sub.add_parser("latest") + sub.add_parser("update-versions").add_argument("version") + readme = sub.add_parser("update-readme") + readme.add_argument("version") + readme.add_argument("pymongo_version") + readme.add_argument("bench_path") + args = parser.parse_args() + + if args.cmd == "current": + print(current_version()) + elif args.cmd == "latest": + print(latest_version()) + elif args.cmd == "update-versions": + update_versions(args.version) + elif args.cmd == "update-readme": + update_readme(args.version, args.pymongo_version, args.bench_path) + + +if __name__ == "__main__": + main() diff --git a/scripts/fetch_mongo_c_driver.py b/scripts/fetch_mongo_c_driver.py new file mode 100644 index 0000000..ca5c57a --- /dev/null +++ b/scripts/fetch_mongo_c_driver.py @@ -0,0 +1,125 @@ +#!/usr/bin/env python3 +"""Fetch and extract the mongo-c-driver release pinned in meson.build.""" + +import argparse +import hashlib +import re +import sys +import tarfile +import urllib.request +from pathlib import Path + +REPO_ROOT = Path(__file__).resolve().parent.parent +MESON_BUILD = REPO_ROOT / "meson.build" +DEFAULT_DEST = REPO_ROOT / ".mongo-c-driver" +RELEASE_URL = ( + "https://github.com/mongodb/mongo-c-driver/releases/download/" + "{version}/mongo-c-driver-{version}.tar.gz" +) +CONFIG_H = "src/libbson/src/bson/config.h.in" + + +def _log(message): + print(message, file=sys.stderr) + + +def _meson_value(pattern, description): + match = re.search(pattern, MESON_BUILD.read_text(), re.MULTILINE) + if not match: + raise SystemExit("Could not read {} from meson.build".format(description)) + return match.group(1) + + +def pinned_version(): + """Return the mongo-c-driver version pinned in meson.build.""" + return _meson_value( + r"mcd_version\s*=\s*'([0-9]+\.[0-9]+\.[0-9]+)'", "the mongo-c-driver version" + ) + + +def pinned_sha256(): + """Return the tarball SHA256 pinned in meson.build.""" + return _meson_value(r"mcd_sha256\s*=\s*'([0-9a-f]{64})'", "mcd_sha256") + + +def sha256_of(path): + """Return the hex SHA256 digest of path.""" + digest = hashlib.sha256() + with path.open("rb") as handle: + for chunk in iter(lambda: handle.read(1024 * 1024), b""): + digest.update(chunk) + return digest.hexdigest() + + +def download(url, dest): + """Download url to dest.""" + _log("[bsonjs] downloading {}".format(url)) + request = urllib.request.Request(url, headers={"User-Agent": "python-bsonjs"}) + with urllib.request.urlopen(request, timeout=180) as response, dest.open( + "wb" + ) as handle: + while True: + chunk = response.read(1024 * 1024) + if not chunk: + break + handle.write(chunk) + + +def extract(tarball, dest_root): + """Extract tarball into dest_root.""" + with tarfile.open(tarball) as archive: + if sys.version_info >= (3, 12): + archive.extractall(dest_root, filter="data") + else: + archive.extractall(dest_root) + + +def fetch(dest_root): + """Ensure the pinned mongo-c-driver release is extracted under dest_root. + + Returns the extracted source directory. Reuses an existing extraction. + """ + version = pinned_version() + expected = pinned_sha256() + srcdir = dest_root / "mongo-c-driver-{}".format(version) + if (srcdir / CONFIG_H).is_file(): + _log("[bsonjs] mongo-c-driver {} already extracted".format(version)) + return srcdir + dest_root.mkdir(parents=True, exist_ok=True) + tarball = dest_root / "mongo-c-driver-{}.tar.gz".format(version) + if tarball.is_file() and sha256_of(tarball) != expected: + _log("[bsonjs] cached tarball checksum mismatch; re-downloading") + tarball.unlink() + if not tarball.is_file(): + download(RELEASE_URL.format(version=version), tarball) + actual = sha256_of(tarball) + if actual != expected: + tarball.unlink() + raise SystemExit( + "SHA256 mismatch for mongo-c-driver {}: expected {}, got {}".format( + version, expected, actual + ) + ) + extract(tarball, dest_root) + if not (srcdir / CONFIG_H).is_file(): + raise SystemExit("Extraction of mongo-c-driver {} failed".format(version)) + _log("[bsonjs] extracted mongo-c-driver {} to {}".format(version, srcdir)) + return srcdir + + +def main(): + parser = argparse.ArgumentParser(description=__doc__) + parser.add_argument("--dest", type=Path, default=DEFAULT_DEST) + parser.add_argument( + "--print-srcdir", + action="store_true", + help="print the extracted source directory to stdout", + ) + args = parser.parse_args() + srcdir = fetch(args.dest) + if args.print_srcdir: + print(srcdir) + + +if __name__ == "__main__": + main() diff --git a/setup.py b/setup.py deleted file mode 100644 index 7b89aeb..0000000 --- a/setup.py +++ /dev/null @@ -1,61 +0,0 @@ -# Copyright 2016 MongoDB, Inc. -# -# 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. - -import glob -import re -import sys -from pathlib import Path - -from setuptools import setup, Extension - - -def _read_version(): - """Read the package version from pyproject.toml. - - Keeps bsonjs.__version__ from drifting out of sync with the - package version, since this extension has no pure-Python __init__.py - to derive it from package metadata at import time instead. - """ - text = (Path(__file__).parent / "pyproject.toml").read_text() - match = re.search(r'(?m)^version\s*=\s*"([^"]+)"', text) - if not match: - raise RuntimeError("Could not find version in pyproject.toml") - return match.group(1) - - -libraries = [] -if sys.platform == "win32": - libraries.append("ws2_32") -elif sys.platform != "darwin": - # librt may be needed for clock_gettime() - libraries.append("rt") - -setup( - ext_modules=[ - Extension( - "bsonjs", - sources=["bsonjs/bsonjs.c"] + glob.glob("bsonjs/*/*.c"), - include_dirs=["bsonjs", - "bsonjs/bson", - "bsonjs/jsonsl", - "bsonjs/common"], - py_limited_api=True, - define_macros=[("BSON_COMPILATION", 1), - ("Py_LIMITED_API", "0x03090000"), - ("BSONJS_VERSION", '"%s"' % _read_version())], - libraries=libraries - ) - ], - options={'bdist_wheel': {'py_limited_api': 'cp39'} } -) diff --git a/vendor.sh b/vendor.sh deleted file mode 100644 index af34580..0000000 --- a/vendor.sh +++ /dev/null @@ -1,27 +0,0 @@ -#!/bin/bash -set -eu -VERSION="1.27.2" -rm -rf mongo-c-driver -git clone git@github.com:mongodb/mongo-c-driver.git -pushd mongo-c-driver -git checkout $VERSION -python build/calc_release_version.py > VERSION_CURRENT -mkdir cmake-build && cd cmake-build -cmake -DENABLE_AUTOMATIC_INIT_AND_CLEANUP=OFF -DENABLE_MONGOC=OFF .. -popd -rm -r bsonjs/bson -rm -r bsonjs/jsonsl -rm -r bsonjs/common -rsync -r mongo-c-driver/src/libbson/src/bson/*.[hc] bsonjs/bson/ -rsync -r mongo-c-driver/src/libbson/src/jsonsl/*.[hc] bsonjs/jsonsl/ -rsync -r mongo-c-driver/src/libbson/src/jsonsl/LICENSE bsonjs/jsonsl/ - -rsync -r mongo-c-driver/src/common/*.[hc] bsonjs/common/ -rsync -r mongo-c-driver/cmake-build/src/common/*.[hc] bsonjs/common/ - -rsync -r mongo-c-driver/cmake-build/src/libbson/src/bson/*.[hc] bsonjs/bson/ - -# Ignore autogenerated bson-config.h -git diff -- bsonjs/bson/bson-config.h | tee -echo "**** Review libbson's autogenerated src/bson/bson-config.h (above) for newly added (or removed) macros ****" -git checkout -- bsonjs/bson/bson-config.h